]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
gtk/gtkadjustment.c gtk/gtkclist.c gtk/gtkcolorsel.c gtk/gtkiconview.c
[~andy/gtk] / gtk / gtkiconview.c
1 /* gtkiconview.c
2  * Copyright (C) 2002, 2004  Anders Carlsson <andersca@gnu.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include <string.h>
22
23 #include <atk/atk.h>
24
25 #include <gdk/gdkkeysyms.h>
26
27 #include "gtkiconview.h"
28 #include "gtkcelllayout.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkcellrenderertext.h"
31 #include "gtkcellrendererpixbuf.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbindings.h"
34 #include "gtkdnd.h"
35 #include "gtkmain.h"
36 #include "gtkintl.h"
37 #include "gtkaccessible.h"
38 #include "gtkwindow.h"
39 #include "gtkentry.h"
40 #include "gtkcombobox.h"
41 #include "gtktextbuffer.h"
42 #include "gtktreednd.h"
43 #include "gtkprivate.h"
44 #include "gtkalias.h"
45
46 #undef DEBUG_ICON_VIEW
47
48 #define SCROLL_EDGE_SIZE 15
49
50 #define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
51
52 typedef struct _GtkIconViewItem GtkIconViewItem;
53 struct _GtkIconViewItem
54 {
55   GtkTreeIter iter;
56   gint index;
57   
58   gint row, col;
59
60   /* Bounding box */
61   gint x, y, width, height;
62
63   /* Individual cells.
64    * box[i] is the actual area occupied by cell i,
65    * before, after are used to calculate the cell 
66    * area relative to the box. 
67    * See gtk_icon_view_get_cell_area().
68    */
69   gint n_cells;
70   GdkRectangle *box;
71   gint *before;
72   gint *after;
73
74   guint selected : 1;
75   guint selected_before_rubberbanding : 1;
76
77 };
78
79 typedef struct _GtkIconViewCellInfo GtkIconViewCellInfo;
80 struct _GtkIconViewCellInfo
81 {
82   GtkCellRenderer *cell;
83
84   guint expand : 1;
85   guint pack : 1;
86   guint editing : 1;
87
88   gint position;
89
90   GSList *attributes;
91
92   GtkCellLayoutDataFunc func;
93   gpointer func_data;
94   GDestroyNotify destroy;
95 };
96
97 typedef struct _GtkIconViewChild GtkIconViewChild;
98 struct _GtkIconViewChild
99 {
100   GtkWidget *widget;
101   GtkIconViewItem *item;
102   gint cell;
103 };
104
105 struct _GtkIconViewPrivate
106 {
107   gint width, height;
108
109   GtkSelectionMode selection_mode;
110
111   GdkWindow *bin_window;
112
113   GList *children;
114
115   GtkTreeModel *model;
116   
117   GList *items;
118   
119   GtkAdjustment *hadjustment;
120   GtkAdjustment *vadjustment;
121
122   guint layout_idle_id;
123   
124   gboolean doing_rubberband;
125   gint rubberband_x1, rubberband_y1;
126   gint rubberband_x2, rubberband_y2;
127
128   guint scroll_timeout_id;
129   gint scroll_value_diff;
130   gint event_last_x, event_last_y;
131
132   GtkIconViewItem *anchor_item;
133   GtkIconViewItem *cursor_item;
134   GtkIconViewItem *edited_item;
135   GtkCellEditable *editable;
136
137   GtkIconViewItem *last_single_clicked;
138
139   GList *cell_list;
140   guint n_cells;
141
142   gint cursor_cell;
143
144   GtkOrientation orientation;
145
146   gint columns;
147   gint item_width;
148   gint spacing;
149   gint row_spacing;
150   gint column_spacing;
151   gint margin;
152
153   gint text_column;
154   gint markup_column;
155   gint pixbuf_column;
156
157   gint pixbuf_cell;
158   gint text_cell;
159
160   gint tooltip_column;
161
162   /* Drag-and-drop. */
163   GdkModifierType start_button_mask;
164   gint pressed_button;
165   gint press_start_x;
166   gint press_start_y;
167
168   GtkTargetList *source_targets;
169   GdkDragAction source_actions;
170
171   GtkTargetList *dest_targets;
172   GdkDragAction dest_actions;
173
174   GtkTreeRowReference *dest_item;
175   GtkIconViewDropPosition dest_pos;
176
177   /* scroll to */
178   GtkTreeRowReference *scroll_to_path;
179   gfloat scroll_to_row_align;
180   gfloat scroll_to_col_align;
181   guint scroll_to_use_align : 1;
182
183   guint source_set : 1;
184   guint dest_set : 1;
185   guint reorderable : 1;
186   guint empty_view_drop :1;
187
188   guint ctrl_pressed : 1;
189   guint shift_pressed : 1;  
190 };
191
192 /* Signals */
193 enum
194 {
195   ITEM_ACTIVATED,
196   SELECTION_CHANGED,
197   SELECT_ALL,
198   UNSELECT_ALL,
199   SELECT_CURSOR_ITEM,
200   TOGGLE_CURSOR_ITEM,
201   MOVE_CURSOR,
202   ACTIVATE_CURSOR_ITEM,
203   LAST_SIGNAL
204 };
205
206 /* Properties */
207 enum
208 {
209   PROP_0,
210   PROP_PIXBUF_COLUMN,
211   PROP_TEXT_COLUMN,
212   PROP_MARKUP_COLUMN,  
213   PROP_SELECTION_MODE,
214   PROP_ORIENTATION,
215   PROP_MODEL,
216   PROP_COLUMNS,
217   PROP_ITEM_WIDTH,
218   PROP_SPACING,
219   PROP_ROW_SPACING,
220   PROP_COLUMN_SPACING,
221   PROP_MARGIN,
222   PROP_REORDERABLE,
223   PROP_TOOLTIP_COLUMN
224 };
225
226 /* GObject vfuncs */
227 static void             gtk_icon_view_cell_layout_init          (GtkCellLayoutIface *iface);
228 static void             gtk_icon_view_finalize                  (GObject            *object);
229 static void             gtk_icon_view_set_property              (GObject            *object,
230                                                                  guint               prop_id,
231                                                                  const GValue       *value,
232                                                                  GParamSpec         *pspec);
233 static void             gtk_icon_view_get_property              (GObject            *object,
234                                                                  guint               prop_id,
235                                                                  GValue             *value,
236                                                                  GParamSpec         *pspec);
237
238 /* GtkObject vfuncs */
239 static void             gtk_icon_view_destroy                   (GtkObject          *object);
240
241 /* GtkWidget vfuncs */
242 static void             gtk_icon_view_realize                   (GtkWidget          *widget);
243 static void             gtk_icon_view_unrealize                 (GtkWidget          *widget);
244 static void             gtk_icon_view_style_set                 (GtkWidget        *widget,
245                                                                  GtkStyle         *previous_style);
246 static void             gtk_icon_view_state_changed             (GtkWidget        *widget,
247                                                                  GtkStateType      previous_state);
248 static void             gtk_icon_view_size_request              (GtkWidget          *widget,
249                                                                  GtkRequisition     *requisition);
250 static void             gtk_icon_view_size_allocate             (GtkWidget          *widget,
251                                                                  GtkAllocation      *allocation);
252 static gboolean         gtk_icon_view_expose                    (GtkWidget          *widget,
253                                                                  GdkEventExpose     *expose);
254 static gboolean         gtk_icon_view_motion                    (GtkWidget          *widget,
255                                                                  GdkEventMotion     *event);
256 static gboolean         gtk_icon_view_button_press              (GtkWidget          *widget,
257                                                                  GdkEventButton     *event);
258 static gboolean         gtk_icon_view_button_release            (GtkWidget          *widget,
259                                                                  GdkEventButton     *event);
260 static gboolean         gtk_icon_view_key_press                 (GtkWidget          *widget,
261                                                                  GdkEventKey        *event);
262 static gboolean         gtk_icon_view_key_release               (GtkWidget          *widget,
263                                                                  GdkEventKey        *event);
264 static AtkObject       *gtk_icon_view_get_accessible            (GtkWidget          *widget);
265
266
267 /* GtkContainer vfuncs */
268 static void             gtk_icon_view_remove                    (GtkContainer       *container,
269                                                                  GtkWidget          *widget);
270 static void             gtk_icon_view_forall                    (GtkContainer       *container,
271                                                                  gboolean            include_internals,
272                                                                  GtkCallback         callback,
273                                                                  gpointer            callback_data);
274
275 /* GtkIconView vfuncs */
276 static void             gtk_icon_view_set_adjustments           (GtkIconView        *icon_view,
277                                                                  GtkAdjustment      *hadj,
278                                                                  GtkAdjustment      *vadj);
279 static void             gtk_icon_view_real_select_all           (GtkIconView        *icon_view);
280 static void             gtk_icon_view_real_unselect_all         (GtkIconView        *icon_view);
281 static void             gtk_icon_view_real_select_cursor_item   (GtkIconView        *icon_view);
282 static void             gtk_icon_view_real_toggle_cursor_item   (GtkIconView        *icon_view);
283 static gboolean         gtk_icon_view_real_activate_cursor_item (GtkIconView        *icon_view);
284
285  /* Internal functions */
286 static void                 gtk_icon_view_adjustment_changed             (GtkAdjustment          *adjustment,
287                                                                           GtkIconView            *icon_view);
288 static void                 gtk_icon_view_layout                         (GtkIconView            *icon_view);
289 static void                 gtk_icon_view_paint_item                     (GtkIconView            *icon_view,
290                                                                           cairo_t *cr,
291
292                                                                           GtkIconViewItem        *item,
293                                                                           GdkRectangle           *area,
294                                                                           GdkDrawable *drawable,
295                                                                           gint         x,
296                                                                           gint         y,
297                                                                           gboolean     draw_focus);
298 static void                 gtk_icon_view_paint_rubberband               (GtkIconView            *icon_view,
299                                                                           cairo_t *cr,
300                                                                           GdkRectangle           *area);
301 static void                 gtk_icon_view_queue_draw_path                (GtkIconView *icon_view,
302                                                                           GtkTreePath *path);
303 static void                 gtk_icon_view_queue_draw_item                (GtkIconView            *icon_view,
304                                                                           GtkIconViewItem        *item);
305 static void                 gtk_icon_view_queue_layout                   (GtkIconView            *icon_view);
306 static void                 gtk_icon_view_set_cursor_item                (GtkIconView            *icon_view,
307                                                                           GtkIconViewItem        *item,
308                                                                           gint                    cursor_cell);
309 static void                 gtk_icon_view_start_rubberbanding            (GtkIconView            *icon_view,
310                                                                           gint                    x,
311                                                                           gint                    y);
312 static void                 gtk_icon_view_stop_rubberbanding             (GtkIconView            *icon_view);
313 static void                 gtk_icon_view_update_rubberband_selection    (GtkIconView            *icon_view);
314 static gboolean             gtk_icon_view_item_hit_test                  (GtkIconView            *icon_view,
315                                                                           GtkIconViewItem        *item,
316                                                                           gint                    x,
317                                                                           gint                    y,
318                                                                           gint                    width,
319                                                                           gint                    height);
320 static gboolean             gtk_icon_view_unselect_all_internal          (GtkIconView            *icon_view);
321 static void                 gtk_icon_view_calculate_item_size            (GtkIconView            *icon_view,
322                                                                           GtkIconViewItem        *item);
323 static void                 gtk_icon_view_calculate_item_size2           (GtkIconView            *icon_view,
324                                                                           GtkIconViewItem        *item,
325                                                                           gint                   *max_height);
326 static void                 gtk_icon_view_update_rubberband              (gpointer                data);
327 static void                 gtk_icon_view_item_invalidate_size           (GtkIconViewItem        *item);
328 static void                 gtk_icon_view_invalidate_sizes               (GtkIconView            *icon_view);
329 static void                 gtk_icon_view_add_move_binding               (GtkBindingSet          *binding_set,
330                                                                           guint                   keyval,
331                                                                           guint                   modmask,
332                                                                           GtkMovementStep         step,
333                                                                           gint                    count);
334 static gboolean             gtk_icon_view_real_move_cursor               (GtkIconView            *icon_view,
335                                                                           GtkMovementStep         step,
336                                                                           gint                    count);
337 static void                 gtk_icon_view_move_cursor_up_down            (GtkIconView            *icon_view,
338                                                                           gint                    count);
339 static void                 gtk_icon_view_move_cursor_page_up_down       (GtkIconView            *icon_view,
340                                                                           gint                    count);
341 static void                 gtk_icon_view_move_cursor_left_right         (GtkIconView            *icon_view,
342                                                                           gint                    count);
343 static void                 gtk_icon_view_move_cursor_start_end          (GtkIconView            *icon_view,
344                                                                           gint                    count);
345 static void                 gtk_icon_view_scroll_to_item                 (GtkIconView            *icon_view,
346                                                                           GtkIconViewItem        *item);
347 static void                 gtk_icon_view_select_item                    (GtkIconView            *icon_view,
348                                                                           GtkIconViewItem        *item);
349 static void                 gtk_icon_view_unselect_item                  (GtkIconView            *icon_view,
350                                                                           GtkIconViewItem        *item);
351 static gboolean             gtk_icon_view_select_all_between             (GtkIconView            *icon_view,
352                                                                           GtkIconViewItem        *anchor,
353                                                                           GtkIconViewItem        *cursor);
354 static GtkIconViewItem *    gtk_icon_view_get_item_at_coords             (GtkIconView            *icon_view,
355                                                                           gint                    x,
356                                                                           gint                    y,
357                                                                           gboolean                only_in_cell,
358                                                                           GtkIconViewCellInfo   **cell_at_pos);
359 static void                 gtk_icon_view_get_cell_area                  (GtkIconView            *icon_view,
360                                                                           GtkIconViewItem        *item,
361                                                                           GtkIconViewCellInfo    *cell_info,
362                                                                           GdkRectangle           *cell_area);
363 static void                 gtk_icon_view_get_cell_box                   (GtkIconView            *icon_view,
364                                                                           GtkIconViewItem        *item,
365                                                                           GtkIconViewCellInfo    *info,
366                                                                           GdkRectangle           *box);
367 static GtkIconViewCellInfo *gtk_icon_view_get_cell_info                  (GtkIconView            *icon_view,
368                                                                           GtkCellRenderer        *renderer);
369 static void                 gtk_icon_view_set_cell_data                  (GtkIconView            *icon_view,
370                                                                           GtkIconViewItem        *item);
371 static void                 gtk_icon_view_cell_layout_pack_start         (GtkCellLayout          *layout,
372                                                                           GtkCellRenderer        *renderer,
373                                                                           gboolean                expand);
374 static void                 gtk_icon_view_cell_layout_pack_end           (GtkCellLayout          *layout,
375                                                                           GtkCellRenderer        *renderer,
376                                                                           gboolean                expand);
377 static void                 gtk_icon_view_cell_layout_add_attribute      (GtkCellLayout          *layout,
378                                                                           GtkCellRenderer        *renderer,
379                                                                           const gchar            *attribute,
380                                                                           gint                    column);
381 static void                 gtk_icon_view_cell_layout_clear              (GtkCellLayout          *layout);
382 static void                 gtk_icon_view_cell_layout_clear_attributes   (GtkCellLayout          *layout,
383                                                                           GtkCellRenderer        *renderer);
384 static void                 gtk_icon_view_cell_layout_set_cell_data_func (GtkCellLayout          *layout,
385                                                                           GtkCellRenderer        *cell,
386                                                                           GtkCellLayoutDataFunc   func,
387                                                                           gpointer                func_data,
388                                                                           GDestroyNotify          destroy);
389 static void                 gtk_icon_view_cell_layout_reorder            (GtkCellLayout          *layout,
390                                                                           GtkCellRenderer        *cell,
391                                                                           gint                    position);
392 static GList *              gtk_icon_view_cell_layout_get_cells          (GtkCellLayout          *layout);
393
394 static void                 gtk_icon_view_item_activate_cell             (GtkIconView            *icon_view,
395                                                                           GtkIconViewItem        *item,
396                                                                           GtkIconViewCellInfo    *cell_info,
397                                                                           GdkEvent               *event);
398 static void                 gtk_icon_view_item_selected_changed          (GtkIconView            *icon_view,
399                                                                           GtkIconViewItem        *item);
400 static void                 gtk_icon_view_put                            (GtkIconView            *icon_view,
401                                                                           GtkWidget              *widget,
402                                                                           GtkIconViewItem        *item,
403                                                                           gint                    cell);
404 static void                 gtk_icon_view_remove_widget                  (GtkCellEditable        *editable,
405                                                                           GtkIconView            *icon_view);
406 static void                 gtk_icon_view_start_editing                  (GtkIconView            *icon_view,
407                                                                           GtkIconViewItem        *item,
408                                                                           GtkIconViewCellInfo    *cell_info,
409                                                                           GdkEvent               *event);
410 static void                 gtk_icon_view_stop_editing                   (GtkIconView            *icon_view,
411                                                                           gboolean                cancel_editing);
412
413 /* Source side drag signals */
414 static void gtk_icon_view_drag_begin       (GtkWidget        *widget,
415                                             GdkDragContext   *context);
416 static void gtk_icon_view_drag_end         (GtkWidget        *widget,
417                                             GdkDragContext   *context);
418 static void gtk_icon_view_drag_data_get    (GtkWidget        *widget,
419                                             GdkDragContext   *context,
420                                             GtkSelectionData *selection_data,
421                                             guint             info,
422                                             guint             time);
423 static void gtk_icon_view_drag_data_delete (GtkWidget        *widget,
424                                             GdkDragContext   *context);
425
426 /* Target side drag signals */
427 static void     gtk_icon_view_drag_leave         (GtkWidget        *widget,
428                                                   GdkDragContext   *context,
429                                                   guint             time);
430 static gboolean gtk_icon_view_drag_motion        (GtkWidget        *widget,
431                                                   GdkDragContext   *context,
432                                                   gint              x,
433                                                   gint              y,
434                                                   guint             time);
435 static gboolean gtk_icon_view_drag_drop          (GtkWidget        *widget,
436                                                   GdkDragContext   *context,
437                                                   gint              x,
438                                                   gint              y,
439                                                   guint             time);
440 static void     gtk_icon_view_drag_data_received (GtkWidget        *widget,
441                                                   GdkDragContext   *context,
442                                                   gint              x,
443                                                   gint              y,
444                                                   GtkSelectionData *selection_data,
445                                                   guint             info,
446                                                   guint             time);
447 static gboolean gtk_icon_view_maybe_begin_drag   (GtkIconView             *icon_view,
448                                                   GdkEventMotion          *event);
449
450 static void     remove_scroll_timeout            (GtkIconView *icon_view);
451 static void     clear_dest_info                  (GtkIconView *icon_view);
452 static void     clear_source_info                (GtkIconView *icon_view);
453
454 static void     adjust_wrap_width                (GtkIconView     *icon_view,
455                                                   GtkIconViewItem *item);
456
457 /* GtkBuildable */
458 static GtkBuildableIface *parent_buildable_iface;
459 static void     gtk_icon_view_buildable_init             (GtkBuildableIface *iface);
460 static gboolean gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
461                                                           GtkBuilder    *builder,
462                                                           GObject       *child,
463                                                           const gchar   *tagname,
464                                                           GMarkupParser *parser,
465                                                           gpointer      *data);
466 static void     gtk_icon_view_buildable_custom_tag_end   (GtkBuildable  *buildable,
467                                                           GtkBuilder    *builder,
468                                                           GObject       *child,
469                                                           const gchar   *tagname,
470                                                           gpointer      *data);
471
472 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
473
474 G_DEFINE_TYPE_WITH_CODE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER,
475                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
476                                                 gtk_icon_view_cell_layout_init)
477                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
478                                                 gtk_icon_view_buildable_init))
479
480 static void
481 gtk_icon_view_class_init (GtkIconViewClass *klass)
482 {
483   GObjectClass *gobject_class;
484   GtkObjectClass *object_class;
485   GtkWidgetClass *widget_class;
486   GtkContainerClass *container_class;
487   GtkBindingSet *binding_set;
488   
489   binding_set = gtk_binding_set_by_class (klass);
490
491   g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
492
493   gobject_class = (GObjectClass *) klass;
494   object_class = (GtkObjectClass *) klass;
495   widget_class = (GtkWidgetClass *) klass;
496   container_class = (GtkContainerClass *) klass;
497
498   gobject_class->finalize = gtk_icon_view_finalize;
499   gobject_class->set_property = gtk_icon_view_set_property;
500   gobject_class->get_property = gtk_icon_view_get_property;
501
502   object_class->destroy = gtk_icon_view_destroy;
503   
504   widget_class->realize = gtk_icon_view_realize;
505   widget_class->unrealize = gtk_icon_view_unrealize;
506   widget_class->style_set = gtk_icon_view_style_set;
507   widget_class->get_accessible = gtk_icon_view_get_accessible;
508   widget_class->size_request = gtk_icon_view_size_request;
509   widget_class->size_allocate = gtk_icon_view_size_allocate;
510   widget_class->expose_event = gtk_icon_view_expose;
511   widget_class->motion_notify_event = gtk_icon_view_motion;
512   widget_class->button_press_event = gtk_icon_view_button_press;
513   widget_class->button_release_event = gtk_icon_view_button_release;
514   widget_class->key_press_event = gtk_icon_view_key_press;
515   widget_class->key_release_event = gtk_icon_view_key_release;
516   widget_class->drag_begin = gtk_icon_view_drag_begin;
517   widget_class->drag_end = gtk_icon_view_drag_end;
518   widget_class->drag_data_get = gtk_icon_view_drag_data_get;
519   widget_class->drag_data_delete = gtk_icon_view_drag_data_delete;
520   widget_class->drag_leave = gtk_icon_view_drag_leave;
521   widget_class->drag_motion = gtk_icon_view_drag_motion;
522   widget_class->drag_drop = gtk_icon_view_drag_drop;
523   widget_class->drag_data_received = gtk_icon_view_drag_data_received;
524   widget_class->state_changed = gtk_icon_view_state_changed;
525
526   container_class->remove = gtk_icon_view_remove;
527   container_class->forall = gtk_icon_view_forall;
528
529   klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
530   klass->select_all = gtk_icon_view_real_select_all;
531   klass->unselect_all = gtk_icon_view_real_unselect_all;
532   klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
533   klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
534   klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;  
535   klass->move_cursor = gtk_icon_view_real_move_cursor;
536   
537   /* Properties */
538   /**
539    * GtkIconView:selection-mode:
540    * 
541    * The ::selection-mode property specifies the selection mode of
542    * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
543    * is enabled, for the other modes, only keyboard selection is possible.
544    *
545    * Since: 2.6
546    */
547   g_object_class_install_property (gobject_class,
548                                    PROP_SELECTION_MODE,
549                                    g_param_spec_enum ("selection-mode",
550                                                       P_("Selection mode"),
551                                                       P_("The selection mode"),
552                                                       GTK_TYPE_SELECTION_MODE,
553                                                       GTK_SELECTION_SINGLE,
554                                                       GTK_PARAM_READWRITE));
555
556   /**
557    * GtkIconView:pixbuf-column:
558    *
559    * The ::pixbuf-column property contains the number of the model column
560    * containing the pixbufs which are displayed. The pixbuf column must be 
561    * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
562    * display of pixbufs.
563    *
564    * Since: 2.6
565    */
566   g_object_class_install_property (gobject_class,
567                                    PROP_PIXBUF_COLUMN,
568                                    g_param_spec_int ("pixbuf-column",
569                                                      P_("Pixbuf column"),
570                                                      P_("Model column used to retrieve the icon pixbuf from"),
571                                                      -1, G_MAXINT, -1,
572                                                      GTK_PARAM_READWRITE));
573
574   /**
575    * GtkIconView:text-column:
576    *
577    * The ::text-column property contains the number of the model column
578    * containing the texts which are displayed. The text column must be 
579    * of type #G_TYPE_STRING. If this property and the :markup-column 
580    * property are both set to -1, no texts are displayed.   
581    *
582    * Since: 2.6
583    */
584   g_object_class_install_property (gobject_class,
585                                    PROP_TEXT_COLUMN,
586                                    g_param_spec_int ("text-column",
587                                                      P_("Text column"),
588                                                      P_("Model column used to retrieve the text from"),
589                                                      -1, G_MAXINT, -1,
590                                                      GTK_PARAM_READWRITE));
591
592   
593   /**
594    * GtkIconView:markup-column:
595    *
596    * The ::markup-column property contains the number of the model column
597    * containing markup information to be displayed. The markup column must be 
598    * of type #G_TYPE_STRING. If this property and the :text-column property 
599    * are both set to column numbers, it overrides the text column.
600    * If both are set to -1, no texts are displayed.   
601    *
602    * Since: 2.6
603    */
604   g_object_class_install_property (gobject_class,
605                                    PROP_MARKUP_COLUMN,
606                                    g_param_spec_int ("markup-column",
607                                                      P_("Markup column"),
608                                                      P_("Model column used to retrieve the text if using Pango markup"),
609                                                      -1, G_MAXINT, -1,
610                                                      GTK_PARAM_READWRITE));
611   
612   g_object_class_install_property (gobject_class,
613                                    PROP_MODEL,
614                                    g_param_spec_object ("model",
615                                                         P_("Icon View Model"),
616                                                         P_("The model for the icon view"),
617                                                         GTK_TYPE_TREE_MODEL,
618                                                         GTK_PARAM_READWRITE));
619   
620   /**
621    * GtkIconView:columns:
622    *
623    * The columns property contains the number of the columns in which the
624    * items should be displayed. If it is -1, the number of columns will
625    * be chosen automatically to fill the available area.
626    *
627    * Since: 2.6
628    */
629   g_object_class_install_property (gobject_class,
630                                    PROP_COLUMNS,
631                                    g_param_spec_int ("columns",
632                                                      P_("Number of columns"),
633                                                      P_("Number of columns to display"),
634                                                      -1, G_MAXINT, -1,
635                                                      GTK_PARAM_READWRITE));
636   
637
638   /**
639    * GtkIconView:item-width:
640    *
641    * The item-width property specifies the width to use for each item. 
642    * If it is set to -1, the icon view will automatically determine a 
643    * suitable item size.
644    *
645    * Since: 2.6
646    */
647   g_object_class_install_property (gobject_class,
648                                    PROP_ITEM_WIDTH,
649                                    g_param_spec_int ("item-width",
650                                                      P_("Width for each item"),
651                                                      P_("The width used for each item"),
652                                                      -1, G_MAXINT, -1,
653                                                      GTK_PARAM_READWRITE));  
654
655   /**
656    * GtkIconView:spacing:
657    *
658    * The spacing property specifies the space which is inserted between
659    * the cells (i.e. the icon and the text) of an item.
660    *
661    * Since: 2.6
662    */
663   g_object_class_install_property (gobject_class,
664                                    PROP_SPACING,
665                                    g_param_spec_int ("spacing",
666                                                      P_("Spacing"),
667                                                      P_("Space which is inserted between cells of an item"),
668                                                      0, G_MAXINT, 0,
669                                                      GTK_PARAM_READWRITE));
670
671   /**
672    * GtkIconView:row-spacing:
673    *
674    * The row-spacing property specifies the space which is inserted between
675    * the rows of the icon view.
676    *
677    * Since: 2.6
678    */
679   g_object_class_install_property (gobject_class,
680                                    PROP_ROW_SPACING,
681                                    g_param_spec_int ("row-spacing",
682                                                      P_("Row Spacing"),
683                                                      P_("Space which is inserted between grid rows"),
684                                                      0, G_MAXINT, 6,
685                                                      GTK_PARAM_READWRITE));
686
687   /**
688    * GtkIconView:column-spacing:
689    *
690    * The column-spacing property specifies the space which is inserted between
691    * the columns of the icon view.
692    *
693    * Since: 2.6
694    */
695   g_object_class_install_property (gobject_class,
696                                    PROP_COLUMN_SPACING,
697                                    g_param_spec_int ("column-spacing",
698                                                      P_("Column Spacing"),
699                                                      P_("Space which is inserted between grid columns"),
700                                                      0, G_MAXINT, 6,
701                                                      GTK_PARAM_READWRITE));
702
703   /**
704    * GtkIconView:margin:
705    *
706    * The margin property specifies the space which is inserted 
707    * at the edges of the icon view.
708    *
709    * Since: 2.6
710    */
711   g_object_class_install_property (gobject_class,
712                                    PROP_MARGIN,
713                                    g_param_spec_int ("margin",
714                                                      P_("Margin"),
715                                                      P_("Space which is inserted at the edges of the icon view"),
716                                                      0, G_MAXINT, 6,
717                                                      GTK_PARAM_READWRITE));
718
719
720   /**
721    * GtkIconView:orientation:
722    *
723    * The orientation property specifies how the cells (i.e. the icon and 
724    * the text) of the item are positioned relative to each other.
725    *
726    * Since: 2.6
727    */
728   g_object_class_install_property (gobject_class,
729                                    PROP_ORIENTATION,
730                                    g_param_spec_enum ("orientation",
731                                                       P_("Orientation"),
732                                                       P_("How the text and icon of each item are positioned relative to each other"),
733                                                       GTK_TYPE_ORIENTATION,
734                                                       GTK_ORIENTATION_VERTICAL,
735                                                       GTK_PARAM_READWRITE));
736
737   /**
738    * GtkIconView:reorderable:
739    *
740    * The reorderable property specifies if the items can be reordered
741    * by DND.
742    *
743    * Since: 2.8
744    */
745   g_object_class_install_property (gobject_class,
746                                    PROP_REORDERABLE,
747                                    g_param_spec_boolean ("reorderable",
748                                                          P_("Reorderable"),
749                                                          P_("View is reorderable"),
750                                                          FALSE,
751                                                          G_PARAM_READWRITE));
752
753     g_object_class_install_property (gobject_class,
754                                      PROP_TOOLTIP_COLUMN,
755                                      g_param_spec_int ("tooltip-column",
756                                                        P_("Tooltip Column"),
757                                                        P_("The column in the model containing the tooltip texts for the items"),
758                                                        -1,
759                                                        G_MAXINT,
760                                                        -1,
761                                                        GTK_PARAM_READWRITE));
762
763
764
765   /* Style properties */
766   gtk_widget_class_install_style_property (widget_class,
767                                            g_param_spec_boxed ("selection-box-color",
768                                                                P_("Selection Box Color"),
769                                                                P_("Color of the selection box"),
770                                                                GDK_TYPE_COLOR,
771                                                                GTK_PARAM_READABLE));
772
773   gtk_widget_class_install_style_property (widget_class,
774                                            g_param_spec_uchar ("selection-box-alpha",
775                                                                P_("Selection Box Alpha"),
776                                                                P_("Opacity of the selection box"),
777                                                                0, 0xff,
778                                                                0x40,
779                                                                GTK_PARAM_READABLE));
780
781   /* Signals */
782   widget_class->set_scroll_adjustments_signal =
783     g_signal_new (I_("set_scroll_adjustments"),
784                   G_TYPE_FROM_CLASS (gobject_class),
785                   G_SIGNAL_RUN_LAST,
786                   G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
787                   NULL, NULL, 
788                   _gtk_marshal_VOID__OBJECT_OBJECT,
789                   G_TYPE_NONE, 2,
790                   GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
791
792   icon_view_signals[ITEM_ACTIVATED] =
793     g_signal_new (I_("item_activated"),
794                   G_TYPE_FROM_CLASS (gobject_class),
795                   G_SIGNAL_RUN_LAST,
796                   G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
797                   NULL, NULL,
798                   g_cclosure_marshal_VOID__BOXED,
799                   G_TYPE_NONE, 1,
800                   GTK_TYPE_TREE_PATH);
801
802   icon_view_signals[SELECTION_CHANGED] =
803     g_signal_new (I_("selection-changed"),
804                   G_TYPE_FROM_CLASS (gobject_class),
805                   G_SIGNAL_RUN_FIRST,
806                   G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
807                   NULL, NULL,
808                   g_cclosure_marshal_VOID__VOID,
809                   G_TYPE_NONE, 0);
810   
811   icon_view_signals[SELECT_ALL] =
812     g_signal_new (I_("select_all"),
813                   G_TYPE_FROM_CLASS (gobject_class),
814                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
815                   G_STRUCT_OFFSET (GtkIconViewClass, select_all),
816                   NULL, NULL,
817                   g_cclosure_marshal_VOID__VOID,
818                   G_TYPE_NONE, 0);
819   
820   icon_view_signals[UNSELECT_ALL] =
821     g_signal_new (I_("unselect_all"),
822                   G_TYPE_FROM_CLASS (gobject_class),
823                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
824                   G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
825                   NULL, NULL,
826                   g_cclosure_marshal_VOID__VOID,
827                   G_TYPE_NONE, 0);
828
829   icon_view_signals[SELECT_CURSOR_ITEM] =
830     g_signal_new (I_("select_cursor_item"),
831                   G_TYPE_FROM_CLASS (gobject_class),
832                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
833                   G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
834                   NULL, NULL,
835                   g_cclosure_marshal_VOID__VOID,
836                   G_TYPE_NONE, 0);
837
838   icon_view_signals[TOGGLE_CURSOR_ITEM] =
839     g_signal_new (I_("toggle_cursor_item"),
840                   G_TYPE_FROM_CLASS (gobject_class),
841                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
842                   G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
843                   NULL, NULL,
844                   g_cclosure_marshal_VOID__VOID,
845                   G_TYPE_NONE, 0);
846
847   icon_view_signals[ACTIVATE_CURSOR_ITEM] =
848     g_signal_new (I_("activate_cursor_item"),
849                   G_TYPE_FROM_CLASS (gobject_class),
850                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
851                   G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
852                   NULL, NULL,
853                   _gtk_marshal_BOOLEAN__VOID,
854                   G_TYPE_BOOLEAN, 0);
855   
856   icon_view_signals[MOVE_CURSOR] =
857     g_signal_new (I_("move_cursor"),
858                   G_TYPE_FROM_CLASS (gobject_class),
859                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
860                   G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
861                   NULL, NULL,
862                   _gtk_marshal_BOOLEAN__ENUM_INT,
863                   G_TYPE_BOOLEAN, 2,
864                   GTK_TYPE_MOVEMENT_STEP,
865                   G_TYPE_INT);
866
867   /* Key bindings */
868   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, 
869                                 "select_all", 0);
870   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, 
871                                 "unselect_all", 0);
872   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, 
873                                 "toggle_cursor_item", 0);
874   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK,
875                                 "toggle_cursor_item", 0);
876
877   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, 
878                                 "activate_cursor_item", 0);
879   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0,
880                                 "activate_cursor_item", 0);
881   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, 
882                                 "activate_cursor_item", 0);
883   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, 
884                                 "activate_cursor_item", 0);
885   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, 
886                                 "activate_cursor_item", 0);
887
888   gtk_icon_view_add_move_binding (binding_set, GDK_Up, 0,
889                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
890   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Up, 0,
891                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
892
893   gtk_icon_view_add_move_binding (binding_set, GDK_Down, 0,
894                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
895   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Down, 0,
896                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
897
898   gtk_icon_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
899                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
900
901   gtk_icon_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
902                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
903
904   gtk_icon_view_add_move_binding (binding_set, GDK_Home, 0,
905                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
906   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Home, 0,
907                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
908
909   gtk_icon_view_add_move_binding (binding_set, GDK_End, 0,
910                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
911   gtk_icon_view_add_move_binding (binding_set, GDK_KP_End, 0,
912                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
913
914   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Up, 0,
915                                   GTK_MOVEMENT_PAGES, -1);
916   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
917                                   GTK_MOVEMENT_PAGES, -1);
918
919   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Down, 0,
920                                   GTK_MOVEMENT_PAGES, 1);
921   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
922                                   GTK_MOVEMENT_PAGES, 1);
923
924   gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0, 
925                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
926   gtk_icon_view_add_move_binding (binding_set, GDK_Left, 0, 
927                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
928
929   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Right, 0, 
930                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
931   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Left, 0, 
932                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
933 }
934
935 static void
936 gtk_icon_view_buildable_init (GtkBuildableIface *iface)
937 {
938   parent_buildable_iface = g_type_interface_peek_parent (iface);
939   iface->add_child = _gtk_cell_layout_buildable_add_child;
940   iface->custom_tag_start = gtk_icon_view_buildable_custom_tag_start;
941   iface->custom_tag_end = gtk_icon_view_buildable_custom_tag_end;
942 }
943
944 static void
945 gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
946 {
947   iface->pack_start = gtk_icon_view_cell_layout_pack_start;
948   iface->pack_end = gtk_icon_view_cell_layout_pack_end;
949   iface->clear = gtk_icon_view_cell_layout_clear;
950   iface->add_attribute = gtk_icon_view_cell_layout_add_attribute;
951   iface->set_cell_data_func = gtk_icon_view_cell_layout_set_cell_data_func;
952   iface->clear_attributes = gtk_icon_view_cell_layout_clear_attributes;
953   iface->reorder = gtk_icon_view_cell_layout_reorder;
954   iface->get_cells = gtk_icon_view_cell_layout_get_cells;
955 }
956
957 static void
958 gtk_icon_view_init (GtkIconView *icon_view)
959 {
960   icon_view->priv = GTK_ICON_VIEW_GET_PRIVATE (icon_view);
961   
962   icon_view->priv->width = 0;
963   icon_view->priv->height = 0;
964   icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
965   icon_view->priv->pressed_button = -1;
966   icon_view->priv->press_start_x = -1;
967   icon_view->priv->press_start_y = -1;
968   icon_view->priv->text_column = -1;
969   icon_view->priv->markup_column = -1;  
970   icon_view->priv->pixbuf_column = -1;
971   icon_view->priv->text_cell = -1;
972   icon_view->priv->pixbuf_cell = -1;  
973   icon_view->priv->tooltip_column = -1;  
974
975   GTK_WIDGET_SET_FLAGS (icon_view, GTK_CAN_FOCUS);
976   
977   gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
978
979   icon_view->priv->cell_list = NULL;
980   icon_view->priv->n_cells = 0;
981   icon_view->priv->cursor_cell = -1;
982
983   icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
984
985   icon_view->priv->columns = -1;
986   icon_view->priv->item_width = -1;
987   icon_view->priv->spacing = 0;
988   icon_view->priv->row_spacing = 6;
989   icon_view->priv->column_spacing = 6;
990   icon_view->priv->margin = 6;
991 }
992
993 static void
994 gtk_icon_view_destroy (GtkObject *object)
995 {
996   GtkIconView *icon_view;
997
998   icon_view = GTK_ICON_VIEW (object);
999   
1000   gtk_icon_view_stop_editing (icon_view, TRUE);
1001
1002   gtk_icon_view_set_model (icon_view, NULL);
1003   
1004   if (icon_view->priv->layout_idle_id != 0)
1005     {
1006       g_source_remove (icon_view->priv->layout_idle_id);
1007       icon_view->priv->layout_idle_id = 0;
1008     }
1009
1010   if (icon_view->priv->scroll_to_path != NULL)
1011     {
1012       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1013       icon_view->priv->scroll_to_path = NULL;
1014     }
1015
1016   remove_scroll_timeout (icon_view);
1017
1018   if (icon_view->priv->hadjustment != NULL)
1019     {
1020       g_object_unref (icon_view->priv->hadjustment);
1021       icon_view->priv->hadjustment = NULL;
1022     }
1023
1024   if (icon_view->priv->vadjustment != NULL)
1025     {
1026       g_object_unref (icon_view->priv->vadjustment);
1027       icon_view->priv->vadjustment = NULL;
1028     }
1029   
1030   clear_dest_info (icon_view);
1031   clear_source_info (icon_view);
1032
1033   (* GTK_OBJECT_CLASS (gtk_icon_view_parent_class)->destroy) (object);
1034 }
1035
1036 /* GObject methods */
1037 static void
1038 gtk_icon_view_finalize (GObject *object)
1039 {
1040   gtk_icon_view_cell_layout_clear (GTK_CELL_LAYOUT (object));
1041
1042   (* G_OBJECT_CLASS (gtk_icon_view_parent_class)->finalize) (object);
1043 }
1044
1045
1046 static void
1047 gtk_icon_view_set_property (GObject      *object,
1048                             guint         prop_id,
1049                             const GValue *value,
1050                             GParamSpec   *pspec)
1051 {
1052   GtkIconView *icon_view;
1053
1054   icon_view = GTK_ICON_VIEW (object);
1055
1056   switch (prop_id)
1057     {
1058     case PROP_SELECTION_MODE:
1059       gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
1060       break;
1061     case PROP_PIXBUF_COLUMN:
1062       gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
1063       break;
1064     case PROP_TEXT_COLUMN:
1065       gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
1066       break;
1067     case PROP_MARKUP_COLUMN:
1068       gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
1069       break;
1070     case PROP_MODEL:
1071       gtk_icon_view_set_model (icon_view, g_value_get_object (value));
1072       break;
1073     case PROP_ORIENTATION:
1074       gtk_icon_view_set_orientation (icon_view, g_value_get_enum (value));
1075       break;
1076     case PROP_COLUMNS:
1077       gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
1078       break;
1079     case PROP_ITEM_WIDTH:
1080       gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
1081       break;
1082     case PROP_SPACING:
1083       gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
1084       break;
1085     case PROP_ROW_SPACING:
1086       gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
1087       break;
1088     case PROP_COLUMN_SPACING:
1089       gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
1090       break;
1091     case PROP_MARGIN:
1092       gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
1093       break;
1094     case PROP_REORDERABLE:
1095       gtk_icon_view_set_reorderable (icon_view, g_value_get_boolean (value));
1096       break;
1097       
1098     case PROP_TOOLTIP_COLUMN:
1099       gtk_icon_view_set_tooltip_column (icon_view, g_value_get_int (value));
1100       break;
1101
1102     default:
1103       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1104       break;
1105     }
1106 }
1107
1108 static void
1109 gtk_icon_view_get_property (GObject      *object,
1110                             guint         prop_id,
1111                             GValue       *value,
1112                             GParamSpec   *pspec)
1113 {
1114   GtkIconView *icon_view;
1115
1116   icon_view = GTK_ICON_VIEW (object);
1117
1118   switch (prop_id)
1119     {
1120     case PROP_SELECTION_MODE:
1121       g_value_set_enum (value, icon_view->priv->selection_mode);
1122       break;
1123     case PROP_PIXBUF_COLUMN:
1124       g_value_set_int (value, icon_view->priv->pixbuf_column);
1125       break;
1126     case PROP_TEXT_COLUMN:
1127       g_value_set_int (value, icon_view->priv->text_column);
1128       break;
1129     case PROP_MARKUP_COLUMN:
1130       g_value_set_int (value, icon_view->priv->markup_column);
1131       break;
1132     case PROP_MODEL:
1133       g_value_set_object (value, icon_view->priv->model);
1134       break;
1135     case PROP_ORIENTATION:
1136       g_value_set_enum (value, icon_view->priv->orientation);
1137       break;
1138     case PROP_COLUMNS:
1139       g_value_set_int (value, icon_view->priv->columns);
1140       break;
1141     case PROP_ITEM_WIDTH:
1142       g_value_set_int (value, icon_view->priv->item_width);
1143       break;
1144     case PROP_SPACING:
1145       g_value_set_int (value, icon_view->priv->spacing);
1146       break;
1147     case PROP_ROW_SPACING:
1148       g_value_set_int (value, icon_view->priv->row_spacing);
1149       break;
1150     case PROP_COLUMN_SPACING:
1151       g_value_set_int (value, icon_view->priv->column_spacing);
1152       break;
1153     case PROP_MARGIN:
1154       g_value_set_int (value, icon_view->priv->margin);
1155       break;
1156     case PROP_REORDERABLE:
1157       g_value_set_boolean (value, icon_view->priv->reorderable);
1158       break;
1159     case PROP_TOOLTIP_COLUMN:
1160       g_value_set_int (value, icon_view->priv->tooltip_column);
1161       break;
1162
1163     default:
1164       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1165       break;
1166     }
1167 }
1168
1169 /* GtkWidget signals */
1170 static void
1171 gtk_icon_view_realize (GtkWidget *widget)
1172 {
1173   GtkIconView *icon_view;
1174   GdkWindowAttr attributes;
1175   gint attributes_mask;
1176   
1177   icon_view = GTK_ICON_VIEW (widget);
1178
1179   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1180
1181   /* Make the main, clipping window */
1182   attributes.window_type = GDK_WINDOW_CHILD;
1183   attributes.x = widget->allocation.x;
1184   attributes.y = widget->allocation.y;
1185   attributes.width = widget->allocation.width;
1186   attributes.height = widget->allocation.height;
1187   attributes.wclass = GDK_INPUT_OUTPUT;
1188   attributes.visual = gtk_widget_get_visual (widget);
1189   attributes.colormap = gtk_widget_get_colormap (widget);
1190   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1191
1192   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1193
1194   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1195                                    &attributes, attributes_mask);
1196   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1197   gdk_window_set_user_data (widget->window, widget);
1198
1199   /* Make the window for the icon view */
1200   attributes.x = 0;
1201   attributes.y = 0;
1202   attributes.width = MAX (icon_view->priv->width, widget->allocation.width);
1203   attributes.height = MAX (icon_view->priv->height, widget->allocation.height);
1204   attributes.event_mask = (GDK_EXPOSURE_MASK |
1205                            GDK_SCROLL_MASK |
1206                            GDK_POINTER_MOTION_MASK |
1207                            GDK_BUTTON_PRESS_MASK |
1208                            GDK_BUTTON_RELEASE_MASK |
1209                            GDK_KEY_PRESS_MASK |
1210                            GDK_KEY_RELEASE_MASK) |
1211     gtk_widget_get_events (widget);
1212   
1213   icon_view->priv->bin_window = gdk_window_new (widget->window,
1214                                                 &attributes, attributes_mask);
1215   gdk_window_set_user_data (icon_view->priv->bin_window, widget);
1216
1217   widget->style = gtk_style_attach (widget->style, widget->window);
1218   gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
1219
1220   gdk_window_show (icon_view->priv->bin_window);
1221 }
1222
1223 static void
1224 gtk_icon_view_unrealize (GtkWidget *widget)
1225 {
1226   GtkIconView *icon_view;
1227
1228   icon_view = GTK_ICON_VIEW (widget);
1229
1230   gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
1231   gdk_window_destroy (icon_view->priv->bin_window);
1232   icon_view->priv->bin_window = NULL;
1233
1234   /* GtkWidget::unrealize destroys children and widget->window */
1235   if (GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize)
1236     (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize) (widget);
1237 }
1238
1239 static void
1240 gtk_icon_view_state_changed (GtkWidget      *widget,
1241                              GtkStateType    previous_state)
1242 {
1243   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1244
1245   if (GTK_WIDGET_REALIZED (widget))
1246     {
1247       gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1248       gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
1249     }
1250
1251   gtk_widget_queue_draw (widget);
1252 }
1253
1254 static void
1255 gtk_icon_view_style_set (GtkWidget *widget,
1256                          GtkStyle *previous_style)
1257 {
1258   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1259
1260   if (GTK_WIDGET_REALIZED (widget))
1261     {
1262       gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
1263       gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
1264     }
1265
1266   gtk_widget_queue_resize (widget);
1267 }
1268
1269 static void
1270 gtk_icon_view_size_request (GtkWidget      *widget,
1271                             GtkRequisition *requisition)
1272 {
1273   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1274   GList *tmp_list;
1275
1276   requisition->width = icon_view->priv->width;
1277   requisition->height = icon_view->priv->height;
1278
1279   tmp_list = icon_view->priv->children;
1280
1281   while (tmp_list)
1282     {
1283       GtkIconViewChild *child = tmp_list->data;
1284       GtkRequisition child_requisition;
1285
1286       tmp_list = tmp_list->next;
1287
1288       if (GTK_WIDGET_VISIBLE (child->widget))
1289         gtk_widget_size_request (child->widget, &child_requisition);
1290     }  
1291 }
1292
1293 static void
1294 gtk_icon_view_allocate_children (GtkIconView *icon_view)
1295 {
1296   GList *list;
1297
1298   for (list = icon_view->priv->children; list; list = list->next)
1299     {
1300       GtkIconViewChild *child = list->data;
1301       GtkAllocation allocation;
1302
1303       /* totally ignore our child's requisition */
1304       if (child->cell < 0)
1305         {
1306           allocation.x = child->item->x;
1307           allocation.y = child->item->y;
1308           allocation.width = child->item->width;
1309           allocation.height = child->item->height;
1310         }
1311       else
1312         {
1313           GdkRectangle *box = &child->item->box[child->cell];
1314
1315           allocation.x = box->x;
1316           allocation.y = box->y;
1317           allocation.width = box->width;
1318           allocation.height = box->height;
1319         }
1320
1321       gtk_widget_size_allocate (child->widget, &allocation);
1322     }
1323 }
1324
1325 static void
1326 gtk_icon_view_size_allocate (GtkWidget      *widget,
1327                              GtkAllocation  *allocation)
1328 {
1329   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1330
1331   GtkAdjustment *hadjustment, *vadjustment;
1332
1333   widget->allocation = *allocation;
1334   
1335   if (GTK_WIDGET_REALIZED (widget))
1336     {
1337       gdk_window_move_resize (widget->window,
1338                               allocation->x, allocation->y,
1339                               allocation->width, allocation->height);
1340       gdk_window_resize (icon_view->priv->bin_window,
1341                          MAX (icon_view->priv->width, allocation->width),
1342                          MAX (icon_view->priv->height, allocation->height));
1343     }
1344
1345   gtk_icon_view_layout (icon_view);
1346   
1347   gtk_icon_view_allocate_children (icon_view);
1348
1349   hadjustment = icon_view->priv->hadjustment;
1350   vadjustment = icon_view->priv->vadjustment;
1351
1352   hadjustment->page_size = allocation->width;
1353   hadjustment->page_increment = allocation->width * 0.9;
1354   hadjustment->step_increment = allocation->width * 0.1;
1355   hadjustment->lower = 0;
1356   hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
1357
1358   if (hadjustment->value > hadjustment->upper - hadjustment->page_size)
1359     gtk_adjustment_set_value (hadjustment, hadjustment->upper - hadjustment->page_size);
1360
1361   vadjustment->page_size = allocation->height;
1362   vadjustment->page_increment = allocation->height * 0.9;
1363   vadjustment->step_increment = allocation->height * 0.1;
1364   vadjustment->lower = 0;
1365   vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
1366
1367   if (vadjustment->value > vadjustment->upper - vadjustment->page_size)
1368     gtk_adjustment_set_value (vadjustment, vadjustment->upper - vadjustment->page_size);
1369
1370   if (GTK_WIDGET_REALIZED (widget) &&
1371       icon_view->priv->scroll_to_path)
1372     {
1373       GtkTreePath *path;
1374       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
1375       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1376       icon_view->priv->scroll_to_path = NULL;
1377
1378       gtk_icon_view_scroll_to_path (icon_view, path,
1379                                     icon_view->priv->scroll_to_use_align,
1380                                     icon_view->priv->scroll_to_row_align,
1381                                     icon_view->priv->scroll_to_col_align);
1382       gtk_tree_path_free (path);
1383     }
1384   else
1385     {
1386       gtk_adjustment_changed (hadjustment);
1387       gtk_adjustment_changed (vadjustment);
1388     }
1389 }
1390
1391 static gboolean
1392 gtk_icon_view_expose (GtkWidget *widget,
1393                       GdkEventExpose *expose)
1394 {
1395   GtkIconView *icon_view;
1396   GList *icons;
1397   cairo_t *cr;
1398   GtkTreePath *path;
1399   gint dest_index;
1400   GtkIconViewDropPosition dest_pos;
1401   GtkIconViewItem *dest_item = NULL;
1402
1403   icon_view = GTK_ICON_VIEW (widget);
1404
1405   if (expose->window != icon_view->priv->bin_window)
1406     return FALSE;
1407
1408   cr = gdk_cairo_create (icon_view->priv->bin_window);
1409   cairo_set_line_width (cr, 1.);
1410
1411   gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
1412
1413   if (path)
1414     {
1415       dest_index = gtk_tree_path_get_indices (path)[0];
1416       gtk_tree_path_free (path);
1417     }
1418   else
1419     dest_index = -1;
1420
1421   for (icons = icon_view->priv->items; icons; icons = icons->next) 
1422     {
1423       GtkIconViewItem *item = icons->data;
1424       GdkRectangle area;
1425       
1426       area.x = item->x;
1427       area.y = item->y;
1428       area.width = item->width;
1429       area.height = item->height;
1430         
1431       if (gdk_region_rect_in (expose->region, &area) == GDK_OVERLAP_RECTANGLE_OUT)
1432         continue;
1433       
1434       gtk_icon_view_paint_item (icon_view, cr, item, &expose->area, 
1435                                 icon_view->priv->bin_window,
1436                                 item->x, item->y, TRUE); 
1437  
1438       if (dest_index == item->index)
1439         dest_item = item;
1440     }
1441
1442   if (dest_item)
1443     {
1444       switch (dest_pos)
1445         {
1446         case GTK_ICON_VIEW_DROP_INTO:
1447           gtk_paint_focus (widget->style,
1448                            icon_view->priv->bin_window,
1449                            GTK_WIDGET_STATE (widget),
1450                            NULL,
1451                            widget,
1452                            "iconview-drop-indicator",
1453                            dest_item->x, dest_item->y,
1454                            dest_item->width, dest_item->height);
1455           break;
1456         case GTK_ICON_VIEW_DROP_ABOVE:
1457           gtk_paint_focus (widget->style,
1458                            icon_view->priv->bin_window,
1459                            GTK_WIDGET_STATE (widget),
1460                            NULL,
1461                            widget,
1462                            "iconview-drop-indicator",
1463                            dest_item->x, dest_item->y - 1,
1464                            dest_item->width, 2);
1465           break;
1466         case GTK_ICON_VIEW_DROP_LEFT:
1467           gtk_paint_focus (widget->style,
1468                            icon_view->priv->bin_window,
1469                            GTK_WIDGET_STATE (widget),
1470                            NULL,
1471                            widget,
1472                            "iconview-drop-indicator",
1473                            dest_item->x - 1, dest_item->y,
1474                            2, dest_item->height);
1475           break;
1476         case GTK_ICON_VIEW_DROP_BELOW:
1477           gtk_paint_focus (widget->style,
1478                            icon_view->priv->bin_window,
1479                            GTK_WIDGET_STATE (widget),
1480                            NULL,
1481                            widget,
1482                            "iconview-drop-indicator",
1483                            dest_item->x, dest_item->y + dest_item->height - 1,
1484                            dest_item->width, 2);
1485           break;
1486         case GTK_ICON_VIEW_DROP_RIGHT:
1487           gtk_paint_focus (widget->style,
1488                            icon_view->priv->bin_window,
1489                            GTK_WIDGET_STATE (widget),
1490                            NULL,
1491                            widget,
1492                            "iconview-drop-indicator",
1493                            dest_item->x + dest_item->width - 1, dest_item->y,
1494                            2, dest_item->height);
1495         case GTK_ICON_VIEW_NO_DROP: ;
1496           break;
1497         }
1498     }
1499   
1500   if (icon_view->priv->doing_rubberband)
1501     {
1502       GdkRectangle *rectangles;
1503       gint n_rectangles;
1504       
1505       gdk_region_get_rectangles (expose->region,
1506                                  &rectangles,
1507                                  &n_rectangles);
1508       
1509       while (n_rectangles--)
1510         gtk_icon_view_paint_rubberband (icon_view, cr, &rectangles[n_rectangles]);
1511
1512       g_free (rectangles);
1513     }
1514
1515   cairo_destroy (cr);
1516
1517   (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->expose_event) (widget, expose);
1518
1519   return TRUE;
1520 }
1521
1522 static gboolean
1523 rubberband_scroll_timeout (gpointer data)
1524 {
1525   GtkIconView *icon_view = data;
1526
1527   gtk_adjustment_set_value (icon_view->priv->vadjustment,
1528                             icon_view->priv->vadjustment->value +
1529                             icon_view->priv->scroll_value_diff);
1530
1531   gtk_icon_view_update_rubberband (icon_view);
1532   
1533   return TRUE;
1534 }
1535
1536 static gboolean
1537 gtk_icon_view_motion (GtkWidget      *widget,
1538                       GdkEventMotion *event)
1539 {
1540   GtkIconView *icon_view;
1541   gint abs_y;
1542   
1543   icon_view = GTK_ICON_VIEW (widget);
1544
1545   gtk_icon_view_maybe_begin_drag (icon_view, event);
1546
1547   if (icon_view->priv->doing_rubberband)
1548     {
1549       gtk_icon_view_update_rubberband (widget);
1550       
1551       abs_y = event->y - icon_view->priv->height *
1552         (icon_view->priv->vadjustment->value /
1553          (icon_view->priv->vadjustment->upper -
1554           icon_view->priv->vadjustment->lower));
1555
1556       if (abs_y < 0 || abs_y > widget->allocation.height)
1557         {
1558           if (abs_y < 0)
1559             icon_view->priv->scroll_value_diff = abs_y;
1560           else
1561             icon_view->priv->scroll_value_diff = abs_y - widget->allocation.height;
1562
1563           icon_view->priv->event_last_x = event->x;
1564           icon_view->priv->event_last_y = event->y;
1565
1566           if (icon_view->priv->scroll_timeout_id == 0)
1567             icon_view->priv->scroll_timeout_id = gdk_threads_add_timeout (30, rubberband_scroll_timeout, 
1568                                                                 icon_view);
1569         }
1570       else 
1571         remove_scroll_timeout (icon_view);
1572     }
1573   
1574   return TRUE;
1575 }
1576
1577 static void
1578 gtk_icon_view_remove (GtkContainer *container,
1579                       GtkWidget    *widget)
1580 {
1581   GtkIconView *icon_view;
1582   GtkIconViewChild *child = NULL;
1583   GList *tmp_list;
1584
1585   icon_view = GTK_ICON_VIEW (container);
1586   
1587   tmp_list = icon_view->priv->children;
1588   while (tmp_list)
1589     {
1590       child = tmp_list->data;
1591       if (child->widget == widget)
1592         {
1593           gtk_widget_unparent (widget);
1594
1595           icon_view->priv->children = g_list_remove_link (icon_view->priv->children, tmp_list);
1596           g_list_free_1 (tmp_list);
1597           g_free (child);
1598           return;
1599         }
1600
1601       tmp_list = tmp_list->next;
1602     }
1603 }
1604
1605 static void
1606 gtk_icon_view_forall (GtkContainer *container,
1607                       gboolean      include_internals,
1608                       GtkCallback   callback,
1609                       gpointer      callback_data)
1610 {
1611   GtkIconView *icon_view;
1612   GtkIconViewChild *child = NULL;
1613   GList *tmp_list;
1614
1615   icon_view = GTK_ICON_VIEW (container);
1616
1617   tmp_list = icon_view->priv->children;
1618   while (tmp_list)
1619     {
1620       child = tmp_list->data;
1621       tmp_list = tmp_list->next;
1622
1623       (* callback) (child->widget, callback_data);
1624     }
1625 }
1626
1627 static void
1628 gtk_icon_view_item_activate_cell (GtkIconView         *icon_view, 
1629                                   GtkIconViewItem     *item, 
1630                                   GtkIconViewCellInfo *info,
1631                                   GdkEvent            *event)
1632 {
1633   GtkTreePath *path;  
1634   gchar *path_string;
1635   GdkRectangle cell_area;
1636   gboolean visible, mode;
1637
1638   gtk_icon_view_set_cell_data (icon_view, item);
1639
1640   g_object_get (info->cell,
1641                 "visible", &visible,
1642                 "mode", &mode,
1643                 NULL);
1644
1645   if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
1646     {
1647       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
1648
1649       path = gtk_tree_path_new_from_indices (item->index, -1);
1650       path_string = gtk_tree_path_to_string (path);
1651       gtk_tree_path_free (path);
1652
1653       gtk_cell_renderer_activate (info->cell, 
1654                                   event, 
1655                                   GTK_WIDGET (icon_view),
1656                                   path_string, 
1657                                   &cell_area, 
1658                                   &cell_area, 
1659                                   0);
1660
1661       g_free (path_string);      
1662     }
1663 }
1664
1665 static void 
1666 gtk_icon_view_item_selected_changed (GtkIconView      *icon_view,
1667                                      GtkIconViewItem  *item)
1668 {
1669   AtkObject *obj;
1670   AtkObject *item_obj;
1671
1672   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
1673   if (obj != NULL)
1674     {
1675       item_obj = atk_object_ref_accessible_child (obj, item->index);
1676       if (item_obj != NULL)
1677         {
1678           atk_object_notify_state_change (item_obj, ATK_STATE_SELECTED, item->selected);
1679           g_object_unref (item_obj);
1680         }
1681     }
1682 }
1683
1684 static void 
1685 gtk_icon_view_put (GtkIconView     *icon_view,
1686                    GtkWidget       *widget,
1687                    GtkIconViewItem *item,
1688                    gint             cell)
1689 {
1690   GtkIconViewChild *child;
1691   
1692   child = g_new (GtkIconViewChild, 1);
1693   
1694   child->widget = widget;
1695   child->item = item;
1696   child->cell = cell;
1697
1698   icon_view->priv->children = g_list_append (icon_view->priv->children, child);
1699
1700   if (GTK_WIDGET_REALIZED (icon_view))
1701     gtk_widget_set_parent_window (child->widget, icon_view->priv->bin_window);
1702   
1703   gtk_widget_set_parent (widget, GTK_WIDGET (icon_view));
1704 }
1705
1706 static void
1707 gtk_icon_view_remove_widget (GtkCellEditable *editable,
1708                              GtkIconView     *icon_view)
1709 {
1710   GList *l;
1711   GtkIconViewItem *item;
1712
1713   if (icon_view->priv->edited_item == NULL)
1714     return;
1715
1716   item = icon_view->priv->edited_item;
1717   icon_view->priv->edited_item = NULL;
1718   icon_view->priv->editable = NULL;
1719   for (l = icon_view->priv->cell_list; l; l = l->next)
1720     {
1721       GtkIconViewCellInfo *info = l->data;
1722
1723       info->editing = FALSE;
1724     }
1725
1726   if (GTK_WIDGET_HAS_FOCUS (editable))
1727     gtk_widget_grab_focus (GTK_WIDGET (icon_view));
1728   
1729   g_signal_handlers_disconnect_by_func (editable,
1730                                         gtk_icon_view_remove_widget,
1731                                         icon_view);
1732
1733   gtk_container_remove (GTK_CONTAINER (icon_view),
1734                         GTK_WIDGET (editable));  
1735
1736   gtk_icon_view_queue_draw_item (icon_view, item);
1737 }
1738
1739
1740 static void
1741 gtk_icon_view_start_editing (GtkIconView         *icon_view, 
1742                              GtkIconViewItem     *item, 
1743                              GtkIconViewCellInfo *info,
1744                              GdkEvent            *event)
1745 {
1746   GtkTreePath *path;  
1747   gchar *path_string;
1748   GdkRectangle cell_area;
1749   gboolean visible, mode;
1750   GtkCellEditable *editable;
1751
1752   gtk_icon_view_set_cell_data (icon_view, item);
1753
1754   g_object_get (info->cell,
1755                 "visible", &visible,
1756                 "mode", &mode,
1757                 NULL);
1758   if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1759     {
1760       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
1761
1762       path = gtk_tree_path_new_from_indices (item->index, -1);
1763       path_string = gtk_tree_path_to_string (path);
1764       gtk_tree_path_free (path);
1765
1766       editable = gtk_cell_renderer_start_editing (info->cell, 
1767                                                   event, 
1768                                                   GTK_WIDGET (icon_view),
1769                                                   path_string, 
1770                                                   &cell_area, 
1771                                                   &cell_area, 
1772                                                   0);
1773       g_free (path_string);      
1774
1775       /* FIXME ugly special case */ 
1776       if (GTK_IS_ENTRY (editable) || GTK_IS_COMBO_BOX (editable))
1777         g_object_set (editable, "has-frame", TRUE, NULL);
1778
1779       /* the rest corresponds to tree_view_real_start_editing... */
1780       icon_view->priv->edited_item = item;
1781       icon_view->priv->editable = editable;
1782       info->editing = TRUE;
1783
1784       gtk_icon_view_put (icon_view, GTK_WIDGET (editable), item, 
1785                          info->position);
1786       gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (editable), 
1787                                        (GdkEvent *)event);
1788       gtk_widget_grab_focus (GTK_WIDGET (editable));
1789       g_signal_connect (editable, "remove_widget",
1790                         G_CALLBACK (gtk_icon_view_remove_widget), 
1791                         icon_view);
1792
1793     }
1794 }
1795
1796 static void
1797 gtk_icon_view_stop_editing (GtkIconView *icon_view,
1798                             gboolean     cancel_editing)
1799 {
1800   GtkCellRenderer *cell = NULL;
1801   GtkIconViewItem *item;
1802   GList *l;
1803
1804   if (icon_view->priv->edited_item == NULL)
1805     return;
1806
1807   /*
1808    * This is very evil. We need to do this, because
1809    * gtk_cell_editable_editing_done may trigger gtk_icon_view_row_changed
1810    * later on. If gtk_icon_view_row_changed notices
1811    * icon_view->priv->edited_item != NULL, it'll call
1812    * gtk_icon_view_stop_editing again. Bad things will happen then.
1813    *
1814    * Please read that again if you intend to modify anything here.
1815    */
1816
1817   item = icon_view->priv->edited_item;
1818   icon_view->priv->edited_item = NULL;
1819
1820   for (l = icon_view->priv->cell_list; l; l = l->next)
1821     {
1822       GtkIconViewCellInfo *info = l->data;
1823
1824       if (info->editing)
1825         {
1826           cell = info->cell;
1827           break;
1828         }
1829     }
1830
1831   if (cell == NULL)
1832     return;
1833
1834   gtk_cell_renderer_stop_editing (cell, cancel_editing);
1835   if (!cancel_editing)
1836     gtk_cell_editable_editing_done (icon_view->priv->editable);
1837
1838   icon_view->priv->edited_item = item;
1839
1840   gtk_cell_editable_remove_widget (icon_view->priv->editable);
1841 }
1842
1843 /**
1844  * gtk_icon_view_set_cursor:
1845  * @icon_view: A #GtkIconView
1846  * @path: A #GtkTreePath
1847  * @cell: One of the cell renderers of @icon_view, or %NULL
1848  * @start_editing: %TRUE if the specified cell should start being edited.
1849  *
1850  * Sets the current keyboard focus to be at @path, and selects it.  This is
1851  * useful when you want to focus the user's attention on a particular item.  
1852  * If @cell is not %NULL, then focus is given to the cell specified by 
1853  * it. Additionally, if @start_editing is %TRUE, then editing should be 
1854  * started in the specified cell.  
1855  *
1856  * This function is often followed by <literal>gtk_widget_grab_focus 
1857  * (icon_view)</literal> in order to give keyboard focus to the widget.  
1858  * Please note that editing can only happen when the widget is realized.
1859  *
1860  * Since: 2.8
1861  **/
1862 void
1863 gtk_icon_view_set_cursor (GtkIconView     *icon_view,
1864                           GtkTreePath     *path,
1865                           GtkCellRenderer *cell,
1866                           gboolean         start_editing)
1867 {
1868   GtkIconViewItem *item = NULL;
1869   GtkIconViewCellInfo *info =  NULL;
1870   GList *l;
1871   gint i, cell_pos;
1872
1873   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
1874   g_return_if_fail (path != NULL);
1875   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
1876
1877   gtk_icon_view_stop_editing (icon_view, TRUE);
1878
1879   if (gtk_tree_path_get_depth (path) == 1)
1880     item = g_list_nth_data (icon_view->priv->items,
1881                             gtk_tree_path_get_indices(path)[0]);
1882   
1883   if (!item)
1884     return;
1885
1886   cell_pos = -1;
1887   for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
1888     {
1889       info = l->data;
1890       
1891       if (info->cell == cell)
1892         {
1893           cell_pos = i;
1894           break;
1895         }
1896           
1897       info = NULL;
1898     }
1899   
1900   g_return_if_fail (cell == NULL || info != NULL);
1901
1902   gtk_icon_view_set_cursor_item (icon_view, item, cell_pos);
1903   gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
1904   
1905   if (info && start_editing)
1906     gtk_icon_view_start_editing (icon_view, item, info, NULL);
1907 }
1908
1909 /**
1910  * gtk_icon_view_get_cursor:
1911  * @icon_view: A #GtkIconView
1912  * @path: Return location for the current cursor path, or %NULL
1913  * @cell: Return location the current focus cell, or %NULL
1914  *
1915  * Fills in @path and @cell with the current cursor path and cell. 
1916  * If the cursor isn't currently set, then *@path will be %NULL.  
1917  * If no cell currently has focus, then *@cell will be %NULL.
1918  *
1919  * The returned #GtkTreePath must be freed with gtk_tree_path_free().
1920  *
1921  * Return value: %TRUE if the cursor is set.
1922  *
1923  * Since: 2.8
1924  **/
1925 gboolean
1926 gtk_icon_view_get_cursor (GtkIconView      *icon_view,
1927                           GtkTreePath     **path,
1928                           GtkCellRenderer **cell)
1929 {
1930   GtkIconViewItem *item;
1931   GtkIconViewCellInfo *info;
1932
1933   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
1934
1935   item = icon_view->priv->cursor_item;
1936   if (icon_view->priv->cursor_cell < 0)
1937     info = NULL;
1938   else
1939     info = g_list_nth_data (icon_view->priv->cell_list, 
1940                             icon_view->priv->cursor_cell);
1941
1942   if (path != NULL)
1943     {
1944       if (item != NULL)
1945         *path = gtk_tree_path_new_from_indices (item->index, -1);
1946       else
1947         *path = NULL;
1948     }
1949
1950   if (cell != NULL)
1951     {
1952       if (info != NULL)
1953         *cell = info->cell;
1954       else 
1955         *cell = NULL;
1956     }
1957
1958   return (item != NULL);
1959 }
1960
1961 static gboolean
1962 gtk_icon_view_button_press (GtkWidget      *widget,
1963                             GdkEventButton *event)
1964 {
1965   GtkIconView *icon_view;
1966   GtkIconViewItem *item;
1967   GtkIconViewCellInfo *info = NULL;
1968   gboolean dirty = FALSE;
1969   GtkCellRendererMode mode;
1970   gint cursor_cell;
1971
1972   icon_view = GTK_ICON_VIEW (widget);
1973
1974   if (event->window != icon_view->priv->bin_window)
1975     return FALSE;
1976
1977   if (!GTK_WIDGET_HAS_FOCUS (widget))
1978     gtk_widget_grab_focus (widget);
1979
1980   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1981     {
1982       item = gtk_icon_view_get_item_at_coords (icon_view, 
1983                                                event->x, event->y,
1984                                                TRUE,
1985                                                &info);      
1986       if (item != NULL)
1987         {
1988           g_object_get (info->cell, "mode", &mode, NULL);
1989           
1990           if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE ||
1991               mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1992             cursor_cell = g_list_index (icon_view->priv->cell_list, info);
1993           else
1994             cursor_cell = -1;
1995           
1996           gtk_icon_view_scroll_to_item (icon_view, item);
1997           
1998           if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
1999             {
2000               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2001             }
2002           else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
2003                    (event->state & GDK_SHIFT_MASK))
2004             {
2005               gtk_icon_view_unselect_all_internal (icon_view);
2006
2007               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2008               if (!icon_view->priv->anchor_item)
2009                 icon_view->priv->anchor_item = item;
2010               else 
2011                 gtk_icon_view_select_all_between (icon_view,
2012                                                   icon_view->priv->anchor_item,
2013                                                   item);
2014               dirty = TRUE;
2015             }
2016           else 
2017             {
2018               if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
2019                   ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
2020                   (event->state & GDK_CONTROL_MASK))
2021                 {
2022                   item->selected = !item->selected;
2023                   gtk_icon_view_queue_draw_item (icon_view, item);
2024                   dirty = TRUE;
2025                 }
2026               else
2027                 {
2028                   if (!item->selected)
2029                     {
2030                       gtk_icon_view_unselect_all_internal (icon_view);
2031                       
2032                       item->selected = TRUE;
2033                       gtk_icon_view_queue_draw_item (icon_view, item);
2034                       dirty = TRUE;
2035                     }
2036                 }
2037               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2038               icon_view->priv->anchor_item = item;
2039             }
2040
2041           /* Save press to possibly begin a drag */
2042           if (icon_view->priv->pressed_button < 0)
2043             {
2044               icon_view->priv->pressed_button = event->button;
2045               icon_view->priv->press_start_x = event->x;
2046               icon_view->priv->press_start_y = event->y;
2047             }
2048
2049           if (!icon_view->priv->last_single_clicked)
2050             icon_view->priv->last_single_clicked = item;
2051
2052           /* cancel the current editing, if it exists */
2053           gtk_icon_view_stop_editing (icon_view, TRUE);
2054           
2055           if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2056             gtk_icon_view_item_activate_cell (icon_view, item, info, 
2057                                               (GdkEvent *)event);
2058           else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2059             gtk_icon_view_start_editing (icon_view, item, info, 
2060                                          (GdkEvent *)event);      
2061         }
2062       else
2063         {
2064           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
2065               !(event->state & GDK_CONTROL_MASK))
2066             {
2067               dirty = gtk_icon_view_unselect_all_internal (icon_view);
2068             }
2069           
2070           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2071             gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
2072         }
2073
2074     }
2075
2076   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
2077     {
2078       item = gtk_icon_view_get_item_at_coords (icon_view,
2079                                                event->x, event->y,
2080                                                TRUE,
2081                                                NULL);
2082
2083       if (item && item == icon_view->priv->last_single_clicked)
2084         {
2085           GtkTreePath *path;
2086
2087           path = gtk_tree_path_new_from_indices (item->index, -1);
2088           gtk_icon_view_item_activated (icon_view, path);
2089           gtk_tree_path_free (path);
2090         }
2091
2092       icon_view->priv->last_single_clicked = NULL;
2093       icon_view->priv->pressed_button = -1;
2094     }
2095   
2096   if (dirty)
2097     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2098
2099   return event->button == 1;
2100 }
2101
2102 static gboolean
2103 gtk_icon_view_button_release (GtkWidget      *widget,
2104                               GdkEventButton *event)
2105 {
2106   GtkIconView *icon_view;
2107
2108   icon_view = GTK_ICON_VIEW (widget);
2109   
2110   if (icon_view->priv->pressed_button == event->button)
2111     icon_view->priv->pressed_button = -1;
2112
2113   gtk_icon_view_stop_rubberbanding (icon_view);
2114
2115   remove_scroll_timeout (icon_view);
2116
2117   return TRUE;
2118 }
2119
2120 static gboolean
2121 gtk_icon_view_key_press (GtkWidget      *widget,
2122                          GdkEventKey    *event)
2123 {
2124   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2125
2126   if (icon_view->priv->doing_rubberband)
2127     {
2128       if (event->keyval == GDK_Escape)
2129         gtk_icon_view_stop_rubberbanding (icon_view);
2130
2131       return TRUE;
2132     }
2133
2134   return (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event) (widget, event);
2135 }
2136
2137 static gboolean
2138 gtk_icon_view_key_release (GtkWidget      *widget,
2139                            GdkEventKey    *event)
2140 {
2141   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2142
2143   if (icon_view->priv->doing_rubberband)
2144     return TRUE;
2145
2146   return (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event) (widget, event);
2147 }
2148
2149 static void
2150 gtk_icon_view_update_rubberband (gpointer data)
2151 {
2152   GtkIconView *icon_view;
2153   gint x, y;
2154   GdkRectangle old_area;
2155   GdkRectangle new_area;
2156   GdkRectangle common;
2157   GdkRegion *invalid_region;
2158   
2159   icon_view = GTK_ICON_VIEW (data);
2160
2161   gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
2162
2163   x = MAX (x, 0);
2164   y = MAX (y, 0);
2165
2166   old_area.x = MIN (icon_view->priv->rubberband_x1,
2167                     icon_view->priv->rubberband_x2);
2168   old_area.y = MIN (icon_view->priv->rubberband_y1,
2169                     icon_view->priv->rubberband_y2);
2170   old_area.width = ABS (icon_view->priv->rubberband_x2 -
2171                         icon_view->priv->rubberband_x1) + 1;
2172   old_area.height = ABS (icon_view->priv->rubberband_y2 -
2173                          icon_view->priv->rubberband_y1) + 1;
2174   
2175   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
2176   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
2177   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
2178   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
2179
2180   invalid_region = gdk_region_rectangle (&old_area);
2181   gdk_region_union_with_rect (invalid_region, &new_area);
2182
2183   gdk_rectangle_intersect (&old_area, &new_area, &common);
2184   if (common.width > 2 && common.height > 2)
2185     {
2186       GdkRegion *common_region;
2187
2188       /* make sure the border is invalidated */
2189       common.x += 1;
2190       common.y += 1;
2191       common.width -= 2;
2192       common.height -= 2;
2193       
2194       common_region = gdk_region_rectangle (&common);
2195
2196       gdk_region_subtract (invalid_region, common_region);
2197       gdk_region_destroy (common_region);
2198     }
2199   
2200   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
2201     
2202   gdk_region_destroy (invalid_region);
2203
2204   icon_view->priv->rubberband_x2 = x;
2205   icon_view->priv->rubberband_y2 = y;  
2206
2207   gtk_icon_view_update_rubberband_selection (icon_view);
2208 }
2209
2210 static void
2211 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
2212                                    gint          x,
2213                                    gint          y)
2214 {
2215   GList *items;
2216
2217   g_assert (!icon_view->priv->doing_rubberband);
2218
2219   for (items = icon_view->priv->items; items; items = items->next)
2220     {
2221       GtkIconViewItem *item = items->data;
2222
2223       item->selected_before_rubberbanding = item->selected;
2224     }
2225   
2226   icon_view->priv->rubberband_x1 = x;
2227   icon_view->priv->rubberband_y1 = y;
2228   icon_view->priv->rubberband_x2 = x;
2229   icon_view->priv->rubberband_y2 = y;
2230
2231   icon_view->priv->doing_rubberband = TRUE;
2232
2233   gtk_grab_add (GTK_WIDGET (icon_view));
2234 }
2235
2236 static void
2237 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
2238 {
2239   if (!icon_view->priv->doing_rubberband)
2240     return;
2241
2242   icon_view->priv->doing_rubberband = FALSE;
2243
2244   gtk_grab_remove (GTK_WIDGET (icon_view));
2245   
2246   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
2247 }
2248
2249 static void
2250 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
2251 {
2252   GList *items;
2253   gint x, y, width, height;
2254   gboolean dirty = FALSE;
2255   
2256   x = MIN (icon_view->priv->rubberband_x1,
2257            icon_view->priv->rubberband_x2);
2258   y = MIN (icon_view->priv->rubberband_y1,
2259            icon_view->priv->rubberband_y2);
2260   width = ABS (icon_view->priv->rubberband_x1 - 
2261                icon_view->priv->rubberband_x2);
2262   height = ABS (icon_view->priv->rubberband_y1 - 
2263                 icon_view->priv->rubberband_y2);
2264   
2265   for (items = icon_view->priv->items; items; items = items->next)
2266     {
2267       GtkIconViewItem *item = items->data;
2268       gboolean is_in;
2269       gboolean selected;
2270       
2271       is_in = gtk_icon_view_item_hit_test (icon_view, item, 
2272                                            x, y, width, height);
2273
2274       selected = is_in ^ item->selected_before_rubberbanding;
2275
2276       if (item->selected != selected)
2277         {
2278           item->selected = selected;
2279           dirty = TRUE;
2280           gtk_icon_view_queue_draw_item (icon_view, item);
2281         }
2282     }
2283
2284   if (dirty)
2285     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2286 }
2287
2288 static gboolean
2289 gtk_icon_view_item_hit_test (GtkIconView      *icon_view,
2290                              GtkIconViewItem  *item,
2291                              gint              x,
2292                              gint              y,
2293                              gint              width,
2294                              gint              height)
2295 {
2296   GList *l;
2297   GdkRectangle box;
2298  
2299   if (MIN (x + width, item->x + item->width) - MAX (x, item->x) <= 0 ||
2300       MIN (y + height, item->y + item->height) - MAX (y, item->y) <= 0)
2301     return FALSE;
2302
2303   for (l = icon_view->priv->cell_list; l; l = l->next)
2304     {
2305       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2306       
2307       if (!info->cell->visible)
2308         continue;
2309       
2310       gtk_icon_view_get_cell_box (icon_view, item, info, &box);
2311
2312       if (MIN (x + width, box.x + box.width) - MAX (x, box.x) > 0 &&
2313         MIN (y + height, box.y + box.height) - MAX (y, box.y) > 0)
2314         return TRUE;
2315     }
2316
2317   return FALSE;
2318 }
2319
2320 static gboolean
2321 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
2322 {
2323   gboolean dirty = FALSE;
2324   GList *items;
2325
2326   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2327     return FALSE;
2328
2329   for (items = icon_view->priv->items; items; items = items->next)
2330     {
2331       GtkIconViewItem *item = items->data;
2332
2333       if (item->selected)
2334         {
2335           item->selected = FALSE;
2336           dirty = TRUE;
2337           gtk_icon_view_queue_draw_item (icon_view, item);
2338           gtk_icon_view_item_selected_changed (icon_view, item);
2339         }
2340     }
2341
2342   return dirty;
2343 }
2344
2345
2346 /* GtkIconView signals */
2347 static void
2348 gtk_icon_view_set_adjustments (GtkIconView   *icon_view,
2349                                GtkAdjustment *hadj,
2350                                GtkAdjustment *vadj)
2351 {
2352   gboolean need_adjust = FALSE;
2353
2354   if (hadj)
2355     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
2356   else
2357     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2358   if (vadj)
2359     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
2360   else
2361     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2362
2363   if (icon_view->priv->hadjustment && (icon_view->priv->hadjustment != hadj))
2364     {
2365       g_signal_handlers_disconnect_matched (icon_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
2366                                            0, 0, NULL, NULL, icon_view);
2367       g_object_unref (icon_view->priv->hadjustment);
2368     }
2369
2370   if (icon_view->priv->vadjustment && (icon_view->priv->vadjustment != vadj))
2371     {
2372       g_signal_handlers_disconnect_matched (icon_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
2373                                             0, 0, NULL, NULL, icon_view);
2374       g_object_unref (icon_view->priv->vadjustment);
2375     }
2376
2377   if (icon_view->priv->hadjustment != hadj)
2378     {
2379       icon_view->priv->hadjustment = hadj;
2380       g_object_ref_sink (icon_view->priv->hadjustment);
2381
2382       g_signal_connect (icon_view->priv->hadjustment, "value-changed",
2383                         G_CALLBACK (gtk_icon_view_adjustment_changed),
2384                         icon_view);
2385       need_adjust = TRUE;
2386     }
2387
2388   if (icon_view->priv->vadjustment != vadj)
2389     {
2390       icon_view->priv->vadjustment = vadj;
2391       g_object_ref_sink (icon_view->priv->vadjustment);
2392
2393       g_signal_connect (icon_view->priv->vadjustment, "value-changed",
2394                         G_CALLBACK (gtk_icon_view_adjustment_changed),
2395                         icon_view);
2396       need_adjust = TRUE;
2397     }
2398
2399   if (need_adjust)
2400     gtk_icon_view_adjustment_changed (NULL, icon_view);
2401 }
2402
2403 static void
2404 gtk_icon_view_real_select_all (GtkIconView *icon_view)
2405 {
2406   gtk_icon_view_select_all (icon_view);
2407 }
2408
2409 static void
2410 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
2411 {
2412   gtk_icon_view_unselect_all (icon_view);
2413 }
2414
2415 static void
2416 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
2417 {
2418   gtk_icon_view_unselect_all (icon_view);
2419   
2420   if (icon_view->priv->cursor_item != NULL)
2421     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2422 }
2423
2424 static gboolean
2425 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
2426 {
2427   GtkTreePath *path;
2428   GtkCellRendererMode mode;
2429   GtkIconViewCellInfo *info = NULL;
2430   
2431   if (!icon_view->priv->cursor_item)
2432     return FALSE;
2433
2434   info = g_list_nth_data (icon_view->priv->cell_list, 
2435                           icon_view->priv->cursor_cell);
2436
2437   if (info) 
2438     {  
2439       g_object_get (info->cell, "mode", &mode, NULL);
2440
2441       if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2442         {
2443           gtk_icon_view_item_activate_cell (icon_view, 
2444                                             icon_view->priv->cursor_item, 
2445                                             info, NULL);
2446           return TRUE;
2447         }
2448       else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2449         {
2450           gtk_icon_view_start_editing (icon_view, 
2451                                        icon_view->priv->cursor_item, 
2452                                        info, NULL);
2453           return TRUE;
2454         }
2455     }
2456   
2457   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
2458   gtk_icon_view_item_activated (icon_view, path);
2459   gtk_tree_path_free (path);
2460
2461   return TRUE;
2462 }
2463
2464 static void
2465 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
2466 {
2467   if (!icon_view->priv->cursor_item)
2468     return;
2469
2470   switch (icon_view->priv->selection_mode)
2471     {
2472     case GTK_SELECTION_NONE:
2473       break;
2474     case GTK_SELECTION_BROWSE:
2475       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2476       break;
2477     case GTK_SELECTION_SINGLE:
2478       if (icon_view->priv->cursor_item->selected)
2479         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
2480       else
2481         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2482       break;
2483     case GTK_SELECTION_MULTIPLE:
2484       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
2485       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
2486       
2487       gtk_icon_view_item_selected_changed (icon_view, icon_view->priv->cursor_item);      
2488       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2489       break;
2490     }
2491 }
2492
2493 /* Internal functions */
2494 static void
2495 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
2496                                   GtkIconView   *icon_view)
2497 {
2498   if (GTK_WIDGET_REALIZED (icon_view))
2499     {
2500       gdk_window_move (icon_view->priv->bin_window,
2501                        - icon_view->priv->hadjustment->value,
2502                        - icon_view->priv->vadjustment->value);
2503
2504       if (icon_view->priv->doing_rubberband)
2505         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
2506
2507       gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
2508     }
2509 }
2510
2511 static GList *
2512 gtk_icon_view_layout_single_row (GtkIconView *icon_view, 
2513                                  GList       *first_item, 
2514                                  gint         item_width,
2515                                  gint         row,
2516                                  gint        *y, 
2517                                  gint        *maximum_width)
2518 {
2519   gint focus_width;
2520   gint x, current_width;
2521   GList *items, *last_item;
2522   gint col;
2523   gint colspan;
2524   gint *max_height;
2525   gint i;
2526   gboolean rtl;
2527
2528   rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
2529   max_height = g_new0 (gint, icon_view->priv->n_cells);
2530
2531   x = 0;
2532   col = 0;
2533   items = first_item;
2534   current_width = 0;
2535
2536   gtk_widget_style_get (GTK_WIDGET (icon_view),
2537                         "focus-line-width", &focus_width,
2538                         NULL);
2539
2540   x += icon_view->priv->margin + focus_width;
2541   current_width += 2 * (icon_view->priv->margin + focus_width);
2542
2543   items = first_item;
2544   while (items)
2545     {
2546       GtkIconViewItem *item = items->data;
2547
2548       gtk_icon_view_calculate_item_size (icon_view, item);
2549       colspan = 1 + (item->width - 1) / (item_width + icon_view->priv->column_spacing);
2550
2551       item->width = colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing;
2552
2553       current_width += item->width;
2554
2555       if (items != first_item)
2556         {
2557           if ((icon_view->priv->columns <= 0 && current_width > GTK_WIDGET (icon_view)->allocation.width) ||
2558               (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
2559             break;
2560         }
2561
2562       current_width += icon_view->priv->column_spacing + 2 * focus_width;
2563
2564       item->y = *y + focus_width;
2565       item->x = rtl ? GTK_WIDGET (icon_view)->allocation.width - item->width - x : x;
2566
2567       x = current_width - (icon_view->priv->margin + focus_width); 
2568
2569       for (i = 0; i < icon_view->priv->n_cells; i++)
2570         max_height[i] = MAX (max_height[i], item->box[i].height);
2571               
2572       if (current_width > *maximum_width)
2573         *maximum_width = current_width;
2574
2575       item->row = row;
2576       item->col = col;
2577
2578       col += colspan;
2579       items = items->next;
2580     }
2581
2582   last_item = items;
2583
2584   /* Now go through the row again and align the icons */
2585   for (items = first_item; items != last_item; items = items->next)
2586     {
2587       GtkIconViewItem *item = items->data;
2588
2589       gtk_icon_view_calculate_item_size2 (icon_view, item, max_height);
2590
2591       /* We may want to readjust the new y coordinate. */
2592       if (item->y + item->height + focus_width + icon_view->priv->row_spacing > *y)
2593         *y = item->y + item->height + focus_width + icon_view->priv->row_spacing;
2594
2595       if (rtl)
2596         item->col = col - 1 - item->col;
2597     }
2598
2599   g_free (max_height);
2600   
2601   return last_item;
2602 }
2603
2604 static void
2605 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
2606                                     gdouble        upper)
2607 {
2608   if (upper != adj->upper)
2609     {
2610       gdouble min = MAX (0.0, upper - adj->page_size);
2611       gboolean value_changed = FALSE;
2612       
2613       adj->upper = upper;
2614
2615       if (adj->value > min)
2616         {
2617           adj->value = min;
2618           value_changed = TRUE;
2619         }
2620       
2621       gtk_adjustment_changed (adj);
2622       
2623       if (value_changed)
2624         gtk_adjustment_value_changed (adj);
2625     }
2626 }
2627
2628 static void
2629 gtk_icon_view_layout (GtkIconView *icon_view)
2630 {
2631   gint y = 0, maximum_width = 0;
2632   GList *icons;
2633   GtkWidget *widget;
2634   gint row;
2635   gint item_width;
2636
2637   if (icon_view->priv->layout_idle_id != 0)
2638     {
2639       g_source_remove (icon_view->priv->layout_idle_id);
2640       icon_view->priv->layout_idle_id = 0;
2641     }
2642   
2643   if (icon_view->priv->model == NULL)
2644     return;
2645
2646   widget = GTK_WIDGET (icon_view);
2647
2648   item_width = icon_view->priv->item_width;
2649
2650   if (item_width < 0)
2651     {
2652       for (icons = icon_view->priv->items; icons; icons = icons->next)
2653         {
2654           GtkIconViewItem *item = icons->data;
2655           gtk_icon_view_calculate_item_size (icon_view, item);
2656           item_width = MAX (item_width, item->width);
2657         }
2658     }
2659
2660
2661   icons = icon_view->priv->items;
2662   y += icon_view->priv->margin;
2663   row = 0;
2664
2665   if (icons)
2666     {
2667       gtk_icon_view_set_cell_data (icon_view, icons->data);
2668       adjust_wrap_width (icon_view, icons->data);
2669     }
2670   
2671   do
2672     {
2673       icons = gtk_icon_view_layout_single_row (icon_view, icons, 
2674                                                item_width, row,
2675                                                &y, &maximum_width);
2676       row++;
2677     }
2678   while (icons != NULL);
2679
2680   if (maximum_width != icon_view->priv->width)
2681     icon_view->priv->width = maximum_width;
2682
2683   y += icon_view->priv->margin;
2684   
2685   if (y != icon_view->priv->height)
2686     icon_view->priv->height = y;
2687
2688   gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, 
2689                                       icon_view->priv->width);
2690   gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, 
2691                                       icon_view->priv->height);
2692
2693   if (icon_view->priv->width != widget->requisition.width ||
2694       icon_view->priv->height != widget->requisition.height)
2695     gtk_widget_queue_resize_no_redraw (widget);
2696
2697   if (GTK_WIDGET_REALIZED (icon_view))
2698     gdk_window_resize (icon_view->priv->bin_window,
2699                        MAX (icon_view->priv->width, widget->allocation.width),
2700                        MAX (icon_view->priv->height, widget->allocation.height));
2701
2702   if (icon_view->priv->scroll_to_path)
2703     {
2704       GtkTreePath *path;
2705
2706       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
2707       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
2708       icon_view->priv->scroll_to_path = NULL;
2709       
2710       gtk_icon_view_scroll_to_path (icon_view, path,
2711                                     icon_view->priv->scroll_to_use_align,
2712                                     icon_view->priv->scroll_to_row_align,
2713                                     icon_view->priv->scroll_to_col_align);
2714       gtk_tree_path_free (path);
2715     }
2716   
2717   gtk_widget_queue_draw (widget);
2718 }
2719
2720 static void 
2721 gtk_icon_view_get_cell_area (GtkIconView         *icon_view,
2722                              GtkIconViewItem     *item,
2723                              GtkIconViewCellInfo *info,
2724                              GdkRectangle        *cell_area)
2725 {
2726   g_return_if_fail (info->position < item->n_cells);
2727
2728   if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2729     {
2730       cell_area->x = item->box[info->position].x - item->before[info->position];
2731       cell_area->y = item->y;
2732       cell_area->width = item->box[info->position].width + 
2733         item->before[info->position] + item->after[info->position];
2734       cell_area->height = item->height;
2735     }
2736   else
2737     {
2738       cell_area->x = item->x;
2739       cell_area->y = item->box[info->position].y - item->before[info->position];
2740       cell_area->width = item->width;
2741       cell_area->height = item->box[info->position].height + 
2742         item->before[info->position] + item->after[info->position];
2743     }
2744 }
2745
2746 static void 
2747 gtk_icon_view_get_cell_box (GtkIconView         *icon_view,
2748                             GtkIconViewItem     *item,
2749                             GtkIconViewCellInfo *info,
2750                             GdkRectangle        *box)
2751 {
2752   g_return_if_fail (info->position < item->n_cells);
2753
2754   *box = item->box[info->position];
2755 }
2756
2757 /* try to guess a reasonable wrap width for an implicit text cell renderer
2758  */
2759 static void
2760 adjust_wrap_width (GtkIconView     *icon_view,
2761                    GtkIconViewItem *item)
2762 {
2763   GtkIconViewCellInfo *text_info;
2764   GtkIconViewCellInfo *pixbuf_info;
2765   gint pixbuf_width, wrap_width;
2766       
2767   if (icon_view->priv->text_cell != -1 &&
2768       icon_view->priv->pixbuf_cell != -1)
2769     {
2770       gint item_width;
2771
2772       text_info = g_list_nth_data (icon_view->priv->cell_list,
2773                                    icon_view->priv->text_cell);
2774       pixbuf_info = g_list_nth_data (icon_view->priv->cell_list,
2775                                      icon_view->priv->pixbuf_cell);
2776       
2777       gtk_cell_renderer_get_size (pixbuf_info->cell, 
2778                                   GTK_WIDGET (icon_view), 
2779                                   NULL, NULL, NULL,
2780                                   &pixbuf_width, 
2781                                   NULL);
2782           
2783
2784       if (icon_view->priv->item_width > 0)
2785         item_width = icon_view->priv->item_width;
2786       else
2787         item_width = item->width;
2788
2789       if (item->width == -1)
2790         {
2791           if (item_width > 0)
2792             wrap_width = item_width - pixbuf_width - icon_view->priv->spacing;
2793           else
2794             wrap_width = MAX (2 * pixbuf_width, 50);
2795         }
2796       else if (icon_view->priv->orientation == GTK_ORIENTATION_VERTICAL)
2797         wrap_width = item_width;
2798       else
2799         wrap_width = item_width - pixbuf_width - icon_view->priv->spacing;
2800
2801       g_object_set (text_info->cell, "wrap-width", wrap_width, NULL);
2802       g_object_set (text_info->cell, "width", wrap_width, NULL);
2803     }
2804 }
2805
2806 static void
2807 gtk_icon_view_calculate_item_size (GtkIconView     *icon_view,
2808                                    GtkIconViewItem *item)
2809 {
2810   gint spacing;
2811   GList *l;
2812
2813   if (item->width != -1 && item->height != -1) 
2814     return;
2815
2816   if (item->n_cells != icon_view->priv->n_cells)
2817     {
2818       g_free (item->before);
2819       g_free (item->after);
2820       g_free (item->box);
2821       
2822       item->before = g_new0 (gint, icon_view->priv->n_cells);
2823       item->after = g_new0 (gint, icon_view->priv->n_cells);
2824       item->box = g_new0 (GdkRectangle, icon_view->priv->n_cells);
2825
2826       item->n_cells = icon_view->priv->n_cells;
2827     }
2828
2829   gtk_icon_view_set_cell_data (icon_view, item);
2830
2831   spacing = icon_view->priv->spacing;
2832
2833   item->width = 0;
2834   item->height = 0;
2835   for (l = icon_view->priv->cell_list; l; l = l->next)
2836     {
2837       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2838       
2839       if (!info->cell->visible)
2840         continue;
2841       
2842       gtk_cell_renderer_get_size (info->cell, GTK_WIDGET (icon_view), 
2843                                   NULL, NULL, NULL,
2844                                   &item->box[info->position].width, 
2845                                   &item->box[info->position].height);
2846
2847       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2848         {
2849           item->width += item->box[info->position].width 
2850             + (info->position > 0 ? spacing : 0);
2851           item->height = MAX (item->height, item->box[info->position].height);
2852         }
2853       else
2854         {
2855           item->width = MAX (item->width, item->box[info->position].width);
2856           item->height += item->box[info->position].height + (info->position > 0 ? spacing : 0);
2857         }
2858     }
2859 }
2860
2861 static void
2862 gtk_icon_view_calculate_item_size2 (GtkIconView     *icon_view,
2863                                     GtkIconViewItem *item,
2864                                     gint            *max_height)
2865 {
2866   GdkRectangle cell_area;
2867   gint spacing;
2868   GList *l;
2869   gint i, k;
2870   gboolean rtl;
2871
2872   rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
2873
2874   gtk_icon_view_set_cell_data (icon_view, item);
2875
2876   spacing = icon_view->priv->spacing;
2877
2878   item->height = 0;
2879   for (i = 0; i < icon_view->priv->n_cells; i++)
2880     {
2881       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2882         item->height = MAX (item->height, max_height[i]);
2883       else
2884         item->height += max_height[i] + (i > 0 ? spacing : 0);
2885     }
2886
2887   cell_area.x = item->x;
2888   cell_area.y = item->y;
2889       
2890   for (k = 0; k < 2; k++)
2891     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
2892       {
2893         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
2894         
2895         if (info->pack == (k ? GTK_PACK_START : GTK_PACK_END))
2896           continue;
2897
2898         if (!info->cell->visible)
2899           continue;
2900
2901         if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2902           {
2903             cell_area.width = item->box[info->position].width;
2904             cell_area.height = item->height;
2905           }
2906         else
2907           {
2908             cell_area.width = item->width;
2909             cell_area.height = max_height[i];
2910           }
2911         
2912         gtk_cell_renderer_get_size (info->cell, GTK_WIDGET (icon_view), 
2913                                     &cell_area,
2914                                     &item->box[info->position].x, &item->box[info->position].y,
2915                                     &item->box[info->position].width, &item->box[info->position].height);
2916         
2917         item->box[info->position].x += cell_area.x;
2918         item->box[info->position].y += cell_area.y;
2919         if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2920           {
2921             item->before[info->position] = item->box[info->position].x - cell_area.x;
2922             item->after[info->position] = cell_area.width - item->box[info->position].width - item->before[info->position];
2923             cell_area.x += cell_area.width + spacing;
2924           }
2925         else
2926           {
2927             if (item->box[info->position].width > item->width)
2928               {
2929                 item->width = item->box[info->position].width;
2930                 cell_area.width = item->width;
2931               }
2932             item->before[info->position] = item->box[info->position].y - cell_area.y;
2933             item->after[info->position] = cell_area.height - item->box[info->position].height - item->before[info->position];
2934             cell_area.y += cell_area.height + spacing;
2935           }
2936       }
2937   
2938   if (rtl && icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2939     {
2940       for (i = 0; i < icon_view->priv->n_cells; i++)
2941         {
2942           item->box[i].x = item->x + item->width - 
2943             (item->box[i].x + item->box[i].width - item->x);
2944         }      
2945     }   
2946 }
2947
2948 static void
2949 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
2950 {
2951   g_list_foreach (icon_view->priv->items,
2952                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
2953 }
2954
2955 static void
2956 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
2957 {
2958   item->width = -1;
2959   item->height = -1;
2960 }
2961
2962 static void
2963 gtk_icon_view_paint_item (GtkIconView     *icon_view,
2964                           cairo_t         *cr,
2965                           GtkIconViewItem *item,
2966                           GdkRectangle    *area,
2967                           GdkDrawable     *drawable,
2968                           gint             x,
2969                           gint             y,
2970                           gboolean         draw_focus)
2971 {
2972   gint focus_width;
2973   gint padding;
2974   GdkRectangle cell_area, box;
2975   GList *l;
2976   gint i;
2977   GtkStateType state;
2978   GtkCellRendererState flags;
2979       
2980   if (icon_view->priv->model == NULL)
2981     return;
2982   
2983   gtk_icon_view_set_cell_data (icon_view, item);
2984
2985   gtk_widget_style_get (GTK_WIDGET (icon_view),
2986                         "focus-line-width", &focus_width,
2987                         NULL);
2988   
2989   padding = focus_width; 
2990   
2991   if (item->selected)
2992     {
2993       flags = GTK_CELL_RENDERER_SELECTED;
2994       if (GTK_WIDGET_HAS_FOCUS (icon_view))
2995         state = GTK_STATE_SELECTED;
2996       else
2997         state = GTK_STATE_ACTIVE;
2998     }
2999   else
3000     {
3001       flags = 0;
3002       state = GTK_STATE_NORMAL;
3003     }
3004   
3005 #ifdef DEBUG_ICON_VIEW
3006   gdk_draw_rectangle (drawable,
3007                       GTK_WIDGET (icon_view)->style->black_gc,
3008                       FALSE,
3009                       x, y, 
3010                       item->width, item->height);
3011 #endif
3012
3013   if (item->selected)
3014     for (l = icon_view->priv->cell_list; l; l = l->next)
3015       {
3016         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3017         
3018         if (!info->cell->visible)
3019           continue;
3020         
3021         gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3022
3023         /* FIXME we hardwire background drawing behind text
3024          * cell renderers here 
3025          */
3026         if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
3027           {
3028             gdk_cairo_set_source_color (cr, &GTK_WIDGET (icon_view)->style->base[state]);
3029             cairo_rectangle (cr,
3030                              x - item->x + box.x, 
3031                              y - item->y + box.y,
3032                              box.width, box.height);
3033             cairo_fill (cr);
3034           }
3035       }
3036   
3037   for (l = icon_view->priv->cell_list; l; l = l->next)
3038     {
3039       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3040       
3041       if (!info->cell->visible)
3042         continue;
3043       
3044       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
3045       
3046 #ifdef DEBUG_ICON_VIEW
3047       gdk_draw_rectangle (drawable,
3048                           GTK_WIDGET (icon_view)->style->black_gc,
3049                           FALSE,
3050                           x - item->x + cell_area.x, 
3051                           y - item->y + cell_area.y, 
3052                           cell_area.width, cell_area.height);
3053
3054       gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3055           
3056       gdk_draw_rectangle (drawable,
3057                           GTK_WIDGET (icon_view)->style->black_gc,
3058                           FALSE,
3059                           x - item->x + box.x, 
3060                           y - item->y + box.y, 
3061                           box.width, box.height);
3062 #endif
3063
3064       cell_area.x = x - item->x + cell_area.x;
3065       cell_area.y = y - item->y + cell_area.y;
3066
3067       gtk_cell_renderer_render (info->cell,
3068                                 drawable,
3069                                 GTK_WIDGET (icon_view),
3070                                 &cell_area, &cell_area, area, flags);
3071       
3072     }
3073
3074   /* FIXME where to draw the focus with generic cell renderers ? */
3075   if (draw_focus && 
3076       GTK_WIDGET_HAS_FOCUS (icon_view) &&
3077       item == icon_view->priv->cursor_item)
3078     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
3079       {
3080         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3081         
3082         if (!info->cell->visible)
3083           continue;
3084         
3085         if (icon_view->priv->cursor_cell < 0 &&
3086             (info->cell->mode != GTK_CELL_RENDERER_MODE_INERT ||
3087              GTK_IS_CELL_RENDERER_TEXT (info->cell)))
3088           icon_view->priv->cursor_cell = i;
3089         
3090         if (i == icon_view->priv->cursor_cell)
3091           {
3092             gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3093
3094             gtk_paint_focus (GTK_WIDGET (icon_view)->style,
3095                              drawable,
3096                              GTK_STATE_NORMAL,
3097                              area,
3098                              GTK_WIDGET (icon_view),
3099                              "icon_view",
3100                              x - item->x + box.x - padding,
3101                              y - item->y + box.y - padding,
3102                              box.width + 2 * padding,
3103                              box.height + 2 * padding);
3104             break;
3105           }
3106       }
3107 }
3108
3109 static void
3110 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
3111                                 cairo_t         *cr,
3112                                 GdkRectangle    *area)
3113 {
3114   GdkRectangle rect;
3115   GdkRectangle rubber_rect;
3116   GdkColor *fill_color_gdk;
3117   guchar fill_color_alpha;
3118
3119   rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
3120   rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
3121   rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
3122   rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
3123
3124   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
3125     return;
3126
3127   gtk_widget_style_get (GTK_WIDGET (icon_view),
3128                         "selection-box-color", &fill_color_gdk,
3129                         "selection-box-alpha", &fill_color_alpha,
3130                         NULL);
3131
3132   if (!fill_color_gdk)
3133     fill_color_gdk = gdk_color_copy (&GTK_WIDGET (icon_view)->style->base[GTK_STATE_SELECTED]);
3134
3135   cairo_set_source_rgba (cr,
3136                          fill_color_gdk->red / 65535.,
3137                          fill_color_gdk->green / 65535.,
3138                          fill_color_gdk->blue / 65535.,
3139                          fill_color_alpha / 255.);
3140
3141   cairo_save (cr);
3142   gdk_cairo_rectangle (cr, &rect);
3143   cairo_clip (cr);
3144   cairo_paint (cr);
3145
3146   /* Draw the border without alpha */
3147   cairo_set_source_rgb (cr,
3148                         fill_color_gdk->red / 65535.,
3149                         fill_color_gdk->green / 65535.,
3150                         fill_color_gdk->blue / 65535.);
3151   cairo_rectangle (cr, 
3152                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
3153                    rubber_rect.width - 1, rubber_rect.height - 1);
3154   cairo_stroke (cr);
3155   cairo_restore (cr);
3156
3157   gdk_color_free (fill_color_gdk);
3158 }
3159
3160 static void
3161 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3162                                GtkTreePath *path)
3163 {
3164   GList *l;
3165   gint index;
3166
3167   index = gtk_tree_path_get_indices (path)[0];
3168
3169   for (l = icon_view->priv->items; l; l = l->next) 
3170     {
3171       GtkIconViewItem *item = l->data;
3172
3173       if (item->index == index)
3174         {
3175           gtk_icon_view_queue_draw_item (icon_view, item);
3176           break;
3177         }
3178     }
3179 }
3180
3181 static void
3182 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
3183                                GtkIconViewItem *item)
3184 {
3185   gint focus_width;
3186   GdkRectangle rect;
3187
3188   gtk_widget_style_get (GTK_WIDGET (icon_view),
3189                         "focus-line-width", &focus_width,
3190                         NULL);
3191
3192   rect.x = item->x - focus_width;
3193   rect.y = item->y - focus_width;
3194   rect.width = item->width + 2 * focus_width;
3195   rect.height = item->height + 2 * focus_width;
3196
3197   if (icon_view->priv->bin_window)
3198     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3199 }
3200
3201 static gboolean
3202 layout_callback (gpointer user_data)
3203 {
3204   GtkIconView *icon_view;
3205
3206   icon_view = GTK_ICON_VIEW (user_data);
3207   
3208   icon_view->priv->layout_idle_id = 0;
3209
3210   gtk_icon_view_layout (icon_view);
3211   
3212   return FALSE;
3213 }
3214
3215 static void
3216 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3217 {
3218   if (icon_view->priv->layout_idle_id != 0)
3219     return;
3220
3221   icon_view->priv->layout_idle_id = gdk_threads_add_idle (layout_callback, icon_view);
3222 }
3223
3224 static void
3225 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
3226                                GtkIconViewItem *item,
3227                                gint             cursor_cell)
3228 {
3229   AtkObject *obj;
3230   AtkObject *item_obj;
3231   AtkObject *cursor_item_obj;
3232
3233   if (icon_view->priv->cursor_item == item &&
3234       (cursor_cell < 0 || cursor_cell == icon_view->priv->cursor_cell))
3235     return;
3236
3237   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3238   if (icon_view->priv->cursor_item != NULL)
3239     {
3240       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3241       if (obj != NULL)
3242         {
3243           cursor_item_obj = atk_object_ref_accessible_child (obj, icon_view->priv->cursor_item->index);
3244           if (cursor_item_obj != NULL)
3245             atk_object_notify_state_change (cursor_item_obj, ATK_STATE_FOCUSED, FALSE);
3246         }
3247     }
3248   icon_view->priv->cursor_item = item;
3249   if (cursor_cell >= 0)
3250     icon_view->priv->cursor_cell = cursor_cell;
3251
3252   gtk_icon_view_queue_draw_item (icon_view, item);
3253   
3254   /* Notify that accessible focus object has changed */
3255   item_obj = atk_object_ref_accessible_child (obj, item->index);
3256
3257   if (item_obj != NULL)
3258     {
3259       atk_focus_tracker_notify (item_obj);
3260       atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
3261       g_object_unref (item_obj); 
3262     }
3263 }
3264
3265
3266 static GtkIconViewItem *
3267 gtk_icon_view_item_new (void)
3268 {
3269   GtkIconViewItem *item;
3270
3271   item = g_new0 (GtkIconViewItem, 1);
3272
3273   item->width = -1;
3274   item->height = -1;
3275   
3276   return item;
3277 }
3278
3279 static void
3280 gtk_icon_view_item_free (GtkIconViewItem *item)
3281 {
3282   g_return_if_fail (item != NULL);
3283
3284   g_free (item->before);
3285   g_free (item->after);
3286   g_free (item->box);
3287
3288   g_free (item);
3289 }
3290
3291
3292 static GtkIconViewItem *
3293 gtk_icon_view_get_item_at_coords (GtkIconView          *icon_view,
3294                                   gint                  x,
3295                                   gint                  y,
3296                                   gboolean              only_in_cell,
3297                                   GtkIconViewCellInfo **cell_at_pos)
3298 {
3299   GList *items, *l;
3300   GdkRectangle box;
3301
3302   for (items = icon_view->priv->items; items; items = items->next)
3303     {
3304       GtkIconViewItem *item = items->data;
3305
3306       if (x >= item->x - icon_view->priv->column_spacing/2 && x <= item->x + item->width + icon_view->priv->column_spacing/2 &&
3307           y >= item->y - icon_view->priv->row_spacing/2 && y <= item->y + item->height + icon_view->priv->row_spacing/2)
3308         {
3309           if (only_in_cell || cell_at_pos)
3310             {
3311               gtk_icon_view_set_cell_data (icon_view, item);
3312
3313               for (l = icon_view->priv->cell_list; l; l = l->next)
3314                 {
3315                   GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3316                   
3317                   if (!info->cell->visible)
3318                     continue;
3319                   
3320                   gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3321                   
3322                   if ((x >= box.x && x <= box.x + box.width &&
3323                        y >= box.y && y <= box.y + box.height) ||
3324                       (x >= box.x  &&
3325                        x <= box.x + box.width &&
3326                        y >= box.y &&
3327                        y <= box.y + box.height))
3328                     {
3329                       if (cell_at_pos)
3330                         *cell_at_pos = info;
3331                       
3332                       return item;
3333                     }
3334                 }
3335
3336               if (only_in_cell)
3337                 return NULL;
3338               
3339               if (cell_at_pos)
3340                 *cell_at_pos = NULL;
3341             }
3342
3343           return item;
3344         }
3345     }
3346
3347   return NULL;
3348 }
3349
3350 static void
3351 gtk_icon_view_select_item (GtkIconView      *icon_view,
3352                            GtkIconViewItem  *item)
3353 {
3354   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3355   g_return_if_fail (item != NULL);
3356
3357   if (item->selected)
3358     return;
3359   
3360   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3361     return;
3362   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3363     gtk_icon_view_unselect_all_internal (icon_view);
3364
3365   item->selected = TRUE;
3366
3367   gtk_icon_view_item_selected_changed (icon_view, item);
3368   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3369
3370   gtk_icon_view_queue_draw_item (icon_view, item);
3371 }
3372
3373
3374 static void
3375 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
3376                              GtkIconViewItem  *item)
3377 {
3378   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3379   g_return_if_fail (item != NULL);
3380
3381   if (!item->selected)
3382     return;
3383   
3384   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3385       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3386     return;
3387   
3388   item->selected = FALSE;
3389
3390   gtk_icon_view_item_selected_changed (icon_view, item);
3391   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3392
3393   gtk_icon_view_queue_draw_item (icon_view, item);
3394 }
3395
3396 static void
3397 verify_items (GtkIconView *icon_view)
3398 {
3399   GList *items;
3400   int i = 0;
3401
3402   for (items = icon_view->priv->items; items; items = items->next)
3403     {
3404       GtkIconViewItem *item = items->data;
3405
3406       if (item->index != i)
3407         g_error ("List item does not match its index: "
3408                  "item index %d and list index %d\n", item->index, i);
3409
3410       i++;
3411     }
3412 }
3413
3414 static void
3415 gtk_icon_view_row_changed (GtkTreeModel *model,
3416                            GtkTreePath  *path,
3417                            GtkTreeIter  *iter,
3418                            gpointer      data)
3419 {
3420   GtkIconViewItem *item;
3421   gint index;
3422   GtkIconView *icon_view;
3423
3424   icon_view = GTK_ICON_VIEW (data);
3425
3426   gtk_icon_view_stop_editing (icon_view, TRUE);
3427   
3428   index = gtk_tree_path_get_indices(path)[0];
3429   item = g_list_nth_data (icon_view->priv->items, index);
3430
3431   gtk_icon_view_item_invalidate_size (item);
3432   gtk_icon_view_queue_layout (icon_view);
3433
3434   verify_items (icon_view);
3435 }
3436
3437 static void
3438 gtk_icon_view_row_inserted (GtkTreeModel *model,
3439                             GtkTreePath  *path,
3440                             GtkTreeIter  *iter,
3441                             gpointer      data)
3442 {
3443   gint index;
3444   GtkIconViewItem *item;
3445   gboolean iters_persist;
3446   GtkIconView *icon_view;
3447   GList *list;
3448   
3449   icon_view = GTK_ICON_VIEW (data);
3450
3451   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3452   
3453   index = gtk_tree_path_get_indices(path)[0];
3454
3455   item = gtk_icon_view_item_new ();
3456
3457   if (iters_persist)
3458     item->iter = *iter;
3459
3460   item->index = index;
3461
3462   /* FIXME: We can be more efficient here,
3463      we can store a tail pointer and use that when
3464      appending (which is a rather common operation)
3465   */
3466   icon_view->priv->items = g_list_insert (icon_view->priv->items,
3467                                          item, index);
3468   
3469   list = g_list_nth (icon_view->priv->items, index + 1);
3470   for (; list; list = list->next)
3471     {
3472       item = list->data;
3473
3474       item->index++;
3475     }
3476     
3477   verify_items (icon_view);
3478
3479   gtk_icon_view_queue_layout (icon_view);
3480 }
3481
3482 static void
3483 gtk_icon_view_row_deleted (GtkTreeModel *model,
3484                            GtkTreePath  *path,
3485                            gpointer      data)
3486 {
3487   gint index;
3488   GtkIconView *icon_view;
3489   GtkIconViewItem *item;
3490   GList *list, *next;
3491   gboolean emit = FALSE;
3492   
3493   icon_view = GTK_ICON_VIEW (data);
3494
3495   index = gtk_tree_path_get_indices(path)[0];
3496
3497   list = g_list_nth (icon_view->priv->items, index);
3498   item = list->data;
3499
3500   gtk_icon_view_stop_editing (icon_view, TRUE);
3501
3502   if (item == icon_view->priv->anchor_item)
3503     icon_view->priv->anchor_item = NULL;
3504
3505   if (item == icon_view->priv->cursor_item)
3506     icon_view->priv->cursor_item = NULL;
3507
3508   if (item->selected)
3509     emit = TRUE;
3510   
3511   gtk_icon_view_item_free (item);
3512
3513   for (next = list->next; next; next = next->next)
3514     {
3515       item = next->data;
3516
3517       item->index--;
3518     }
3519   
3520   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3521
3522   verify_items (icon_view);  
3523   
3524   gtk_icon_view_queue_layout (icon_view);
3525
3526   if (emit)
3527     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3528 }
3529
3530 static void
3531 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3532                               GtkTreePath  *parent,
3533                               GtkTreeIter  *iter,
3534                               gint         *new_order,
3535                               gpointer      data)
3536 {
3537   int i;
3538   int length;
3539   GtkIconView *icon_view;
3540   GList *items = NULL, *list;
3541   GtkIconViewItem **item_array;
3542   gint *order;
3543   
3544   icon_view = GTK_ICON_VIEW (data);
3545
3546   gtk_icon_view_stop_editing (icon_view, TRUE);
3547
3548   length = gtk_tree_model_iter_n_children (model, NULL);
3549
3550   order = g_new (gint, length);
3551   for (i = 0; i < length; i++)
3552     order [new_order[i]] = i;
3553
3554   item_array = g_new (GtkIconViewItem *, length);
3555   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3556     item_array[order[i]] = list->data;
3557   g_free (order);
3558
3559   for (i = length - 1; i >= 0; i--)
3560     {
3561       item_array[i]->index = i;
3562       items = g_list_prepend (items, item_array[i]);
3563     }
3564   
3565   g_free (item_array);
3566   g_list_free (icon_view->priv->items);
3567   icon_view->priv->items = items;
3568
3569   gtk_icon_view_queue_layout (icon_view);
3570
3571   verify_items (icon_view);  
3572 }
3573
3574 static void
3575 gtk_icon_view_build_items (GtkIconView *icon_view)
3576 {
3577   GtkTreeIter iter;
3578   int i;
3579   gboolean iters_persist;
3580   GList *items = NULL;
3581
3582   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3583   
3584   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3585                                       &iter))
3586     return;
3587
3588   i = 0;
3589   
3590   do
3591     {
3592       GtkIconViewItem *item = gtk_icon_view_item_new ();
3593
3594       if (iters_persist)
3595         item->iter = iter;
3596
3597       item->index = i;
3598       
3599       i++;
3600
3601       items = g_list_prepend (items, item);
3602       
3603     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3604
3605   icon_view->priv->items = g_list_reverse (items);
3606 }
3607
3608 static void
3609 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
3610                                 guint           keyval,
3611                                 guint           modmask,
3612                                 GtkMovementStep step,
3613                                 gint            count)
3614 {
3615   
3616   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3617                                 I_("move_cursor"), 2,
3618                                 G_TYPE_ENUM, step,
3619                                 G_TYPE_INT, count);
3620
3621   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3622                                 "move_cursor", 2,
3623                                 G_TYPE_ENUM, step,
3624                                 G_TYPE_INT, count);
3625
3626   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3627    return;
3628
3629   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3630                                 "move_cursor", 2,
3631                                 G_TYPE_ENUM, step,
3632                                 G_TYPE_INT, count);
3633
3634   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3635                                 "move_cursor", 2,
3636                                 G_TYPE_ENUM, step,
3637                                 G_TYPE_INT, count);
3638 }
3639
3640 static gboolean
3641 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
3642                                 GtkMovementStep  step,
3643                                 gint             count)
3644 {
3645   GdkModifierType state;
3646
3647   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3648   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3649                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3650                         step == GTK_MOVEMENT_DISPLAY_LINES ||
3651                         step == GTK_MOVEMENT_PAGES ||
3652                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3653
3654   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_view)))
3655     return FALSE;
3656
3657   gtk_icon_view_stop_editing (icon_view, FALSE);
3658   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3659
3660   if (gtk_get_current_event_state (&state))
3661     {
3662       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3663         icon_view->priv->ctrl_pressed = TRUE;
3664       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3665         icon_view->priv->shift_pressed = TRUE;
3666     }
3667   /* else we assume not pressed */
3668
3669   switch (step)
3670     {
3671     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3672     case GTK_MOVEMENT_VISUAL_POSITIONS:
3673       gtk_icon_view_move_cursor_left_right (icon_view, count);
3674       break;
3675     case GTK_MOVEMENT_DISPLAY_LINES:
3676       gtk_icon_view_move_cursor_up_down (icon_view, count);
3677       break;
3678     case GTK_MOVEMENT_PAGES:
3679       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3680       break;
3681     case GTK_MOVEMENT_BUFFER_ENDS:
3682       gtk_icon_view_move_cursor_start_end (icon_view, count);
3683       break;
3684     default:
3685       g_assert_not_reached ();
3686     }
3687
3688   icon_view->priv->ctrl_pressed = FALSE;
3689   icon_view->priv->shift_pressed = FALSE;
3690
3691   return TRUE;
3692 }
3693
3694 static GtkIconViewItem *
3695 find_item (GtkIconView     *icon_view,
3696            GtkIconViewItem *current,
3697            gint             row_ofs,
3698            gint             col_ofs)
3699 {
3700   gint row, col;
3701   GList *items;
3702   GtkIconViewItem *item;
3703
3704   /* FIXME: this could be more efficient 
3705    */
3706   row = current->row + row_ofs;
3707   col = current->col + col_ofs;
3708
3709   for (items = icon_view->priv->items; items; items = items->next)
3710     {
3711       item = items->data;
3712       if (item->row == row && item->col == col)
3713         return item;
3714     }
3715   
3716   return NULL;
3717 }
3718
3719 static gint
3720 find_cell (GtkIconView     *icon_view,
3721            GtkIconViewItem *item,
3722            gint             cell,
3723            GtkOrientation   orientation,
3724            gint             step,
3725            gint            *count)
3726 {
3727   gint n_focusable;
3728   gint *focusable;
3729   gint first_text;
3730   gint current;
3731   gint i, k;
3732   GList *l;
3733
3734   if (icon_view->priv->orientation != orientation)
3735     return cell;
3736
3737   gtk_icon_view_set_cell_data (icon_view, item);
3738
3739   focusable = g_new0 (gint, icon_view->priv->n_cells);
3740   n_focusable = 0;
3741
3742   first_text = 0;
3743   current = 0;
3744   for (k = 0; k < 2; k++)
3745     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
3746       {
3747         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3748         
3749         if (info->pack == (k ? GTK_PACK_START : GTK_PACK_END))
3750           continue;
3751         
3752         if (!info->cell->visible)
3753           continue;
3754         
3755         if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
3756           first_text = i;
3757
3758         if (info->cell->mode != GTK_CELL_RENDERER_MODE_INERT)
3759           {
3760             if (cell == i)
3761               current = n_focusable;
3762
3763             focusable[n_focusable] = i;
3764
3765             n_focusable++;
3766           }
3767       }
3768   
3769   if (n_focusable == 0)
3770     focusable[n_focusable++] = first_text;
3771
3772   if (cell < 0)
3773     {
3774       current = step > 0 ? 0 : n_focusable - 1;
3775       cell = focusable[current];
3776     }
3777
3778   if (current + *count < 0)
3779     {
3780       cell = -1;
3781       *count = current + *count;
3782     }
3783   else if (current + *count > n_focusable - 1)
3784     {
3785       cell = -1;
3786       *count = current + *count - (n_focusable - 1);
3787     }
3788   else
3789     {
3790       cell = focusable[current + *count];
3791       *count = 0;
3792     }
3793   
3794   g_free (focusable);
3795   
3796   return cell;
3797 }
3798
3799 static GtkIconViewItem *
3800 find_item_page_up_down (GtkIconView     *icon_view,
3801                         GtkIconViewItem *current,
3802                         gint             count)
3803 {
3804   GList *item, *next;
3805   gint y, col;
3806   
3807   col = current->col;
3808   y = current->y + count * icon_view->priv->vadjustment->page_size;
3809
3810   item = g_list_find (icon_view->priv->items, current);
3811   if (count > 0)
3812     {
3813       while (item)
3814         {
3815           for (next = item->next; next; next = next->next)
3816             {
3817               if (((GtkIconViewItem *)next->data)->col == col)
3818                 break;
3819             }
3820           if (!next || ((GtkIconViewItem *)next->data)->y > y)
3821             break;
3822
3823           item = next;
3824         }
3825     }
3826   else 
3827     {
3828       while (item)
3829         {
3830           for (next = item->prev; next; next = next->prev)
3831             {
3832               if (((GtkIconViewItem *)next->data)->col == col)
3833                 break;
3834             }
3835           if (!next || ((GtkIconViewItem *)next->data)->y < y)
3836             break;
3837
3838           item = next;
3839         }
3840     }
3841
3842   if (item)
3843     return item->data;
3844
3845   return NULL;
3846 }
3847
3848 static gboolean
3849 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
3850                                   GtkIconViewItem *anchor,
3851                                   GtkIconViewItem *cursor)
3852 {
3853   GList *items;
3854   GtkIconViewItem *item;
3855   gint row1, row2, col1, col2;
3856   gboolean dirty = FALSE;
3857   
3858   if (anchor->row < cursor->row)
3859     {
3860       row1 = anchor->row;
3861       row2 = cursor->row;
3862     }
3863   else
3864     {
3865       row1 = cursor->row;
3866       row2 = anchor->row;
3867     }
3868
3869   if (anchor->col < cursor->col)
3870     {
3871       col1 = anchor->col;
3872       col2 = cursor->col;
3873     }
3874   else
3875     {
3876       col1 = cursor->col;
3877       col2 = anchor->col;
3878     }
3879
3880   for (items = icon_view->priv->items; items; items = items->next)
3881     {
3882       item = items->data;
3883
3884       if (row1 <= item->row && item->row <= row2 &&
3885           col1 <= item->col && item->col <= col2)
3886         {
3887           if (!item->selected)
3888             {
3889               dirty = TRUE;
3890               item->selected = TRUE;
3891               gtk_icon_view_item_selected_changed (icon_view, item);
3892             }
3893           gtk_icon_view_queue_draw_item (icon_view, item);
3894         }
3895     }
3896
3897   return dirty;
3898 }
3899
3900 static void 
3901 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3902                                    gint         count)
3903 {
3904   GtkIconViewItem *item;
3905   gint cell;
3906   gboolean dirty = FALSE;
3907   gint step;
3908   
3909   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
3910     return;
3911   
3912   if (!icon_view->priv->cursor_item)
3913     {
3914       GList *list;
3915
3916       if (count > 0)
3917         list = icon_view->priv->items;
3918       else
3919         list = g_list_last (icon_view->priv->items);
3920
3921       item = list ? list->data : NULL;
3922       cell = -1;
3923     }
3924   else
3925     {
3926       item = icon_view->priv->cursor_item;
3927       cell = icon_view->priv->cursor_cell;
3928       step = count > 0 ? 1 : -1;      
3929       while (item)
3930         {
3931           cell = find_cell (icon_view, item, cell,
3932                             GTK_ORIENTATION_VERTICAL, 
3933                             step, &count);
3934           if (count == 0)
3935             break;
3936
3937           item = find_item (icon_view, item, step, 0);
3938           count = count - step;
3939         }
3940     }
3941
3942   if (!item)
3943     {
3944       gtk_widget_error_bell (GTK_WIDGET (icon_view));
3945       return;
3946     }
3947
3948   if (icon_view->priv->ctrl_pressed ||
3949       !icon_view->priv->shift_pressed ||
3950       !icon_view->priv->anchor_item ||
3951       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3952     icon_view->priv->anchor_item = item;
3953
3954   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3955
3956   if (!icon_view->priv->ctrl_pressed &&
3957       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3958     {
3959       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3960       dirty = gtk_icon_view_select_all_between (icon_view, 
3961                                                 icon_view->priv->anchor_item,
3962                                                 item) || dirty;
3963     }
3964
3965   gtk_icon_view_scroll_to_item (icon_view, item);
3966
3967   if (dirty)
3968     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3969 }
3970
3971 static void 
3972 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3973                                         gint         count)
3974 {
3975   GtkIconViewItem *item;
3976   gboolean dirty = FALSE;
3977   
3978   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
3979     return;
3980   
3981   if (!icon_view->priv->cursor_item)
3982     {
3983       GList *list;
3984
3985       if (count > 0)
3986         list = icon_view->priv->items;
3987       else
3988         list = g_list_last (icon_view->priv->items);
3989
3990       item = list ? list->data : NULL;
3991     }
3992   else
3993     item = find_item_page_up_down (icon_view, 
3994                                    icon_view->priv->cursor_item,
3995                                    count);
3996
3997   if (item == icon_view->priv->cursor_item)
3998     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3999
4000   if (!item)
4001     return;
4002
4003   if (icon_view->priv->ctrl_pressed ||
4004       !icon_view->priv->shift_pressed ||
4005       !icon_view->priv->anchor_item ||
4006       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4007     icon_view->priv->anchor_item = item;
4008
4009   gtk_icon_view_set_cursor_item (icon_view, item, -1);
4010
4011   if (!icon_view->priv->ctrl_pressed &&
4012       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4013     {
4014       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4015       dirty = gtk_icon_view_select_all_between (icon_view, 
4016                                                 icon_view->priv->anchor_item,
4017                                                 item) || dirty;
4018     }
4019
4020   gtk_icon_view_scroll_to_item (icon_view, item);
4021
4022   if (dirty)
4023     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
4024 }
4025
4026 static void 
4027 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
4028                                       gint         count)
4029 {
4030   GtkIconViewItem *item;
4031   gint cell = -1;
4032   gboolean dirty = FALSE;
4033   gint step;
4034   
4035   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
4036     return;
4037   
4038   if (!icon_view->priv->cursor_item)
4039     {
4040       GList *list;
4041
4042       if (count > 0)
4043         list = icon_view->priv->items;
4044       else
4045         list = g_list_last (icon_view->priv->items);
4046
4047       item = list ? list->data : NULL;
4048     }
4049   else
4050     {
4051       item = icon_view->priv->cursor_item;
4052       cell = icon_view->priv->cursor_cell;
4053       step = count > 0 ? 1 : -1;
4054       while (item)
4055         {
4056           cell = find_cell (icon_view, item, cell,
4057                             GTK_ORIENTATION_HORIZONTAL, 
4058                             step, &count);
4059           if (count == 0)
4060             break;
4061           
4062           item = find_item (icon_view, item, 0, step);
4063           count = count - step;
4064         }
4065     }
4066
4067   if (!item)
4068     {
4069       gtk_widget_error_bell (GTK_WIDGET (icon_view));
4070       return;
4071     }
4072
4073   if (icon_view->priv->ctrl_pressed ||
4074       !icon_view->priv->shift_pressed ||
4075       !icon_view->priv->anchor_item ||
4076       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4077     icon_view->priv->anchor_item = item;
4078
4079   gtk_icon_view_set_cursor_item (icon_view, item, cell);
4080
4081   if (!icon_view->priv->ctrl_pressed &&
4082       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4083     {
4084       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4085       dirty = gtk_icon_view_select_all_between (icon_view, 
4086                                                 icon_view->priv->anchor_item,
4087                                                 item) || dirty;
4088     }
4089
4090   gtk_icon_view_scroll_to_item (icon_view, item);
4091
4092   if (dirty)
4093     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
4094 }
4095
4096 static void 
4097 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
4098                                      gint         count)
4099 {
4100   GtkIconViewItem *item;
4101   GList *list;
4102   gboolean dirty = FALSE;
4103   
4104   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
4105     return;
4106   
4107   if (count < 0)
4108     list = icon_view->priv->items;
4109   else
4110     list = g_list_last (icon_view->priv->items);
4111   
4112   item = list ? list->data : NULL;
4113
4114   if (item == icon_view->priv->cursor_item)
4115     gtk_widget_error_bell (GTK_WIDGET (icon_view));
4116
4117   if (!item)
4118     return;
4119
4120   if (icon_view->priv->ctrl_pressed ||
4121       !icon_view->priv->shift_pressed ||
4122       !icon_view->priv->anchor_item ||
4123       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4124     icon_view->priv->anchor_item = item;
4125
4126   gtk_icon_view_set_cursor_item (icon_view, item, -1);
4127
4128   if (!icon_view->priv->ctrl_pressed &&
4129       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4130     {
4131       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4132       dirty = gtk_icon_view_select_all_between (icon_view, 
4133                                                 icon_view->priv->anchor_item,
4134                                                 item) || dirty;
4135     }
4136
4137   gtk_icon_view_scroll_to_item (icon_view, item);
4138
4139   if (dirty)
4140     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
4141 }
4142
4143 /**
4144  * gtk_icon_view_scroll_to_path:
4145  * @icon_view: A #GtkIconView.
4146  * @path: The path of the item to move to.
4147  * @use_align: whether to use alignment arguments, or %FALSE.
4148  * @row_align: The vertical alignment of the item specified by @path.
4149  * @col_align: The horizontal alignment of the item specified by @path.
4150  *
4151  * Moves the alignments of @icon_view to the position specified by @path.  
4152  * @row_align determines where the row is placed, and @col_align determines 
4153  * where @column is placed.  Both are expected to be between 0.0 and 1.0. 
4154  * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means 
4155  * center.
4156  *
4157  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
4158  * tree does the minimum amount of work to scroll the item onto the screen.
4159  * This means that the item will be scrolled to the edge closest to its current
4160  * position.  If the item is currently visible on the screen, nothing is done.
4161  *
4162  * This function only works if the model is set, and @path is a valid row on 
4163  * the model. If the model changes before the @icon_view is realized, the 
4164  * centered path will be modified to reflect this change.
4165  *
4166  * Since: 2.8
4167  **/
4168 void
4169 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
4170                               GtkTreePath *path,
4171                               gboolean     use_align,
4172                               gfloat       row_align,
4173                               gfloat       col_align)
4174 {
4175   GtkIconViewItem *item = NULL;
4176
4177   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4178   g_return_if_fail (path != NULL);
4179   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
4180   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
4181
4182   if (gtk_tree_path_get_depth (path) > 0)
4183     item = g_list_nth_data (icon_view->priv->items,
4184                             gtk_tree_path_get_indices(path)[0]);
4185   
4186   if (!GTK_WIDGET_REALIZED (icon_view) || !item || item->width < 0)
4187     {
4188       if (icon_view->priv->scroll_to_path)
4189         gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4190
4191       icon_view->priv->scroll_to_path = NULL;
4192
4193       if (path)
4194         icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4195
4196       icon_view->priv->scroll_to_use_align = use_align;
4197       icon_view->priv->scroll_to_row_align = row_align;
4198       icon_view->priv->scroll_to_col_align = col_align;
4199
4200       return;
4201     }
4202
4203   if (use_align)
4204     {
4205       gint x, y;
4206       gint focus_width;
4207       gfloat offset;
4208
4209       gtk_widget_style_get (GTK_WIDGET (icon_view),
4210                             "focus-line-width", &focus_width,
4211                             NULL);
4212       
4213       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4214       
4215       offset =  y + item->y - focus_width - 
4216         row_align * (GTK_WIDGET (icon_view)->allocation.height - item->height);
4217
4218       gtk_adjustment_set_value (icon_view->priv->vadjustment,
4219                                 icon_view->priv->vadjustment->value + offset);
4220
4221       offset = x + item->x - focus_width - 
4222         col_align * (GTK_WIDGET (icon_view)->allocation.width - item->width);
4223
4224       gtk_adjustment_set_value (icon_view->priv->hadjustment,
4225                                 icon_view->priv->hadjustment->value + offset);
4226
4227       gtk_adjustment_changed (icon_view->priv->hadjustment);
4228       gtk_adjustment_changed (icon_view->priv->vadjustment);
4229     }
4230   else
4231     gtk_icon_view_scroll_to_item (icon_view, item);
4232 }
4233
4234
4235 static void     
4236 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view, 
4237                               GtkIconViewItem *item)
4238 {
4239   gint x, y, width, height;
4240   gint focus_width;
4241
4242   gtk_widget_style_get (GTK_WIDGET (icon_view),
4243                         "focus-line-width", &focus_width,
4244                         NULL);
4245
4246   gdk_drawable_get_size (GDK_DRAWABLE (icon_view->priv->bin_window), 
4247                          &width, &height);
4248   gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4249   
4250   if (y + item->y - focus_width < 0)
4251     gtk_adjustment_set_value (icon_view->priv->vadjustment, 
4252                               icon_view->priv->vadjustment->value + y + item->y - focus_width);
4253   else if (y + item->y + item->height + focus_width > GTK_WIDGET (icon_view)->allocation.height)
4254     gtk_adjustment_set_value (icon_view->priv->vadjustment, 
4255                               icon_view->priv->vadjustment->value + y + item->y + item->height 
4256                               + focus_width - GTK_WIDGET (icon_view)->allocation.height);
4257
4258   if (x + item->x - focus_width < 0)
4259     gtk_adjustment_set_value (icon_view->priv->hadjustment, 
4260                               icon_view->priv->hadjustment->value + x + item->x - focus_width);
4261   else if (x + item->x + item->width + focus_width > GTK_WIDGET (icon_view)->allocation.width)
4262     gtk_adjustment_set_value (icon_view->priv->hadjustment, 
4263                               icon_view->priv->hadjustment->value + x + item->x + item->width 
4264                               + focus_width - GTK_WIDGET (icon_view)->allocation.width);
4265
4266   gtk_adjustment_changed (icon_view->priv->hadjustment);
4267   gtk_adjustment_changed (icon_view->priv->vadjustment);
4268 }
4269
4270 /* GtkCellLayout implementation */
4271 static GtkIconViewCellInfo *
4272 gtk_icon_view_get_cell_info (GtkIconView     *icon_view,
4273                              GtkCellRenderer *renderer)
4274 {
4275   GList *i;
4276
4277   for (i = icon_view->priv->cell_list; i; i = i->next)
4278     {
4279       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)i->data;
4280
4281       if (info->cell == renderer)
4282         return info;
4283     }
4284
4285   return NULL;
4286 }
4287
4288 static void
4289 gtk_icon_view_set_cell_data (GtkIconView     *icon_view, 
4290                              GtkIconViewItem *item)
4291 {
4292   GList *i;
4293   gboolean iters_persist;
4294   GtkTreeIter iter;
4295   
4296   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4297   
4298   if (!iters_persist)
4299     {
4300       GtkTreePath *path;
4301
4302       path = gtk_tree_path_new_from_indices (item->index, -1);
4303       if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4304         return;
4305       gtk_tree_path_free (path);
4306     }
4307   else
4308     iter = item->iter;
4309   
4310   for (i = icon_view->priv->cell_list; i; i = i->next)
4311     {
4312       GSList *j;
4313       GtkIconViewCellInfo *info = i->data;
4314
4315       g_object_freeze_notify (G_OBJECT (info->cell));
4316
4317       for (j = info->attributes; j && j->next; j = j->next->next)
4318         {
4319           gchar *property = j->data;
4320           gint column = GPOINTER_TO_INT (j->next->data);
4321           GValue value = {0, };
4322
4323           gtk_tree_model_get_value (icon_view->priv->model, &iter,
4324                                     column, &value);
4325           g_object_set_property (G_OBJECT (info->cell),
4326                                  property, &value);
4327           g_value_unset (&value);
4328         }
4329
4330       if (info->func)
4331         (* info->func) (GTK_CELL_LAYOUT (icon_view),
4332                         info->cell,
4333                         icon_view->priv->model,
4334                         &iter,
4335                         info->func_data);
4336       
4337       g_object_thaw_notify (G_OBJECT (info->cell));
4338     }  
4339 }
4340
4341 static void 
4342 free_cell_attributes (GtkIconViewCellInfo *info)
4343
4344   GSList *list;
4345
4346   list = info->attributes;
4347   while (list && list->next)
4348     {
4349       g_free (list->data);
4350       list = list->next->next;
4351     }
4352   
4353   g_slist_free (info->attributes);
4354   info->attributes = NULL;
4355 }
4356
4357 static void
4358 free_cell_info (GtkIconViewCellInfo *info)
4359 {
4360   free_cell_attributes (info);
4361
4362   g_object_unref (info->cell);
4363   
4364   if (info->destroy)
4365     (* info->destroy) (info->func_data);
4366
4367   g_free (info);
4368 }
4369
4370 static void
4371 gtk_icon_view_cell_layout_pack_start (GtkCellLayout   *layout,
4372                                       GtkCellRenderer *renderer,
4373                                       gboolean         expand)
4374 {
4375   GtkIconViewCellInfo *info;
4376   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4377
4378   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
4379   g_return_if_fail (!gtk_icon_view_get_cell_info (icon_view, renderer));
4380
4381   g_object_ref_sink (renderer);
4382
4383   info = g_new0 (GtkIconViewCellInfo, 1);
4384   info->cell = renderer;
4385   info->expand = expand ? TRUE : FALSE;
4386   info->pack = GTK_PACK_START;
4387   info->position = icon_view->priv->n_cells;
4388   
4389   icon_view->priv->cell_list = g_list_append (icon_view->priv->cell_list, info);
4390   icon_view->priv->n_cells++;
4391 }
4392
4393 static void
4394 gtk_icon_view_cell_layout_pack_end (GtkCellLayout   *layout,
4395                                     GtkCellRenderer *renderer,
4396                                     gboolean         expand)
4397 {
4398   GtkIconViewCellInfo *info;
4399   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4400
4401   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
4402   g_return_if_fail (!gtk_icon_view_get_cell_info (icon_view, renderer));
4403
4404   g_object_ref_sink (renderer);
4405
4406   info = g_new0 (GtkIconViewCellInfo, 1);
4407   info->cell = renderer;
4408   info->expand = expand ? TRUE : FALSE;
4409   info->pack = GTK_PACK_END;
4410   info->position = icon_view->priv->n_cells;
4411
4412   icon_view->priv->cell_list = g_list_append (icon_view->priv->cell_list, info);
4413   icon_view->priv->n_cells++;
4414 }
4415
4416 static void
4417 gtk_icon_view_cell_layout_add_attribute (GtkCellLayout   *layout,
4418                                          GtkCellRenderer *renderer,
4419                                          const gchar     *attribute,
4420                                          gint             column)
4421 {
4422   GtkIconViewCellInfo *info;
4423   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4424
4425   info = gtk_icon_view_get_cell_info (icon_view, renderer);
4426   g_return_if_fail (info != NULL);
4427
4428   info->attributes = g_slist_prepend (info->attributes,
4429                                       GINT_TO_POINTER (column));
4430   info->attributes = g_slist_prepend (info->attributes,
4431                                       g_strdup (attribute));
4432 }
4433
4434 static void
4435 gtk_icon_view_cell_layout_clear (GtkCellLayout *layout)
4436 {
4437   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4438
4439   while (icon_view->priv->cell_list)
4440     {
4441       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)icon_view->priv->cell_list->data;
4442       free_cell_info (info);
4443       icon_view->priv->cell_list = g_list_delete_link (icon_view->priv->cell_list, 
4444                                                        icon_view->priv->cell_list);
4445     }
4446
4447   icon_view->priv->n_cells = 0;
4448 }
4449
4450 static void
4451 gtk_icon_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
4452                                               GtkCellRenderer       *cell,
4453                                               GtkCellLayoutDataFunc  func,
4454                                               gpointer               func_data,
4455                                               GDestroyNotify         destroy)
4456 {
4457   GtkIconViewCellInfo *info;
4458   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4459
4460   info = gtk_icon_view_get_cell_info (icon_view, cell);
4461   g_return_if_fail (info != NULL);
4462
4463   if (info->destroy)
4464     {
4465       GDestroyNotify d = info->destroy;
4466
4467       info->destroy = NULL;
4468       d (info->func_data);
4469     }
4470
4471   info->func = func;
4472   info->func_data = func_data;
4473   info->destroy = destroy;
4474 }
4475
4476 static void
4477 gtk_icon_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
4478                                             GtkCellRenderer *renderer)
4479 {
4480   GtkIconViewCellInfo *info;
4481
4482   info = gtk_icon_view_get_cell_info (GTK_ICON_VIEW (layout), renderer);
4483   if (info != NULL)
4484     free_cell_attributes (info);
4485 }
4486
4487 static void
4488 gtk_icon_view_cell_layout_reorder (GtkCellLayout   *layout,
4489                                    GtkCellRenderer *cell,
4490                                    gint             position)
4491 {
4492   GtkIconView *icon_view;
4493   GList *link, *l;
4494   GtkIconViewCellInfo *info;
4495   gint i;
4496
4497   icon_view = GTK_ICON_VIEW (layout);
4498
4499   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
4500
4501   info = gtk_icon_view_get_cell_info (icon_view, cell);
4502
4503   g_return_if_fail (info != NULL);
4504   g_return_if_fail (position >= 0);
4505
4506   link = g_list_find (icon_view->priv->cell_list, info);
4507
4508   g_return_if_fail (link != NULL);
4509
4510   icon_view->priv->cell_list = g_list_delete_link (icon_view->priv->cell_list,
4511                                                    link);
4512   icon_view->priv->cell_list = g_list_insert (icon_view->priv->cell_list,
4513                                              info, position);
4514
4515   for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
4516     {
4517       info = l->data;
4518
4519       info->position = i;
4520     }
4521
4522   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
4523 }
4524
4525 static GList *
4526 gtk_icon_view_cell_layout_get_cells (GtkCellLayout *layout)
4527 {
4528   GtkIconView *icon_view = (GtkIconView *)layout;
4529   GList *retval = NULL, *l;
4530
4531   for (l = icon_view->priv->cell_list; l; l = l->next)
4532     {
4533       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
4534
4535       retval = g_list_prepend (retval, info->cell);
4536     }
4537
4538   return g_list_reverse (retval);
4539 }
4540
4541 /* Public API */
4542
4543
4544 /**
4545  * gtk_icon_view_new:
4546  * 
4547  * Creates a new #GtkIconView widget
4548  * 
4549  * Return value: A newly created #GtkIconView widget
4550  *
4551  * Since: 2.6
4552  **/
4553 GtkWidget *
4554 gtk_icon_view_new (void)
4555 {
4556   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4557 }
4558
4559 /**
4560  * gtk_icon_view_new_with_model:
4561  * @model: The model.
4562  * 
4563  * Creates a new #GtkIconView widget with the model @model.
4564  * 
4565  * Return value: A newly created #GtkIconView widget.
4566  *
4567  * Since: 2.6 
4568  **/
4569 GtkWidget *
4570 gtk_icon_view_new_with_model (GtkTreeModel *model)
4571 {
4572   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4573 }
4574
4575 /**
4576  * gtk_icon_view_convert_widget_to_bin_window_coords:
4577  * @icon_view: a #GtkIconView 
4578  * @wx: X coordinate relative to the widget
4579  * @wy: Y coordinate relative to the widget
4580  * @bx: return location for bin_window X coordinate
4581  * @by: return location for bin_window Y coordinate
4582  * 
4583  * Converts widget coordinates to coordinates for the bin_window,
4584  * as expected by e.g. gtk_icon_view_get_path_at_pos(). 
4585  *
4586  * Since: 2.12
4587  */
4588 void
4589 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4590                                                    gint         wx,
4591                                                    gint         wy, 
4592                                                    gint        *bx,
4593                                                    gint        *by)
4594 {
4595   gint x, y;
4596
4597   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4598
4599   if (icon_view->priv->bin_window) 
4600     gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4601   else
4602     x = y = 0;
4603  
4604   if (bx)
4605     *bx = wx - x;
4606   if (by)
4607     *by = wy - y;
4608 }
4609
4610 /**
4611  * gtk_icon_view_get_path_at_pos:
4612  * @icon_view: A #GtkIconView.
4613  * @x: The x position to be identified
4614  * @y: The y position to be identified
4615  * 
4616  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4617  * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4618  * the cell at the specified position. 
4619  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4620  * widget coordinates to bin_window coordinates.
4621  * 
4622  * Return value: The #GtkTreePath corresponding to the icon or %NULL
4623  * if no icon exists at that position.
4624  *
4625  * Since: 2.6 
4626  **/
4627 GtkTreePath *
4628 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4629                                gint         x,
4630                                gint         y)
4631 {
4632   GtkIconViewItem *item;
4633   GtkTreePath *path;
4634   
4635   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4636
4637   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4638
4639   if (!item)
4640     return NULL;
4641
4642   path = gtk_tree_path_new_from_indices (item->index, -1);
4643
4644   return path;
4645 }
4646
4647 /**
4648  * gtk_icon_view_get_item_at_pos:
4649  * @icon_view: A #GtkIconView.
4650  * @x: The x position to be identified
4651  * @y: The y position to be identified
4652  * @path: Return location for the path, or %NULL
4653  * @cell: Return location for the renderer responsible for the cell
4654  *   at (@x, @y), or %NULL
4655  * 
4656  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4657  * In contrast to gtk_icon_view_get_path_at_pos(), this function also 
4658  * obtains the cell at the specified position. The returned path should
4659  * be freed with gtk_tree_path_free().
4660  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4661  * widget coordinates to bin_window coordinates.
4662  * 
4663  * Return value: %TRUE if an item exists at the specified position
4664  *
4665  * Since: 2.8
4666  **/
4667 gboolean 
4668 gtk_icon_view_get_item_at_pos (GtkIconView      *icon_view,
4669                                gint              x,
4670                                gint              y,
4671                                GtkTreePath     **path,
4672                                GtkCellRenderer **cell)
4673 {
4674   GtkIconViewItem *item;
4675   GtkIconViewCellInfo *info;
4676   
4677   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4678
4679   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &info);
4680
4681   if (path != NULL)
4682     {
4683       if (item != NULL)
4684         *path = gtk_tree_path_new_from_indices (item->index, -1);
4685       else
4686         *path = NULL;
4687     }
4688
4689   if (cell != NULL)
4690     {
4691       if (info != NULL)
4692         *cell = info->cell;
4693       else 
4694         *cell = NULL;
4695     }
4696
4697   return (item != NULL);
4698 }
4699
4700 /**
4701  * gtk_icon_view_set_tooltip_item:
4702  * @icon_view: a #GtkIconView
4703  * @tooltip: a #GtkTooltip
4704  * @path: a #GtkTreePath
4705  * 
4706  * Sets the tip area of @tooltip to be the area covered by the item at @path.
4707  * See also gtk_tooltip_set_tip_area().
4708  * 
4709  * Since: 2.12
4710  */
4711 void 
4712 gtk_icon_view_set_tooltip_item (GtkIconView     *icon_view,
4713                                 GtkTooltip      *tooltip,
4714                                 GtkTreePath     *path)
4715 {
4716   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4717   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4718
4719   gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
4720 }
4721
4722 /**
4723  * gtk_icon_view_set_tooltip_cell:
4724  * @icon_view: a #GtkIconView
4725  * @tooltip: a #GtkTooltip
4726  * @path: a #GtkTreePath
4727  * @cell: a #GtkCellRenderer or %NULL
4728  *
4729  * Sets the tip area of @tooltip to the area which @cell occupies in
4730  * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
4731  *
4732  * Since: 2.12
4733  */
4734 void
4735 gtk_icon_view_set_tooltip_cell (GtkIconView     *icon_view,
4736                                 GtkTooltip      *tooltip,
4737                                 GtkTreePath     *path,
4738                                 GtkCellRenderer *cell)
4739 {
4740   GdkRectangle rect;
4741   GtkIconViewItem *item = NULL;
4742   GtkIconViewCellInfo *info = NULL;
4743   gint x, y;
4744  
4745   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4746   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4747   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
4748
4749   if (gtk_tree_path_get_depth (path) > 0)
4750     item = g_list_nth_data (icon_view->priv->items,
4751                             gtk_tree_path_get_indices(path)[0]);
4752  
4753   if (!item)
4754     return;
4755
4756   if (cell)
4757     {
4758       info = gtk_icon_view_get_cell_info (icon_view, cell);
4759       gtk_icon_view_get_cell_area (icon_view, item, info, &rect);
4760     }
4761   else
4762     {
4763       rect.x = item->x;
4764       rect.y = item->y;
4765       rect.width = item->width;
4766       rect.height = item->height;
4767     }
4768   
4769   if (icon_view->priv->bin_window)
4770     {
4771       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4772       rect.x += x;
4773       rect.y += y; 
4774     }
4775
4776   gtk_tooltip_set_tip_area (tooltip, &rect); 
4777 }
4778
4779
4780 /**
4781  * gtk_icon_view_get_tooltip_context:
4782  * @icon_view: an #GtkIconView
4783  * @x: the x coordinate (relative to widget coordinates)
4784  * @y: the y coordinate (relative to widget coordinates)
4785  * @keyboard_tip: whether this is a keyboard tooltip or not
4786  * @model: a pointer to receive a #GtkTreeModel or %NULL
4787  * @path: a pointer to receive a #GtkTreePath or %NULL
4788  * @iter: a pointer to receive a #GtkTreeIter or %NULL
4789  *
4790  * This function is supposed to be used in a #GtkWidget::query-tooltip
4791  * signal handler for #GtkIconView.  The @x, @y and @keyboard_tip values
4792  * which are received in the signal handler, should be passed to this
4793  * function without modification.
4794  *
4795  * The return value indicates whether there is an icon view item at the given
4796  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
4797  * tooltips the item returned will be the cursor item. When %TRUE, then any of
4798  * @model, @path and @iter which have been provided will be set to point to
4799  * that row and the corresponding model. @x and @y will always be converted
4800  * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
4801  *
4802  * Return value: whether or not the given tooltip context points to a item
4803  *
4804  * Since: 2.12
4805  */
4806 gboolean
4807 gtk_icon_view_get_tooltip_context (GtkIconView   *icon_view,
4808                                    gint          *x,
4809                                    gint          *y,
4810                                    gboolean       keyboard_tip,
4811                                    GtkTreeModel **model,
4812                                    GtkTreePath  **path,
4813                                    GtkTreeIter   *iter)
4814 {
4815   GtkTreePath *tmppath = NULL;
4816
4817   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4818   g_return_val_if_fail (x != NULL, FALSE);
4819   g_return_val_if_fail (y != NULL, FALSE);
4820
4821   if (keyboard_tip)
4822     {
4823       gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
4824
4825       if (!tmppath)
4826         return FALSE;
4827     }
4828   else
4829     {
4830       gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
4831                                                          x, y);
4832
4833       if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
4834         return FALSE;
4835     }
4836
4837   if (model)
4838     *model = gtk_icon_view_get_model (icon_view);
4839
4840   if (iter)
4841     gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
4842                              iter, tmppath);
4843
4844   if (path)
4845     *path = tmppath;
4846   else
4847     gtk_tree_path_free (tmppath);
4848
4849   return TRUE;
4850 }
4851
4852 static gboolean
4853 gtk_icon_view_set_tooltip_query_cb (GtkWidget  *widget,
4854                                     gint        x,
4855                                     gint        y,
4856                                     gboolean    keyboard_tip,
4857                                     GtkTooltip *tooltip,
4858                                     gpointer    data)
4859 {
4860   gchar *str;
4861   GtkTreeIter iter;
4862   GtkTreePath *path;
4863   GtkTreeModel *model;
4864   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
4865
4866   if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
4867                                           &x, &y,
4868                                           keyboard_tip,
4869                                           &model, &path, &iter))
4870     return FALSE;
4871
4872   gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
4873
4874   if (!str)
4875     {
4876       gtk_tree_path_free (path);
4877       return FALSE;
4878     }
4879
4880   gtk_tooltip_set_markup (tooltip, str);
4881   gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
4882
4883   gtk_tree_path_free (path);
4884   g_free (str);
4885
4886   return TRUE;
4887 }
4888
4889
4890 /**
4891  * gtk_icon_view_set_tooltip_column:
4892  * @icon_view: a #GtkIconView
4893  * @column: an integer, which is a valid column number for @icon_view's model
4894  *
4895  * If you only plan to have simple (text-only) tooltips on full items, you
4896  * can use this function to have #GtkIconView handle these automatically
4897  * for you. @column should be set to the column in @icon_view's model
4898  * containing the tooltip texts, or -1 to disable this feature.
4899  *
4900  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
4901  * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
4902  *
4903  * Since: 2.12
4904  */
4905 void
4906 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
4907                                   gint         column)
4908 {
4909   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4910
4911   if (column == icon_view->priv->tooltip_column)
4912     return;
4913
4914   if (column == -1)
4915     {
4916       g_signal_handlers_disconnect_by_func (icon_view,
4917                                             gtk_icon_view_set_tooltip_query_cb,
4918                                             NULL);
4919       gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
4920     }
4921   else
4922     {
4923       if (icon_view->priv->tooltip_column == -1)
4924         {
4925           g_signal_connect (icon_view, "query-tooltip",
4926                             G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
4927           gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
4928         }
4929     }
4930
4931   icon_view->priv->tooltip_column = column;
4932   g_object_notify (G_OBJECT (icon_view), "tooltip-column");
4933 }
4934
4935 /** 
4936  * gtk_icon_view_get_tooltip_column:
4937  * @icon_view: a #GtkIconView
4938  *
4939  * Returns the column of @icon_view's model which is being used for
4940  * displaying tooltips on @icon_view's rows.
4941  *
4942  * Return value: the index of the tooltip column that is currently being
4943  * used, or -1 if this is disabled.
4944  *
4945  * Since: 2.12
4946  */
4947 gint
4948 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
4949 {
4950   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
4951
4952   return icon_view->priv->tooltip_column;
4953 }
4954
4955 /**
4956  * gtk_icon_view_get_visible_range:
4957  * @icon_view: A #GtkIconView
4958  * @start_path: Return location for start of region, or %NULL
4959  * @end_path: Return location for end of region, or %NULL
4960  * 
4961  * Sets @start_path and @end_path to be the first and last visible path. 
4962  * Note that there may be invisible paths in between.
4963  * 
4964  * Both paths should be freed with gtk_tree_path_free() after use.
4965  * 
4966  * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4967  *
4968  * Since: 2.8
4969  **/
4970 gboolean
4971 gtk_icon_view_get_visible_range (GtkIconView  *icon_view,
4972                                  GtkTreePath **start_path,
4973                                  GtkTreePath **end_path)
4974 {
4975   gint start_index = -1;
4976   gint end_index = -1;
4977   GList *icons;
4978
4979   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4980
4981   if (icon_view->priv->hadjustment == NULL ||
4982       icon_view->priv->vadjustment == NULL)
4983     return FALSE;
4984
4985   if (start_path == NULL && end_path == NULL)
4986     return FALSE;
4987   
4988   for (icons = icon_view->priv->items; icons; icons = icons->next) 
4989     {
4990       GtkIconViewItem *item = icons->data;
4991
4992       if ((item->x + item->width >= (int)icon_view->priv->hadjustment->value) &&
4993           (item->y + item->height >= (int)icon_view->priv->vadjustment->value) &&
4994           (item->x <= (int) (icon_view->priv->hadjustment->value + icon_view->priv->hadjustment->page_size)) &&
4995           (item->y <= (int) (icon_view->priv->vadjustment->value + icon_view->priv->vadjustment->page_size)))
4996         {
4997           if (start_index == -1)
4998             start_index = item->index;
4999           end_index = item->index;
5000         }
5001     }
5002
5003   if (start_path && start_index != -1)
5004     *start_path = gtk_tree_path_new_from_indices (start_index, -1);
5005   if (end_path && end_index != -1)
5006     *end_path = gtk_tree_path_new_from_indices (end_index, -1);
5007   
5008   return start_index != -1;
5009 }
5010
5011 /**
5012  * gtk_icon_view_selected_foreach:
5013  * @icon_view: A #GtkIconView.
5014  * @func: The funcion to call for each selected icon.
5015  * @data: User data to pass to the function.
5016  * 
5017  * Calls a function for each selected icon. Note that the model or
5018  * selection cannot be modified from within this function.
5019  *
5020  * Since: 2.6 
5021  **/
5022 void
5023 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
5024                                 GtkIconViewForeachFunc func,
5025                                 gpointer               data)
5026 {
5027   GList *list;
5028   
5029   for (list = icon_view->priv->items; list; list = list->next)
5030     {
5031       GtkIconViewItem *item = list->data;
5032       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5033
5034       if (item->selected)
5035         (* func) (icon_view, path, data);
5036
5037       gtk_tree_path_free (path);
5038     }
5039 }
5040
5041 /**
5042  * gtk_icon_view_set_selection_mode:
5043  * @icon_view: A #GtkIconView.
5044  * @mode: The selection mode
5045  * 
5046  * Sets the selection mode of the @icon_view.
5047  *
5048  * Since: 2.6 
5049  **/
5050 void
5051 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
5052                                   GtkSelectionMode  mode)
5053 {
5054   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5055
5056   if (mode == icon_view->priv->selection_mode)
5057     return;
5058   
5059   if (mode == GTK_SELECTION_NONE ||
5060       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
5061     gtk_icon_view_unselect_all (icon_view);
5062   
5063   icon_view->priv->selection_mode = mode;
5064
5065   g_object_notify (G_OBJECT (icon_view), "selection-mode");
5066 }
5067
5068 /**
5069  * gtk_icon_view_get_selection_mode:
5070  * @icon_view: A #GtkIconView.
5071  * 
5072  * Gets the selection mode of the @icon_view.
5073  *
5074  * Return value: the current selection mode
5075  *
5076  * Since: 2.6 
5077  **/
5078 GtkSelectionMode
5079 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
5080 {
5081   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
5082
5083   return icon_view->priv->selection_mode;
5084 }
5085
5086 /**
5087  * gtk_icon_view_set_model:
5088  * @icon_view: A #GtkIconView.
5089  * @model: The model.
5090  *
5091  * Sets the model for a #GtkIconView.  
5092  * If the @icon_view already has a model set, it will remove 
5093  * it before setting the new model.  If @model is %NULL, then
5094  * it will unset the old model.
5095  *
5096  * Since: 2.6 
5097  **/
5098 void
5099 gtk_icon_view_set_model (GtkIconView *icon_view,
5100                          GtkTreeModel *model)
5101 {
5102   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5103   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
5104   
5105   if (icon_view->priv->model == model)
5106     return;
5107
5108   if (icon_view->priv->scroll_to_path)
5109     {
5110       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
5111       icon_view->priv->scroll_to_path = NULL;
5112     }
5113
5114   gtk_icon_view_stop_editing (icon_view, TRUE);
5115
5116   if (model)
5117     {
5118       GType column_type;
5119       
5120       g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
5121
5122       if (icon_view->priv->pixbuf_column != -1)
5123         {
5124           column_type = gtk_tree_model_get_column_type (model,
5125                                                         icon_view->priv->pixbuf_column);          
5126
5127           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5128         }
5129
5130       if (icon_view->priv->text_column != -1)
5131         {
5132           column_type = gtk_tree_model_get_column_type (model,
5133                                                         icon_view->priv->text_column);    
5134
5135           g_return_if_fail (column_type == G_TYPE_STRING);
5136         }
5137
5138       if (icon_view->priv->markup_column != -1)
5139         {
5140           column_type = gtk_tree_model_get_column_type (model,
5141                                                         icon_view->priv->markup_column);          
5142
5143           g_return_if_fail (column_type == G_TYPE_STRING);
5144         }
5145       
5146     }
5147   
5148   if (icon_view->priv->model)
5149     {
5150       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5151                                             gtk_icon_view_row_changed,
5152                                             icon_view);
5153       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5154                                             gtk_icon_view_row_inserted,
5155                                             icon_view);
5156       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5157                                             gtk_icon_view_row_deleted,
5158                                             icon_view);
5159       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5160                                             gtk_icon_view_rows_reordered,
5161                                             icon_view);
5162
5163       g_object_unref (icon_view->priv->model);
5164       
5165       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
5166       g_list_free (icon_view->priv->items);
5167       icon_view->priv->items = NULL;
5168       icon_view->priv->anchor_item = NULL;
5169       icon_view->priv->cursor_item = NULL;
5170       icon_view->priv->last_single_clicked = NULL;
5171       icon_view->priv->width = 0;
5172       icon_view->priv->height = 0;
5173     }
5174
5175   icon_view->priv->model = model;
5176
5177   if (icon_view->priv->model)
5178     {
5179       g_object_ref (icon_view->priv->model);
5180       g_signal_connect (icon_view->priv->model,
5181                         "row_changed",
5182                         G_CALLBACK (gtk_icon_view_row_changed),
5183                         icon_view);
5184       g_signal_connect (icon_view->priv->model,
5185                         "row_inserted",
5186                         G_CALLBACK (gtk_icon_view_row_inserted),
5187                         icon_view);
5188       g_signal_connect (icon_view->priv->model,
5189                         "row_deleted",
5190                         G_CALLBACK (gtk_icon_view_row_deleted),
5191                         icon_view);
5192       g_signal_connect (icon_view->priv->model,
5193                         "rows_reordered",
5194                         G_CALLBACK (gtk_icon_view_rows_reordered),
5195                         icon_view);
5196
5197       gtk_icon_view_build_items (icon_view);
5198
5199       gtk_icon_view_queue_layout (icon_view);
5200     }
5201
5202   g_object_notify (G_OBJECT (icon_view), "model");  
5203
5204   if (GTK_WIDGET_REALIZED (icon_view))
5205     gtk_widget_queue_resize (GTK_WIDGET (icon_view));
5206 }
5207
5208 /**
5209  * gtk_icon_view_get_model:
5210  * @icon_view: a #GtkIconView
5211  *
5212  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
5213  * model is unset.
5214  *
5215  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
5216  *
5217  * Since: 2.6 
5218  **/
5219 GtkTreeModel *
5220 gtk_icon_view_get_model (GtkIconView *icon_view)
5221 {
5222   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5223
5224   return icon_view->priv->model;
5225 }
5226
5227 static void
5228 update_text_cell (GtkIconView *icon_view)
5229 {
5230   GtkIconViewCellInfo *info;
5231   GList *l;
5232   gint i;
5233           
5234   if (icon_view->priv->text_column == -1 &&
5235       icon_view->priv->markup_column == -1)
5236     {
5237       if (icon_view->priv->text_cell != -1)
5238         {
5239           if (icon_view->priv->pixbuf_cell > icon_view->priv->text_cell)
5240             icon_view->priv->pixbuf_cell--;
5241
5242           info = g_list_nth_data (icon_view->priv->cell_list, 
5243                                   icon_view->priv->text_cell);
5244           
5245           icon_view->priv->cell_list = g_list_remove (icon_view->priv->cell_list, info);
5246           
5247           free_cell_info (info);
5248           
5249           icon_view->priv->n_cells--;
5250           icon_view->priv->text_cell = -1;
5251         }
5252     }
5253   else 
5254     {
5255       if (icon_view->priv->text_cell == -1)
5256         {
5257           GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
5258           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), cell, FALSE);
5259           for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
5260             {
5261               info = l->data;
5262               if (info->cell == cell)
5263                 {
5264                   icon_view->priv->text_cell = i;
5265                   break;
5266                 }
5267             }
5268         }
5269       
5270       info = g_list_nth_data (icon_view->priv->cell_list,
5271                               icon_view->priv->text_cell);
5272
5273       if (icon_view->priv->markup_column != -1)
5274         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5275                                         info->cell, 
5276                                         "markup", icon_view->priv->markup_column, 
5277                                         NULL);
5278       else
5279         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5280                                         info->cell, 
5281                                         "text", icon_view->priv->text_column, 
5282                                         NULL);
5283
5284       if (icon_view->priv->orientation == GTK_ORIENTATION_VERTICAL)
5285         g_object_set (info->cell,
5286                       "alignment", PANGO_ALIGN_CENTER,
5287                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
5288                       "xalign", 0.0,
5289                       "yalign", 0.0,
5290                       NULL);
5291       else
5292         g_object_set (info->cell,
5293                       "alignment", PANGO_ALIGN_LEFT,
5294                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
5295                       "xalign", 0.0,
5296                       "yalign", 0.0,
5297                       NULL);
5298     }
5299 }
5300
5301 static void
5302 update_pixbuf_cell (GtkIconView *icon_view)
5303 {
5304   GtkIconViewCellInfo *info;
5305   GList *l;
5306   gint i;
5307
5308   if (icon_view->priv->pixbuf_column == -1)
5309     {
5310       if (icon_view->priv->pixbuf_cell != -1)
5311         {
5312           if (icon_view->priv->text_cell > icon_view->priv->pixbuf_cell)
5313             icon_view->priv->text_cell--;
5314
5315           info = g_list_nth_data (icon_view->priv->cell_list, 
5316                                   icon_view->priv->pixbuf_cell);
5317           
5318           icon_view->priv->cell_list = g_list_remove (icon_view->priv->cell_list, info);
5319           
5320           free_cell_info (info);
5321           
5322           icon_view->priv->n_cells--;
5323           icon_view->priv->pixbuf_cell = -1;
5324         }
5325     }
5326   else 
5327     {
5328       if (icon_view->priv->pixbuf_cell == -1)
5329         {
5330           GtkCellRenderer *cell = gtk_cell_renderer_pixbuf_new ();
5331           
5332           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), cell, FALSE);
5333           for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
5334             {
5335               info = l->data;
5336               if (info->cell == cell)
5337                 {
5338                   icon_view->priv->pixbuf_cell = i;
5339                   break;
5340                 }
5341             }
5342         }
5343       
5344         info = g_list_nth_data (icon_view->priv->cell_list, 
5345                                 icon_view->priv->pixbuf_cell);
5346         
5347         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5348                                         info->cell, 
5349                                         "pixbuf", icon_view->priv->pixbuf_column, 
5350                                         NULL);
5351
5352         if (icon_view->priv->orientation == GTK_ORIENTATION_VERTICAL)
5353           g_object_set (info->cell,
5354                         "follow-state", TRUE, 
5355                         "xalign", 0.5,
5356                         "yalign", 1.0,
5357                         NULL);
5358         else
5359           g_object_set (info->cell,
5360                         "follow-state", TRUE, 
5361                         "xalign", 0.0,
5362                         "yalign", 0.0,
5363                         NULL);
5364     }
5365 }
5366
5367 /**
5368  * gtk_icon_view_set_text_column:
5369  * @icon_view: A #GtkIconView.
5370  * @column: A column in the currently used model, or -1 to display no text
5371  * 
5372  * Sets the column with text for @icon_view to be @column. The text
5373  * column must be of type #G_TYPE_STRING.
5374  *
5375  * Since: 2.6 
5376  **/
5377 void
5378 gtk_icon_view_set_text_column (GtkIconView *icon_view,
5379                                gint          column)
5380 {
5381   if (column == icon_view->priv->text_column)
5382     return;
5383   
5384   if (column == -1)
5385     icon_view->priv->text_column = -1;
5386   else
5387     {
5388       if (icon_view->priv->model != NULL)
5389         {
5390           GType column_type;
5391           
5392           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5393
5394           g_return_if_fail (column_type == G_TYPE_STRING);
5395         }
5396       
5397       icon_view->priv->text_column = column;
5398     }
5399
5400   gtk_icon_view_stop_editing (icon_view, TRUE);
5401
5402   update_text_cell (icon_view);
5403
5404   gtk_icon_view_invalidate_sizes (icon_view);
5405   gtk_icon_view_queue_layout (icon_view);
5406   
5407   g_object_notify (G_OBJECT (icon_view), "text-column");
5408 }
5409
5410 /**
5411  * gtk_icon_view_get_text_column:
5412  * @icon_view: A #GtkIconView.
5413  *
5414  * Returns the column with text for @icon_view.
5415  *
5416  * Returns: the text column, or -1 if it's unset.
5417  *
5418  * Since: 2.6
5419  */
5420 gint
5421 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
5422 {
5423   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5424
5425   return icon_view->priv->text_column;
5426 }
5427
5428 /**
5429  * gtk_icon_view_set_markup_column:
5430  * @icon_view: A #GtkIconView.
5431  * @column: A column in the currently used model, or -1 to display no text
5432  * 
5433  * Sets the column with markup information for @icon_view to be
5434  * @column. The markup column must be of type #G_TYPE_STRING.
5435  * If the markup column is set to something, it overrides
5436  * the text column set by gtk_icon_view_set_text_column().
5437  *
5438  * Since: 2.6
5439  **/
5440 void
5441 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5442                                  gint         column)
5443 {
5444   if (column == icon_view->priv->markup_column)
5445     return;
5446   
5447   if (column == -1)
5448     icon_view->priv->markup_column = -1;
5449   else
5450     {
5451       if (icon_view->priv->model != NULL)
5452         {
5453           GType column_type;
5454           
5455           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5456
5457           g_return_if_fail (column_type == G_TYPE_STRING);
5458         }
5459       
5460       icon_view->priv->markup_column = column;
5461     }
5462
5463   gtk_icon_view_stop_editing (icon_view, TRUE);
5464
5465   update_text_cell (icon_view);
5466
5467   gtk_icon_view_invalidate_sizes (icon_view);
5468   gtk_icon_view_queue_layout (icon_view);
5469   
5470   g_object_notify (G_OBJECT (icon_view), "markup-column");
5471 }
5472
5473 /**
5474  * gtk_icon_view_get_markup_column:
5475  * @icon_view: A #GtkIconView.
5476  *
5477  * Returns the column with markup text for @icon_view.
5478  *
5479  * Returns: the markup column, or -1 if it's unset.
5480  *
5481  * Since: 2.6
5482  */
5483 gint
5484 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
5485 {
5486   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5487
5488   return icon_view->priv->markup_column;
5489 }
5490
5491 /**
5492  * gtk_icon_view_set_pixbuf_column:
5493  * @icon_view: A #GtkIconView.
5494  * @column: A column in the currently used model, or -1 to disable
5495  * 
5496  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5497  * column must be of type #GDK_TYPE_PIXBUF
5498  *
5499  * Since: 2.6 
5500  **/
5501 void
5502 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5503                                  gint         column)
5504 {
5505   if (column == icon_view->priv->pixbuf_column)
5506     return;
5507   
5508   if (column == -1)
5509     icon_view->priv->pixbuf_column = -1;
5510   else
5511     {
5512       if (icon_view->priv->model != NULL)
5513         {
5514           GType column_type;
5515           
5516           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5517
5518           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5519         }
5520       
5521       icon_view->priv->pixbuf_column = column;
5522     }
5523
5524   gtk_icon_view_stop_editing (icon_view, TRUE);
5525
5526   update_pixbuf_cell (icon_view);
5527
5528   gtk_icon_view_invalidate_sizes (icon_view);
5529   gtk_icon_view_queue_layout (icon_view);
5530   
5531   g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5532   
5533 }
5534
5535 /**
5536  * gtk_icon_view_get_pixbuf_column:
5537  * @icon_view: A #GtkIconView.
5538  *
5539  * Returns the column with pixbufs for @icon_view.
5540  *
5541  * Returns: the pixbuf column, or -1 if it's unset.
5542  *
5543  * Since: 2.6
5544  */
5545 gint
5546 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
5547 {
5548   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5549
5550   return icon_view->priv->pixbuf_column;
5551 }
5552
5553 /**
5554  * gtk_icon_view_select_path:
5555  * @icon_view: A #GtkIconView.
5556  * @path: The #GtkTreePath to be selected.
5557  * 
5558  * Selects the row at @path.
5559  *
5560  * Since: 2.6
5561  **/
5562 void
5563 gtk_icon_view_select_path (GtkIconView *icon_view,
5564                            GtkTreePath *path)
5565 {
5566   GtkIconViewItem *item = NULL;
5567
5568   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5569   g_return_if_fail (icon_view->priv->model != NULL);
5570   g_return_if_fail (path != NULL);
5571
5572   if (gtk_tree_path_get_depth (path) > 0)
5573     item = g_list_nth_data (icon_view->priv->items,
5574                             gtk_tree_path_get_indices(path)[0]);
5575
5576   if (item)
5577     gtk_icon_view_select_item (icon_view, item);
5578 }
5579
5580 /**
5581  * gtk_icon_view_unselect_path:
5582  * @icon_view: A #GtkIconView.
5583  * @path: The #GtkTreePath to be unselected.
5584  * 
5585  * Unselects the row at @path.
5586  *
5587  * Since: 2.6
5588  **/
5589 void
5590 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5591                              GtkTreePath *path)
5592 {
5593   GtkIconViewItem *item;
5594   
5595   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5596   g_return_if_fail (icon_view->priv->model != NULL);
5597   g_return_if_fail (path != NULL);
5598
5599   item = g_list_nth_data (icon_view->priv->items,
5600                           gtk_tree_path_get_indices(path)[0]);
5601
5602   if (!item)
5603     return;
5604   
5605   gtk_icon_view_unselect_item (icon_view, item);
5606 }
5607
5608 /**
5609  * gtk_icon_view_get_selected_items:
5610  * @icon_view: A #GtkIconView.
5611  *
5612  * Creates a list of paths of all selected items. Additionally, if you are
5613  * planning on modifying the model after calling this function, you may
5614  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5615  * To do this, you can use gtk_tree_row_reference_new().
5616  *
5617  * To free the return value, use:
5618  * |[
5619  * g_list_foreach (list, gtk_tree_path_free, NULL);
5620  * g_list_free (list);
5621  * ]|
5622  *
5623  * Return value: A #GList containing a #GtkTreePath for each selected row.
5624  *
5625  * Since: 2.6
5626  **/
5627 GList *
5628 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5629 {
5630   GList *list;
5631   GList *selected = NULL;
5632   
5633   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5634   
5635   for (list = icon_view->priv->items; list != NULL; list = list->next)
5636     {
5637       GtkIconViewItem *item = list->data;
5638
5639       if (item->selected)
5640         {
5641           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5642
5643           selected = g_list_prepend (selected, path);
5644         }
5645     }
5646
5647   return selected;
5648 }
5649
5650 /**
5651  * gtk_icon_view_select_all:
5652  * @icon_view: A #GtkIconView.
5653  * 
5654  * Selects all the icons. @icon_view must has its selection mode set
5655  * to #GTK_SELECTION_MULTIPLE.
5656  *
5657  * Since: 2.6
5658  **/
5659 void
5660 gtk_icon_view_select_all (GtkIconView *icon_view)
5661 {
5662   GList *items;
5663   gboolean dirty = FALSE;
5664   
5665   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5666
5667   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5668     return;
5669
5670   for (items = icon_view->priv->items; items; items = items->next)
5671     {
5672       GtkIconViewItem *item = items->data;
5673       
5674       if (!item->selected)
5675         {
5676           dirty = TRUE;
5677           item->selected = TRUE;
5678           gtk_icon_view_queue_draw_item (icon_view, item);
5679         }
5680     }
5681
5682   if (dirty)
5683     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5684 }
5685
5686 /**
5687  * gtk_icon_view_unselect_all:
5688  * @icon_view: A #GtkIconView.
5689  * 
5690  * Unselects all the icons.
5691  *
5692  * Since: 2.6
5693  **/
5694 void
5695 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5696 {
5697   gboolean dirty = FALSE;
5698   
5699   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5700
5701   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5702     return;
5703
5704   dirty = gtk_icon_view_unselect_all_internal (icon_view);
5705
5706   if (dirty)
5707     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5708 }
5709
5710 /**
5711  * gtk_icon_view_path_is_selected:
5712  * @icon_view: A #GtkIconView.
5713  * @path: A #GtkTreePath to check selection on.
5714  * 
5715  * Returns %TRUE if the icon pointed to by @path is currently
5716  * selected. If @path does not point to a valid location, %FALSE is returned.
5717  * 
5718  * Return value: %TRUE if @path is selected.
5719  *
5720  * Since: 2.6
5721  **/
5722 gboolean
5723 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5724                                 GtkTreePath *path)
5725 {
5726   GtkIconViewItem *item;
5727   
5728   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5729   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5730   g_return_val_if_fail (path != NULL, FALSE);
5731   
5732   item = g_list_nth_data (icon_view->priv->items,
5733                           gtk_tree_path_get_indices(path)[0]);
5734
5735   if (!item)
5736     return FALSE;
5737   
5738   return item->selected;
5739 }
5740
5741 /**
5742  * gtk_icon_view_item_activated:
5743  * @icon_view: A #GtkIconView
5744  * @path: The #GtkTreePath to be activated
5745  * 
5746  * Activates the item determined by @path.
5747  *
5748  * Since: 2.6
5749  **/
5750 void
5751 gtk_icon_view_item_activated (GtkIconView      *icon_view,
5752                               GtkTreePath      *path)
5753 {
5754   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5755   g_return_if_fail (path != NULL);
5756   
5757   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5758 }
5759
5760 /**
5761  * gtk_icon_view_set_orientation:
5762  * @icon_view: a #GtkIconView
5763  * @orientation: the relative position of texts and icons 
5764  * 
5765  * Sets the ::orientation property which determines whether the labels 
5766  * are drawn beside the icons instead of below.
5767  *
5768  * Since: 2.6
5769  **/
5770 void 
5771 gtk_icon_view_set_orientation (GtkIconView    *icon_view,
5772                                GtkOrientation  orientation)
5773 {
5774   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5775
5776   if (icon_view->priv->orientation != orientation)
5777     {
5778       icon_view->priv->orientation = orientation;
5779
5780       gtk_icon_view_stop_editing (icon_view, TRUE);
5781       gtk_icon_view_invalidate_sizes (icon_view);
5782       gtk_icon_view_queue_layout (icon_view);
5783
5784       update_text_cell (icon_view);
5785       update_pixbuf_cell (icon_view);
5786       
5787       g_object_notify (G_OBJECT (icon_view), "orientation");
5788     }
5789 }
5790
5791 /**
5792  * gtk_icon_view_get_orientation:
5793  * @icon_view: a #GtkIconView
5794  * 
5795  * Returns the value of the ::orientation property which determines 
5796  * whether the labels are drawn beside the icons instead of below. 
5797  * 
5798  * Return value: the relative position of texts and icons 
5799  *
5800  * Since: 2.6
5801  **/
5802 GtkOrientation
5803 gtk_icon_view_get_orientation (GtkIconView *icon_view)
5804 {
5805   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
5806                         GTK_ORIENTATION_VERTICAL);
5807
5808   return icon_view->priv->orientation;
5809 }
5810
5811 /**
5812  * gtk_icon_view_set_columns:
5813  * @icon_view: a #GtkIconView
5814  * @columns: the number of columns
5815  * 
5816  * Sets the ::columns property which determines in how
5817  * many columns the icons are arranged. If @columns is
5818  * -1, the number of columns will be chosen automatically 
5819  * to fill the available area. 
5820  *
5821  * Since: 2.6
5822  */
5823 void 
5824 gtk_icon_view_set_columns (GtkIconView *icon_view,
5825                            gint         columns)
5826 {
5827   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5828   
5829   if (icon_view->priv->columns != columns)
5830     {
5831       icon_view->priv->columns = columns;
5832
5833       gtk_icon_view_stop_editing (icon_view, TRUE);
5834       gtk_icon_view_queue_layout (icon_view);
5835       
5836       g_object_notify (G_OBJECT (icon_view), "columns");
5837     }  
5838 }
5839
5840 /**
5841  * gtk_icon_view_get_columns:
5842  * @icon_view: a #GtkIconView
5843  * 
5844  * Returns the value of the ::columns property.
5845  * 
5846  * Return value: the number of columns, or -1
5847  *
5848  * Since: 2.6
5849  */
5850 gint
5851 gtk_icon_view_get_columns (GtkIconView *icon_view)
5852 {
5853   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5854
5855   return icon_view->priv->columns;
5856 }
5857
5858 /**
5859  * gtk_icon_view_set_item_width:
5860  * @icon_view: a #GtkIconView
5861  * @item_width: the width for each item
5862  * 
5863  * Sets the ::item-width property which specifies the width 
5864  * to use for each item. If it is set to -1, the icon view will 
5865  * automatically determine a suitable item size.
5866  *
5867  * Since: 2.6
5868  */
5869 void 
5870 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5871                               gint         item_width)
5872 {
5873   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5874   
5875   if (icon_view->priv->item_width != item_width)
5876     {
5877       icon_view->priv->item_width = item_width;
5878       
5879       gtk_icon_view_stop_editing (icon_view, TRUE);
5880       gtk_icon_view_invalidate_sizes (icon_view);
5881       gtk_icon_view_queue_layout (icon_view);
5882       
5883       update_text_cell (icon_view);
5884
5885       g_object_notify (G_OBJECT (icon_view), "item-width");
5886     }  
5887 }
5888
5889 /**
5890  * gtk_icon_view_get_item_width:
5891  * @icon_view: a #GtkIconView
5892  * 
5893  * Returns the value of the ::item-width property.
5894  * 
5895  * Return value: the width of a single item, or -1
5896  *
5897  * Since: 2.6
5898  */
5899 gint
5900 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5901 {
5902   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5903
5904   return icon_view->priv->item_width;
5905 }
5906
5907
5908 /**
5909  * gtk_icon_view_set_spacing:
5910  * @icon_view: a #GtkIconView
5911  * @spacing: the spacing
5912  * 
5913  * Sets the ::spacing property which specifies the space 
5914  * which is inserted between the cells (i.e. the icon and 
5915  * the text) of an item.
5916  *
5917  * Since: 2.6
5918  */
5919 void 
5920 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5921                            gint         spacing)
5922 {
5923   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5924   
5925   if (icon_view->priv->spacing != spacing)
5926     {
5927       icon_view->priv->spacing = spacing;
5928
5929       gtk_icon_view_stop_editing (icon_view, TRUE);
5930       gtk_icon_view_invalidate_sizes (icon_view);
5931       gtk_icon_view_queue_layout (icon_view);
5932       
5933       g_object_notify (G_OBJECT (icon_view), "spacing");
5934     }  
5935 }
5936
5937 /**
5938  * gtk_icon_view_get_spacing:
5939  * @icon_view: a #GtkIconView
5940  * 
5941  * Returns the value of the ::spacing property.
5942  * 
5943  * Return value: the space between cells 
5944  *
5945  * Since: 2.6
5946  */
5947 gint
5948 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5949 {
5950   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5951
5952   return icon_view->priv->spacing;
5953 }
5954
5955 /**
5956  * gtk_icon_view_set_row_spacing:
5957  * @icon_view: a #GtkIconView
5958  * @row_spacing: the row spacing
5959  * 
5960  * Sets the ::row-spacing property which specifies the space 
5961  * which is inserted between the rows of the icon view.
5962  *
5963  * Since: 2.6
5964  */
5965 void 
5966 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5967                                gint         row_spacing)
5968 {
5969   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5970   
5971   if (icon_view->priv->row_spacing != row_spacing)
5972     {
5973       icon_view->priv->row_spacing = row_spacing;
5974
5975       gtk_icon_view_stop_editing (icon_view, TRUE);
5976       gtk_icon_view_invalidate_sizes (icon_view);
5977       gtk_icon_view_queue_layout (icon_view);
5978       
5979       g_object_notify (G_OBJECT (icon_view), "row-spacing");
5980     }  
5981 }
5982
5983 /**
5984  * gtk_icon_view_get_row_spacing:
5985  * @icon_view: a #GtkIconView
5986  * 
5987  * Returns the value of the ::row-spacing property.
5988  * 
5989  * Return value: the space between rows
5990  *
5991  * Since: 2.6
5992  */
5993 gint
5994 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5995 {
5996   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5997
5998   return icon_view->priv->row_spacing;
5999 }
6000
6001 /**
6002  * gtk_icon_view_set_column_spacing:
6003  * @icon_view: a #GtkIconView
6004  * @column_spacing: the column spacing
6005  * 
6006  * Sets the ::column-spacing property which specifies the space 
6007  * which is inserted between the columns of the icon view.
6008  *
6009  * Since: 2.6
6010  */
6011 void 
6012 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
6013                                   gint         column_spacing)
6014 {
6015   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6016   
6017   if (icon_view->priv->column_spacing != column_spacing)
6018     {
6019       icon_view->priv->column_spacing = column_spacing;
6020
6021       gtk_icon_view_stop_editing (icon_view, TRUE);
6022       gtk_icon_view_invalidate_sizes (icon_view);
6023       gtk_icon_view_queue_layout (icon_view);
6024       
6025       g_object_notify (G_OBJECT (icon_view), "column-spacing");
6026     }  
6027 }
6028
6029 /**
6030  * gtk_icon_view_get_column_spacing:
6031  * @icon_view: a #GtkIconView
6032  * 
6033  * Returns the value of the ::column-spacing property.
6034  * 
6035  * Return value: the space between columns
6036  *
6037  * Since: 2.6
6038  */
6039 gint
6040 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
6041 {
6042   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6043
6044   return icon_view->priv->column_spacing;
6045 }
6046
6047 /**
6048  * gtk_icon_view_set_margin:
6049  * @icon_view: a #GtkIconView
6050  * @margin: the margin
6051  * 
6052  * Sets the ::margin property which specifies the space 
6053  * which is inserted at the top, bottom, left and right 
6054  * of the icon view.
6055  *
6056  * Since: 2.6
6057  */
6058 void 
6059 gtk_icon_view_set_margin (GtkIconView *icon_view,
6060                           gint         margin)
6061 {
6062   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6063   
6064   if (icon_view->priv->margin != margin)
6065     {
6066       icon_view->priv->margin = margin;
6067
6068       gtk_icon_view_stop_editing (icon_view, TRUE);
6069       gtk_icon_view_invalidate_sizes (icon_view);
6070       gtk_icon_view_queue_layout (icon_view);
6071       
6072       g_object_notify (G_OBJECT (icon_view), "margin");
6073     }  
6074 }
6075
6076 /**
6077  * gtk_icon_view_get_margin:
6078  * @icon_view: a #GtkIconView
6079  * 
6080  * Returns the value of the ::margin property.
6081  * 
6082  * Return value: the space at the borders 
6083  *
6084  * Since: 2.6
6085  */
6086 gint
6087 gtk_icon_view_get_margin (GtkIconView *icon_view)
6088 {
6089   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6090
6091   return icon_view->priv->margin;
6092 }
6093
6094
6095 /* Get/set whether drag_motion requested the drag data and
6096  * drag_data_received should thus not actually insert the data,
6097  * since the data doesn't result from a drop.
6098  */
6099 static void
6100 set_status_pending (GdkDragContext *context,
6101                     GdkDragAction   suggested_action)
6102 {
6103   g_object_set_data (G_OBJECT (context),
6104                      I_("gtk-icon-view-status-pending"),
6105                      GINT_TO_POINTER (suggested_action));
6106 }
6107
6108 static GdkDragAction
6109 get_status_pending (GdkDragContext *context)
6110 {
6111   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6112                                              "gtk-icon-view-status-pending"));
6113 }
6114
6115 static void
6116 unset_reorderable (GtkIconView *icon_view)
6117 {
6118   if (icon_view->priv->reorderable)
6119     {
6120       icon_view->priv->reorderable = FALSE;
6121       g_object_notify (G_OBJECT (icon_view), "reorderable");
6122     }
6123 }
6124
6125 static void
6126 clear_source_info (GtkIconView *icon_view)
6127 {
6128   if (icon_view->priv->source_targets)
6129     gtk_target_list_unref (icon_view->priv->source_targets);
6130   icon_view->priv->source_targets = NULL;
6131
6132   icon_view->priv->source_set = FALSE;
6133 }
6134
6135 static void
6136 clear_dest_info (GtkIconView *icon_view)
6137 {
6138   if (icon_view->priv->dest_targets)
6139     gtk_target_list_unref (icon_view->priv->dest_targets);
6140   icon_view->priv->dest_targets = NULL;
6141
6142   icon_view->priv->dest_set = FALSE;
6143 }
6144
6145 static void
6146 set_source_row (GdkDragContext *context,
6147                 GtkTreeModel   *model,
6148                 GtkTreePath    *source_row)
6149 {
6150   if (source_row)
6151     g_object_set_data_full (G_OBJECT (context),
6152                             I_("gtk-icon-view-source-row"),
6153                             gtk_tree_row_reference_new (model, source_row),
6154                             (GDestroyNotify) gtk_tree_row_reference_free);
6155   else
6156     g_object_set_data_full (G_OBJECT (context),
6157                             I_("gtk-icon-view-source-row"),
6158                             NULL, NULL);
6159 }
6160
6161 static GtkTreePath*
6162 get_source_row (GdkDragContext *context)
6163 {
6164   GtkTreeRowReference *ref;
6165
6166   ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
6167
6168   if (ref)
6169     return gtk_tree_row_reference_get_path (ref);
6170   else
6171     return NULL;
6172 }
6173
6174 typedef struct
6175 {
6176   GtkTreeRowReference *dest_row;
6177   gboolean             empty_view_drop;
6178   gboolean             drop_append_mode;
6179 } DestRow;
6180
6181 static void
6182 dest_row_free (gpointer data)
6183 {
6184   DestRow *dr = (DestRow *)data;
6185
6186   gtk_tree_row_reference_free (dr->dest_row);
6187   g_free (dr);
6188 }
6189
6190 static void
6191 set_dest_row (GdkDragContext *context,
6192               GtkTreeModel   *model,
6193               GtkTreePath    *dest_row,
6194               gboolean        empty_view_drop,
6195               gboolean        drop_append_mode)
6196 {
6197   DestRow *dr;
6198
6199   if (!dest_row)
6200     {
6201       g_object_set_data_full (G_OBJECT (context),
6202                               I_("gtk-icon-view-dest-row"),
6203                               NULL, NULL);
6204       return;
6205     }
6206   
6207   dr = g_new0 (DestRow, 1);
6208      
6209   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6210   dr->empty_view_drop = empty_view_drop;
6211   dr->drop_append_mode = drop_append_mode;
6212   g_object_set_data_full (G_OBJECT (context),
6213                           I_("gtk-icon-view-dest-row"),
6214                           dr, (GDestroyNotify) dest_row_free);
6215 }
6216
6217 static GtkTreePath*
6218 get_dest_row (GdkDragContext *context)
6219 {
6220   DestRow *dr;
6221
6222   dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
6223
6224   if (dr)
6225     {
6226       GtkTreePath *path = NULL;
6227       
6228       if (dr->dest_row)
6229         path = gtk_tree_row_reference_get_path (dr->dest_row);
6230       else if (dr->empty_view_drop)
6231         path = gtk_tree_path_new_from_indices (0, -1);
6232       else
6233         path = NULL;
6234
6235       if (path && dr->drop_append_mode)
6236         gtk_tree_path_next (path);
6237
6238       return path;
6239     }
6240   else
6241     return NULL;
6242 }
6243
6244 static gboolean
6245 check_model_dnd (GtkTreeModel *model,
6246                  GType         required_iface,
6247                  const gchar  *signal)
6248 {
6249   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6250     {
6251       g_warning ("You must override the default '%s' handler "
6252                  "on GtkIconView when using models that don't support "
6253                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6254                  "is to connect to '%s' and call "
6255                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6256                  "the default handler from running. Look at the source code "
6257                  "for the default handler in gtkiconview.c to get an idea what "
6258                  "your handler should do. (gtkiconview.c is in the GTK+ source "
6259                  "code.) If you're using GTK+ from a language other than C, "
6260                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6261                  signal, g_type_name (required_iface), signal);
6262       return FALSE;
6263     }
6264   else
6265     return TRUE;
6266 }
6267
6268 static void
6269 remove_scroll_timeout (GtkIconView *icon_view)
6270 {
6271   if (icon_view->priv->scroll_timeout_id != 0)
6272     {
6273       g_source_remove (icon_view->priv->scroll_timeout_id);
6274
6275       icon_view->priv->scroll_timeout_id = 0;
6276     }
6277 }
6278
6279 static void
6280 gtk_icon_view_autoscroll (GtkIconView *icon_view)
6281 {
6282   gint px, py, x, y, width, height;
6283   gint hoffset, voffset;
6284
6285   gdk_window_get_pointer (GTK_WIDGET (icon_view)->window, &px, &py, NULL);
6286   gdk_window_get_geometry (GTK_WIDGET (icon_view)->window, &x, &y, &width, &height, NULL);
6287
6288   /* see if we are near the edge. */
6289   voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
6290   if (voffset > 0)
6291     voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
6292
6293   hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
6294   if (hoffset > 0)
6295     hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
6296
6297   if (voffset != 0)
6298     gtk_adjustment_set_value (icon_view->priv->vadjustment,
6299                               icon_view->priv->vadjustment->value + voffset);
6300
6301   if (hoffset != 0)
6302     gtk_adjustment_set_value (icon_view->priv->hadjustment,
6303                               icon_view->priv->hadjustment->value + hoffset);
6304 }
6305
6306
6307 static gboolean
6308 drag_scroll_timeout (gpointer data)
6309 {
6310   GtkIconView *icon_view = GTK_ICON_VIEW (data);
6311
6312   gtk_icon_view_autoscroll (icon_view);
6313
6314   return TRUE;
6315 }
6316
6317
6318 static gboolean
6319 set_destination (GtkIconView    *icon_view,
6320                  GdkDragContext *context,
6321                  gint            x,
6322                  gint            y,
6323                  GdkDragAction  *suggested_action,
6324                  GdkAtom        *target)
6325 {
6326   GtkWidget *widget;
6327   GtkTreePath *path = NULL;
6328   GtkIconViewDropPosition pos;
6329   GtkIconViewDropPosition old_pos;
6330   GtkTreePath *old_dest_path = NULL;
6331   gboolean can_drop = FALSE;
6332
6333   widget = GTK_WIDGET (icon_view);
6334
6335   *suggested_action = 0;
6336   *target = GDK_NONE;
6337
6338   if (!icon_view->priv->dest_set)
6339     {
6340       /* someone unset us as a drag dest, note that if
6341        * we return FALSE drag_leave isn't called
6342        */
6343
6344       gtk_icon_view_set_drag_dest_item (icon_view,
6345                                         NULL,
6346                                         GTK_ICON_VIEW_DROP_LEFT);
6347
6348       remove_scroll_timeout (GTK_ICON_VIEW (widget));
6349
6350       return FALSE; /* no longer a drop site */
6351     }
6352
6353   *target = gtk_drag_dest_find_target (widget, context, icon_view->priv->dest_targets);
6354   if (*target == GDK_NONE)
6355     return FALSE;
6356
6357   if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos)) 
6358     {
6359       gint n_children;
6360       GtkTreeModel *model;
6361       
6362       /* the row got dropped on empty space, let's setup a special case
6363        */
6364
6365       if (path)
6366         gtk_tree_path_free (path);
6367
6368       model = gtk_icon_view_get_model (icon_view);
6369
6370       n_children = gtk_tree_model_iter_n_children (model, NULL);
6371       if (n_children)
6372         {
6373           pos = GTK_ICON_VIEW_DROP_BELOW;
6374           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6375         }
6376       else
6377         {
6378           pos = GTK_ICON_VIEW_DROP_ABOVE;
6379           path = gtk_tree_path_new_from_indices (0, -1);
6380         }
6381
6382       can_drop = TRUE;
6383
6384       goto out;
6385     }
6386
6387   g_assert (path);
6388
6389   gtk_icon_view_get_drag_dest_item (icon_view,
6390                                     &old_dest_path,
6391                                     &old_pos);
6392   
6393   if (old_dest_path)
6394     gtk_tree_path_free (old_dest_path);
6395   
6396   if (TRUE /* FIXME if the location droppable predicate */)
6397     {
6398       can_drop = TRUE;
6399     }
6400
6401 out:
6402   if (can_drop)
6403     {
6404       GtkWidget *source_widget;
6405
6406       *suggested_action = context->suggested_action;
6407       source_widget = gtk_drag_get_source_widget (context);
6408
6409       if (source_widget == widget)
6410         {
6411           /* Default to MOVE, unless the user has
6412            * pressed ctrl or shift to affect available actions
6413            */
6414           if ((context->actions & GDK_ACTION_MOVE) != 0)
6415             *suggested_action = GDK_ACTION_MOVE;
6416         }
6417
6418       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6419                                         path, pos);
6420     }
6421   else
6422     {
6423       /* can't drop here */
6424       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6425                                         NULL,
6426                                         GTK_ICON_VIEW_DROP_LEFT);
6427     }
6428   
6429   if (path)
6430     gtk_tree_path_free (path);
6431   
6432   return TRUE;
6433 }
6434
6435 static GtkTreePath*
6436 get_logical_destination (GtkIconView *icon_view,
6437                          gboolean    *drop_append_mode)
6438 {
6439   /* adjust path to point to the row the drop goes in front of */
6440   GtkTreePath *path = NULL;
6441   GtkIconViewDropPosition pos;
6442   
6443   *drop_append_mode = FALSE;
6444
6445   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6446
6447   if (path == NULL)
6448     return NULL;
6449
6450   if (pos == GTK_ICON_VIEW_DROP_RIGHT || 
6451       pos == GTK_ICON_VIEW_DROP_BELOW)
6452     {
6453       GtkTreeIter iter;
6454       GtkTreeModel *model = icon_view->priv->model;
6455
6456       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6457           !gtk_tree_model_iter_next (model, &iter))
6458         *drop_append_mode = TRUE;
6459       else
6460         {
6461           *drop_append_mode = FALSE;
6462           gtk_tree_path_next (path);
6463         }      
6464     }
6465
6466   return path;
6467 }
6468
6469 static gboolean
6470 gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
6471                                 GdkEventMotion *event)
6472 {
6473   GdkDragContext *context;
6474   GtkTreePath *path = NULL;
6475   gint button;
6476   GtkTreeModel *model;
6477   gboolean retval = FALSE;
6478
6479   if (!icon_view->priv->source_set)
6480     goto out;
6481
6482   if (icon_view->priv->pressed_button < 0)
6483     goto out;
6484
6485   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6486                                  icon_view->priv->press_start_x,
6487                                  icon_view->priv->press_start_y,
6488                                  event->x, event->y))
6489     goto out;
6490
6491   model = gtk_icon_view_get_model (icon_view);
6492
6493   if (model == NULL)
6494     goto out;
6495
6496   button = icon_view->priv->pressed_button;
6497   icon_view->priv->pressed_button = -1;
6498
6499   path = gtk_icon_view_get_path_at_pos (icon_view,
6500                                         icon_view->priv->press_start_x,
6501                                         icon_view->priv->press_start_y);
6502
6503   if (path == NULL)
6504     goto out;
6505
6506   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6507       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6508                                            path))
6509     goto out;
6510
6511   /* FIXME Check whether we're a start button, if not return FALSE and
6512    * free path
6513    */
6514
6515   /* Now we can begin the drag */
6516   
6517   retval = TRUE;
6518
6519   context = gtk_drag_begin (GTK_WIDGET (icon_view),
6520                             icon_view->priv->source_targets,
6521                             icon_view->priv->source_actions,
6522                             button,
6523                             (GdkEvent*)event);
6524
6525   set_source_row (context, model, path);
6526   
6527  out:
6528   if (path)
6529     gtk_tree_path_free (path);
6530
6531   return retval;
6532 }
6533
6534 /* Source side drag signals */
6535 static void 
6536 gtk_icon_view_drag_begin (GtkWidget      *widget,
6537                           GdkDragContext *context)
6538 {
6539   GtkIconView *icon_view;
6540   GtkIconViewItem *item;
6541   GdkPixmap *icon;
6542   gint x, y;
6543   GtkTreePath *path;
6544
6545   icon_view = GTK_ICON_VIEW (widget);
6546
6547   /* if the user uses a custom DnD impl, we don't set the icon here */
6548   if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6549     return;
6550
6551   item = gtk_icon_view_get_item_at_coords (icon_view,
6552                                            icon_view->priv->press_start_x,
6553                                            icon_view->priv->press_start_y,
6554                                            TRUE,
6555                                            NULL);
6556
6557   g_return_if_fail (item != NULL);
6558
6559   x = icon_view->priv->press_start_x - item->x + 1;
6560   y = icon_view->priv->press_start_y - item->y + 1;
6561   
6562   path = gtk_tree_path_new_from_indices (item->index, -1);
6563   icon = gtk_icon_view_create_drag_icon (icon_view, path);
6564   gtk_tree_path_free (path);
6565
6566   gtk_drag_set_icon_pixmap (context, 
6567                             gdk_drawable_get_colormap (icon),
6568                             icon, 
6569                             NULL, 
6570                             x, y);
6571
6572   g_object_unref (icon);
6573 }
6574
6575 static void 
6576 gtk_icon_view_drag_end (GtkWidget      *widget,
6577                         GdkDragContext *context)
6578 {
6579   /* do nothing */
6580 }
6581
6582 static void 
6583 gtk_icon_view_drag_data_get (GtkWidget        *widget,
6584                              GdkDragContext   *context,
6585                              GtkSelectionData *selection_data,
6586                              guint             info,
6587                              guint             time)
6588 {
6589   GtkIconView *icon_view;
6590   GtkTreeModel *model;
6591   GtkTreePath *source_row;
6592
6593   icon_view = GTK_ICON_VIEW (widget);
6594   model = gtk_icon_view_get_model (icon_view);
6595
6596   if (model == NULL)
6597     return;
6598
6599   if (!icon_view->priv->dest_set)
6600     return;
6601
6602   source_row = get_source_row (context);
6603
6604   if (source_row == NULL)
6605     return;
6606
6607   /* We can implement the GTK_TREE_MODEL_ROW target generically for
6608    * any model; for DragSource models there are some other targets
6609    * we also support.
6610    */
6611
6612   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6613       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6614                                           source_row,
6615                                           selection_data))
6616     goto done;
6617
6618   /* If drag_data_get does nothing, try providing row data. */
6619   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6620     gtk_tree_set_row_drag_data (selection_data,
6621                                 model,
6622                                 source_row);
6623
6624  done:
6625   gtk_tree_path_free (source_row);
6626 }
6627
6628 static void 
6629 gtk_icon_view_drag_data_delete (GtkWidget      *widget,
6630                                 GdkDragContext *context)
6631 {
6632   GtkTreeModel *model;
6633   GtkIconView *icon_view;
6634   GtkTreePath *source_row;
6635
6636   icon_view = GTK_ICON_VIEW (widget);
6637   model = gtk_icon_view_get_model (icon_view);
6638
6639   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
6640     return;
6641
6642   if (!icon_view->priv->dest_set)
6643     return;
6644
6645   source_row = get_source_row (context);
6646
6647   if (source_row == NULL)
6648     return;
6649
6650   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6651                                          source_row);
6652
6653   gtk_tree_path_free (source_row);
6654
6655   set_source_row (context, NULL, NULL);
6656 }
6657
6658 /* Target side drag signals */
6659 static void
6660 gtk_icon_view_drag_leave (GtkWidget      *widget,
6661                           GdkDragContext *context,
6662                           guint           time)
6663 {
6664   GtkIconView *icon_view;
6665
6666   icon_view = GTK_ICON_VIEW (widget);
6667
6668   /* unset any highlight row */
6669   gtk_icon_view_set_drag_dest_item (icon_view,
6670                                     NULL,
6671                                     GTK_ICON_VIEW_DROP_LEFT);
6672
6673   remove_scroll_timeout (icon_view);
6674 }
6675
6676 static gboolean 
6677 gtk_icon_view_drag_motion (GtkWidget      *widget,
6678                            GdkDragContext *context,
6679                            gint            x,
6680                            gint            y,
6681                            guint           time)
6682 {
6683   GtkTreePath *path = NULL;
6684   GtkIconViewDropPosition pos;
6685   GtkIconView *icon_view;
6686   GdkDragAction suggested_action = 0;
6687   GdkAtom target;
6688   gboolean empty;
6689
6690   icon_view = GTK_ICON_VIEW (widget);
6691
6692   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6693     return FALSE;
6694
6695   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6696
6697   /* we only know this *after* set_desination_row */
6698   empty = icon_view->priv->empty_view_drop;
6699
6700   if (path == NULL && !empty)
6701     {
6702       /* Can't drop here. */
6703       gdk_drag_status (context, 0, time);
6704     }
6705   else
6706     {
6707       if (icon_view->priv->scroll_timeout_id == 0)
6708         {
6709           icon_view->priv->scroll_timeout_id =
6710             gdk_threads_add_timeout (50, drag_scroll_timeout, icon_view);
6711         }
6712
6713       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6714         {
6715           /* Request data so we can use the source row when
6716            * determining whether to accept the drop
6717            */
6718           set_status_pending (context, suggested_action);
6719           gtk_drag_get_data (widget, context, target, time);
6720         }
6721       else
6722         {
6723           set_status_pending (context, 0);
6724           gdk_drag_status (context, suggested_action, time);
6725         }
6726     }
6727
6728   if (path)
6729     gtk_tree_path_free (path);
6730
6731   return TRUE;
6732 }
6733
6734 static gboolean 
6735 gtk_icon_view_drag_drop (GtkWidget      *widget,
6736                          GdkDragContext *context,
6737                          gint            x,
6738                          gint            y,
6739                          guint           time)
6740 {
6741   GtkIconView *icon_view;
6742   GtkTreePath *path;
6743   GdkDragAction suggested_action = 0;
6744   GdkAtom target = GDK_NONE;
6745   GtkTreeModel *model;
6746   gboolean drop_append_mode;
6747
6748   icon_view = GTK_ICON_VIEW (widget);
6749   model = gtk_icon_view_get_model (icon_view);
6750
6751   remove_scroll_timeout (GTK_ICON_VIEW (widget));
6752
6753   if (!icon_view->priv->dest_set)
6754     return FALSE;
6755
6756   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
6757     return FALSE;
6758
6759   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6760     return FALSE;
6761   
6762   path = get_logical_destination (icon_view, &drop_append_mode);
6763
6764   if (target != GDK_NONE && path != NULL)
6765     {
6766       /* in case a motion had requested drag data, change things so we
6767        * treat drag data receives as a drop.
6768        */
6769       set_status_pending (context, 0);
6770       set_dest_row (context, model, path, 
6771                     icon_view->priv->empty_view_drop, drop_append_mode);
6772     }
6773
6774   if (path)
6775     gtk_tree_path_free (path);
6776
6777   /* Unset this thing */
6778   gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6779
6780   if (target != GDK_NONE)
6781     {
6782       gtk_drag_get_data (widget, context, target, time);
6783       return TRUE;
6784     }
6785   else
6786     return FALSE;
6787 }
6788
6789 static void
6790 gtk_icon_view_drag_data_received (GtkWidget        *widget,
6791                                   GdkDragContext   *context,
6792                                   gint              x,
6793                                   gint              y,
6794                                   GtkSelectionData *selection_data,
6795                                   guint             info,
6796                                   guint             time)
6797 {
6798   GtkTreePath *path;
6799   gboolean accepted = FALSE;
6800   GtkTreeModel *model;
6801   GtkIconView *icon_view;
6802   GtkTreePath *dest_row;
6803   GdkDragAction suggested_action;
6804   gboolean drop_append_mode;
6805   
6806   icon_view = GTK_ICON_VIEW (widget);  
6807   model = gtk_icon_view_get_model (icon_view);
6808
6809   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
6810     return;
6811
6812   if (!icon_view->priv->dest_set)
6813     return;
6814
6815   suggested_action = get_status_pending (context);
6816
6817   if (suggested_action)
6818     {
6819       /* We are getting this data due to a request in drag_motion,
6820        * rather than due to a request in drag_drop, so we are just
6821        * supposed to call drag_status, not actually paste in the
6822        * data.
6823        */
6824       path = get_logical_destination (icon_view, &drop_append_mode);
6825
6826       if (path == NULL)
6827         suggested_action = 0;
6828
6829       if (suggested_action)
6830         {
6831           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6832                                                      path,
6833                                                      selection_data))
6834             suggested_action = 0;
6835         }
6836
6837       gdk_drag_status (context, suggested_action, time);
6838
6839       if (path)
6840         gtk_tree_path_free (path);
6841
6842       /* If you can't drop, remove user drop indicator until the next motion */
6843       if (suggested_action == 0)
6844         gtk_icon_view_set_drag_dest_item (icon_view,
6845                                           NULL,
6846                                           GTK_ICON_VIEW_DROP_LEFT);
6847       return;
6848     }
6849   
6850
6851   dest_row = get_dest_row (context);
6852
6853   if (dest_row == NULL)
6854     return;
6855
6856   if (selection_data->length >= 0)
6857     {
6858       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6859                                                  dest_row,
6860                                                  selection_data))
6861         accepted = TRUE;
6862     }
6863
6864   gtk_drag_finish (context,
6865                    accepted,
6866                    (context->action == GDK_ACTION_MOVE),
6867                    time);
6868
6869   gtk_tree_path_free (dest_row);
6870
6871   /* drop dest_row */
6872   set_dest_row (context, NULL, NULL, FALSE, FALSE);
6873 }
6874
6875 /* Drag-and-Drop support */
6876 /**
6877  * gtk_icon_view_enable_model_drag_source:
6878  * @icon_view: a #GtkIconTreeView
6879  * @start_button_mask: Mask of allowed buttons to start drag
6880  * @targets: the table of targets that the drag will support
6881  * @n_targets: the number of items in @targets
6882  * @actions: the bitmask of possible actions for a drag from this
6883  *    widget
6884  * 
6885  * Turns @icon_view into a drag source for automatic DND.
6886  *
6887  * Since: 2.8
6888  **/
6889 void
6890 gtk_icon_view_enable_model_drag_source (GtkIconView              *icon_view,
6891                                         GdkModifierType           start_button_mask,
6892                                         const GtkTargetEntry     *targets,
6893                                         gint                      n_targets,
6894                                         GdkDragAction             actions)
6895 {
6896   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6897
6898   gtk_drag_source_set (GTK_WIDGET (icon_view), 0, NULL, 0, actions);
6899
6900   clear_source_info (icon_view);
6901   icon_view->priv->start_button_mask = start_button_mask;
6902   icon_view->priv->source_targets = gtk_target_list_new (targets, n_targets);
6903   icon_view->priv->source_actions = actions;
6904
6905   icon_view->priv->source_set = TRUE;
6906
6907   unset_reorderable (icon_view);
6908 }
6909
6910 /**
6911  * gtk_icon_view_enable_model_drag_dest:
6912  * @icon_view: a #GtkIconView
6913  * @targets: the table of targets that the drag will support
6914  * @n_targets: the number of items in @targets
6915  * @actions: the bitmask of possible actions for a drag to this
6916  *    widget
6917  * 
6918  * Turns @icon_view into a drop destination for automatic DND.
6919  *
6920  * Since: 2.8
6921  **/
6922 void 
6923 gtk_icon_view_enable_model_drag_dest (GtkIconView          *icon_view,
6924                                       const GtkTargetEntry *targets,
6925                                       gint                  n_targets,
6926                                       GdkDragAction         actions)
6927 {
6928   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6929
6930   gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, NULL, 0, actions);
6931
6932   clear_dest_info (icon_view);
6933
6934   icon_view->priv->dest_targets = gtk_target_list_new (targets, n_targets);
6935   icon_view->priv->dest_actions = actions;
6936
6937   icon_view->priv->dest_set = TRUE;
6938
6939   unset_reorderable (icon_view);  
6940 }
6941
6942 /**
6943  * gtk_icon_view_unset_model_drag_source:
6944  * @icon_view: a #GtkIconView
6945  * 
6946  * Undoes the effect of gtk_icon_view_enable_model_drag_source().
6947  *
6948  * Since: 2.8
6949  **/
6950 void
6951 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6952 {
6953   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6954
6955   if (icon_view->priv->source_set)
6956     {
6957       gtk_drag_source_unset (GTK_WIDGET (icon_view));
6958       clear_source_info (icon_view);
6959     }
6960
6961   unset_reorderable (icon_view);
6962 }
6963
6964 /**
6965  * gtk_icon_view_unset_model_drag_dest:
6966  * @icon_view: a #GtkIconView
6967  * 
6968  * Undoes the effect of gtk_icon_view_enable_model_drag_dest().
6969  *
6970  * Since: 2.8
6971  **/
6972 void
6973 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6974 {
6975   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6976
6977   if (icon_view->priv->dest_set)
6978     {
6979       gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6980       clear_dest_info (icon_view);
6981     }
6982
6983   unset_reorderable (icon_view);
6984 }
6985
6986 /* These are useful to implement your own custom stuff. */
6987 /**
6988  * gtk_icon_view_set_drag_dest_item:
6989  * @icon_view: a #GtkIconView
6990  * @path: The path of the item to highlight, or %NULL.
6991  * @pos: Specifies where to drop, relative to the item
6992  * 
6993  * Sets the item that is highlighted for feedback.
6994  *
6995  * Since: 2.8
6996  */
6997 void
6998 gtk_icon_view_set_drag_dest_item (GtkIconView              *icon_view,
6999                                   GtkTreePath              *path,
7000                                   GtkIconViewDropPosition   pos)
7001 {
7002   /* Note; this function is exported to allow a custom DND
7003    * implementation, so it can't touch TreeViewDragInfo
7004    */
7005
7006   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7007
7008   if (icon_view->priv->dest_item)
7009     {
7010       GtkTreePath *current_path;
7011       current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
7012       gtk_tree_row_reference_free (icon_view->priv->dest_item);
7013       icon_view->priv->dest_item = NULL;      
7014
7015       gtk_icon_view_queue_draw_path (icon_view, current_path);
7016       gtk_tree_path_free (current_path);
7017     }
7018   
7019   /* special case a drop on an empty model */
7020   icon_view->priv->empty_view_drop = FALSE;
7021   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
7022       && gtk_tree_path_get_depth (path) == 1
7023       && gtk_tree_path_get_indices (path)[0] == 0)
7024     {
7025       gint n_children;
7026
7027       n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
7028                                                    NULL);
7029
7030       if (n_children == 0)
7031         icon_view->priv->empty_view_drop = TRUE;
7032     }
7033
7034   icon_view->priv->dest_pos = pos;
7035
7036   if (path)
7037     {
7038       icon_view->priv->dest_item =
7039         gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), 
7040                                           icon_view->priv->model, path);
7041       
7042       gtk_icon_view_queue_draw_path (icon_view, path);
7043     }
7044 }
7045
7046 /**
7047  * gtk_icon_view_get_drag_dest_item:
7048  * @icon_view: a #GtkIconView
7049  * @path: Return location for the path of the highlighted item, or %NULL.
7050  * @pos: Return location for the drop position, or %NULL
7051  * 
7052  * Gets information about the item that is highlighted for feedback.
7053  *
7054  * Since: 2.8
7055  **/
7056 void
7057 gtk_icon_view_get_drag_dest_item (GtkIconView              *icon_view,
7058                                   GtkTreePath             **path,
7059                                   GtkIconViewDropPosition  *pos)
7060 {
7061   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7062
7063   if (path)
7064     {
7065       if (icon_view->priv->dest_item)
7066         *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
7067       else
7068         *path = NULL;
7069     }
7070
7071   if (pos)
7072     *pos = icon_view->priv->dest_pos;
7073 }
7074
7075 /**
7076  * gtk_icon_view_get_dest_item_at_pos:
7077  * @icon_view: a #GtkIconView
7078  * @drag_x: the position to determine the destination item for
7079  * @drag_y: the position to determine the destination item for
7080  * @path: Return location for the path of the item, or %NULL.
7081  * @pos: Return location for the drop position, or %NULL
7082  * 
7083  * Determines the destination item for a given position.
7084  * 
7085  * Return value: whether there is an item at the given position.
7086  *
7087  * Since: 2.8
7088  **/
7089 gboolean
7090 gtk_icon_view_get_dest_item_at_pos (GtkIconView              *icon_view,
7091                                     gint                      drag_x,
7092                                     gint                      drag_y,
7093                                     GtkTreePath             **path,
7094                                     GtkIconViewDropPosition  *pos)
7095 {
7096   GtkIconViewItem *item;
7097
7098   /* Note; this function is exported to allow a custom DND
7099    * implementation, so it can't touch TreeViewDragInfo
7100    */
7101
7102   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
7103   g_return_val_if_fail (drag_x >= 0, FALSE);
7104   g_return_val_if_fail (drag_y >= 0, FALSE);
7105   g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
7106
7107
7108   if (path)
7109     *path = NULL;
7110
7111   item = gtk_icon_view_get_item_at_coords (icon_view, 
7112                                            drag_x + icon_view->priv->hadjustment->value, 
7113                                            drag_y + icon_view->priv->vadjustment->value,
7114                                            FALSE, NULL);
7115
7116   if (item == NULL)
7117     return FALSE;
7118
7119   if (path)
7120     *path = gtk_tree_path_new_from_indices (item->index, -1);
7121
7122   if (pos)
7123     {
7124       if (drag_x < item->x + item->width / 4)
7125         *pos = GTK_ICON_VIEW_DROP_LEFT;
7126       else if (drag_x > item->x + item->width * 3 / 4)
7127         *pos = GTK_ICON_VIEW_DROP_RIGHT;
7128       else if (drag_y < item->y + item->height / 4)
7129         *pos = GTK_ICON_VIEW_DROP_ABOVE;
7130       else if (drag_y > item->y + item->height * 3 / 4)
7131         *pos = GTK_ICON_VIEW_DROP_BELOW;
7132       else
7133         *pos = GTK_ICON_VIEW_DROP_INTO;
7134     }
7135
7136   return TRUE;
7137 }
7138
7139 /**
7140  * gtk_icon_view_create_drag_icon:
7141  * @icon_view: a #GtkIconView
7142  * @path: a #GtkTreePath in @icon_view
7143  *
7144  * Creates a #GdkPixmap representation of the item at @path.  
7145  * This image is used for a drag icon.
7146  *
7147  * Return value: a newly-allocated pixmap of the drag icon.
7148  * 
7149  * Since: 2.8
7150  **/
7151 GdkPixmap *
7152 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
7153                                 GtkTreePath *path)
7154 {
7155   GtkWidget *widget;
7156   cairo_t *cr;
7157   GdkPixmap *drawable;
7158   GList *l;
7159   gint index;
7160   GdkRectangle area;
7161
7162   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
7163   g_return_val_if_fail (path != NULL, NULL);
7164
7165   widget = GTK_WIDGET (icon_view);
7166
7167   if (!GTK_WIDGET_REALIZED (widget))
7168     return NULL;
7169
7170   index = gtk_tree_path_get_indices (path)[0];
7171
7172   for (l = icon_view->priv->items; l; l = l->next) 
7173     {
7174       GtkIconViewItem *item = l->data;
7175       
7176       if (index == item->index)
7177         {
7178           drawable = gdk_pixmap_new (icon_view->priv->bin_window,
7179                                      item->width + 2,
7180                                      item->height + 2,
7181                                      -1);
7182
7183           cr = gdk_cairo_create (drawable);
7184           cairo_set_line_width (cr, 1.);
7185
7186           gdk_cairo_set_source_color
7187             (cr, &widget->style->base[GTK_WIDGET_STATE (widget)]);
7188           cairo_rectangle (cr, 0, 0, item->width + 2, item->height + 2);
7189           cairo_fill (cr);
7190
7191           area.x = 0;
7192           area.y = 0;
7193           area.width = item->width;
7194           area.height = item->height;
7195
7196           gtk_icon_view_paint_item (icon_view, cr, item, &area, 
7197                                     drawable, 1, 1, FALSE); 
7198
7199           cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
7200           cairo_rectangle (cr, 0.5, 0.5, item->width + 1, item->height + 1);
7201           cairo_stroke (cr);
7202
7203           cairo_destroy (cr);
7204
7205           return drawable;
7206         }
7207     }
7208   
7209   return NULL;
7210 }
7211
7212 /**
7213  * gtk_icon_view_get_reorderable:
7214  * @icon_view: a #GtkIconView
7215  *
7216  * Retrieves whether the user can reorder the list via drag-and-drop. 
7217  * See gtk_icon_view_set_reorderable().
7218  *
7219  * Return value: %TRUE if the list can be reordered.
7220  *
7221  * Since: 2.8
7222  **/
7223 gboolean
7224 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
7225 {
7226   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
7227
7228   return icon_view->priv->reorderable;
7229 }
7230
7231 static const GtkTargetEntry item_targets[] = {
7232   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7233 };
7234
7235
7236 /**
7237  * gtk_icon_view_set_reorderable:
7238  * @icon_view: A #GtkIconView.
7239  * @reorderable: %TRUE, if the list of items can be reordered.
7240  *
7241  * This function is a convenience function to allow you to reorder models that
7242  * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface.  Both
7243  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
7244  * the user can reorder the model by dragging and dropping rows.  The
7245  * developer can listen to these changes by connecting to the model's
7246  * row_inserted and row_deleted signals.
7247  *
7248  * This function does not give you any degree of control over the order -- any
7249  * reordering is allowed.  If more control is needed, you should probably
7250  * handle drag and drop manually.
7251  *
7252  * Since: 2.8
7253  **/
7254 void
7255 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
7256                                gboolean     reorderable)
7257 {
7258   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7259
7260   reorderable = reorderable != FALSE;
7261
7262   if (icon_view->priv->reorderable == reorderable)
7263     return;
7264
7265   if (reorderable)
7266     {
7267       gtk_icon_view_enable_model_drag_source (icon_view,
7268                                               GDK_BUTTON1_MASK,
7269                                               item_targets,
7270                                               G_N_ELEMENTS (item_targets),
7271                                               GDK_ACTION_MOVE);
7272       gtk_icon_view_enable_model_drag_dest (icon_view,
7273                                             item_targets,
7274                                             G_N_ELEMENTS (item_targets),
7275                                             GDK_ACTION_MOVE);
7276     }
7277   else
7278     {
7279       gtk_icon_view_unset_model_drag_source (icon_view);
7280       gtk_icon_view_unset_model_drag_dest (icon_view);
7281     }
7282
7283   icon_view->priv->reorderable = reorderable;
7284
7285   g_object_notify (G_OBJECT (icon_view), "reorderable");
7286 }
7287
7288
7289 /* Accessibility Support */
7290
7291 static gpointer accessible_parent_class;
7292 static gpointer accessible_item_parent_class;
7293 static GQuark accessible_private_data_quark = 0;
7294
7295 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (gtk_icon_view_item_accessible_get_type ())
7296 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
7297 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
7298
7299 static GType gtk_icon_view_item_accessible_get_type (void);
7300
7301 enum {
7302     ACTION_ACTIVATE,
7303     LAST_ACTION
7304 };
7305
7306 typedef struct
7307 {
7308   AtkObject parent;
7309
7310   GtkIconViewItem *item;
7311
7312   GtkWidget *widget;
7313
7314   AtkStateSet *state_set;
7315
7316   gchar *text;
7317
7318   GtkTextBuffer *text_buffer;
7319
7320   gchar *action_descriptions[LAST_ACTION];
7321   gchar *image_description;
7322   guint action_idle_handler;
7323 } GtkIconViewItemAccessible;
7324
7325 static const gchar *const gtk_icon_view_item_accessible_action_names[] = 
7326 {
7327   "activate",
7328   NULL
7329 };
7330
7331 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
7332 {
7333   "Activate item",
7334   NULL
7335 };
7336 typedef struct _GtkIconViewItemAccessibleClass
7337 {
7338   AtkObjectClass parent_class;
7339
7340 } GtkIconViewItemAccessibleClass;
7341
7342 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
7343
7344 static gboolean
7345 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
7346 {
7347   GtkIconViewItemAccessible *item;
7348   GtkIconView *icon_view;
7349   GtkTreePath *path;
7350
7351   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
7352   item->action_idle_handler = 0;
7353
7354   if (item->widget != NULL)
7355     {
7356       icon_view = GTK_ICON_VIEW (item->widget);
7357       path = gtk_tree_path_new_from_indices (item->item->index, -1);
7358       gtk_icon_view_item_activated (icon_view, path);
7359       gtk_tree_path_free (path);
7360     }
7361
7362   return FALSE;
7363 }
7364
7365 static gboolean
7366 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
7367                                                 gint       i)
7368 {
7369   GtkIconViewItemAccessible *item;
7370
7371   if (i < 0 || i >= LAST_ACTION) 
7372     return FALSE;
7373
7374   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7375
7376   if (!GTK_IS_ICON_VIEW (item->widget))
7377     return FALSE;
7378
7379   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7380     return FALSE;
7381
7382   switch (i)
7383     {
7384     case ACTION_ACTIVATE:
7385       if (!item->action_idle_handler)
7386         item->action_idle_handler = gdk_threads_add_idle (gtk_icon_view_item_accessible_idle_do_action, item);
7387       break;
7388     default:
7389       g_assert_not_reached ();
7390       return FALSE;
7391
7392     }        
7393   return TRUE;
7394 }
7395
7396 static gint
7397 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
7398 {
7399         return LAST_ACTION;
7400 }
7401
7402 static const gchar *
7403 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
7404                                                       gint       i)
7405 {
7406   GtkIconViewItemAccessible *item;
7407
7408   if (i < 0 || i >= LAST_ACTION) 
7409     return NULL;
7410
7411   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7412
7413   if (item->action_descriptions[i])
7414     return item->action_descriptions[i];
7415   else
7416     return gtk_icon_view_item_accessible_action_descriptions[i];
7417 }
7418
7419 static const gchar *
7420 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
7421                                                gint       i)
7422 {
7423   if (i < 0 || i >= LAST_ACTION) 
7424     return NULL;
7425
7426   return gtk_icon_view_item_accessible_action_names[i];
7427 }
7428
7429 static gboolean
7430 gtk_icon_view_item_accessible_action_set_description (AtkAction   *action,
7431                                                       gint         i,
7432                                                       const gchar *description)
7433 {
7434   GtkIconViewItemAccessible *item;
7435
7436   if (i < 0 || i >= LAST_ACTION) 
7437     return FALSE;
7438
7439   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7440
7441   g_free (item->action_descriptions[i]);
7442
7443   item->action_descriptions[i] = g_strdup (description);
7444
7445   return TRUE;
7446 }
7447
7448 static void
7449 atk_action_item_interface_init (AtkActionIface *iface)
7450 {
7451   iface->do_action = gtk_icon_view_item_accessible_action_do_action;
7452   iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
7453   iface->get_description = gtk_icon_view_item_accessible_action_get_description;
7454   iface->get_name = gtk_icon_view_item_accessible_action_get_name;
7455   iface->set_description = gtk_icon_view_item_accessible_action_set_description;
7456 }
7457
7458 static const gchar *
7459 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
7460 {
7461   GtkIconViewItemAccessible *item;
7462
7463   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7464
7465   return item->image_description;
7466 }
7467
7468 static gboolean
7469 gtk_icon_view_item_accessible_image_set_image_description (AtkImage    *image,
7470                                                            const gchar *description)
7471 {
7472   GtkIconViewItemAccessible *item;
7473
7474   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7475
7476   g_free (item->image_description);
7477   item->image_description = g_strdup (item->image_description);
7478
7479   return TRUE;
7480 }
7481
7482 static gboolean
7483 get_pixbuf_box (GtkIconView     *icon_view,
7484                 GtkIconViewItem *item,
7485                 GdkRectangle    *box)
7486 {
7487   GList *l;
7488
7489   for (l = icon_view->priv->cell_list; l; l = l->next)
7490     {
7491       GtkIconViewCellInfo *info = l->data;
7492       
7493       if (GTK_IS_CELL_RENDERER_PIXBUF (info->cell))
7494         {
7495           gtk_icon_view_get_cell_box (icon_view, item, info, box);
7496
7497           return TRUE;
7498         }
7499     }
7500
7501   return FALSE;
7502 }
7503
7504 static gchar *
7505 get_text (GtkIconView     *icon_view,
7506           GtkIconViewItem *item)
7507 {
7508   GList *l;
7509   gchar *text;
7510
7511   for (l = icon_view->priv->cell_list; l; l = l->next)
7512     {
7513       GtkIconViewCellInfo *info = l->data;
7514       
7515       if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
7516         {
7517           g_object_get (info->cell, "text", &text, NULL);
7518           
7519           return text;
7520         }
7521     }
7522
7523   return NULL;
7524 }
7525
7526 static void
7527 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
7528                                                     gint     *width,
7529                                                     gint     *height)
7530 {
7531   GtkIconViewItemAccessible *item;
7532   GdkRectangle box;
7533
7534   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7535
7536   if (!GTK_IS_ICON_VIEW (item->widget))
7537     return;
7538
7539   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7540     return;
7541
7542   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7543     {
7544       *width = box.width;
7545       *height = box.height;  
7546     }
7547 }
7548
7549 static void
7550 gtk_icon_view_item_accessible_image_get_image_position (AtkImage    *image,
7551                                                         gint        *x,
7552                                                         gint        *y,
7553                                                         AtkCoordType coord_type)
7554 {
7555   GtkIconViewItemAccessible *item;
7556   GdkRectangle box;
7557
7558   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7559
7560   if (!GTK_IS_ICON_VIEW (item->widget))
7561     return;
7562
7563   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7564     return;
7565
7566   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7567
7568   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7569     {
7570       *x+= box.x - item->item->x;
7571       *y+= box.y - item->item->y;
7572     }
7573
7574 }
7575
7576 static void
7577 atk_image_item_interface_init (AtkImageIface *iface)
7578 {
7579   iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
7580   iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
7581   iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
7582   iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
7583 }
7584
7585 static gchar *
7586 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
7587                                              gint     start_pos,
7588                                              gint     end_pos)
7589 {
7590   GtkIconViewItemAccessible *item;
7591   GtkTextIter start, end;
7592   GtkTextBuffer *buffer;
7593
7594   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7595
7596   if (!GTK_IS_ICON_VIEW (item->widget))
7597     return NULL;
7598
7599   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7600     return NULL;
7601
7602   buffer = item->text_buffer;
7603   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
7604   if (end_pos < 0)
7605     gtk_text_buffer_get_end_iter (buffer, &end);
7606   else
7607     gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
7608
7609   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7610 }
7611
7612 static gunichar
7613 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
7614                                                             gint     offset)
7615 {
7616   GtkIconViewItemAccessible *item;
7617   GtkTextIter start, end;
7618   GtkTextBuffer *buffer;
7619   gchar *string;
7620   gunichar unichar;
7621
7622   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7623
7624   if (!GTK_IS_ICON_VIEW (item->widget))
7625     return '\0';
7626
7627   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7628     return '\0';
7629
7630   buffer = item->text_buffer;
7631   if (offset >= gtk_text_buffer_get_char_count (buffer))
7632     return '\0';
7633
7634   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7635   end = start;
7636   gtk_text_iter_forward_char (&end);
7637   string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
7638   unichar = g_utf8_get_char (string);
7639   g_free(string);
7640
7641   return unichar;
7642 }
7643
7644 #if 0
7645 static void
7646 get_pango_text_offsets (PangoLayout     *layout,
7647                         GtkTextBuffer   *buffer,
7648                         gint             function,
7649                         AtkTextBoundary  boundary_type,
7650                         gint             offset,
7651                         gint            *start_offset,
7652                         gint            *end_offset,
7653                         GtkTextIter     *start_iter,
7654                         GtkTextIter     *end_iter)
7655 {
7656   PangoLayoutIter *iter;
7657   PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
7658   gint index, start_index, end_index;
7659   const gchar *text;
7660   gboolean found = FALSE;
7661
7662   text = pango_layout_get_text (layout);
7663   index = g_utf8_offset_to_pointer (text, offset) - text;
7664   iter = pango_layout_get_iter (layout);
7665   do
7666     {
7667       line = pango_layout_iter_get_line_readonly (iter);
7668       start_index = line->start_index;
7669       end_index = start_index + line->length;
7670
7671       if (index >= start_index && index <= end_index)
7672         {
7673           /*
7674            * Found line for offset
7675            */
7676           switch (function)
7677             {
7678             case 0:
7679                   /*
7680                    * We want the previous line
7681                    */
7682               if (prev_line)
7683                 {
7684                   switch (boundary_type)
7685                     {
7686                     case ATK_TEXT_BOUNDARY_LINE_START:
7687                       end_index = start_index;
7688                       start_index = prev_line->start_index;
7689                       break;
7690                     case ATK_TEXT_BOUNDARY_LINE_END:
7691                       if (prev_prev_line)
7692                         start_index = prev_prev_line->start_index + 
7693                                   prev_prev_line->length;
7694                       end_index = prev_line->start_index + prev_line->length;
7695                       break;
7696                     default:
7697                       g_assert_not_reached();
7698                     }
7699                 }
7700               else
7701                 start_index = end_index = 0;
7702               break;
7703             case 1:
7704               switch (boundary_type)
7705                 {
7706                 case ATK_TEXT_BOUNDARY_LINE_START:
7707                   if (pango_layout_iter_next_line (iter))
7708                     end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7709                   break;
7710                 case ATK_TEXT_BOUNDARY_LINE_END:
7711                   if (prev_line)
7712                     start_index = prev_line->start_index + 
7713                                   prev_line->length;
7714                   break;
7715                 default:
7716                   g_assert_not_reached();
7717                 }
7718               break;
7719             case 2:
7720                /*
7721                 * We want the next line
7722                 */
7723               if (pango_layout_iter_next_line (iter))
7724                 {
7725                   line = pango_layout_iter_get_line_readonly (iter);
7726                   switch (boundary_type)
7727                     {
7728                     case ATK_TEXT_BOUNDARY_LINE_START:
7729                       start_index = line->start_index;
7730                       if (pango_layout_iter_next_line (iter))
7731                         end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7732                       else
7733                         end_index = start_index + line->length;
7734                       break;
7735                     case ATK_TEXT_BOUNDARY_LINE_END:
7736                       start_index = end_index;
7737                       end_index = line->start_index + line->length;
7738                       break;
7739                     default:
7740                       g_assert_not_reached();
7741                     }
7742                 }
7743               else
7744                 start_index = end_index;
7745               break;
7746             }
7747           found = TRUE;
7748           break;
7749         }
7750       prev_prev_line = prev_line; 
7751       prev_line = line; 
7752     }
7753   while (pango_layout_iter_next_line (iter));
7754
7755   if (!found)
7756     {
7757       start_index = prev_line->start_index + prev_line->length;
7758       end_index = start_index;
7759     }
7760   pango_layout_iter_free (iter);
7761   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
7762   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
7763  
7764   gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
7765   gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
7766 }
7767 #endif
7768
7769 static gchar*
7770 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText         *text,
7771                                                            gint            offset,
7772                                                            AtkTextBoundary boundary_type,
7773                                                            gint            *start_offset,
7774                                                            gint            *end_offset)
7775 {
7776   GtkIconViewItemAccessible *item;
7777   GtkTextIter start, end;
7778   GtkTextBuffer *buffer;
7779 #if 0
7780   GtkIconView *icon_view;
7781 #endif
7782
7783   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7784
7785   if (!GTK_IS_ICON_VIEW (item->widget))
7786     return NULL;
7787
7788   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7789     return NULL;
7790
7791   buffer = item->text_buffer;
7792
7793   if (!gtk_text_buffer_get_char_count (buffer))
7794     {
7795       *start_offset = 0;
7796       *end_offset = 0;
7797       return g_strdup ("");
7798     }
7799   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7800    
7801   end = start;
7802
7803   switch (boundary_type)
7804     {
7805     case ATK_TEXT_BOUNDARY_CHAR:
7806       gtk_text_iter_backward_char(&start);
7807       break;
7808     case ATK_TEXT_BOUNDARY_WORD_START:
7809       if (!gtk_text_iter_starts_word (&start))
7810         gtk_text_iter_backward_word_start (&start);
7811       end = start;
7812       gtk_text_iter_backward_word_start(&start);
7813       break;
7814     case ATK_TEXT_BOUNDARY_WORD_END:
7815       if (gtk_text_iter_inside_word (&start) &&
7816           !gtk_text_iter_starts_word (&start))
7817         gtk_text_iter_backward_word_start (&start);
7818       while (!gtk_text_iter_ends_word (&start))
7819         {
7820           if (!gtk_text_iter_backward_char (&start))
7821             break;
7822         }
7823       end = start;
7824       gtk_text_iter_backward_word_start(&start);
7825       while (!gtk_text_iter_ends_word (&start))
7826         {
7827           if (!gtk_text_iter_backward_char (&start))
7828             break;
7829         }
7830       break;
7831     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7832       if (!gtk_text_iter_starts_sentence (&start))
7833         gtk_text_iter_backward_sentence_start (&start);
7834       end = start;
7835       gtk_text_iter_backward_sentence_start (&start);
7836       break;
7837     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7838       if (gtk_text_iter_inside_sentence (&start) &&
7839           !gtk_text_iter_starts_sentence (&start))
7840         gtk_text_iter_backward_sentence_start (&start);
7841       while (!gtk_text_iter_ends_sentence (&start))
7842         {
7843           if (!gtk_text_iter_backward_char (&start))
7844             break;
7845         }
7846       end = start;
7847       gtk_text_iter_backward_sentence_start (&start);
7848       while (!gtk_text_iter_ends_sentence (&start))
7849         {
7850           if (!gtk_text_iter_backward_char (&start))
7851             break;
7852         }
7853       break;
7854    case ATK_TEXT_BOUNDARY_LINE_START:
7855    case ATK_TEXT_BOUNDARY_LINE_END:
7856 #if 0
7857       icon_view = GTK_ICON_VIEW (item->widget);
7858       /* FIXME we probably have to use GailTextCell to salvage this */
7859       gtk_icon_view_update_item_text (icon_view, item->item);
7860       get_pango_text_offsets (icon_view->priv->layout,
7861                               buffer,
7862                               0,
7863                               boundary_type,
7864                               offset,
7865                               start_offset,
7866                               end_offset,
7867                               &start,
7868                               &end);
7869 #endif
7870       break;
7871     }
7872
7873   *start_offset = gtk_text_iter_get_offset (&start);
7874   *end_offset = gtk_text_iter_get_offset (&end);
7875
7876   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7877 }
7878
7879 static gchar*
7880 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText         *text,
7881                                                        gint            offset,
7882                                                        AtkTextBoundary boundary_type,
7883                                                        gint            *start_offset,
7884                                                        gint            *end_offset)
7885 {
7886   GtkIconViewItemAccessible *item;
7887   GtkTextIter start, end;
7888   GtkTextBuffer *buffer;
7889 #if 0
7890   GtkIconView *icon_view;
7891 #endif
7892
7893   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7894
7895   if (!GTK_IS_ICON_VIEW (item->widget))
7896     return NULL;
7897
7898   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7899     return NULL;
7900
7901   buffer = item->text_buffer;
7902
7903   if (!gtk_text_buffer_get_char_count (buffer))
7904     {
7905       *start_offset = 0;
7906       *end_offset = 0;
7907       return g_strdup ("");
7908     }
7909   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7910    
7911   end = start;
7912
7913   switch (boundary_type)
7914     {
7915     case ATK_TEXT_BOUNDARY_CHAR:
7916       gtk_text_iter_forward_char (&end);
7917       break;
7918     case ATK_TEXT_BOUNDARY_WORD_START:
7919       if (!gtk_text_iter_starts_word (&start))
7920         gtk_text_iter_backward_word_start (&start);
7921       if (gtk_text_iter_inside_word (&end))
7922         gtk_text_iter_forward_word_end (&end);
7923       while (!gtk_text_iter_starts_word (&end))
7924         {
7925           if (!gtk_text_iter_forward_char (&end))
7926             break;
7927         }
7928       break;
7929     case ATK_TEXT_BOUNDARY_WORD_END:
7930       if (gtk_text_iter_inside_word (&start) &&
7931           !gtk_text_iter_starts_word (&start))
7932         gtk_text_iter_backward_word_start (&start);
7933       while (!gtk_text_iter_ends_word (&start))
7934         {
7935           if (!gtk_text_iter_backward_char (&start))
7936             break;
7937         }
7938       gtk_text_iter_forward_word_end (&end);
7939       break;
7940     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7941       if (!gtk_text_iter_starts_sentence (&start))
7942         gtk_text_iter_backward_sentence_start (&start);
7943       if (gtk_text_iter_inside_sentence (&end))
7944         gtk_text_iter_forward_sentence_end (&end);
7945       while (!gtk_text_iter_starts_sentence (&end))
7946         {
7947           if (!gtk_text_iter_forward_char (&end))
7948             break;
7949         }
7950       break;
7951     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7952       if (gtk_text_iter_inside_sentence (&start) &&
7953           !gtk_text_iter_starts_sentence (&start))
7954         gtk_text_iter_backward_sentence_start (&start);
7955       while (!gtk_text_iter_ends_sentence (&start))
7956         {
7957           if (!gtk_text_iter_backward_char (&start))
7958             break;
7959         }
7960       gtk_text_iter_forward_sentence_end (&end);
7961       break;
7962    case ATK_TEXT_BOUNDARY_LINE_START:
7963    case ATK_TEXT_BOUNDARY_LINE_END:
7964 #if 0
7965       icon_view = GTK_ICON_VIEW (item->widget);
7966       /* FIXME we probably have to use GailTextCell to salvage this */
7967       gtk_icon_view_update_item_text (icon_view, item->item);
7968       get_pango_text_offsets (icon_view->priv->layout,
7969                               buffer,
7970                               1,
7971                               boundary_type,
7972                               offset,
7973                               start_offset,
7974                               end_offset,
7975                               &start,
7976                               &end);
7977 #endif
7978       break;
7979     }
7980
7981
7982   *start_offset = gtk_text_iter_get_offset (&start);
7983   *end_offset = gtk_text_iter_get_offset (&end);
7984
7985   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7986 }
7987
7988 static gchar*
7989 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText         *text,
7990                                                           gint            offset,
7991                                                           AtkTextBoundary boundary_type,
7992                                                           gint            *start_offset,
7993                                                           gint            *end_offset)
7994 {
7995   GtkIconViewItemAccessible *item;
7996   GtkTextIter start, end;
7997   GtkTextBuffer *buffer;
7998 #if 0
7999   GtkIconView *icon_view;
8000 #endif
8001
8002   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8003
8004   if (!GTK_IS_ICON_VIEW (item->widget))
8005     return NULL;
8006
8007   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8008     return NULL;
8009
8010   buffer = item->text_buffer;
8011
8012   if (!gtk_text_buffer_get_char_count (buffer))
8013     {
8014       *start_offset = 0;
8015       *end_offset = 0;
8016       return g_strdup ("");
8017     }
8018   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
8019    
8020   end = start;
8021
8022   switch (boundary_type)
8023     {
8024     case ATK_TEXT_BOUNDARY_CHAR:
8025       gtk_text_iter_forward_char(&start);
8026       gtk_text_iter_forward_chars(&end, 2);
8027       break;
8028     case ATK_TEXT_BOUNDARY_WORD_START:
8029       if (gtk_text_iter_inside_word (&end))
8030         gtk_text_iter_forward_word_end (&end);
8031       while (!gtk_text_iter_starts_word (&end))
8032         {
8033           if (!gtk_text_iter_forward_char (&end))
8034             break;
8035         }
8036       start = end;
8037       if (!gtk_text_iter_is_end (&end))
8038         {
8039           gtk_text_iter_forward_word_end (&end);
8040           while (!gtk_text_iter_starts_word (&end))
8041             {
8042               if (!gtk_text_iter_forward_char (&end))
8043                 break;
8044             }
8045         }
8046       break;
8047     case ATK_TEXT_BOUNDARY_WORD_END:
8048       gtk_text_iter_forward_word_end (&end);
8049       start = end;
8050       if (!gtk_text_iter_is_end (&end))
8051         gtk_text_iter_forward_word_end (&end);
8052       break;
8053     case ATK_TEXT_BOUNDARY_SENTENCE_START:
8054       if (gtk_text_iter_inside_sentence (&end))
8055         gtk_text_iter_forward_sentence_end (&end);
8056       while (!gtk_text_iter_starts_sentence (&end))
8057         {
8058           if (!gtk_text_iter_forward_char (&end))
8059             break;
8060         }
8061       start = end;
8062       if (!gtk_text_iter_is_end (&end))
8063         {
8064           gtk_text_iter_forward_sentence_end (&end);
8065           while (!gtk_text_iter_starts_sentence (&end))
8066             {
8067               if (!gtk_text_iter_forward_char (&end))
8068                 break;
8069             }
8070         }
8071       break;
8072     case ATK_TEXT_BOUNDARY_SENTENCE_END:
8073       gtk_text_iter_forward_sentence_end (&end);
8074       start = end;
8075       if (!gtk_text_iter_is_end (&end))
8076         gtk_text_iter_forward_sentence_end (&end);
8077       break;
8078    case ATK_TEXT_BOUNDARY_LINE_START:
8079    case ATK_TEXT_BOUNDARY_LINE_END:
8080 #if 0
8081       icon_view = GTK_ICON_VIEW (item->widget);
8082       /* FIXME we probably have to use GailTextCell to salvage this */
8083       gtk_icon_view_update_item_text (icon_view, item->item);
8084       get_pango_text_offsets (icon_view->priv->layout,
8085                               buffer,
8086                               2,
8087                               boundary_type,
8088                               offset,
8089                               start_offset,
8090                               end_offset,
8091                               &start,
8092                               &end);
8093 #endif
8094       break;
8095     }
8096   *start_offset = gtk_text_iter_get_offset (&start);
8097   *end_offset = gtk_text_iter_get_offset (&end);
8098
8099   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
8100 }
8101
8102 static gint
8103 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
8104 {
8105   GtkIconViewItemAccessible *item;
8106
8107   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8108
8109   if (!GTK_IS_ICON_VIEW (item->widget))
8110     return 0;
8111
8112   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8113     return 0;
8114
8115   return gtk_text_buffer_get_char_count (item->text_buffer);
8116 }
8117
8118 static void
8119 gtk_icon_view_item_accessible_text_get_character_extents (AtkText      *text,
8120                                                           gint         offset,
8121                                                           gint         *x,
8122                                                           gint         *y,
8123                                                           gint         *width,
8124                                                           gint         *height,
8125                                                           AtkCoordType coord_type)
8126 {
8127   GtkIconViewItemAccessible *item;
8128 #if 0
8129   GtkIconView *icon_view;
8130   PangoRectangle char_rect;
8131   const gchar *item_text;
8132   gint index;
8133 #endif
8134
8135   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8136
8137   if (!GTK_IS_ICON_VIEW (item->widget))
8138     return;
8139
8140   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8141     return;
8142
8143 #if 0
8144   icon_view = GTK_ICON_VIEW (item->widget);
8145       /* FIXME we probably have to use GailTextCell to salvage this */
8146   gtk_icon_view_update_item_text (icon_view, item->item);
8147   item_text = pango_layout_get_text (icon_view->priv->layout);
8148   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
8149   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
8150
8151   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
8152   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
8153   /* Look at gtk_icon_view_paint_item() to see where the text is. */
8154   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
8155   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
8156   *width = char_rect.width / PANGO_SCALE;
8157   *height = char_rect.height / PANGO_SCALE;
8158 #endif
8159 }
8160
8161 static gint
8162 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText      *text,
8163                                                         gint          x,
8164                                                         gint          y,
8165                                                         AtkCoordType coord_type)
8166 {
8167   GtkIconViewItemAccessible *item;
8168   gint offset = 0;
8169 #if 0
8170   GtkIconView *icon_view;
8171   const gchar *item_text;
8172   gint index;
8173   gint l_x, l_y;
8174 #endif
8175
8176   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8177
8178   if (!GTK_IS_ICON_VIEW (item->widget))
8179     return -1;
8180
8181   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8182     return -1;
8183
8184 #if 0
8185   icon_view = GTK_ICON_VIEW (item->widget);
8186       /* FIXME we probably have to use GailTextCell to salvage this */
8187   gtk_icon_view_update_item_text (icon_view, item->item);
8188   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
8189   x -= l_x + item->item->layout_x - item->item->x;
8190   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
8191   y -= l_y + item->item->layout_y - item->item->y;
8192   item_text = pango_layout_get_text (icon_view->priv->layout);
8193   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
8194                                 x * PANGO_SCALE,
8195                                 y * PANGO_SCALE,
8196                                 &index, NULL))
8197     {
8198       if (x < 0 || y < 0)
8199         index = 0;
8200       else
8201         index = -1;
8202     } 
8203   if (index == -1)
8204     offset = g_utf8_strlen (item_text, -1);
8205   else
8206     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
8207 #endif
8208   return offset;
8209 }
8210
8211 static void
8212 atk_text_item_interface_init (AtkTextIface *iface)
8213 {
8214   iface->get_text = gtk_icon_view_item_accessible_text_get_text;
8215   iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
8216   iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
8217   iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
8218   iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
8219   iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
8220   iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
8221   iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
8222 }
8223
8224 static void
8225 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
8226                                            gint         *x,
8227                                            gint         *y,
8228                                            gint         *width,
8229                                            gint         *height,
8230                                            AtkCoordType  coord_type)
8231 {
8232   GtkIconViewItemAccessible *item;
8233   AtkObject *parent_obj;
8234   gint l_x, l_y;
8235
8236   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
8237
8238   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8239   if (!GTK_IS_WIDGET (item->widget))
8240     return;
8241
8242   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8243     return;
8244
8245   *width = item->item->width;
8246   *height = item->item->height;
8247   if (gtk_icon_view_item_accessible_is_showing (item))
8248     {
8249       parent_obj = gtk_widget_get_accessible (item->widget);
8250       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
8251       *x = l_x + item->item->x;
8252       *y = l_y + item->item->y;
8253     }
8254   else
8255     {
8256       *x = G_MININT;
8257       *y = G_MININT;
8258     }
8259 }
8260
8261 static gboolean
8262 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
8263 {
8264   GtkIconViewItemAccessible *item;
8265   GtkWidget *toplevel;
8266
8267   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
8268
8269   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8270   if (!GTK_IS_WIDGET (item->widget))
8271     return FALSE;
8272
8273   gtk_widget_grab_focus (item->widget);
8274   gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, -1);
8275   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
8276   if (GTK_WIDGET_TOPLEVEL (toplevel))
8277     gtk_window_present (GTK_WINDOW (toplevel));
8278
8279   return TRUE;
8280 }
8281
8282 static void
8283 atk_component_item_interface_init (AtkComponentIface *iface)
8284 {
8285   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
8286   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
8287 }
8288
8289 static gboolean
8290 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
8291                                          AtkStateType               state_type,
8292                                          gboolean                   emit_signal)
8293 {
8294   gboolean rc;
8295
8296   rc = atk_state_set_add_state (item->state_set, state_type);
8297   /*
8298    * The signal should only be generated if the value changed,
8299    * not when the item is set up.  So states that are set
8300    * initially should pass FALSE as the emit_signal argument.
8301    */
8302
8303   if (emit_signal)
8304     {
8305       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
8306       /* If state_type is ATK_STATE_VISIBLE, additional notification */
8307       if (state_type == ATK_STATE_VISIBLE)
8308         g_signal_emit_by_name (item, "visible_data_changed");
8309     }
8310
8311   return rc;
8312 }
8313
8314 static gboolean
8315 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
8316                                             AtkStateType               state_type,
8317                                             gboolean                   emit_signal)
8318 {
8319   if (atk_state_set_contains_state (item->state_set, state_type))
8320     {
8321       gboolean rc;
8322
8323       rc = atk_state_set_remove_state (item->state_set, state_type);
8324       /*
8325        * The signal should only be generated if the value changed,
8326        * not when the item is set up.  So states that are set
8327        * initially should pass FALSE as the emit_signal argument.
8328        */
8329
8330       if (emit_signal)
8331         {
8332           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
8333           /* If state_type is ATK_STATE_VISIBLE, additional notification */
8334           if (state_type == ATK_STATE_VISIBLE)
8335             g_signal_emit_by_name (item, "visible_data_changed");
8336         }
8337
8338       return rc;
8339     }
8340   else
8341     return FALSE;
8342 }
8343
8344 static gboolean
8345 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
8346 {
8347   GtkIconView *icon_view;
8348   GdkRectangle visible_rect;
8349   gboolean is_showing;
8350
8351   /*
8352    * An item is considered "SHOWING" if any part of the item is in the
8353    * visible rectangle.
8354    */
8355
8356   if (!GTK_IS_ICON_VIEW (item->widget))
8357     return FALSE;
8358
8359   if (item->item == NULL)
8360     return FALSE;
8361
8362   icon_view = GTK_ICON_VIEW (item->widget);
8363   visible_rect.x = 0;
8364   if (icon_view->priv->hadjustment)
8365     visible_rect.x += icon_view->priv->hadjustment->value;
8366   visible_rect.y = 0;
8367   if (icon_view->priv->hadjustment)
8368     visible_rect.y += icon_view->priv->vadjustment->value;
8369   visible_rect.width = item->widget->allocation.width;
8370   visible_rect.height = item->widget->allocation.height;
8371
8372   if (((item->item->x + item->item->width) < visible_rect.x) ||
8373      ((item->item->y + item->item->height) < (visible_rect.y)) ||
8374      (item->item->x > (visible_rect.x + visible_rect.width)) ||
8375      (item->item->y > (visible_rect.y + visible_rect.height)))
8376     is_showing =  FALSE;
8377   else
8378     is_showing = TRUE;
8379
8380   return is_showing;
8381 }
8382
8383 static gboolean
8384 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
8385                                               gboolean                   emit_signal)
8386 {
8387   if (gtk_icon_view_item_accessible_is_showing (item))
8388     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
8389                                                     emit_signal);
8390   else
8391     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
8392                                                        emit_signal);
8393 }
8394
8395 static void
8396 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
8397 {
8398   gint i;
8399
8400   item->state_set = atk_state_set_new ();
8401
8402   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
8403   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
8404   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
8405   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
8406   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
8407
8408   for (i = 0; i < LAST_ACTION; i++)
8409     item->action_descriptions[i] = NULL;
8410
8411   item->image_description = NULL;
8412
8413   item->action_idle_handler = 0;
8414 }
8415
8416 static void
8417 gtk_icon_view_item_accessible_finalize (GObject *object)
8418 {
8419   GtkIconViewItemAccessible *item;
8420   gint i;
8421
8422   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
8423
8424   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
8425
8426   if (item->widget)
8427     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
8428
8429   if (item->state_set)
8430     g_object_unref (item->state_set);
8431
8432   if (item->text_buffer)
8433      g_object_unref (item->text_buffer);
8434
8435   for (i = 0; i < LAST_ACTION; i++)
8436     g_free (item->action_descriptions[i]);
8437
8438   g_free (item->image_description);
8439
8440   if (item->action_idle_handler)
8441     {
8442       g_source_remove (item->action_idle_handler);
8443       item->action_idle_handler = 0;
8444     }
8445
8446   G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
8447 }
8448
8449 static G_CONST_RETURN gchar*
8450 gtk_icon_view_item_accessible_get_name (AtkObject *obj)
8451 {
8452   if (obj->name)
8453     return obj->name;
8454   else
8455     {
8456       GtkIconViewItemAccessible *item;
8457       GtkTextIter start_iter;
8458       GtkTextIter end_iter;
8459
8460       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8461  
8462       gtk_text_buffer_get_start_iter (item->text_buffer, &start_iter); 
8463       gtk_text_buffer_get_end_iter (item->text_buffer, &end_iter); 
8464
8465       return gtk_text_buffer_get_text (item->text_buffer, &start_iter, &end_iter, FALSE);
8466     }
8467 }
8468
8469 static AtkObject*
8470 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
8471 {
8472   GtkIconViewItemAccessible *item;
8473
8474   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
8475   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8476
8477   if (item->widget)
8478     return gtk_widget_get_accessible (item->widget);
8479   else
8480     return NULL;
8481 }
8482
8483 static gint
8484 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
8485 {
8486   GtkIconViewItemAccessible *item;
8487
8488   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
8489   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8490
8491   return item->item->index; 
8492 }
8493
8494 static AtkStateSet *
8495 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
8496 {
8497   GtkIconViewItemAccessible *item;
8498   GtkIconView *icon_view;
8499
8500   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8501   g_return_val_if_fail (item->state_set, NULL);
8502
8503   if (!item->widget)
8504     return NULL;
8505
8506   icon_view = GTK_ICON_VIEW (item->widget);
8507   if (icon_view->priv->cursor_item == item->item)
8508     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
8509   else
8510     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
8511   if (item->item->selected)
8512     atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
8513   else
8514     atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
8515
8516   return g_object_ref (item->state_set);
8517 }
8518
8519 static void
8520 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
8521 {
8522   GObjectClass *gobject_class;
8523
8524   accessible_item_parent_class = g_type_class_peek_parent (klass);
8525
8526   gobject_class = (GObjectClass *)klass;
8527
8528   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
8529
8530   klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent; 
8531   klass->get_name = gtk_icon_view_item_accessible_get_name; 
8532   klass->get_parent = gtk_icon_view_item_accessible_get_parent; 
8533   klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set; 
8534 }
8535
8536 static GType
8537 gtk_icon_view_item_accessible_get_type (void)
8538 {
8539   static GType type = 0;
8540
8541   if (!type)
8542     {
8543       const GTypeInfo tinfo =
8544       {
8545         sizeof (GtkIconViewItemAccessibleClass),
8546         (GBaseInitFunc) NULL, /* base init */
8547         (GBaseFinalizeFunc) NULL, /* base finalize */
8548         (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
8549         (GClassFinalizeFunc) NULL, /* class finalize */
8550         NULL, /* class data */
8551         sizeof (GtkIconViewItemAccessible), /* instance size */
8552         0, /* nb preallocs */
8553         (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
8554         NULL /* value table */
8555       };
8556
8557       static const GInterfaceInfo atk_component_info =
8558       {
8559         (GInterfaceInitFunc) atk_component_item_interface_init,
8560         (GInterfaceFinalizeFunc) NULL,
8561         NULL
8562       };
8563       static const GInterfaceInfo atk_action_info =
8564       {
8565         (GInterfaceInitFunc) atk_action_item_interface_init,
8566         (GInterfaceFinalizeFunc) NULL,
8567         NULL
8568       };
8569       static const GInterfaceInfo atk_image_info =
8570       {
8571         (GInterfaceInitFunc) atk_image_item_interface_init,
8572         (GInterfaceFinalizeFunc) NULL,
8573         NULL
8574       };
8575       static const GInterfaceInfo atk_text_info =
8576       {
8577         (GInterfaceInitFunc) atk_text_item_interface_init,
8578         (GInterfaceFinalizeFunc) NULL,
8579         NULL
8580       };
8581
8582       type = g_type_register_static (ATK_TYPE_OBJECT,
8583                                      I_("GtkIconViewItemAccessible"), &tinfo, 0);
8584       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
8585                                    &atk_component_info);
8586       g_type_add_interface_static (type, ATK_TYPE_ACTION,
8587                                    &atk_action_info);
8588       g_type_add_interface_static (type, ATK_TYPE_IMAGE,
8589                                    &atk_image_info);
8590       g_type_add_interface_static (type, ATK_TYPE_TEXT,
8591                                    &atk_text_info);
8592     }
8593
8594   return type;
8595 }
8596
8597 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE      (gtk_icon_view_accessible_get_type ())
8598 #define GTK_ICON_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
8599 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
8600
8601 static GType gtk_icon_view_accessible_get_type (void);
8602
8603 typedef struct
8604 {
8605    AtkObject parent;
8606 } GtkIconViewAccessible;
8607
8608 typedef struct
8609 {
8610   AtkObject *item;
8611   gint       index;
8612 } GtkIconViewItemAccessibleInfo;
8613
8614 typedef struct
8615 {
8616   GList *items;
8617
8618   GtkAdjustment *old_hadj;
8619   GtkAdjustment *old_vadj;
8620
8621   GtkTreeModel *model;
8622
8623 } GtkIconViewAccessiblePrivate;
8624
8625 static GtkIconViewAccessiblePrivate *
8626 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
8627 {
8628   return g_object_get_qdata (G_OBJECT (accessible),
8629                              accessible_private_data_quark);
8630 }
8631
8632 static void
8633 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
8634                                         AtkObject *item,
8635                                         gint       index)
8636 {
8637   GtkIconViewItemAccessibleInfo *info;
8638   GtkIconViewItemAccessibleInfo *tmp_info;
8639   GtkIconViewAccessiblePrivate *priv;
8640   GList *items;
8641
8642   info = g_new (GtkIconViewItemAccessibleInfo, 1);
8643   info->item = item;
8644   info->index = index;
8645
8646   priv = gtk_icon_view_accessible_get_priv (accessible);
8647   items = priv->items;
8648   while (items)
8649     {
8650       tmp_info = items->data;
8651       if (tmp_info->index > index)
8652         break;
8653       items = items->next;
8654     }
8655   priv->items = g_list_insert_before (priv->items, items, info);
8656   priv->old_hadj = NULL;
8657   priv->old_vadj = NULL;
8658 }
8659
8660 static gint
8661 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
8662 {
8663   GtkIconView *icon_view;
8664   GtkWidget *widget;
8665
8666   widget = GTK_ACCESSIBLE (accessible)->widget;
8667   if (!widget)
8668       return 0;
8669
8670   icon_view = GTK_ICON_VIEW (widget);
8671
8672   return g_list_length (icon_view->priv->items);
8673 }
8674
8675 static AtkObject *
8676 gtk_icon_view_accessible_find_child (AtkObject *accessible,
8677                                      gint       index)
8678 {
8679   GtkIconViewAccessiblePrivate *priv;
8680   GtkIconViewItemAccessibleInfo *info;
8681   GList *items;
8682
8683   priv = gtk_icon_view_accessible_get_priv (accessible);
8684   items = priv->items;
8685
8686   while (items)
8687     {
8688       info = items->data;
8689       if (info->index == index)
8690         return info->item;
8691       items = items->next; 
8692     }
8693   return NULL;
8694 }
8695
8696 static AtkObject *
8697 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
8698                                     gint       index)
8699 {
8700   GtkIconView *icon_view;
8701   GtkWidget *widget;
8702   GList *icons;
8703   AtkObject *obj;
8704   GtkIconViewItemAccessible *a11y_item;
8705
8706   widget = GTK_ACCESSIBLE (accessible)->widget;
8707   if (!widget)
8708     return NULL;
8709
8710   icon_view = GTK_ICON_VIEW (widget);
8711   icons = g_list_nth (icon_view->priv->items, index);
8712   obj = NULL;
8713   if (icons)
8714     {
8715       GtkIconViewItem *item = icons->data;
8716    
8717       g_return_val_if_fail (item->index == index, NULL);
8718       obj = gtk_icon_view_accessible_find_child (accessible, index);
8719       if (!obj)
8720         {
8721           gchar *text;
8722
8723           obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
8724           gtk_icon_view_item_accessible_info_new (accessible,
8725                                                   obj,
8726                                                   index);
8727           obj->role = ATK_ROLE_ICON;
8728           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8729           a11y_item->item = item;
8730           a11y_item->widget = widget;
8731           a11y_item->text_buffer = gtk_text_buffer_new (NULL);
8732
8733           gtk_icon_view_set_cell_data (icon_view, item);
8734           text = get_text (icon_view, item);
8735           if (text)
8736             {
8737               gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8738               g_free (text);
8739             } 
8740
8741           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
8742           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
8743        }
8744       g_object_ref (obj);
8745     }
8746   return obj;
8747 }
8748
8749 static void
8750 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
8751                                          GList                 *list)
8752 {
8753   GtkIconViewAccessiblePrivate *priv;
8754   GtkIconViewItemAccessibleInfo *info;
8755   GtkIconViewItemAccessible *item;
8756   GList *items;
8757   
8758   priv =  gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
8759   if (priv->items)
8760     {
8761       GtkWidget *widget;
8762       gboolean act_on_item;
8763
8764       widget = GTK_ACCESSIBLE (view)->widget;
8765       if (widget == NULL)
8766         return;
8767
8768       items = priv->items;
8769
8770       act_on_item = (list == NULL);
8771
8772       while (items)
8773         {
8774
8775           info = (GtkIconViewItemAccessibleInfo *)items->data;
8776           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8777
8778           if (act_on_item == FALSE && list == items)
8779             act_on_item = TRUE;
8780
8781           if (act_on_item)
8782             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
8783
8784           items = items->next;
8785        }
8786    }
8787 }
8788
8789 static void
8790 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
8791                                              GtkIconView   *icon_view)
8792 {
8793   AtkObject *obj;
8794   GtkIconViewAccessible *view;
8795
8796   /*
8797    * The scrollbars have changed
8798    */
8799   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
8800   view = GTK_ICON_VIEW_ACCESSIBLE (obj);
8801
8802   gtk_icon_view_accessible_traverse_items (view, NULL);
8803 }
8804
8805 static void
8806 gtk_icon_view_accessible_set_scroll_adjustments (GtkWidget      *widget,
8807                                                  GtkAdjustment *hadj,
8808                                                  GtkAdjustment *vadj)
8809 {
8810   AtkObject *atk_obj;
8811   GtkIconViewAccessiblePrivate *priv;
8812
8813   atk_obj = gtk_widget_get_accessible (widget);
8814   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8815
8816   if (priv->old_hadj != hadj)
8817     {
8818       if (priv->old_hadj)
8819         {
8820           g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
8821                                         (gpointer *)&priv->old_hadj);
8822           
8823           g_signal_handlers_disconnect_by_func (priv->old_hadj,
8824                                                 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8825                                                 widget);
8826         }
8827       priv->old_hadj = hadj;
8828       if (priv->old_hadj)
8829         {
8830           g_object_add_weak_pointer (G_OBJECT (priv->old_hadj),
8831                                      (gpointer *)&priv->old_hadj);
8832           g_signal_connect (hadj,
8833                             "value-changed",
8834                             G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8835                             widget);
8836         }
8837     }
8838   if (priv->old_vadj != vadj)
8839     {
8840       if (priv->old_vadj)
8841         {
8842           g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
8843                                         (gpointer *)&priv->old_vadj);
8844           
8845           g_signal_handlers_disconnect_by_func (priv->old_vadj,
8846                                                 (gpointer) gtk_icon_view_accessible_adjustment_changed,
8847                                                 widget);
8848         }
8849       priv->old_vadj = vadj;
8850       if (priv->old_vadj)
8851         {
8852           g_object_add_weak_pointer (G_OBJECT (priv->old_vadj),
8853                                      (gpointer *)&priv->old_vadj);
8854           g_signal_connect (vadj,
8855                             "value-changed",
8856                             G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8857                             widget);
8858         }
8859     }
8860 }
8861
8862 static void
8863 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
8864                                             GtkTreePath  *path,
8865                                             GtkTreeIter  *iter,
8866                                             gpointer     user_data)
8867 {
8868   AtkObject *atk_obj;
8869
8870   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8871   g_signal_emit_by_name (atk_obj, "visible_data_changed");
8872
8873   return;
8874 }
8875
8876 static void
8877 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
8878                                              GtkTreePath  *path,
8879                                              GtkTreeIter  *iter,
8880                                              gpointer     user_data)
8881 {
8882   GtkIconViewAccessiblePrivate *priv;
8883   GtkIconViewItemAccessibleInfo *info;
8884   GtkIconViewAccessible *view;
8885   GtkIconViewItemAccessible *item;
8886   GList *items;
8887   GList *tmp_list;
8888   AtkObject *atk_obj;
8889   gint index;
8890
8891   index = gtk_tree_path_get_indices(path)[0];
8892   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8893   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8894   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8895
8896   items = priv->items;
8897   tmp_list = NULL;
8898   while (items)
8899     {
8900       info = items->data;
8901       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8902       if (info->index != item->item->index)
8903         {
8904           if (info->index < index)
8905             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
8906  
8907           if (tmp_list == NULL)
8908             tmp_list = items;
8909    
8910           info->index = item->item->index;
8911         }
8912
8913       items = items->next;
8914     }
8915   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8916   g_signal_emit_by_name (atk_obj, "children_changed::add",
8917                          index, NULL, NULL);
8918   return;
8919 }
8920
8921 static void
8922 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
8923                                             GtkTreePath  *path,
8924                                             gpointer     user_data)
8925 {
8926   GtkIconViewAccessiblePrivate *priv;
8927   GtkIconViewItemAccessibleInfo *info;
8928   GtkIconViewAccessible *view;
8929   GtkIconViewItemAccessible *item;
8930   GList *items;
8931   GList *tmp_list;
8932   GList *deleted_item;
8933   AtkObject *atk_obj;
8934   gint index;
8935
8936   index = gtk_tree_path_get_indices(path)[0];
8937   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8938   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8939   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8940
8941   items = priv->items;
8942   tmp_list = NULL;
8943   deleted_item = NULL;
8944   info = NULL;
8945   while (items)
8946     {
8947       info = items->data;
8948       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8949       if (info->index == index)
8950         {
8951           deleted_item = items;
8952         }
8953       if (info->index != item->item->index)
8954         {
8955           if (tmp_list == NULL)
8956             tmp_list = items;
8957             
8958           info->index = item->item->index;
8959         }
8960
8961       items = items->next;
8962     }
8963   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8964   if (deleted_item)
8965     {
8966       info = deleted_item->data;
8967       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
8968       g_signal_emit_by_name (atk_obj, "children_changed::remove",
8969                              index, NULL, NULL);
8970       priv->items = g_list_remove_link (priv->items, deleted_item);
8971       g_free (info);
8972     }
8973
8974   return;
8975 }
8976
8977 static gint
8978 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
8979                                        GtkIconViewItemAccessibleInfo *i2)
8980 {
8981   return i1->index - i2->index;
8982 }
8983
8984 static void
8985 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
8986                                                GtkTreePath  *path,
8987                                                GtkTreeIter  *iter,
8988                                                gint         *new_order,
8989                                                gpointer     user_data)
8990 {
8991   GtkIconViewAccessiblePrivate *priv;
8992   GtkIconViewItemAccessibleInfo *info;
8993   GtkIconView *icon_view;
8994   GtkIconViewItemAccessible *item;
8995   GList *items;
8996   AtkObject *atk_obj;
8997
8998   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8999   icon_view = GTK_ICON_VIEW (user_data);
9000   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9001
9002   items = priv->items;
9003   while (items)
9004     {
9005       info = items->data;
9006       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
9007       info->index = new_order[info->index];
9008       item->item = g_list_nth_data (icon_view->priv->items, info->index);
9009       items = items->next;
9010     }
9011   priv->items = g_list_sort (priv->items, 
9012                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
9013
9014   return;
9015 }
9016
9017 static void
9018 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
9019                                                    GtkWidget *widget)
9020 {
9021   GObject *obj;
9022
9023   obj = G_OBJECT (model);
9024   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
9025   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
9026   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
9027   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
9028 }
9029
9030 static void
9031 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
9032 {
9033   GObject *obj;
9034
9035   obj = G_OBJECT (icon_view->priv->model);
9036   g_signal_connect_data (obj, "row_changed",
9037                          (GCallback) gtk_icon_view_accessible_model_row_changed,
9038                          icon_view, NULL, 0);
9039   g_signal_connect_data (obj, "row_inserted",
9040                          (GCallback) gtk_icon_view_accessible_model_row_inserted, 
9041                          icon_view, NULL, G_CONNECT_AFTER);
9042   g_signal_connect_data (obj, "row_deleted",
9043                          (GCallback) gtk_icon_view_accessible_model_row_deleted, 
9044                          icon_view, NULL, G_CONNECT_AFTER);
9045   g_signal_connect_data (obj, "rows_reordered",
9046                          (GCallback) gtk_icon_view_accessible_model_rows_reordered, 
9047                          icon_view, NULL, G_CONNECT_AFTER);
9048 }
9049
9050 static void
9051 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
9052 {
9053   GtkIconViewItemAccessibleInfo *info;
9054   GList *items;
9055
9056   items = priv->items;
9057   while (items)
9058     {
9059       info = (GtkIconViewItemAccessibleInfo *) items->data;
9060       g_object_unref (info->item);
9061       g_free (items->data);
9062       items = items->next;
9063     }
9064   g_list_free (priv->items);
9065   priv->items = NULL;
9066 }
9067
9068 static void
9069 gtk_icon_view_accessible_notify_gtk (GObject *obj,
9070                                      GParamSpec *pspec)
9071 {
9072   GtkIconView *icon_view;
9073   GtkWidget *widget;
9074   AtkObject *atk_obj;
9075   GtkIconViewAccessiblePrivate *priv;
9076
9077   if (strcmp (pspec->name, "model") == 0)
9078     {
9079       widget = GTK_WIDGET (obj); 
9080       atk_obj = gtk_widget_get_accessible (widget);
9081       priv = gtk_icon_view_accessible_get_priv (atk_obj);
9082       if (priv->model)
9083         {
9084           g_object_remove_weak_pointer (G_OBJECT (priv->model),
9085                                         (gpointer *)&priv->model);
9086           gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
9087         }
9088       gtk_icon_view_accessible_clear_cache (priv);
9089
9090       icon_view = GTK_ICON_VIEW (obj);
9091       priv->model = icon_view->priv->model;
9092       /* If there is no model the GtkIconView is probably being destroyed */
9093       if (priv->model)
9094         {
9095           g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
9096           gtk_icon_view_accessible_connect_model_signals (icon_view);
9097         }
9098     }
9099
9100   return;
9101 }
9102
9103 static void
9104 gtk_icon_view_accessible_initialize (AtkObject *accessible,
9105                                      gpointer   data)
9106 {
9107   GtkIconViewAccessiblePrivate *priv;
9108   GtkIconView *icon_view;
9109
9110   if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
9111     ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
9112
9113   priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
9114   g_object_set_qdata (G_OBJECT (accessible),
9115                       accessible_private_data_quark,
9116                       priv);
9117
9118   icon_view = GTK_ICON_VIEW (data);
9119   if (icon_view->priv->hadjustment)
9120     {
9121       priv->old_hadj = icon_view->priv->hadjustment;
9122       g_object_add_weak_pointer (G_OBJECT (priv->old_hadj), (gpointer *)&priv->old_hadj);
9123       g_signal_connect (icon_view->priv->hadjustment,
9124                         "value-changed",
9125                         G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
9126                         icon_view);
9127     } 
9128   if (icon_view->priv->vadjustment)
9129     {
9130       priv->old_vadj = icon_view->priv->vadjustment;
9131       g_object_add_weak_pointer (G_OBJECT (priv->old_vadj), (gpointer *)&priv->old_vadj);
9132       g_signal_connect (icon_view->priv->vadjustment,
9133                         "value-changed",
9134                         G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
9135                         icon_view);
9136     }
9137   g_signal_connect_after (data,
9138                           "set_scroll_adjustments",
9139                           G_CALLBACK (gtk_icon_view_accessible_set_scroll_adjustments),
9140                           NULL);
9141   g_signal_connect (data,
9142                     "notify",
9143                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
9144                     NULL);
9145
9146   priv->model = icon_view->priv->model;
9147   if (priv->model)
9148     {
9149       g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
9150       gtk_icon_view_accessible_connect_model_signals (icon_view);
9151     }
9152                           
9153   accessible->role = ATK_ROLE_LAYERED_PANE;
9154 }
9155
9156 static void
9157 gtk_icon_view_accessible_finalize (GObject *object)
9158 {
9159   GtkIconViewAccessiblePrivate *priv;
9160
9161   priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
9162   gtk_icon_view_accessible_clear_cache (priv);
9163
9164   g_free (priv);
9165
9166   G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
9167 }
9168
9169 static void
9170 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
9171                                     GtkAccessible *accessible)
9172 {
9173   AtkObject *atk_obj;
9174   GtkIconViewAccessiblePrivate *priv;
9175
9176   atk_obj = ATK_OBJECT (accessible);
9177   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9178   if (priv->old_hadj)
9179     {
9180       g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
9181                                     (gpointer *)&priv->old_hadj);
9182           
9183       g_signal_handlers_disconnect_by_func (priv->old_hadj,
9184                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
9185                                             widget);
9186       priv->old_hadj = NULL;
9187     }
9188   if (priv->old_vadj)
9189     {
9190       g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
9191                                     (gpointer *)&priv->old_vadj);
9192           
9193       g_signal_handlers_disconnect_by_func (priv->old_vadj,
9194                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
9195                                             widget);
9196       priv->old_vadj = NULL;
9197     }
9198 }
9199
9200 static void
9201 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
9202 {
9203   if (accessible->widget)
9204     {
9205       g_signal_connect_after (accessible->widget,
9206                               "destroy",
9207                               G_CALLBACK (gtk_icon_view_accessible_destroyed),
9208                               accessible);
9209     }
9210   GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
9211 }
9212
9213 static void
9214 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
9215 {
9216   GObjectClass *gobject_class;
9217   GtkAccessibleClass *accessible_class;
9218
9219   accessible_parent_class = g_type_class_peek_parent (klass);
9220
9221   gobject_class = (GObjectClass *)klass;
9222   accessible_class = (GtkAccessibleClass *)klass;
9223
9224   gobject_class->finalize = gtk_icon_view_accessible_finalize;
9225
9226   klass->get_n_children = gtk_icon_view_accessible_get_n_children;
9227   klass->ref_child = gtk_icon_view_accessible_ref_child;
9228   klass->initialize = gtk_icon_view_accessible_initialize;
9229
9230   accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
9231
9232   accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
9233 }
9234
9235 static AtkObject*
9236 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
9237                                                   gint          x,
9238                                                   gint          y,
9239                                                   AtkCoordType  coord_type)
9240 {
9241   GtkWidget *widget;
9242   GtkIconView *icon_view;
9243   GtkIconViewItem *item;
9244   gint x_pos, y_pos;
9245
9246   widget = GTK_ACCESSIBLE (component)->widget;
9247   if (widget == NULL)
9248   /* State is defunct */
9249     return NULL;
9250
9251   icon_view = GTK_ICON_VIEW (widget);
9252   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
9253   item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
9254   if (item)
9255     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
9256
9257   return NULL;
9258 }
9259
9260 static void
9261 atk_component_interface_init (AtkComponentIface *iface)
9262 {
9263   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
9264 }
9265
9266 static gboolean
9267 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
9268                                         gint i)
9269 {
9270   GtkWidget *widget;
9271   GtkIconView *icon_view;
9272   GtkIconViewItem *item;
9273
9274   widget = GTK_ACCESSIBLE (selection)->widget;
9275   if (widget == NULL)
9276     return FALSE;
9277
9278   icon_view = GTK_ICON_VIEW (widget);
9279
9280   item = g_list_nth_data (icon_view->priv->items, i);
9281
9282   if (!item)
9283     return FALSE;
9284
9285   gtk_icon_view_select_item (icon_view, item);
9286
9287   return TRUE;
9288 }
9289
9290 static gboolean
9291 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
9292 {
9293   GtkWidget *widget;
9294   GtkIconView *icon_view;
9295
9296   widget = GTK_ACCESSIBLE (selection)->widget;
9297   if (widget == NULL)
9298     return FALSE;
9299
9300   icon_view = GTK_ICON_VIEW (widget);
9301   gtk_icon_view_unselect_all (icon_view);
9302
9303   return TRUE;
9304 }
9305
9306 static AtkObject*
9307 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
9308                                         gint          i)
9309 {
9310   GList *l;
9311   GtkWidget *widget;
9312   GtkIconView *icon_view;
9313   GtkIconViewItem *item;
9314
9315   widget = GTK_ACCESSIBLE (selection)->widget;
9316   if (widget == NULL)
9317     return NULL;
9318
9319   icon_view = GTK_ICON_VIEW (widget);
9320
9321   l = icon_view->priv->items;
9322   while (l)
9323     {
9324       item = l->data;
9325       if (item->selected)
9326         {
9327           if (i == 0)
9328             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
9329           else
9330             i--;
9331         }
9332       l = l->next;
9333     }
9334
9335   return NULL;
9336 }
9337
9338 static gint
9339 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
9340 {
9341   GtkWidget *widget;
9342   GtkIconView *icon_view;
9343   GtkIconViewItem *item;
9344   GList *l;
9345   gint count;
9346
9347   widget = GTK_ACCESSIBLE (selection)->widget;
9348   if (widget == NULL)
9349     return 0;
9350
9351   icon_view = GTK_ICON_VIEW (widget);
9352
9353   l = icon_view->priv->items;
9354   count = 0;
9355   while (l)
9356     {
9357       item = l->data;
9358
9359       if (item->selected)
9360         count++;
9361
9362       l = l->next;
9363     }
9364
9365   return count;
9366 }
9367
9368 static gboolean
9369 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
9370                                             gint          i)
9371 {
9372   GtkWidget *widget;
9373   GtkIconView *icon_view;
9374   GtkIconViewItem *item;
9375
9376   widget = GTK_ACCESSIBLE (selection)->widget;
9377   if (widget == NULL)
9378     return FALSE;
9379
9380   icon_view = GTK_ICON_VIEW (widget);
9381
9382   item = g_list_nth_data (icon_view->priv->items, i);
9383   if (!item)
9384     return FALSE;
9385
9386   return item->selected;
9387 }
9388
9389 static gboolean
9390 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
9391                                            gint          i)
9392 {
9393   GtkWidget *widget;
9394   GtkIconView *icon_view;
9395   GtkIconViewItem *item;
9396   GList *l;
9397   gint count;
9398
9399   widget = GTK_ACCESSIBLE (selection)->widget;
9400   if (widget == NULL)
9401     return FALSE;
9402
9403   icon_view = GTK_ICON_VIEW (widget);
9404   l = icon_view->priv->items;
9405   count = 0;
9406   while (l)
9407     {
9408       item = l->data;
9409       if (item->selected)
9410         {
9411           if (count == i)
9412             {
9413               gtk_icon_view_unselect_item (icon_view, item);
9414               return TRUE;
9415             }
9416           count++;
9417         }
9418       l = l->next;
9419     }
9420
9421   return FALSE;
9422 }
9423  
9424 static gboolean
9425 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
9426 {
9427   GtkWidget *widget;
9428   GtkIconView *icon_view;
9429
9430   widget = GTK_ACCESSIBLE (selection)->widget;
9431   if (widget == NULL)
9432     return FALSE;
9433
9434   icon_view = GTK_ICON_VIEW (widget);
9435   gtk_icon_view_select_all (icon_view);
9436   return TRUE;
9437 }
9438
9439 static void
9440 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
9441 {
9442   iface->add_selection = gtk_icon_view_accessible_add_selection;
9443   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
9444   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
9445   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
9446   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
9447   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
9448   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
9449 }
9450
9451 static GType
9452 gtk_icon_view_accessible_get_type (void)
9453 {
9454   static GType type = 0;
9455
9456   if (!type)
9457     {
9458       static GTypeInfo tinfo =
9459       {
9460         0, /* class size */
9461         (GBaseInitFunc) NULL, /* base init */
9462         (GBaseFinalizeFunc) NULL, /* base finalize */
9463         (GClassInitFunc) gtk_icon_view_accessible_class_init,
9464         (GClassFinalizeFunc) NULL, /* class finalize */
9465         NULL, /* class data */
9466         0, /* instance size */
9467         0, /* nb preallocs */
9468         (GInstanceInitFunc) NULL, /* instance init */
9469         NULL /* value table */
9470       };
9471       static const GInterfaceInfo atk_component_info =
9472       {
9473         (GInterfaceInitFunc) atk_component_interface_init,
9474         (GInterfaceFinalizeFunc) NULL,
9475         NULL
9476       };
9477       static const GInterfaceInfo atk_selection_info = 
9478       {
9479         (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
9480         (GInterfaceFinalizeFunc) NULL,
9481         NULL
9482       };
9483
9484       /*
9485        * Figure out the size of the class and instance
9486        * we are deriving from
9487        */
9488       AtkObjectFactory *factory;
9489       GType derived_type;
9490       GTypeQuery query;
9491       GType derived_atk_type;
9492
9493       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9494       factory = atk_registry_get_factory (atk_get_default_registry (), 
9495                                           derived_type);
9496       derived_atk_type = atk_object_factory_get_accessible_type (factory);
9497       g_type_query (derived_atk_type, &query);
9498       tinfo.class_size = query.class_size;
9499       tinfo.instance_size = query.instance_size;
9500  
9501       type = g_type_register_static (derived_atk_type, 
9502                                      I_("GtkIconViewAccessible"), 
9503                                      &tinfo, 0);
9504       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9505                                    &atk_component_info);
9506       g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9507                                    &atk_selection_info);
9508     }
9509   return type;
9510 }
9511
9512 static AtkObject *
9513 gtk_icon_view_accessible_new (GObject *obj)
9514 {
9515   AtkObject *accessible;
9516
9517   g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
9518
9519   accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
9520   atk_object_initialize (accessible, obj);
9521
9522   return accessible;
9523 }
9524
9525 static GType
9526 gtk_icon_view_accessible_factory_get_accessible_type (void)
9527 {
9528   return gtk_icon_view_accessible_get_type ();
9529 }
9530
9531 static AtkObject*
9532 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
9533 {
9534   return gtk_icon_view_accessible_new (obj);
9535 }
9536
9537 static void
9538 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
9539 {
9540   klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
9541   klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
9542 }
9543
9544 static GType
9545 gtk_icon_view_accessible_factory_get_type (void)
9546 {
9547   static GType type = 0;
9548
9549   if (!type)
9550     {
9551       const GTypeInfo tinfo =
9552       {
9553         sizeof (AtkObjectFactoryClass),
9554         NULL,           /* base_init */
9555         NULL,           /* base_finalize */
9556         (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
9557         NULL,           /* class_finalize */
9558         NULL,           /* class_data */
9559         sizeof (AtkObjectFactory),
9560         0,             /* n_preallocs */
9561         NULL, NULL
9562       };
9563
9564       type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
9565                                     I_("GtkIconViewAccessibleFactory"),
9566                                     &tinfo, 0);
9567     }
9568   return type;
9569 }
9570
9571
9572 static AtkObject *
9573 gtk_icon_view_get_accessible (GtkWidget *widget)
9574 {
9575   static gboolean first_time = TRUE;
9576
9577   if (first_time)
9578     {
9579       AtkObjectFactory *factory;
9580       AtkRegistry *registry;
9581       GType derived_type; 
9582       GType derived_atk_type; 
9583
9584       /*
9585        * Figure out whether accessibility is enabled by looking at the
9586        * type of the accessible object which would be created for
9587        * the parent type of GtkIconView.
9588        */
9589       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9590
9591       registry = atk_get_default_registry ();
9592       factory = atk_registry_get_factory (registry,
9593                                           derived_type);
9594       derived_atk_type = atk_object_factory_get_accessible_type (factory);
9595       if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
9596         atk_registry_set_factory_type (registry, 
9597                                        GTK_TYPE_ICON_VIEW,
9598                                        gtk_icon_view_accessible_factory_get_type ());
9599       first_time = FALSE;
9600     } 
9601   return (* GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible) (widget);
9602 }
9603
9604 static gboolean
9605 gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
9606                                           GtkBuilder    *builder,
9607                                           GObject       *child,
9608                                           const gchar   *tagname,
9609                                           GMarkupParser *parser,
9610                                           gpointer      *data)
9611 {
9612   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
9613                                                 tagname, parser, data))
9614     return TRUE;
9615
9616   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
9617                                                       tagname, parser, data);
9618 }
9619
9620 static void
9621 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
9622                                         GtkBuilder   *builder,
9623                                         GObject      *child,
9624                                         const gchar  *tagname,
9625                                         gpointer     *data)
9626 {
9627   if (strcmp (tagname, "attributes") == 0)
9628     _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
9629                                                data);
9630   else
9631     parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
9632                                             data);
9633 }
9634
9635
9636
9637 #define __GTK_ICON_VIEW_C__
9638 #include "gtkaliasdef.c"