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