]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
iconview: Keep the device for dnd autoscroll
[~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 modify_selection_pressed : 1;
182   guint extend_selection_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       GdkModifierType extend_mod_mask;
2022       GdkModifierType modify_mod_mask;
2023
2024       extend_mod_mask =
2025         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
2026
2027       modify_mod_mask =
2028         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
2029
2030       item = gtk_icon_view_get_item_at_coords (icon_view, 
2031                                                event->x, event->y,
2032                                                FALSE,
2033                                                &cell);
2034
2035       /*
2036        * We consider only the the cells' area as the item area if the
2037        * item is not selected, but if it *is* selected, the complete
2038        * selection rectangle is considered to be part of the item.
2039        */
2040       if (item != NULL && (cell != NULL || item->selected))
2041         {
2042           if (cell != NULL)
2043             {
2044               if (gtk_cell_renderer_is_activatable (cell))
2045                 cursor_cell = cell;
2046             }
2047
2048           gtk_icon_view_scroll_to_item (icon_view, item);
2049           
2050           if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2051             {
2052               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2053             }
2054           else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
2055                    (event->state & extend_mod_mask))
2056             {
2057               gtk_icon_view_unselect_all_internal (icon_view);
2058
2059               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2060               if (!icon_view->priv->anchor_item)
2061                 icon_view->priv->anchor_item = item;
2062               else 
2063                 gtk_icon_view_select_all_between (icon_view,
2064                                                   icon_view->priv->anchor_item,
2065                                                   item);
2066               dirty = TRUE;
2067             }
2068           else 
2069             {
2070               if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
2071                   ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
2072                   (event->state & modify_mod_mask))
2073                 {
2074                   item->selected = !item->selected;
2075                   gtk_icon_view_queue_draw_item (icon_view, item);
2076                   dirty = TRUE;
2077                 }
2078               else
2079                 {
2080                   gtk_icon_view_unselect_all_internal (icon_view);
2081
2082                   item->selected = TRUE;
2083                   gtk_icon_view_queue_draw_item (icon_view, item);
2084                   dirty = TRUE;
2085                 }
2086               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2087               icon_view->priv->anchor_item = item;
2088             }
2089
2090           /* Save press to possibly begin a drag */
2091           if (icon_view->priv->pressed_button < 0)
2092             {
2093               icon_view->priv->pressed_button = event->button;
2094               icon_view->priv->press_start_x = event->x;
2095               icon_view->priv->press_start_y = event->y;
2096             }
2097
2098           if (!icon_view->priv->last_single_clicked)
2099             icon_view->priv->last_single_clicked = item;
2100
2101           /* cancel the current editing, if it exists */
2102           gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
2103
2104           if (cell != NULL && gtk_cell_renderer_is_activatable (cell))
2105             {
2106               GtkCellAreaContext *context;
2107
2108               context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
2109
2110               gtk_icon_view_set_cell_data (icon_view, item);
2111               gtk_cell_area_activate (icon_view->priv->cell_area, context,
2112                                       GTK_WIDGET (icon_view),
2113                                       (GdkRectangle *)item, 0/* XXX flags */, FALSE);
2114             }
2115         }
2116       else
2117         {
2118           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
2119               !(event->state & modify_mod_mask))
2120             {
2121               dirty = gtk_icon_view_unselect_all_internal (icon_view);
2122             }
2123           
2124           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2125             gtk_icon_view_start_rubberbanding (icon_view, event->device, event->x, event->y);
2126         }
2127
2128       /* don't draw keyboard focus around an clicked-on item */
2129       icon_view->priv->draw_focus = FALSE;
2130     }
2131
2132   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
2133     {
2134       item = gtk_icon_view_get_item_at_coords (icon_view,
2135                                                event->x, event->y,
2136                                                FALSE,
2137                                                NULL);
2138
2139       if (item && item == icon_view->priv->last_single_clicked)
2140         {
2141           GtkTreePath *path;
2142
2143           path = gtk_tree_path_new_from_indices (item->index, -1);
2144           gtk_icon_view_item_activated (icon_view, path);
2145           gtk_tree_path_free (path);
2146         }
2147
2148       icon_view->priv->last_single_clicked = NULL;
2149       icon_view->priv->pressed_button = -1;
2150     }
2151   
2152   if (dirty)
2153     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2154
2155   return event->button == 1;
2156 }
2157
2158 static gboolean
2159 gtk_icon_view_button_release (GtkWidget      *widget,
2160                               GdkEventButton *event)
2161 {
2162   GtkIconView *icon_view;
2163
2164   icon_view = GTK_ICON_VIEW (widget);
2165   
2166   if (icon_view->priv->pressed_button == event->button)
2167     icon_view->priv->pressed_button = -1;
2168
2169   gtk_icon_view_stop_rubberbanding (icon_view);
2170
2171   remove_scroll_timeout (icon_view);
2172
2173   return TRUE;
2174 }
2175
2176 static gboolean
2177 gtk_icon_view_key_press (GtkWidget      *widget,
2178                          GdkEventKey    *event)
2179 {
2180   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2181
2182   if (icon_view->priv->doing_rubberband)
2183     {
2184       if (event->keyval == GDK_KEY_Escape)
2185         gtk_icon_view_stop_rubberbanding (icon_view);
2186
2187       return TRUE;
2188     }
2189
2190   return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event (widget, event);
2191 }
2192
2193 static gboolean
2194 gtk_icon_view_key_release (GtkWidget      *widget,
2195                            GdkEventKey    *event)
2196 {
2197   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2198
2199   if (icon_view->priv->doing_rubberband)
2200     return TRUE;
2201
2202   return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event (widget, event);
2203 }
2204
2205 static void
2206 gtk_icon_view_update_rubberband (gpointer data)
2207 {
2208   GtkIconView *icon_view;
2209   gint x, y;
2210   GdkRectangle old_area;
2211   GdkRectangle new_area;
2212   GdkRectangle common;
2213   cairo_region_t *invalid_region;
2214   
2215   icon_view = GTK_ICON_VIEW (data);
2216
2217   gdk_window_get_device_position (icon_view->priv->bin_window,
2218                                   icon_view->priv->rubberband_device,
2219                                   &x, &y, NULL);
2220
2221   x = MAX (x, 0);
2222   y = MAX (y, 0);
2223
2224   old_area.x = MIN (icon_view->priv->rubberband_x1,
2225                     icon_view->priv->rubberband_x2);
2226   old_area.y = MIN (icon_view->priv->rubberband_y1,
2227                     icon_view->priv->rubberband_y2);
2228   old_area.width = ABS (icon_view->priv->rubberband_x2 -
2229                         icon_view->priv->rubberband_x1) + 1;
2230   old_area.height = ABS (icon_view->priv->rubberband_y2 -
2231                          icon_view->priv->rubberband_y1) + 1;
2232   
2233   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
2234   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
2235   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
2236   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
2237
2238   invalid_region = cairo_region_create_rectangle (&old_area);
2239   cairo_region_union_rectangle (invalid_region, &new_area);
2240
2241   gdk_rectangle_intersect (&old_area, &new_area, &common);
2242   if (common.width > 2 && common.height > 2)
2243     {
2244       cairo_region_t *common_region;
2245
2246       /* make sure the border is invalidated */
2247       common.x += 1;
2248       common.y += 1;
2249       common.width -= 2;
2250       common.height -= 2;
2251       
2252       common_region = cairo_region_create_rectangle (&common);
2253
2254       cairo_region_subtract (invalid_region, common_region);
2255       cairo_region_destroy (common_region);
2256     }
2257   
2258   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
2259     
2260   cairo_region_destroy (invalid_region);
2261
2262   icon_view->priv->rubberband_x2 = x;
2263   icon_view->priv->rubberband_y2 = y;  
2264
2265   gtk_icon_view_update_rubberband_selection (icon_view);
2266 }
2267
2268 static void
2269 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
2270                                    GdkDevice    *device,
2271                                    gint          x,
2272                                    gint          y)
2273 {
2274   GList *items;
2275
2276   if (icon_view->priv->rubberband_device)
2277     return;
2278
2279   for (items = icon_view->priv->items; items; items = items->next)
2280     {
2281       GtkIconViewItem *item = items->data;
2282
2283       item->selected_before_rubberbanding = item->selected;
2284     }
2285   
2286   icon_view->priv->rubberband_x1 = x;
2287   icon_view->priv->rubberband_y1 = y;
2288   icon_view->priv->rubberband_x2 = x;
2289   icon_view->priv->rubberband_y2 = y;
2290
2291   icon_view->priv->doing_rubberband = TRUE;
2292   icon_view->priv->rubberband_device = device;
2293
2294   gtk_device_grab_add (GTK_WIDGET (icon_view), device, TRUE);
2295 }
2296
2297 static void
2298 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
2299 {
2300   if (!icon_view->priv->doing_rubberband)
2301     return;
2302
2303   gtk_device_grab_remove (GTK_WIDGET (icon_view),
2304                           icon_view->priv->rubberband_device);
2305
2306   icon_view->priv->doing_rubberband = FALSE;
2307   icon_view->priv->rubberband_device = NULL;
2308
2309   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
2310 }
2311
2312 static void
2313 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
2314 {
2315   GList *items;
2316   gint x, y, width, height;
2317   gboolean dirty = FALSE;
2318   
2319   x = MIN (icon_view->priv->rubberband_x1,
2320            icon_view->priv->rubberband_x2);
2321   y = MIN (icon_view->priv->rubberband_y1,
2322            icon_view->priv->rubberband_y2);
2323   width = ABS (icon_view->priv->rubberband_x1 - 
2324                icon_view->priv->rubberband_x2);
2325   height = ABS (icon_view->priv->rubberband_y1 - 
2326                 icon_view->priv->rubberband_y2);
2327   
2328   for (items = icon_view->priv->items; items; items = items->next)
2329     {
2330       GtkIconViewItem *item = items->data;
2331       gboolean is_in;
2332       gboolean selected;
2333       
2334       is_in = gtk_icon_view_item_hit_test (icon_view, item, 
2335                                            x, y, width, height);
2336
2337       selected = is_in ^ item->selected_before_rubberbanding;
2338
2339       if (item->selected != selected)
2340         {
2341           item->selected = selected;
2342           dirty = TRUE;
2343           gtk_icon_view_queue_draw_item (icon_view, item);
2344         }
2345     }
2346
2347   if (dirty)
2348     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2349 }
2350
2351
2352 typedef struct {
2353   GdkRectangle hit_rect;
2354   gboolean     hit;
2355 } HitTestData;
2356
2357 static gboolean 
2358 hit_test (GtkCellRenderer    *renderer,
2359           const GdkRectangle *cell_area,
2360           const GdkRectangle *cell_background,
2361           HitTestData        *data)
2362 {
2363   if (MIN (data->hit_rect.x + data->hit_rect.width, cell_area->x + cell_area->width) - 
2364       MAX (data->hit_rect.x, cell_area->x) > 0 &&
2365       MIN (data->hit_rect.y + data->hit_rect.height, cell_area->y + cell_area->height) - 
2366       MAX (data->hit_rect.y, cell_area->y) > 0)
2367     data->hit = TRUE;
2368   
2369   return (data->hit != FALSE);
2370 }
2371
2372 static gboolean
2373 gtk_icon_view_item_hit_test (GtkIconView      *icon_view,
2374                              GtkIconViewItem  *item,
2375                              gint              x,
2376                              gint              y,
2377                              gint              width,
2378                              gint              height)
2379 {
2380   HitTestData data = { { x, y, width, height }, FALSE };
2381   GtkCellAreaContext *context;
2382   GdkRectangle *item_area = (GdkRectangle *)item;
2383    
2384   if (MIN (x + width, item_area->x + item_area->width) - MAX (x, item_area->x) <= 0 ||
2385       MIN (y + height, item_area->y + item_area->height) - MAX (y, item_area->y) <= 0)
2386     return FALSE;
2387
2388   context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
2389
2390   gtk_icon_view_set_cell_data (icon_view, item);
2391   gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
2392                                GTK_WIDGET (icon_view),
2393                                item_area, item_area,
2394                                (GtkCellAllocCallback)hit_test, &data);
2395
2396   return data.hit;
2397 }
2398
2399 static gboolean
2400 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
2401 {
2402   gboolean dirty = FALSE;
2403   GList *items;
2404
2405   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2406     return FALSE;
2407
2408   for (items = icon_view->priv->items; items; items = items->next)
2409     {
2410       GtkIconViewItem *item = items->data;
2411
2412       if (item->selected)
2413         {
2414           item->selected = FALSE;
2415           dirty = TRUE;
2416           gtk_icon_view_queue_draw_item (icon_view, item);
2417           gtk_icon_view_item_selected_changed (icon_view, item);
2418         }
2419     }
2420
2421   return dirty;
2422 }
2423
2424
2425 /* GtkIconView signals */
2426 static void
2427 gtk_icon_view_real_select_all (GtkIconView *icon_view)
2428 {
2429   gtk_icon_view_select_all (icon_view);
2430 }
2431
2432 static void
2433 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
2434 {
2435   gtk_icon_view_unselect_all (icon_view);
2436 }
2437
2438 static void
2439 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
2440 {
2441   gtk_icon_view_unselect_all (icon_view);
2442
2443   if (icon_view->priv->cursor_item != NULL)
2444     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2445 }
2446
2447 static gboolean
2448 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
2449 {
2450   GtkTreePath *path;
2451   GtkCellAreaContext *context;
2452
2453   if (!icon_view->priv->cursor_item)
2454     return FALSE;
2455
2456   context = g_ptr_array_index (icon_view->priv->row_contexts, icon_view->priv->cursor_item->row);
2457
2458   gtk_icon_view_set_cell_data (icon_view, icon_view->priv->cursor_item);
2459   gtk_cell_area_activate (icon_view->priv->cell_area, context,
2460                           GTK_WIDGET (icon_view),
2461                           (GdkRectangle *)icon_view->priv->cursor_item,
2462                           0 /* XXX flags */,
2463                           FALSE);
2464
2465   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
2466   gtk_icon_view_item_activated (icon_view, path);
2467   gtk_tree_path_free (path);
2468
2469   return TRUE;
2470 }
2471
2472 static void
2473 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
2474 {
2475   if (!icon_view->priv->cursor_item)
2476     return;
2477
2478   switch (icon_view->priv->selection_mode)
2479     {
2480     case GTK_SELECTION_NONE:
2481       break;
2482     case GTK_SELECTION_BROWSE:
2483       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2484       break;
2485     case GTK_SELECTION_SINGLE:
2486       if (icon_view->priv->cursor_item->selected)
2487         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
2488       else
2489         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2490       break;
2491     case GTK_SELECTION_MULTIPLE:
2492       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
2493       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
2494       
2495       gtk_icon_view_item_selected_changed (icon_view, icon_view->priv->cursor_item);      
2496       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2497       break;
2498     }
2499 }
2500
2501 /* Internal functions */
2502 static void
2503 gtk_icon_view_process_updates (GtkIconView *icon_view)
2504 {
2505   /* Prior to drawing, we check if a layout has been scheduled.  If so,
2506    * do it now that all cell view items have valid sizes before we proceeed
2507    * (and resize the bin_window if required).
2508    */
2509   if (icon_view->priv->layout_idle_id != 0)
2510     gtk_icon_view_layout (icon_view);
2511
2512   gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
2513 }
2514
2515 static void
2516 gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view)
2517 {
2518   GtkAllocation  allocation;
2519   GtkAdjustment *adj = icon_view->priv->hadjustment;
2520   gdouble old_page_size;
2521   gdouble old_upper;
2522   gdouble old_value;
2523   gdouble new_value;
2524   gdouble new_upper;
2525
2526   gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
2527
2528   old_value = gtk_adjustment_get_value (adj);
2529   old_upper = gtk_adjustment_get_upper (adj);
2530   old_page_size = gtk_adjustment_get_page_size (adj);
2531   new_upper = MAX (allocation.width, icon_view->priv->width);
2532
2533   if (gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL)
2534     {
2535       /* Make sure no scrolling occurs for RTL locales also (if possible) */
2536       /* Quick explanation:
2537        *   In LTR locales, leftmost portion of visible rectangle should stay
2538        *   fixed, which means left edge of scrollbar thumb should remain fixed
2539        *   and thus adjustment's value should stay the same.
2540        *
2541        *   In RTL locales, we want to keep rightmost portion of visible
2542        *   rectangle fixed. This means right edge of thumb should remain fixed.
2543        *   In this case, upper - value - page_size should remain constant.
2544        */
2545       new_value = (new_upper - allocation.width) -
2546                   (old_upper - old_value - old_page_size);
2547       new_value = CLAMP (new_value, 0, new_upper - allocation.width);
2548     }
2549   else
2550     new_value = CLAMP (old_value, 0, new_upper - allocation.width);
2551
2552   gtk_adjustment_configure (adj,
2553                             new_value,
2554                             0.0,
2555                             new_upper,
2556                             allocation.width * 0.1,
2557                             allocation.width * 0.9,
2558                             allocation.width);
2559 }
2560
2561 static void
2562 gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view)
2563 {
2564   GtkAllocation  allocation;
2565   GtkAdjustment *adj = icon_view->priv->vadjustment;
2566
2567   gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
2568
2569   gtk_adjustment_configure (adj,
2570                             gtk_adjustment_get_value (adj),
2571                             0.0,
2572                             MAX (allocation.height, icon_view->priv->height),
2573                             allocation.height * 0.1,
2574                             allocation.height * 0.9,
2575                             allocation.height);
2576 }
2577
2578 static void
2579 gtk_icon_view_set_hadjustment (GtkIconView   *icon_view,
2580                                GtkAdjustment *adjustment)
2581 {
2582   GtkIconViewPrivate *priv = icon_view->priv;
2583   AtkObject *atk_obj;
2584
2585   if (adjustment && priv->hadjustment == adjustment)
2586     return;
2587
2588   if (priv->hadjustment != NULL)
2589     {
2590       g_signal_handlers_disconnect_matched (priv->hadjustment,
2591                                             G_SIGNAL_MATCH_DATA,
2592                                             0, 0, NULL, NULL, icon_view);
2593       g_object_unref (priv->hadjustment);
2594     }
2595
2596   if (!adjustment)
2597     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2598                                      0.0, 0.0, 0.0);
2599
2600   g_signal_connect (adjustment, "value-changed",
2601                     G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2602   priv->hadjustment = g_object_ref_sink (adjustment);
2603   gtk_icon_view_set_hadjustment_values (icon_view);
2604
2605   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2606   gtk_icon_view_accessible_set_adjustment (atk_obj,
2607                                            GTK_ORIENTATION_HORIZONTAL,
2608                                            adjustment);
2609
2610   g_object_notify (G_OBJECT (icon_view), "hadjustment");
2611 }
2612
2613 static void
2614 gtk_icon_view_set_vadjustment (GtkIconView   *icon_view,
2615                                GtkAdjustment *adjustment)
2616 {
2617   GtkIconViewPrivate *priv = icon_view->priv;
2618   AtkObject *atk_obj;
2619
2620   if (adjustment && priv->vadjustment == adjustment)
2621     return;
2622
2623   if (priv->vadjustment != NULL)
2624     {
2625       g_signal_handlers_disconnect_matched (priv->vadjustment,
2626                                             G_SIGNAL_MATCH_DATA,
2627                                             0, 0, NULL, NULL, icon_view);
2628       g_object_unref (priv->vadjustment);
2629     }
2630
2631   if (!adjustment)
2632     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2633                                      0.0, 0.0, 0.0);
2634
2635   g_signal_connect (adjustment, "value-changed",
2636                     G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2637   priv->vadjustment = g_object_ref_sink (adjustment);
2638   gtk_icon_view_set_vadjustment_values (icon_view);
2639
2640   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2641   gtk_icon_view_accessible_set_adjustment (atk_obj,
2642                                            GTK_ORIENTATION_VERTICAL,
2643                                            adjustment);
2644
2645   g_object_notify (G_OBJECT (icon_view), "vadjustment");
2646 }
2647
2648 static void
2649 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
2650                                   GtkIconView   *icon_view)
2651 {
2652   GtkIconViewPrivate *priv = icon_view->priv;
2653
2654   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2655     {
2656       gdk_window_move (priv->bin_window,
2657                        - gtk_adjustment_get_value (priv->hadjustment),
2658                        - gtk_adjustment_get_value (priv->vadjustment));
2659
2660       if (icon_view->priv->doing_rubberband)
2661         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
2662
2663       gtk_icon_view_process_updates (icon_view);
2664     }
2665 }
2666
2667 static GList *
2668 gtk_icon_view_layout_single_row (GtkIconView *icon_view, 
2669                                  GList       *first_item, 
2670                                  gint         item_width,
2671                                  gint         row,
2672                                  gint        *y, 
2673                                  gint        *maximum_width)
2674 {
2675   GtkAllocation allocation;
2676   GtkCellAreaContext *context;
2677   GtkIconViewPrivate *priv = icon_view->priv;
2678   GtkWidget *widget = GTK_WIDGET (icon_view);
2679   gint x, current_width;
2680   GList *items, *last_item;
2681   gint col;
2682   gint max_height = 0;
2683   gboolean rtl;
2684
2685   rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2686
2687   x = 0;
2688   col = 0;
2689   items = first_item;
2690   current_width = 0;
2691
2692   x += priv->margin;
2693   current_width += 2 * priv->margin;
2694
2695   gtk_widget_get_allocation (widget, &allocation);
2696
2697   context = gtk_cell_area_copy_context (priv->cell_area, priv->cell_area_context);
2698   g_ptr_array_add (priv->row_contexts, context);
2699
2700   /* In the first loop we iterate horizontally until we hit allocation width
2701    * and collect the aligned height-for-width */
2702   items = first_item;
2703   while (items)
2704     {
2705       GtkIconViewItem *item = items->data;
2706       GdkRectangle    *item_area = (GdkRectangle *)item;
2707
2708       item_area->width = item_width;
2709
2710       current_width += item_area->width + icon_view->priv->item_padding * 2;
2711
2712       if (items != first_item)
2713         {
2714           if ((icon_view->priv->columns <= 0 && current_width > allocation.width) ||
2715               (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
2716             break;
2717         }
2718
2719       /* Get this item's particular width & height (all alignments are cached by now) */
2720       gtk_icon_view_set_cell_data (icon_view, item);
2721       gtk_cell_area_get_preferred_height_for_width (priv->cell_area,
2722                                                     context,
2723                                                     widget, item_width, 
2724                                                     NULL, NULL);
2725
2726       current_width += icon_view->priv->column_spacing;
2727
2728       item_area->y = *y + icon_view->priv->item_padding;
2729       item_area->x = x  + icon_view->priv->item_padding;
2730
2731       x = current_width - icon_view->priv->margin; 
2732               
2733       if (current_width > *maximum_width)
2734         *maximum_width = current_width;
2735
2736       item->row = row;
2737       item->col = col;
2738
2739       col ++;
2740       items = items->next;
2741     }
2742
2743   last_item = items;
2744
2745   gtk_cell_area_context_get_preferred_height_for_width (context, item_width, &max_height, NULL);
2746   gtk_cell_area_context_allocate (context, item_width, max_height);
2747
2748   /* In the second loop the item height has been aligned and derived and
2749    * we just set the height and handle rtl layout */
2750   for (items = first_item; items != last_item; items = items->next)
2751     {
2752       GtkIconViewItem *item = items->data;
2753       GdkRectangle    *item_area = (GdkRectangle *)item;
2754
2755       if (rtl)
2756         {
2757           item_area->x = *maximum_width - item_area->width - item_area->x;
2758           item->col = col - 1 - item->col;
2759         }
2760
2761       /* All items in the same row get the same height */
2762       item_area->height = max_height;
2763     }
2764
2765   /* Adjust the new y coordinate. */
2766   *y += max_height + icon_view->priv->row_spacing + icon_view->priv->item_padding * 2;
2767   
2768   return last_item;
2769 }
2770
2771 static void
2772 adjust_wrap_width (GtkIconView *icon_view)
2773 {
2774   if (icon_view->priv->text_cell)
2775     {
2776       gint wrap_width = 50;
2777
2778       /* Here we go with the same old guess, try the icon size and set double
2779        * the size of the first icon found in the list, naive but works much
2780        * of the time */
2781       if (icon_view->priv->items && icon_view->priv->pixbuf_cell)
2782         {
2783           gtk_icon_view_set_cell_data (icon_view, icon_view->priv->items->data);
2784           gtk_cell_renderer_get_preferred_width (icon_view->priv->pixbuf_cell,
2785                                                  GTK_WIDGET (icon_view),
2786                                                  &wrap_width, NULL);
2787           
2788           wrap_width = MAX (wrap_width * 2, 50);
2789         }
2790       
2791       g_object_set (icon_view->priv->text_cell, "wrap-width", wrap_width, NULL);
2792       g_object_set (icon_view->priv->text_cell, "width", wrap_width, NULL);
2793     }
2794 }
2795
2796 static void
2797 gtk_icon_view_layout (GtkIconView *icon_view)
2798 {
2799   GtkAllocation allocation;
2800   GtkWidget *widget;
2801   GList *icons;
2802   gint y = 0, maximum_width = 0;
2803   gint row;
2804   gint item_width;
2805   gboolean size_changed = FALSE;
2806
2807   if (icon_view->priv->layout_idle_id != 0)
2808     {
2809       g_source_remove (icon_view->priv->layout_idle_id);
2810       icon_view->priv->layout_idle_id = 0;
2811     }
2812   
2813   if (icon_view->priv->model == NULL)
2814     return;
2815
2816   widget = GTK_WIDGET (icon_view);
2817
2818   item_width = icon_view->priv->item_width;
2819
2820   /* Update the wrap width for the text cell before going and requesting sizes */
2821   adjust_wrap_width (icon_view);
2822
2823   /* Update the context widths for any invalidated items */
2824   gtk_icon_view_cache_widths (icon_view);
2825
2826   /* Fetch the new item width if needed */
2827   if (item_width < 0)
2828     gtk_cell_area_context_get_preferred_width (icon_view->priv->cell_area_context, 
2829                                                &item_width, NULL);
2830
2831   gtk_cell_area_context_allocate (icon_view->priv->cell_area_context, item_width, -1);
2832
2833   icons = icon_view->priv->items;
2834   y += icon_view->priv->margin;
2835   row = 0;
2836
2837   /* Clear the per row contexts */
2838   g_ptr_array_set_size (icon_view->priv->row_contexts, 0);
2839   
2840   do
2841     {
2842       icons = gtk_icon_view_layout_single_row (icon_view, icons, 
2843                                                item_width, row,
2844                                                &y, &maximum_width);
2845       row++;
2846     }
2847   while (icons != NULL);
2848
2849   if (maximum_width != icon_view->priv->width)
2850     {
2851       icon_view->priv->width = maximum_width;
2852       size_changed = TRUE;
2853     }
2854
2855   y += icon_view->priv->margin;
2856   
2857   if (y != icon_view->priv->height)
2858     {
2859       icon_view->priv->height = y;
2860       size_changed = TRUE;
2861     }
2862
2863   gtk_icon_view_set_hadjustment_values (icon_view);
2864   gtk_icon_view_set_vadjustment_values (icon_view);
2865
2866   if (size_changed)
2867     gtk_widget_queue_resize_no_redraw (widget);
2868
2869   gtk_widget_get_allocation (widget, &allocation);
2870   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2871     gdk_window_resize (icon_view->priv->bin_window,
2872                        MAX (icon_view->priv->width, allocation.width),
2873                        MAX (icon_view->priv->height, allocation.height));
2874
2875   if (icon_view->priv->scroll_to_path)
2876     {
2877       GtkTreePath *path;
2878
2879       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
2880       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
2881       icon_view->priv->scroll_to_path = NULL;
2882       
2883       gtk_icon_view_scroll_to_path (icon_view, path,
2884                                     icon_view->priv->scroll_to_use_align,
2885                                     icon_view->priv->scroll_to_row_align,
2886                                     icon_view->priv->scroll_to_col_align);
2887       gtk_tree_path_free (path);
2888     }
2889   
2890   gtk_widget_queue_draw (widget);
2891 }
2892
2893 /* This ensures that all widths have been cached in the
2894  * context and we have proper alignments to go on.
2895  */
2896 static void
2897 gtk_icon_view_cache_widths (GtkIconView *icon_view)
2898 {
2899   GList *items;
2900
2901   g_signal_handler_block (icon_view->priv->cell_area_context, 
2902                           icon_view->priv->context_changed_id);
2903
2904   for (items = icon_view->priv->items; items; items = items->next)
2905     {
2906       GtkIconViewItem *item = items->data;
2907
2908       /* Only fetch the width of items with invalidated sizes */
2909       if (item->cell_area.width < 0)
2910         {
2911           gtk_icon_view_set_cell_data (icon_view, item);
2912           gtk_cell_area_get_preferred_width (icon_view->priv->cell_area, 
2913                                              icon_view->priv->cell_area_context,
2914                                              GTK_WIDGET (icon_view), NULL, NULL);
2915         }
2916     }
2917
2918   g_signal_handler_unblock (icon_view->priv->cell_area_context, 
2919                             icon_view->priv->context_changed_id);
2920 }
2921
2922 static void
2923 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
2924 {
2925   /* Clear all item sizes */
2926   g_list_foreach (icon_view->priv->items,
2927                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
2928
2929   /* Reset the context */
2930   if (icon_view->priv->cell_area_context)
2931     {
2932       g_signal_handler_block (icon_view->priv->cell_area_context, 
2933                               icon_view->priv->context_changed_id);
2934       gtk_cell_area_context_reset (icon_view->priv->cell_area_context);
2935       g_signal_handler_unblock (icon_view->priv->cell_area_context, 
2936                                 icon_view->priv->context_changed_id);
2937     }
2938
2939   /* Re-layout the items */
2940   gtk_icon_view_queue_layout (icon_view);
2941 }
2942
2943 static void
2944 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
2945 {
2946   item->cell_area.width = -1;
2947   item->cell_area.height = -1;
2948 }
2949
2950 static void
2951 gtk_icon_view_paint_item (GtkIconView     *icon_view,
2952                           cairo_t         *cr,
2953                           GtkIconViewItem *item,
2954                           gint             x,
2955                           gint             y,
2956                           gboolean         draw_focus)
2957 {
2958   GdkRectangle cell_area;
2959   GtkStateFlags state = 0;
2960   GtkCellRendererState flags = 0;
2961   GtkStyleContext *style_context;
2962   GtkWidget *widget = GTK_WIDGET (icon_view);
2963   GtkIconViewPrivate *priv = icon_view->priv;
2964   GtkCellAreaContext *context;
2965
2966   if (priv->model == NULL)
2967     return;
2968
2969   gtk_icon_view_set_cell_data (icon_view, item);
2970
2971   style_context = gtk_widget_get_style_context (widget);
2972
2973   gtk_style_context_save (style_context);
2974   gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_VIEW);
2975   gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_CELL);
2976
2977   if (item->selected)
2978     {
2979       if (gtk_widget_has_focus (widget) &&
2980           item == icon_view->priv->cursor_item)
2981         {
2982           state |= GTK_STATE_FLAG_FOCUSED;
2983           flags |= GTK_CELL_RENDERER_FOCUSED;
2984         }
2985
2986       state |= GTK_STATE_FLAG_SELECTED;
2987       flags |= GTK_CELL_RENDERER_SELECTED;
2988     }
2989
2990   if (item->prelight)
2991     {
2992       state |= GTK_STATE_FLAG_PRELIGHT;
2993       flags |= GTK_CELL_RENDERER_PRELIT;
2994     }
2995
2996   gtk_style_context_set_state (style_context, state);
2997
2998   if (item->selected)
2999     {
3000       gtk_render_background (style_context, cr,
3001                              x - icon_view->priv->item_padding,
3002                              y - icon_view->priv->item_padding,
3003                              item->cell_area.width  + icon_view->priv->item_padding * 2,
3004                              item->cell_area.height + icon_view->priv->item_padding * 2);
3005       gtk_render_frame (style_context, cr,
3006                         x - icon_view->priv->item_padding,
3007                         y - icon_view->priv->item_padding,
3008                         item->cell_area.width  + icon_view->priv->item_padding * 2,
3009                         item->cell_area.height + icon_view->priv->item_padding * 2);
3010     }
3011
3012   cell_area.x      = x;
3013   cell_area.y      = y;
3014   cell_area.width  = item->cell_area.width;
3015   cell_area.height = item->cell_area.height;
3016
3017   context = g_ptr_array_index (priv->row_contexts, item->row);
3018   gtk_cell_area_render (priv->cell_area, context,
3019                         widget, cr, &cell_area, &cell_area, flags,
3020                         draw_focus);
3021
3022   gtk_style_context_restore (style_context);
3023 }
3024
3025 static void
3026 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
3027                                 cairo_t         *cr)
3028 {
3029   GtkStyleContext *context;
3030   GdkRectangle rect;
3031
3032   cairo_save (cr);
3033
3034   rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
3035   rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
3036   rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
3037   rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
3038
3039   context = gtk_widget_get_style_context (GTK_WIDGET (icon_view));
3040
3041   gtk_style_context_save (context);
3042   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
3043
3044   gdk_cairo_rectangle (cr, &rect);
3045   cairo_clip (cr);
3046
3047   gtk_render_background (context, cr,
3048                          rect.x, rect.y,
3049                          rect.width, rect.height);
3050   gtk_render_frame (context, cr,
3051                     rect.x, rect.y,
3052                     rect.width, rect.height);
3053
3054   gtk_style_context_restore (context);
3055   cairo_restore (cr);
3056 }
3057
3058 static void
3059 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3060                                GtkTreePath *path)
3061 {
3062   GList *l;
3063   gint index;
3064
3065   index = gtk_tree_path_get_indices (path)[0];
3066
3067   for (l = icon_view->priv->items; l; l = l->next) 
3068     {
3069       GtkIconViewItem *item = l->data;
3070
3071       if (item->index == index)
3072         {
3073           gtk_icon_view_queue_draw_item (icon_view, item);
3074           break;
3075         }
3076     }
3077 }
3078
3079 static void
3080 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
3081                                GtkIconViewItem *item)
3082 {
3083   GdkRectangle  rect;
3084   GdkRectangle *item_area = (GdkRectangle *)item;
3085
3086   rect.x      = item_area->x - icon_view->priv->item_padding;
3087   rect.y      = item_area->y - icon_view->priv->item_padding;
3088   rect.width  = item_area->width  + icon_view->priv->item_padding * 2;
3089   rect.height = item_area->height + icon_view->priv->item_padding * 2;
3090
3091   if (icon_view->priv->bin_window)
3092     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3093 }
3094
3095 static gboolean
3096 layout_callback (gpointer user_data)
3097 {
3098   GtkIconView *icon_view;
3099
3100   icon_view = GTK_ICON_VIEW (user_data);
3101   
3102   icon_view->priv->layout_idle_id = 0;
3103
3104   gtk_icon_view_layout (icon_view);
3105   
3106   return FALSE;
3107 }
3108
3109 static void
3110 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3111 {
3112   if (icon_view->priv->layout_idle_id != 0)
3113     return;
3114
3115   icon_view->priv->layout_idle_id =
3116       gdk_threads_add_idle_full (GTK_ICON_VIEW_PRIORITY_LAYOUT,
3117                                  layout_callback, icon_view, NULL);
3118 }
3119
3120 static void
3121 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
3122                                GtkIconViewItem *item,
3123                                GtkCellRenderer *cursor_cell)
3124 {
3125   AtkObject *obj;
3126   AtkObject *item_obj;
3127   AtkObject *cursor_item_obj;
3128
3129   /* When hitting this path from keynav, the focus cell is
3130    * already set, we dont need to notify the atk object
3131    * but we still need to queue the draw here (in the case
3132    * that the focus cell changes but not the cursor item).
3133    */
3134   gtk_icon_view_queue_draw_item (icon_view, item);
3135
3136   if (icon_view->priv->cursor_item == item &&
3137       (cursor_cell == NULL || cursor_cell == gtk_cell_area_get_focus_cell (icon_view->priv->cell_area)))
3138     return;
3139
3140   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3141   if (icon_view->priv->cursor_item != NULL)
3142     {
3143       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3144       if (obj != NULL)
3145         {
3146           cursor_item_obj = atk_object_ref_accessible_child (obj, icon_view->priv->cursor_item->index);
3147           if (cursor_item_obj != NULL)
3148             atk_object_notify_state_change (cursor_item_obj, ATK_STATE_FOCUSED, FALSE);
3149         }
3150     }
3151   icon_view->priv->cursor_item = item;
3152
3153   if (cursor_cell)
3154     gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cursor_cell);
3155   else
3156     {
3157       /* Make sure there is a cell in focus initially */
3158       if (!gtk_cell_area_get_focus_cell (icon_view->priv->cell_area))
3159         gtk_cell_area_focus (icon_view->priv->cell_area, GTK_DIR_TAB_FORWARD);
3160     }
3161   
3162   /* Notify that accessible focus object has changed */
3163   item_obj = atk_object_ref_accessible_child (obj, item->index);
3164
3165   if (item_obj != NULL)
3166     {
3167       atk_focus_tracker_notify (item_obj);
3168       atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
3169       g_object_unref (item_obj); 
3170     }
3171 }
3172
3173
3174 static GtkIconViewItem *
3175 gtk_icon_view_item_new (void)
3176 {
3177   GtkIconViewItem *item;
3178
3179   item = g_slice_new0 (GtkIconViewItem);
3180
3181   item->cell_area.width  = -1;
3182   item->cell_area.height = -1;
3183   
3184   return item;
3185 }
3186
3187 static void
3188 gtk_icon_view_item_free (GtkIconViewItem *item)
3189 {
3190   g_return_if_fail (item != NULL);
3191
3192   g_slice_free (GtkIconViewItem, item);
3193 }
3194
3195 static GtkIconViewItem *
3196 gtk_icon_view_get_item_at_coords (GtkIconView          *icon_view,
3197                                   gint                  x,
3198                                   gint                  y,
3199                                   gboolean              only_in_cell,
3200                                   GtkCellRenderer     **cell_at_pos)
3201 {
3202   GList *items;
3203
3204   if (cell_at_pos)
3205     *cell_at_pos = NULL;
3206
3207   for (items = icon_view->priv->items; items; items = items->next)
3208     {
3209       GtkIconViewItem *item = items->data;
3210       GdkRectangle    *item_area = (GdkRectangle *)item;
3211
3212       if (x >= item_area->x - icon_view->priv->column_spacing/2 && 
3213           x <= item_area->x + item_area->width + icon_view->priv->column_spacing/2 &&
3214           y >= item_area->y - icon_view->priv->row_spacing/2 && 
3215           y <= item_area->y + item_area->height + icon_view->priv->row_spacing/2)
3216         {
3217           if (only_in_cell || cell_at_pos)
3218             {
3219               GtkCellRenderer *cell = NULL;
3220               GtkCellAreaContext *context;
3221
3222               context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
3223               gtk_icon_view_set_cell_data (icon_view, item);
3224
3225               if (x >= item_area->x && x <= item_area->x + item_area->width &&
3226                   y >= item_area->y && y <= item_area->y + item_area->height)
3227                 cell = gtk_cell_area_get_cell_at_position (icon_view->priv->cell_area, context,
3228                                                            GTK_WIDGET (icon_view),
3229                                                            item_area,
3230                                                            x, y, NULL);
3231
3232               if (cell_at_pos)
3233                 *cell_at_pos = cell;
3234
3235               if (only_in_cell)
3236                 return cell != NULL ? item : NULL;
3237               else
3238                 return item;
3239             }
3240           return item;
3241         }
3242     }
3243   return NULL;
3244 }
3245
3246 static void
3247 gtk_icon_view_select_item (GtkIconView      *icon_view,
3248                            GtkIconViewItem  *item)
3249 {
3250   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3251   g_return_if_fail (item != NULL);
3252
3253   if (item->selected)
3254     return;
3255   
3256   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3257     return;
3258   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3259     gtk_icon_view_unselect_all_internal (icon_view);
3260
3261   item->selected = TRUE;
3262
3263   gtk_icon_view_item_selected_changed (icon_view, item);
3264   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3265
3266   gtk_icon_view_queue_draw_item (icon_view, item);
3267 }
3268
3269
3270 static void
3271 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
3272                              GtkIconViewItem  *item)
3273 {
3274   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3275   g_return_if_fail (item != NULL);
3276
3277   if (!item->selected)
3278     return;
3279   
3280   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3281       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3282     return;
3283   
3284   item->selected = FALSE;
3285
3286   gtk_icon_view_item_selected_changed (icon_view, item);
3287   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3288
3289   gtk_icon_view_queue_draw_item (icon_view, item);
3290 }
3291
3292 static void
3293 verify_items (GtkIconView *icon_view)
3294 {
3295   GList *items;
3296   int i = 0;
3297
3298   for (items = icon_view->priv->items; items; items = items->next)
3299     {
3300       GtkIconViewItem *item = items->data;
3301
3302       if (item->index != i)
3303         g_error ("List item does not match its index: "
3304                  "item index %d and list index %d\n", item->index, i);
3305
3306       i++;
3307     }
3308 }
3309
3310 static void
3311 gtk_icon_view_row_changed (GtkTreeModel *model,
3312                            GtkTreePath  *path,
3313                            GtkTreeIter  *iter,
3314                            gpointer      data)
3315 {
3316   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3317
3318   /* ignore changes in branches */
3319   if (gtk_tree_path_get_depth (path) > 1)
3320     return;
3321
3322   /* An icon view subclass might add it's own model and populate
3323    * things at init() time instead of waiting for the constructor() 
3324    * to be called 
3325    */
3326   if (icon_view->priv->cell_area)
3327     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3328
3329   /* Here we can use a "grow-only" strategy for optimization
3330    * and only invalidate a single item and queue a relayout
3331    * instead of invalidating the whole thing.
3332    *
3333    * For now GtkIconView still cant deal with huge models
3334    * so just invalidate the whole thing when the model
3335    * changes.
3336    */
3337   gtk_icon_view_invalidate_sizes (icon_view);
3338
3339   verify_items (icon_view);
3340 }
3341
3342 static void
3343 gtk_icon_view_row_inserted (GtkTreeModel *model,
3344                             GtkTreePath  *path,
3345                             GtkTreeIter  *iter,
3346                             gpointer      data)
3347 {
3348   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3349   gint index;
3350   GtkIconViewItem *item;
3351   gboolean iters_persist;
3352   GList *list;
3353
3354   /* ignore changes in branches */
3355   if (gtk_tree_path_get_depth (path) > 1)
3356     return;
3357
3358   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3359   
3360   index = gtk_tree_path_get_indices(path)[0];
3361
3362   item = gtk_icon_view_item_new ();
3363
3364   if (iters_persist)
3365     item->iter = *iter;
3366
3367   item->index = index;
3368
3369   /* FIXME: We can be more efficient here,
3370      we can store a tail pointer and use that when
3371      appending (which is a rather common operation)
3372   */
3373   icon_view->priv->items = g_list_insert (icon_view->priv->items,
3374                                          item, index);
3375   
3376   list = g_list_nth (icon_view->priv->items, index + 1);
3377   for (; list; list = list->next)
3378     {
3379       item = list->data;
3380
3381       item->index++;
3382     }
3383     
3384   verify_items (icon_view);
3385
3386   gtk_icon_view_queue_layout (icon_view);
3387 }
3388
3389 static void
3390 gtk_icon_view_row_deleted (GtkTreeModel *model,
3391                            GtkTreePath  *path,
3392                            gpointer      data)
3393 {
3394   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3395   gint index;
3396   GtkIconViewItem *item;
3397   GList *list, *next;
3398   gboolean emit = FALSE;
3399
3400   /* ignore changes in branches */
3401   if (gtk_tree_path_get_depth (path) > 1)
3402     return;
3403
3404   index = gtk_tree_path_get_indices(path)[0];
3405
3406   list = g_list_nth (icon_view->priv->items, index);
3407   item = list->data;
3408
3409   if (icon_view->priv->cell_area)
3410     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3411
3412   if (item == icon_view->priv->anchor_item)
3413     icon_view->priv->anchor_item = NULL;
3414
3415   if (item == icon_view->priv->cursor_item)
3416     icon_view->priv->cursor_item = NULL;
3417
3418   if (item == icon_view->priv->last_prelight)
3419     icon_view->priv->last_prelight = NULL;
3420
3421   if (item->selected)
3422     emit = TRUE;
3423   
3424   gtk_icon_view_item_free (item);
3425
3426   for (next = list->next; next; next = next->next)
3427     {
3428       item = next->data;
3429
3430       item->index--;
3431     }
3432   
3433   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3434
3435   verify_items (icon_view);  
3436   
3437   gtk_icon_view_queue_layout (icon_view);
3438
3439   if (emit)
3440     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3441 }
3442
3443 static void
3444 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3445                               GtkTreePath  *parent,
3446                               GtkTreeIter  *iter,
3447                               gint         *new_order,
3448                               gpointer      data)
3449 {
3450   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3451   int i;
3452   int length;
3453   GList *items = NULL, *list;
3454   GtkIconViewItem **item_array;
3455   gint *order;
3456
3457   /* ignore changes in branches */
3458   if (iter != NULL)
3459     return;
3460
3461   if (icon_view->priv->cell_area)
3462     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3463
3464   length = gtk_tree_model_iter_n_children (model, NULL);
3465
3466   order = g_new (gint, length);
3467   for (i = 0; i < length; i++)
3468     order [new_order[i]] = i;
3469
3470   item_array = g_new (GtkIconViewItem *, length);
3471   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3472     item_array[order[i]] = list->data;
3473   g_free (order);
3474
3475   for (i = length - 1; i >= 0; i--)
3476     {
3477       item_array[i]->index = i;
3478       items = g_list_prepend (items, item_array[i]);
3479     }
3480   
3481   g_free (item_array);
3482   g_list_free (icon_view->priv->items);
3483   icon_view->priv->items = items;
3484
3485   gtk_icon_view_queue_layout (icon_view);
3486
3487   verify_items (icon_view);  
3488 }
3489
3490 static void
3491 gtk_icon_view_build_items (GtkIconView *icon_view)
3492 {
3493   GtkTreeIter iter;
3494   int i;
3495   gboolean iters_persist;
3496   GList *items = NULL;
3497
3498   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3499   
3500   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3501                                       &iter))
3502     return;
3503
3504   i = 0;
3505   
3506   do
3507     {
3508       GtkIconViewItem *item = gtk_icon_view_item_new ();
3509
3510       if (iters_persist)
3511         item->iter = iter;
3512
3513       item->index = i;
3514       
3515       i++;
3516
3517       items = g_list_prepend (items, item);
3518       
3519     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3520
3521   icon_view->priv->items = g_list_reverse (items);
3522 }
3523
3524 static void
3525 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
3526                                 guint           keyval,
3527                                 guint           modmask,
3528                                 GtkMovementStep step,
3529                                 gint            count)
3530 {
3531   
3532   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3533                                 I_("move-cursor"), 2,
3534                                 G_TYPE_ENUM, step,
3535                                 G_TYPE_INT, count);
3536
3537   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3538                                 "move-cursor", 2,
3539                                 G_TYPE_ENUM, step,
3540                                 G_TYPE_INT, count);
3541
3542   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3543    return;
3544
3545   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3546                                 "move-cursor", 2,
3547                                 G_TYPE_ENUM, step,
3548                                 G_TYPE_INT, count);
3549
3550   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3551                                 "move-cursor", 2,
3552                                 G_TYPE_ENUM, step,
3553                                 G_TYPE_INT, count);
3554 }
3555
3556 static gboolean
3557 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
3558                                 GtkMovementStep  step,
3559                                 gint             count)
3560 {
3561   GdkModifierType state;
3562
3563   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3564   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3565                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3566                         step == GTK_MOVEMENT_DISPLAY_LINES ||
3567                         step == GTK_MOVEMENT_PAGES ||
3568                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3569
3570   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3571     return FALSE;
3572
3573   gtk_cell_area_stop_editing (icon_view->priv->cell_area, FALSE);
3574   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3575
3576   if (gtk_get_current_event_state (&state))
3577     {
3578       GdkModifierType extend_mod_mask;
3579       GdkModifierType modify_mod_mask;
3580
3581       extend_mod_mask =
3582         gtk_widget_get_modifier_mask (GTK_WIDGET (icon_view),
3583                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3584       modify_mod_mask =
3585         gtk_widget_get_modifier_mask (GTK_WIDGET (icon_view),
3586                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3587
3588       if ((state & modify_mod_mask) == modify_mod_mask)
3589         icon_view->priv->modify_selection_pressed = TRUE;
3590       if ((state & extend_mod_mask) == extend_mod_mask)
3591         icon_view->priv->extend_selection_pressed = TRUE;
3592     }
3593   /* else we assume not pressed */
3594
3595   switch (step)
3596     {
3597     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3598     case GTK_MOVEMENT_VISUAL_POSITIONS:
3599       gtk_icon_view_move_cursor_left_right (icon_view, count);
3600       break;
3601     case GTK_MOVEMENT_DISPLAY_LINES:
3602       gtk_icon_view_move_cursor_up_down (icon_view, count);
3603       break;
3604     case GTK_MOVEMENT_PAGES:
3605       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3606       break;
3607     case GTK_MOVEMENT_BUFFER_ENDS:
3608       gtk_icon_view_move_cursor_start_end (icon_view, count);
3609       break;
3610     default:
3611       g_assert_not_reached ();
3612     }
3613
3614   icon_view->priv->modify_selection_pressed = FALSE;
3615   icon_view->priv->extend_selection_pressed = FALSE;
3616
3617   icon_view->priv->draw_focus = TRUE;
3618
3619   return TRUE;
3620 }
3621
3622 static GtkIconViewItem *
3623 find_item (GtkIconView     *icon_view,
3624            GtkIconViewItem *current,
3625            gint             row_ofs,
3626            gint             col_ofs)
3627 {
3628   gint row, col;
3629   GList *items;
3630   GtkIconViewItem *item;
3631
3632   /* FIXME: this could be more efficient 
3633    */
3634   row = current->row + row_ofs;
3635   col = current->col + col_ofs;
3636
3637   for (items = icon_view->priv->items; items; items = items->next)
3638     {
3639       item = items->data;
3640       if (item->row == row && item->col == col)
3641         return item;
3642     }
3643   
3644   return NULL;
3645 }
3646
3647 static GtkIconViewItem *
3648 find_item_page_up_down (GtkIconView     *icon_view,
3649                         GtkIconViewItem *current,
3650                         gint             count)
3651 {
3652   GList *item, *next;
3653   gint y, col;
3654   
3655   col = current->col;
3656   y = current->cell_area.y + count * gtk_adjustment_get_page_size (icon_view->priv->vadjustment);
3657
3658   item = g_list_find (icon_view->priv->items, current);
3659   if (count > 0)
3660     {
3661       while (item)
3662         {
3663           for (next = item->next; next; next = next->next)
3664             {
3665               if (((GtkIconViewItem *)next->data)->col == col)
3666                 break;
3667             }
3668           if (!next || ((GtkIconViewItem *)next->data)->cell_area.y > y)
3669             break;
3670
3671           item = next;
3672         }
3673     }
3674   else 
3675     {
3676       while (item)
3677         {
3678           for (next = item->prev; next; next = next->prev)
3679             {
3680               if (((GtkIconViewItem *)next->data)->col == col)
3681                 break;
3682             }
3683           if (!next || ((GtkIconViewItem *)next->data)->cell_area.y < y)
3684             break;
3685
3686           item = next;
3687         }
3688     }
3689
3690   if (item)
3691     return item->data;
3692
3693   return NULL;
3694 }
3695
3696 static gboolean
3697 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
3698                                   GtkIconViewItem *anchor,
3699                                   GtkIconViewItem *cursor)
3700 {
3701   GList *items;
3702   GtkIconViewItem *item;
3703   gint row1, row2, col1, col2;
3704   gboolean dirty = FALSE;
3705   
3706   if (anchor->row < cursor->row)
3707     {
3708       row1 = anchor->row;
3709       row2 = cursor->row;
3710     }
3711   else
3712     {
3713       row1 = cursor->row;
3714       row2 = anchor->row;
3715     }
3716
3717   if (anchor->col < cursor->col)
3718     {
3719       col1 = anchor->col;
3720       col2 = cursor->col;
3721     }
3722   else
3723     {
3724       col1 = cursor->col;
3725       col2 = anchor->col;
3726     }
3727
3728   for (items = icon_view->priv->items; items; items = items->next)
3729     {
3730       item = items->data;
3731
3732       if (row1 <= item->row && item->row <= row2 &&
3733           col1 <= item->col && item->col <= col2)
3734         {
3735           if (!item->selected)
3736             {
3737               dirty = TRUE;
3738               item->selected = TRUE;
3739               gtk_icon_view_item_selected_changed (icon_view, item);
3740             }
3741           gtk_icon_view_queue_draw_item (icon_view, item);
3742         }
3743     }
3744
3745   return dirty;
3746 }
3747
3748 static void 
3749 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3750                                    gint         count)
3751 {
3752   GtkIconViewItem *item;
3753   GtkCellRenderer *cell = NULL;
3754   gboolean dirty = FALSE;
3755   gint step;
3756   GtkDirectionType direction;
3757
3758   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3759     return;
3760
3761   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
3762
3763   if (!icon_view->priv->cursor_item)
3764     {
3765       GList *list;
3766
3767       if (count > 0)
3768         list = icon_view->priv->items;
3769       else
3770         list = g_list_last (icon_view->priv->items);
3771
3772       item = list ? list->data : NULL;
3773
3774       /* Give focus to the first cell initially */
3775       gtk_icon_view_set_cell_data (icon_view, item);
3776       gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3777     }
3778   else
3779     {
3780       item = icon_view->priv->cursor_item;
3781       step = count > 0 ? 1 : -1;      
3782
3783       /* Save the current focus cell in case we hit the edge */
3784       cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3785
3786       while (item)
3787         {
3788           gtk_icon_view_set_cell_data (icon_view, item);
3789
3790           if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3791             break;
3792
3793           item = find_item (icon_view, item, step, 0);
3794         }
3795     }
3796
3797   if (!item)
3798     {
3799       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3800         {
3801           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3802           if (toplevel)
3803             gtk_widget_child_focus (toplevel,
3804                                     direction == GTK_DIR_UP ?
3805                                     GTK_DIR_TAB_BACKWARD :
3806                                     GTK_DIR_TAB_FORWARD);
3807
3808         }
3809
3810       gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3811       return;
3812     }
3813
3814   if (icon_view->priv->modify_selection_pressed ||
3815       !icon_view->priv->extend_selection_pressed ||
3816       !icon_view->priv->anchor_item ||
3817       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3818     icon_view->priv->anchor_item = item;
3819
3820   cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3821   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3822
3823   if (!icon_view->priv->modify_selection_pressed &&
3824       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3825     {
3826       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3827       dirty = gtk_icon_view_select_all_between (icon_view, 
3828                                                 icon_view->priv->anchor_item,
3829                                                 item) || dirty;
3830     }
3831
3832   gtk_icon_view_scroll_to_item (icon_view, item);
3833
3834   if (dirty)
3835     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3836 }
3837
3838 static void 
3839 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3840                                         gint         count)
3841 {
3842   GtkIconViewItem *item;
3843   gboolean dirty = FALSE;
3844   
3845   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3846     return;
3847   
3848   if (!icon_view->priv->cursor_item)
3849     {
3850       GList *list;
3851
3852       if (count > 0)
3853         list = icon_view->priv->items;
3854       else
3855         list = g_list_last (icon_view->priv->items);
3856
3857       item = list ? list->data : NULL;
3858     }
3859   else
3860     item = find_item_page_up_down (icon_view, 
3861                                    icon_view->priv->cursor_item,
3862                                    count);
3863
3864   if (item == icon_view->priv->cursor_item)
3865     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3866
3867   if (!item)
3868     return;
3869
3870   if (icon_view->priv->modify_selection_pressed ||
3871       !icon_view->priv->extend_selection_pressed ||
3872       !icon_view->priv->anchor_item ||
3873       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3874     icon_view->priv->anchor_item = item;
3875
3876   gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3877
3878   if (!icon_view->priv->modify_selection_pressed &&
3879       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3880     {
3881       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3882       dirty = gtk_icon_view_select_all_between (icon_view, 
3883                                                 icon_view->priv->anchor_item,
3884                                                 item) || dirty;
3885     }
3886
3887   gtk_icon_view_scroll_to_item (icon_view, item);
3888
3889   if (dirty)
3890     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
3891 }
3892
3893 static void 
3894 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
3895                                       gint         count)
3896 {
3897   GtkIconViewItem *item;
3898   GtkCellRenderer *cell = NULL;
3899   gboolean dirty = FALSE;
3900   gint step;
3901   GtkDirectionType direction;
3902
3903   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3904     return;
3905
3906   direction = count < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
3907
3908   if (!icon_view->priv->cursor_item)
3909     {
3910       GList *list;
3911
3912       if (count > 0)
3913         list = icon_view->priv->items;
3914       else
3915         list = g_list_last (icon_view->priv->items);
3916
3917       item = list ? list->data : NULL;
3918
3919       /* Give focus to the first cell initially */
3920       gtk_icon_view_set_cell_data (icon_view, item);
3921       gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3922     }
3923   else
3924     {
3925       item = icon_view->priv->cursor_item;
3926       step = count > 0 ? 1 : -1;
3927
3928       /* Save the current focus cell in case we hit the edge */
3929       cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3930
3931       while (item)
3932         {
3933           gtk_icon_view_set_cell_data (icon_view, item);
3934
3935           if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3936             break;
3937           
3938           item = find_item (icon_view, item, 0, step);
3939         }
3940     }
3941
3942   if (!item)
3943     {
3944       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3945         {
3946           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3947           if (toplevel)
3948             gtk_widget_child_focus (toplevel,
3949                                     direction == GTK_DIR_LEFT ?
3950                                     GTK_DIR_TAB_BACKWARD :
3951                                     GTK_DIR_TAB_FORWARD);
3952
3953         }
3954
3955       gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3956       return;
3957     }
3958
3959   if (icon_view->priv->modify_selection_pressed ||
3960       !icon_view->priv->extend_selection_pressed ||
3961       !icon_view->priv->anchor_item ||
3962       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3963     icon_view->priv->anchor_item = item;
3964
3965   cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3966   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3967
3968   if (!icon_view->priv->modify_selection_pressed &&
3969       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3970     {
3971       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3972       dirty = gtk_icon_view_select_all_between (icon_view, 
3973                                                 icon_view->priv->anchor_item,
3974                                                 item) || dirty;
3975     }
3976
3977   gtk_icon_view_scroll_to_item (icon_view, item);
3978
3979   if (dirty)
3980     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3981 }
3982
3983 static void 
3984 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
3985                                      gint         count)
3986 {
3987   GtkIconViewItem *item;
3988   GList *list;
3989   gboolean dirty = FALSE;
3990   
3991   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3992     return;
3993   
3994   if (count < 0)
3995     list = icon_view->priv->items;
3996   else
3997     list = g_list_last (icon_view->priv->items);
3998   
3999   item = list ? list->data : NULL;
4000
4001   if (item == icon_view->priv->cursor_item)
4002     gtk_widget_error_bell (GTK_WIDGET (icon_view));
4003
4004   if (!item)
4005     return;
4006
4007   if (icon_view->priv->modify_selection_pressed ||
4008       !icon_view->priv->extend_selection_pressed ||
4009       !icon_view->priv->anchor_item ||
4010       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4011     icon_view->priv->anchor_item = item;
4012
4013   gtk_icon_view_set_cursor_item (icon_view, item, NULL);
4014
4015   if (!icon_view->priv->modify_selection_pressed &&
4016       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4017     {
4018       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4019       dirty = gtk_icon_view_select_all_between (icon_view, 
4020                                                 icon_view->priv->anchor_item,
4021                                                 item) || dirty;
4022     }
4023
4024   gtk_icon_view_scroll_to_item (icon_view, item);
4025
4026   if (dirty)
4027     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
4028 }
4029
4030 /**
4031  * gtk_icon_view_scroll_to_path:
4032  * @icon_view: A #GtkIconView.
4033  * @path: The path of the item to move to.
4034  * @use_align: whether to use alignment arguments, or %FALSE.
4035  * @row_align: The vertical alignment of the item specified by @path.
4036  * @col_align: The horizontal alignment of the item specified by @path.
4037  *
4038  * Moves the alignments of @icon_view to the position specified by @path.  
4039  * @row_align determines where the row is placed, and @col_align determines 
4040  * where @column is placed.  Both are expected to be between 0.0 and 1.0. 
4041  * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means 
4042  * center.
4043  *
4044  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
4045  * tree does the minimum amount of work to scroll the item onto the screen.
4046  * This means that the item will be scrolled to the edge closest to its current
4047  * position.  If the item is currently visible on the screen, nothing is done.
4048  *
4049  * This function only works if the model is set, and @path is a valid row on 
4050  * the model. If the model changes before the @icon_view is realized, the 
4051  * centered path will be modified to reflect this change.
4052  *
4053  * Since: 2.8
4054  **/
4055 void
4056 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
4057                               GtkTreePath *path,
4058                               gboolean     use_align,
4059                               gfloat       row_align,
4060                               gfloat       col_align)
4061 {
4062   GtkIconViewItem *item = NULL;
4063   GtkWidget *widget;
4064
4065   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4066   g_return_if_fail (path != NULL);
4067   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
4068   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
4069
4070   widget = GTK_WIDGET (icon_view);
4071
4072   if (gtk_tree_path_get_depth (path) > 0)
4073     item = g_list_nth_data (icon_view->priv->items,
4074                             gtk_tree_path_get_indices(path)[0]);
4075   
4076   if (!item || item->cell_area.width < 0 ||
4077       !gtk_widget_get_realized (widget))
4078     {
4079       if (icon_view->priv->scroll_to_path)
4080         gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4081
4082       icon_view->priv->scroll_to_path = NULL;
4083
4084       if (path)
4085         icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4086
4087       icon_view->priv->scroll_to_use_align = use_align;
4088       icon_view->priv->scroll_to_row_align = row_align;
4089       icon_view->priv->scroll_to_col_align = col_align;
4090
4091       return;
4092     }
4093
4094   if (use_align)
4095     {
4096       GtkAllocation allocation;
4097       gint x, y;
4098       gfloat offset;
4099       GdkRectangle item_area = 
4100         { 
4101           item->cell_area.x - icon_view->priv->item_padding, 
4102           item->cell_area.y - icon_view->priv->item_padding, 
4103           item->cell_area.width  + icon_view->priv->item_padding * 2, 
4104           item->cell_area.height + icon_view->priv->item_padding * 2 
4105         };
4106
4107       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4108
4109       gtk_widget_get_allocation (widget, &allocation);
4110
4111       offset = y + item_area.y - row_align * (allocation.height - item_area.height);
4112
4113       gtk_adjustment_set_value (icon_view->priv->vadjustment,
4114                                 gtk_adjustment_get_value (icon_view->priv->vadjustment) + offset);
4115
4116       offset = x + item_area.x - col_align * (allocation.width - item_area.width);
4117
4118       gtk_adjustment_set_value (icon_view->priv->hadjustment,
4119                                 gtk_adjustment_get_value (icon_view->priv->hadjustment) + offset);
4120
4121       gtk_adjustment_changed (icon_view->priv->hadjustment);
4122       gtk_adjustment_changed (icon_view->priv->vadjustment);
4123     }
4124   else
4125     gtk_icon_view_scroll_to_item (icon_view, item);
4126 }
4127
4128
4129 static void
4130 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view,
4131                               GtkIconViewItem *item)
4132 {
4133   GtkIconViewPrivate *priv = icon_view->priv;
4134   GtkWidget *widget = GTK_WIDGET (icon_view);
4135   GtkAdjustment *hadj, *vadj;
4136   GtkAllocation allocation;
4137   gint x, y;
4138   GdkRectangle item_area;
4139
4140   item_area.x = item->cell_area.x - priv->item_padding;
4141   item_area.y = item->cell_area.y - priv->item_padding;
4142   item_area.width = item->cell_area.width  + priv->item_padding * 2;
4143   item_area.height = item->cell_area.height + priv->item_padding * 2;
4144
4145   gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4146   gtk_widget_get_allocation (widget, &allocation);
4147
4148   hadj = icon_view->priv->hadjustment;
4149   vadj = icon_view->priv->vadjustment;
4150
4151   if (y + item_area.y < 0)
4152     gtk_adjustment_set_value (vadj,
4153                               gtk_adjustment_get_value (vadj)
4154                                 + y + item_area.y);
4155   else if (y + item_area.y + item_area.height > allocation.height)
4156     gtk_adjustment_set_value (vadj,
4157                               gtk_adjustment_get_value (vadj)
4158                                 + y + item_area.y + item_area.height - allocation.height);
4159
4160   if (x + item_area.x < 0)
4161     gtk_adjustment_set_value (hadj,
4162                               gtk_adjustment_get_value (hadj)
4163                                 + x + item_area.x);
4164   else if (x + item_area.x + item_area.width > allocation.width)
4165     gtk_adjustment_set_value (hadj,
4166                               gtk_adjustment_get_value (hadj)
4167                                 + x + item_area.x + item_area.width - allocation.width);
4168
4169   gtk_adjustment_changed (hadj);
4170   gtk_adjustment_changed (vadj);
4171 }
4172
4173 /* GtkCellLayout implementation */
4174
4175 static void
4176 gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
4177                                 GtkCellArea *cell_area)
4178 {
4179   GtkIconViewPrivate *priv = icon_view->priv;
4180
4181   if (priv->cell_area)
4182     return;
4183
4184   if (cell_area)
4185     priv->cell_area = cell_area;
4186   else
4187     priv->cell_area = gtk_cell_area_box_new ();
4188
4189   g_object_ref_sink (priv->cell_area);
4190
4191   if (GTK_IS_ORIENTABLE (priv->cell_area))
4192     gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
4193
4194   priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
4195
4196   priv->add_editable_id =
4197     g_signal_connect (priv->cell_area, "add-editable",
4198                       G_CALLBACK (gtk_icon_view_add_editable), icon_view);
4199   priv->remove_editable_id =
4200     g_signal_connect (priv->cell_area, "remove-editable",
4201                       G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
4202   priv->context_changed_id =
4203     g_signal_connect (priv->cell_area_context, "notify",
4204                       G_CALLBACK (gtk_icon_view_context_changed), icon_view);
4205
4206   update_text_cell (icon_view);
4207   update_pixbuf_cell (icon_view);
4208 }
4209
4210 static GtkCellArea *
4211 gtk_icon_view_cell_layout_get_area (GtkCellLayout *cell_layout)
4212 {
4213   GtkIconView *icon_view = GTK_ICON_VIEW (cell_layout);
4214   GtkIconViewPrivate *priv = icon_view->priv;
4215
4216   if (G_UNLIKELY (!priv->cell_area))
4217     gtk_icon_view_ensure_cell_area (icon_view, NULL);
4218
4219   return icon_view->priv->cell_area;
4220 }
4221
4222 static void
4223 gtk_icon_view_set_cell_data (GtkIconView     *icon_view,
4224                              GtkIconViewItem *item)
4225 {
4226   gboolean iters_persist;
4227   GtkTreeIter iter;
4228
4229   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4230   
4231   if (!iters_persist)
4232     {
4233       GtkTreePath *path;
4234
4235       path = gtk_tree_path_new_from_indices (item->index, -1);
4236       if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4237         return;
4238       gtk_tree_path_free (path);
4239     }
4240   else
4241     iter = item->iter;
4242
4243   gtk_cell_area_apply_attributes (icon_view->priv->cell_area, 
4244                                   icon_view->priv->model,
4245                                   &iter, FALSE, FALSE);
4246 }
4247
4248
4249
4250 /* Public API */
4251
4252
4253 /**
4254  * gtk_icon_view_new:
4255  * 
4256  * Creates a new #GtkIconView widget
4257  * 
4258  * Return value: A newly created #GtkIconView widget
4259  *
4260  * Since: 2.6
4261  **/
4262 GtkWidget *
4263 gtk_icon_view_new (void)
4264 {
4265   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4266 }
4267
4268 /**
4269  * gtk_icon_view_new_with_area:
4270  * @area: the #GtkCellArea to use to layout cells
4271  * 
4272  * Creates a new #GtkIconView widget using the
4273  * specified @area to layout cells inside the icons.
4274  * 
4275  * Return value: A newly created #GtkIconView widget
4276  *
4277  * Since: 3.0
4278  **/
4279 GtkWidget *
4280 gtk_icon_view_new_with_area (GtkCellArea *area)
4281 {
4282   return g_object_new (GTK_TYPE_ICON_VIEW, "cell-area", area, NULL);
4283 }
4284
4285 /**
4286  * gtk_icon_view_new_with_model:
4287  * @model: The model.
4288  * 
4289  * Creates a new #GtkIconView widget with the model @model.
4290  * 
4291  * Return value: A newly created #GtkIconView widget.
4292  *
4293  * Since: 2.6 
4294  **/
4295 GtkWidget *
4296 gtk_icon_view_new_with_model (GtkTreeModel *model)
4297 {
4298   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4299 }
4300
4301 /**
4302  * gtk_icon_view_convert_widget_to_bin_window_coords:
4303  * @icon_view: a #GtkIconView 
4304  * @wx: X coordinate relative to the widget
4305  * @wy: Y coordinate relative to the widget
4306  * @bx: (out): return location for bin_window X coordinate
4307  * @by: (out): return location for bin_window Y coordinate
4308  * 
4309  * Converts widget coordinates to coordinates for the bin_window,
4310  * as expected by e.g. gtk_icon_view_get_path_at_pos(). 
4311  *
4312  * Since: 2.12
4313  */
4314 void
4315 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4316                                                    gint         wx,
4317                                                    gint         wy, 
4318                                                    gint        *bx,
4319                                                    gint        *by)
4320 {
4321   gint x, y;
4322
4323   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4324
4325   if (icon_view->priv->bin_window) 
4326     gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4327   else
4328     x = y = 0;
4329  
4330   if (bx)
4331     *bx = wx - x;
4332   if (by)
4333     *by = wy - y;
4334 }
4335
4336 /**
4337  * gtk_icon_view_get_path_at_pos:
4338  * @icon_view: A #GtkIconView.
4339  * @x: The x position to be identified
4340  * @y: The y position to be identified
4341  * 
4342  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4343  * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4344  * the cell at the specified position. 
4345  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4346  * widget coordinates to bin_window coordinates.
4347  * 
4348  * Return value: The #GtkTreePath corresponding to the icon or %NULL
4349  * if no icon exists at that position.
4350  *
4351  * Since: 2.6 
4352  **/
4353 GtkTreePath *
4354 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4355                                gint         x,
4356                                gint         y)
4357 {
4358   GtkIconViewItem *item;
4359   GtkTreePath *path;
4360   
4361   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4362
4363   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4364
4365   if (!item)
4366     return NULL;
4367
4368   path = gtk_tree_path_new_from_indices (item->index, -1);
4369
4370   return path;
4371 }
4372
4373 /**
4374  * gtk_icon_view_get_item_at_pos:
4375  * @icon_view: A #GtkIconView.
4376  * @x: The x position to be identified
4377  * @y: The y position to be identified
4378  * @path: (out) (allow-none): Return location for the path, or %NULL
4379  * @cell: (out) (allow-none): Return location for the renderer
4380  *   responsible for the cell at (@x, @y), or %NULL
4381  * 
4382  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4383  * In contrast to gtk_icon_view_get_path_at_pos(), this function also 
4384  * obtains the cell at the specified position. The returned path should
4385  * be freed with gtk_tree_path_free().
4386  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4387  * widget coordinates to bin_window coordinates.
4388  * 
4389  * Return value: %TRUE if an item exists at the specified position
4390  *
4391  * Since: 2.8
4392  **/
4393 gboolean 
4394 gtk_icon_view_get_item_at_pos (GtkIconView      *icon_view,
4395                                gint              x,
4396                                gint              y,
4397                                GtkTreePath     **path,
4398                                GtkCellRenderer **cell)
4399 {
4400   GtkIconViewItem *item;
4401   GtkCellRenderer *renderer = NULL;
4402   
4403   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4404
4405   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &renderer);
4406
4407   if (path != NULL)
4408     {
4409       if (item != NULL)
4410         *path = gtk_tree_path_new_from_indices (item->index, -1);
4411       else
4412         *path = NULL;
4413     }
4414
4415   if (cell != NULL)
4416     *cell = renderer;
4417
4418   return (item != NULL);
4419 }
4420
4421 /**
4422  * gtk_icon_view_set_tooltip_item:
4423  * @icon_view: a #GtkIconView
4424  * @tooltip: a #GtkTooltip
4425  * @path: a #GtkTreePath
4426  * 
4427  * Sets the tip area of @tooltip to be the area covered by the item at @path.
4428  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4429  * See also gtk_tooltip_set_tip_area().
4430  * 
4431  * Since: 2.12
4432  */
4433 void 
4434 gtk_icon_view_set_tooltip_item (GtkIconView     *icon_view,
4435                                 GtkTooltip      *tooltip,
4436                                 GtkTreePath     *path)
4437 {
4438   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4439   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4440
4441   gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
4442 }
4443
4444 /**
4445  * gtk_icon_view_set_tooltip_cell:
4446  * @icon_view: a #GtkIconView
4447  * @tooltip: a #GtkTooltip
4448  * @path: a #GtkTreePath
4449  * @cell: (allow-none): a #GtkCellRenderer or %NULL
4450  *
4451  * Sets the tip area of @tooltip to the area which @cell occupies in
4452  * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
4453  *
4454  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4455  *
4456  * Since: 2.12
4457  */
4458 void
4459 gtk_icon_view_set_tooltip_cell (GtkIconView     *icon_view,
4460                                 GtkTooltip      *tooltip,
4461                                 GtkTreePath     *path,
4462                                 GtkCellRenderer *cell)
4463 {
4464   GdkRectangle rect;
4465   GtkIconViewItem *item = NULL;
4466   gint x, y;
4467  
4468   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4469   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4470   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
4471
4472   if (gtk_tree_path_get_depth (path) > 0)
4473     item = g_list_nth_data (icon_view->priv->items,
4474                             gtk_tree_path_get_indices(path)[0]);
4475  
4476   if (!item)
4477     return;
4478
4479   if (cell)
4480     {
4481       GtkCellAreaContext *context;
4482
4483       context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
4484       gtk_icon_view_set_cell_data (icon_view, item);
4485       gtk_cell_area_get_cell_allocation (icon_view->priv->cell_area, context,
4486                                          GTK_WIDGET (icon_view),
4487                                          cell, (GdkRectangle *)item, &rect);
4488     }
4489   else
4490     {
4491       rect.x = item->cell_area.x - icon_view->priv->item_padding;
4492       rect.y = item->cell_area.y - icon_view->priv->item_padding;
4493       rect.width  = item->cell_area.width  + icon_view->priv->item_padding * 2;
4494       rect.height = item->cell_area.height + icon_view->priv->item_padding * 2;
4495     }
4496   
4497   if (icon_view->priv->bin_window)
4498     {
4499       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4500       rect.x += x;
4501       rect.y += y; 
4502     }
4503
4504   gtk_tooltip_set_tip_area (tooltip, &rect); 
4505 }
4506
4507
4508 /**
4509  * gtk_icon_view_get_tooltip_context:
4510  * @icon_view: an #GtkIconView
4511  * @x: (inout): the x coordinate (relative to widget coordinates)
4512  * @y: (inout): the y coordinate (relative to widget coordinates)
4513  * @keyboard_tip: whether this is a keyboard tooltip or not
4514  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
4515  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
4516  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
4517  *
4518  * This function is supposed to be used in a #GtkWidget::query-tooltip
4519  * signal handler for #GtkIconView.  The @x, @y and @keyboard_tip values
4520  * which are received in the signal handler, should be passed to this
4521  * function without modification.
4522  *
4523  * The return value indicates whether there is an icon view item at the given
4524  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
4525  * tooltips the item returned will be the cursor item. When %TRUE, then any of
4526  * @model, @path and @iter which have been provided will be set to point to
4527  * that row and the corresponding model. @x and @y will always be converted
4528  * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
4529  *
4530  * Return value: whether or not the given tooltip context points to a item
4531  *
4532  * Since: 2.12
4533  */
4534 gboolean
4535 gtk_icon_view_get_tooltip_context (GtkIconView   *icon_view,
4536                                    gint          *x,
4537                                    gint          *y,
4538                                    gboolean       keyboard_tip,
4539                                    GtkTreeModel **model,
4540                                    GtkTreePath  **path,
4541                                    GtkTreeIter   *iter)
4542 {
4543   GtkTreePath *tmppath = NULL;
4544
4545   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4546   g_return_val_if_fail (x != NULL, FALSE);
4547   g_return_val_if_fail (y != NULL, FALSE);
4548
4549   if (keyboard_tip)
4550     {
4551       gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
4552
4553       if (!tmppath)
4554         return FALSE;
4555     }
4556   else
4557     {
4558       gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
4559                                                          x, y);
4560
4561       if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
4562         return FALSE;
4563     }
4564
4565   if (model)
4566     *model = gtk_icon_view_get_model (icon_view);
4567
4568   if (iter)
4569     gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
4570                              iter, tmppath);
4571
4572   if (path)
4573     *path = tmppath;
4574   else
4575     gtk_tree_path_free (tmppath);
4576
4577   return TRUE;
4578 }
4579
4580 static gboolean
4581 gtk_icon_view_set_tooltip_query_cb (GtkWidget  *widget,
4582                                     gint        x,
4583                                     gint        y,
4584                                     gboolean    keyboard_tip,
4585                                     GtkTooltip *tooltip,
4586                                     gpointer    data)
4587 {
4588   gchar *str;
4589   GtkTreeIter iter;
4590   GtkTreePath *path;
4591   GtkTreeModel *model;
4592   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
4593
4594   if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
4595                                           &x, &y,
4596                                           keyboard_tip,
4597                                           &model, &path, &iter))
4598     return FALSE;
4599
4600   gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
4601
4602   if (!str)
4603     {
4604       gtk_tree_path_free (path);
4605       return FALSE;
4606     }
4607
4608   gtk_tooltip_set_markup (tooltip, str);
4609   gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
4610
4611   gtk_tree_path_free (path);
4612   g_free (str);
4613
4614   return TRUE;
4615 }
4616
4617
4618 /**
4619  * gtk_icon_view_set_tooltip_column:
4620  * @icon_view: a #GtkIconView
4621  * @column: an integer, which is a valid column number for @icon_view's model
4622  *
4623  * If you only plan to have simple (text-only) tooltips on full items, you
4624  * can use this function to have #GtkIconView handle these automatically
4625  * for you. @column should be set to the column in @icon_view's model
4626  * containing the tooltip texts, or -1 to disable this feature.
4627  *
4628  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
4629  * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
4630  *
4631  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
4632  * so &amp;, &lt;, etc have to be escaped in the text.
4633  *
4634  * Since: 2.12
4635  */
4636 void
4637 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
4638                                   gint         column)
4639 {
4640   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4641
4642   if (column == icon_view->priv->tooltip_column)
4643     return;
4644
4645   if (column == -1)
4646     {
4647       g_signal_handlers_disconnect_by_func (icon_view,
4648                                             gtk_icon_view_set_tooltip_query_cb,
4649                                             NULL);
4650       gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
4651     }
4652   else
4653     {
4654       if (icon_view->priv->tooltip_column == -1)
4655         {
4656           g_signal_connect (icon_view, "query-tooltip",
4657                             G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
4658           gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
4659         }
4660     }
4661
4662   icon_view->priv->tooltip_column = column;
4663   g_object_notify (G_OBJECT (icon_view), "tooltip-column");
4664 }
4665
4666 /**
4667  * gtk_icon_view_get_tooltip_column:
4668  * @icon_view: a #GtkIconView
4669  *
4670  * Returns the column of @icon_view's model which is being used for
4671  * displaying tooltips on @icon_view's rows.
4672  *
4673  * Return value: the index of the tooltip column that is currently being
4674  * used, or -1 if this is disabled.
4675  *
4676  * Since: 2.12
4677  */
4678 gint
4679 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
4680 {
4681   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
4682
4683   return icon_view->priv->tooltip_column;
4684 }
4685
4686 /**
4687  * gtk_icon_view_get_visible_range:
4688  * @icon_view: A #GtkIconView
4689  * @start_path: (out) (allow-none): Return location for start of region,
4690  *              or %NULL
4691  * @end_path: (out) (allow-none): Return location for end of region, or %NULL
4692  * 
4693  * Sets @start_path and @end_path to be the first and last visible path. 
4694  * Note that there may be invisible paths in between.
4695  * 
4696  * Both paths should be freed with gtk_tree_path_free() after use.
4697  * 
4698  * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4699  *
4700  * Since: 2.8
4701  **/
4702 gboolean
4703 gtk_icon_view_get_visible_range (GtkIconView  *icon_view,
4704                                  GtkTreePath **start_path,
4705                                  GtkTreePath **end_path)
4706 {
4707   gint start_index = -1;
4708   gint end_index = -1;
4709   GList *icons;
4710
4711   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4712
4713   if (icon_view->priv->hadjustment == NULL ||
4714       icon_view->priv->vadjustment == NULL)
4715     return FALSE;
4716
4717   if (start_path == NULL && end_path == NULL)
4718     return FALSE;
4719   
4720   for (icons = icon_view->priv->items; icons; icons = icons->next) 
4721     {
4722       GtkIconViewItem *item = icons->data;
4723       GdkRectangle    *item_area = (GdkRectangle *)item;
4724
4725       if ((item_area->x + item_area->width >= (int)gtk_adjustment_get_value (icon_view->priv->hadjustment)) &&
4726           (item_area->y + item_area->height >= (int)gtk_adjustment_get_value (icon_view->priv->vadjustment)) &&
4727           (item_area->x <= 
4728            (int) (gtk_adjustment_get_value (icon_view->priv->hadjustment) + 
4729                   gtk_adjustment_get_page_size (icon_view->priv->hadjustment))) &&
4730           (item_area->y <= 
4731            (int) (gtk_adjustment_get_value (icon_view->priv->vadjustment) + 
4732                   gtk_adjustment_get_page_size (icon_view->priv->vadjustment))))
4733         {
4734           if (start_index == -1)
4735             start_index = item->index;
4736           end_index = item->index;
4737         }
4738     }
4739
4740   if (start_path && start_index != -1)
4741     *start_path = gtk_tree_path_new_from_indices (start_index, -1);
4742   if (end_path && end_index != -1)
4743     *end_path = gtk_tree_path_new_from_indices (end_index, -1);
4744   
4745   return start_index != -1;
4746 }
4747
4748 /**
4749  * gtk_icon_view_selected_foreach:
4750  * @icon_view: A #GtkIconView.
4751  * @func: (scope call): The function to call for each selected icon.
4752  * @data: User data to pass to the function.
4753  * 
4754  * Calls a function for each selected icon. Note that the model or
4755  * selection cannot be modified from within this function.
4756  *
4757  * Since: 2.6 
4758  **/
4759 void
4760 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
4761                                 GtkIconViewForeachFunc func,
4762                                 gpointer               data)
4763 {
4764   GList *list;
4765   
4766   for (list = icon_view->priv->items; list; list = list->next)
4767     {
4768       GtkIconViewItem *item = list->data;
4769       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
4770
4771       if (item->selected)
4772         (* func) (icon_view, path, data);
4773
4774       gtk_tree_path_free (path);
4775     }
4776 }
4777
4778 /**
4779  * gtk_icon_view_set_selection_mode:
4780  * @icon_view: A #GtkIconView.
4781  * @mode: The selection mode
4782  * 
4783  * Sets the selection mode of the @icon_view.
4784  *
4785  * Since: 2.6 
4786  **/
4787 void
4788 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
4789                                   GtkSelectionMode  mode)
4790 {
4791   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4792
4793   if (mode == icon_view->priv->selection_mode)
4794     return;
4795   
4796   if (mode == GTK_SELECTION_NONE ||
4797       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
4798     gtk_icon_view_unselect_all (icon_view);
4799   
4800   icon_view->priv->selection_mode = mode;
4801
4802   g_object_notify (G_OBJECT (icon_view), "selection-mode");
4803 }
4804
4805 /**
4806  * gtk_icon_view_get_selection_mode:
4807  * @icon_view: A #GtkIconView.
4808  * 
4809  * Gets the selection mode of the @icon_view.
4810  *
4811  * Return value: the current selection mode
4812  *
4813  * Since: 2.6 
4814  **/
4815 GtkSelectionMode
4816 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
4817 {
4818   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
4819
4820   return icon_view->priv->selection_mode;
4821 }
4822
4823 /**
4824  * gtk_icon_view_set_model:
4825  * @icon_view: A #GtkIconView.
4826  * @model: (allow-none): The model.
4827  *
4828  * Sets the model for a #GtkIconView.
4829  * If the @icon_view already has a model set, it will remove
4830  * it before setting the new model.  If @model is %NULL, then
4831  * it will unset the old model.
4832  *
4833  * Since: 2.6 
4834  **/
4835 void
4836 gtk_icon_view_set_model (GtkIconView *icon_view,
4837                          GtkTreeModel *model)
4838 {
4839   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4840   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
4841   
4842   if (icon_view->priv->model == model)
4843     return;
4844
4845   if (icon_view->priv->scroll_to_path)
4846     {
4847       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4848       icon_view->priv->scroll_to_path = NULL;
4849     }
4850
4851   /* The area can be NULL while disposing */
4852   if (icon_view->priv->cell_area)
4853     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4854
4855   if (model)
4856     {
4857       GType column_type;
4858
4859       if (icon_view->priv->pixbuf_column != -1)
4860         {
4861           column_type = gtk_tree_model_get_column_type (model,
4862                                                         icon_view->priv->pixbuf_column);          
4863
4864           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
4865         }
4866
4867       if (icon_view->priv->text_column != -1)
4868         {
4869           column_type = gtk_tree_model_get_column_type (model,
4870                                                         icon_view->priv->text_column);    
4871
4872           g_return_if_fail (column_type == G_TYPE_STRING);
4873         }
4874
4875       if (icon_view->priv->markup_column != -1)
4876         {
4877           column_type = gtk_tree_model_get_column_type (model,
4878                                                         icon_view->priv->markup_column);          
4879
4880           g_return_if_fail (column_type == G_TYPE_STRING);
4881         }
4882       
4883     }
4884   
4885   if (icon_view->priv->model)
4886     {
4887       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4888                                             gtk_icon_view_row_changed,
4889                                             icon_view);
4890       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4891                                             gtk_icon_view_row_inserted,
4892                                             icon_view);
4893       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4894                                             gtk_icon_view_row_deleted,
4895                                             icon_view);
4896       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4897                                             gtk_icon_view_rows_reordered,
4898                                             icon_view);
4899
4900       g_object_unref (icon_view->priv->model);
4901       
4902       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
4903       g_list_free (icon_view->priv->items);
4904       icon_view->priv->items = NULL;
4905       icon_view->priv->anchor_item = NULL;
4906       icon_view->priv->cursor_item = NULL;
4907       icon_view->priv->last_single_clicked = NULL;
4908       icon_view->priv->last_prelight = NULL;
4909       icon_view->priv->width = 0;
4910       icon_view->priv->height = 0;
4911     }
4912
4913   icon_view->priv->model = model;
4914
4915   if (icon_view->priv->model)
4916     {
4917       g_object_ref (icon_view->priv->model);
4918       g_signal_connect (icon_view->priv->model,
4919                         "row-changed",
4920                         G_CALLBACK (gtk_icon_view_row_changed),
4921                         icon_view);
4922       g_signal_connect (icon_view->priv->model,
4923                         "row-inserted",
4924                         G_CALLBACK (gtk_icon_view_row_inserted),
4925                         icon_view);
4926       g_signal_connect (icon_view->priv->model,
4927                         "row-deleted",
4928                         G_CALLBACK (gtk_icon_view_row_deleted),
4929                         icon_view);
4930       g_signal_connect (icon_view->priv->model,
4931                         "rows-reordered",
4932                         G_CALLBACK (gtk_icon_view_rows_reordered),
4933                         icon_view);
4934
4935       gtk_icon_view_build_items (icon_view);
4936
4937       gtk_icon_view_layout (icon_view);
4938     }
4939
4940   g_object_notify (G_OBJECT (icon_view), "model");  
4941
4942   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
4943     gtk_widget_queue_resize (GTK_WIDGET (icon_view));
4944 }
4945
4946 /**
4947  * gtk_icon_view_get_model:
4948  * @icon_view: a #GtkIconView
4949  *
4950  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
4951  * model is unset.
4952  *
4953  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is
4954  *     currently being used.
4955  *
4956  * Since: 2.6 
4957  **/
4958 GtkTreeModel *
4959 gtk_icon_view_get_model (GtkIconView *icon_view)
4960 {
4961   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4962
4963   return icon_view->priv->model;
4964 }
4965
4966 static void
4967 update_text_cell (GtkIconView *icon_view)
4968 {
4969   if (!icon_view->priv->cell_area)
4970     return;
4971
4972   if (icon_view->priv->text_column == -1 &&
4973       icon_view->priv->markup_column == -1)
4974     {
4975       if (icon_view->priv->text_cell != NULL)
4976         {
4977           gtk_cell_area_remove (icon_view->priv->cell_area, 
4978                                 icon_view->priv->text_cell);
4979           icon_view->priv->text_cell = NULL;
4980         }
4981     }
4982   else 
4983     {
4984       if (icon_view->priv->text_cell == NULL)
4985         {
4986           icon_view->priv->text_cell = gtk_cell_renderer_text_new ();
4987
4988           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), icon_view->priv->text_cell, FALSE);
4989         }
4990
4991       if (icon_view->priv->markup_column != -1)
4992         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4993                                         icon_view->priv->text_cell, 
4994                                         "markup", icon_view->priv->markup_column, 
4995                                         NULL);
4996       else
4997         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4998                                         icon_view->priv->text_cell, 
4999                                         "text", icon_view->priv->text_column, 
5000                                         NULL);
5001
5002       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
5003         g_object_set (icon_view->priv->text_cell,
5004                       "alignment", PANGO_ALIGN_CENTER,
5005                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
5006                       "xalign", 0.5,
5007                       "yalign", 0.0,
5008                       NULL);
5009       else
5010         g_object_set (icon_view->priv->text_cell,
5011                       "alignment", PANGO_ALIGN_LEFT,
5012                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
5013                       "xalign", 0.0,
5014                       "yalign", 0.5,
5015                       NULL);
5016     }
5017 }
5018
5019 static void
5020 update_pixbuf_cell (GtkIconView *icon_view)
5021 {
5022   if (!icon_view->priv->cell_area)
5023     return;
5024
5025   if (icon_view->priv->pixbuf_column == -1)
5026     {
5027       if (icon_view->priv->pixbuf_cell != NULL)
5028         {
5029           gtk_cell_area_remove (icon_view->priv->cell_area, 
5030                                 icon_view->priv->pixbuf_cell);
5031
5032           icon_view->priv->pixbuf_cell = NULL;
5033         }
5034     }
5035   else 
5036     {
5037       if (icon_view->priv->pixbuf_cell == NULL)
5038         {
5039           icon_view->priv->pixbuf_cell = gtk_cell_renderer_pixbuf_new ();
5040           
5041           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), icon_view->priv->pixbuf_cell, FALSE);
5042         }
5043       
5044       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5045                                       icon_view->priv->pixbuf_cell, 
5046                                       "pixbuf", icon_view->priv->pixbuf_column, 
5047                                       NULL);
5048
5049       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
5050         g_object_set (icon_view->priv->pixbuf_cell,
5051                       "xalign", 0.5,
5052                       "yalign", 1.0,
5053                       NULL);
5054       else
5055         g_object_set (icon_view->priv->pixbuf_cell,
5056                       "xalign", 0.0,
5057                       "yalign", 0.0,
5058                       NULL);
5059     }
5060 }
5061
5062 /**
5063  * gtk_icon_view_set_text_column:
5064  * @icon_view: A #GtkIconView.
5065  * @column: A column in the currently used model, or -1 to display no text
5066  * 
5067  * Sets the column with text for @icon_view to be @column. The text
5068  * column must be of type #G_TYPE_STRING.
5069  *
5070  * Since: 2.6 
5071  **/
5072 void
5073 gtk_icon_view_set_text_column (GtkIconView *icon_view,
5074                                gint          column)
5075 {
5076   if (column == icon_view->priv->text_column)
5077     return;
5078   
5079   if (column == -1)
5080     icon_view->priv->text_column = -1;
5081   else
5082     {
5083       if (icon_view->priv->model != NULL)
5084         {
5085           GType column_type;
5086           
5087           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5088
5089           g_return_if_fail (column_type == G_TYPE_STRING);
5090         }
5091       
5092       icon_view->priv->text_column = column;
5093     }
5094
5095   if (icon_view->priv->cell_area)
5096     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5097
5098   update_text_cell (icon_view);
5099
5100   gtk_icon_view_invalidate_sizes (icon_view);
5101   
5102   g_object_notify (G_OBJECT (icon_view), "text-column");
5103 }
5104
5105 /**
5106  * gtk_icon_view_get_text_column:
5107  * @icon_view: A #GtkIconView.
5108  *
5109  * Returns the column with text for @icon_view.
5110  *
5111  * Returns: the text column, or -1 if it's unset.
5112  *
5113  * Since: 2.6
5114  */
5115 gint
5116 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
5117 {
5118   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5119
5120   return icon_view->priv->text_column;
5121 }
5122
5123 /**
5124  * gtk_icon_view_set_markup_column:
5125  * @icon_view: A #GtkIconView.
5126  * @column: A column in the currently used model, or -1 to display no text
5127  * 
5128  * Sets the column with markup information for @icon_view to be
5129  * @column. The markup column must be of type #G_TYPE_STRING.
5130  * If the markup column is set to something, it overrides
5131  * the text column set by gtk_icon_view_set_text_column().
5132  *
5133  * Since: 2.6
5134  **/
5135 void
5136 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5137                                  gint         column)
5138 {
5139   if (column == icon_view->priv->markup_column)
5140     return;
5141   
5142   if (column == -1)
5143     icon_view->priv->markup_column = -1;
5144   else
5145     {
5146       if (icon_view->priv->model != NULL)
5147         {
5148           GType column_type;
5149           
5150           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5151
5152           g_return_if_fail (column_type == G_TYPE_STRING);
5153         }
5154       
5155       icon_view->priv->markup_column = column;
5156     }
5157
5158   if (icon_view->priv->cell_area)
5159     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5160
5161   update_text_cell (icon_view);
5162
5163   gtk_icon_view_invalidate_sizes (icon_view);
5164   
5165   g_object_notify (G_OBJECT (icon_view), "markup-column");
5166 }
5167
5168 /**
5169  * gtk_icon_view_get_markup_column:
5170  * @icon_view: A #GtkIconView.
5171  *
5172  * Returns the column with markup text for @icon_view.
5173  *
5174  * Returns: the markup column, or -1 if it's unset.
5175  *
5176  * Since: 2.6
5177  */
5178 gint
5179 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
5180 {
5181   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5182
5183   return icon_view->priv->markup_column;
5184 }
5185
5186 /**
5187  * gtk_icon_view_set_pixbuf_column:
5188  * @icon_view: A #GtkIconView.
5189  * @column: A column in the currently used model, or -1 to disable
5190  * 
5191  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5192  * column must be of type #GDK_TYPE_PIXBUF
5193  *
5194  * Since: 2.6 
5195  **/
5196 void
5197 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5198                                  gint         column)
5199 {
5200   if (column == icon_view->priv->pixbuf_column)
5201     return;
5202   
5203   if (column == -1)
5204     icon_view->priv->pixbuf_column = -1;
5205   else
5206     {
5207       if (icon_view->priv->model != NULL)
5208         {
5209           GType column_type;
5210           
5211           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5212
5213           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5214         }
5215       
5216       icon_view->priv->pixbuf_column = column;
5217     }
5218
5219   if (icon_view->priv->cell_area)
5220     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5221
5222   update_pixbuf_cell (icon_view);
5223
5224   gtk_icon_view_invalidate_sizes (icon_view);
5225   
5226   g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5227   
5228 }
5229
5230 /**
5231  * gtk_icon_view_get_pixbuf_column:
5232  * @icon_view: A #GtkIconView.
5233  *
5234  * Returns the column with pixbufs for @icon_view.
5235  *
5236  * Returns: the pixbuf column, or -1 if it's unset.
5237  *
5238  * Since: 2.6
5239  */
5240 gint
5241 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
5242 {
5243   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5244
5245   return icon_view->priv->pixbuf_column;
5246 }
5247
5248 /**
5249  * gtk_icon_view_select_path:
5250  * @icon_view: A #GtkIconView.
5251  * @path: The #GtkTreePath to be selected.
5252  * 
5253  * Selects the row at @path.
5254  *
5255  * Since: 2.6
5256  **/
5257 void
5258 gtk_icon_view_select_path (GtkIconView *icon_view,
5259                            GtkTreePath *path)
5260 {
5261   GtkIconViewItem *item = NULL;
5262
5263   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5264   g_return_if_fail (icon_view->priv->model != NULL);
5265   g_return_if_fail (path != NULL);
5266
5267   if (gtk_tree_path_get_depth (path) > 0)
5268     item = g_list_nth_data (icon_view->priv->items,
5269                             gtk_tree_path_get_indices(path)[0]);
5270
5271   if (item)
5272     gtk_icon_view_select_item (icon_view, item);
5273 }
5274
5275 /**
5276  * gtk_icon_view_unselect_path:
5277  * @icon_view: A #GtkIconView.
5278  * @path: The #GtkTreePath to be unselected.
5279  * 
5280  * Unselects the row at @path.
5281  *
5282  * Since: 2.6
5283  **/
5284 void
5285 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5286                              GtkTreePath *path)
5287 {
5288   GtkIconViewItem *item;
5289   
5290   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5291   g_return_if_fail (icon_view->priv->model != NULL);
5292   g_return_if_fail (path != NULL);
5293
5294   item = g_list_nth_data (icon_view->priv->items,
5295                           gtk_tree_path_get_indices(path)[0]);
5296
5297   if (!item)
5298     return;
5299   
5300   gtk_icon_view_unselect_item (icon_view, item);
5301 }
5302
5303 /**
5304  * gtk_icon_view_get_selected_items:
5305  * @icon_view: A #GtkIconView.
5306  *
5307  * Creates a list of paths of all selected items. Additionally, if you are
5308  * planning on modifying the model after calling this function, you may
5309  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5310  * To do this, you can use gtk_tree_row_reference_new().
5311  *
5312  * To free the return value, use:
5313  * |[
5314  * g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
5315  * g_list_free (list);
5316  * ]|
5317  *
5318  * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
5319  *
5320  * Since: 2.6
5321  **/
5322 GList *
5323 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5324 {
5325   GList *list;
5326   GList *selected = NULL;
5327   
5328   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5329   
5330   for (list = icon_view->priv->items; list != NULL; list = list->next)
5331     {
5332       GtkIconViewItem *item = list->data;
5333
5334       if (item->selected)
5335         {
5336           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5337
5338           selected = g_list_prepend (selected, path);
5339         }
5340     }
5341
5342   return selected;
5343 }
5344
5345 /**
5346  * gtk_icon_view_select_all:
5347  * @icon_view: A #GtkIconView.
5348  * 
5349  * Selects all the icons. @icon_view must has its selection mode set
5350  * to #GTK_SELECTION_MULTIPLE.
5351  *
5352  * Since: 2.6
5353  **/
5354 void
5355 gtk_icon_view_select_all (GtkIconView *icon_view)
5356 {
5357   GList *items;
5358   gboolean dirty = FALSE;
5359   
5360   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5361
5362   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5363     return;
5364
5365   for (items = icon_view->priv->items; items; items = items->next)
5366     {
5367       GtkIconViewItem *item = items->data;
5368       
5369       if (!item->selected)
5370         {
5371           dirty = TRUE;
5372           item->selected = TRUE;
5373           gtk_icon_view_queue_draw_item (icon_view, item);
5374         }
5375     }
5376
5377   if (dirty)
5378     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5379 }
5380
5381 /**
5382  * gtk_icon_view_unselect_all:
5383  * @icon_view: A #GtkIconView.
5384  * 
5385  * Unselects all the icons.
5386  *
5387  * Since: 2.6
5388  **/
5389 void
5390 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5391 {
5392   gboolean dirty = FALSE;
5393   
5394   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5395
5396   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5397     return;
5398
5399   dirty = gtk_icon_view_unselect_all_internal (icon_view);
5400
5401   if (dirty)
5402     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5403 }
5404
5405 /**
5406  * gtk_icon_view_path_is_selected:
5407  * @icon_view: A #GtkIconView.
5408  * @path: A #GtkTreePath to check selection on.
5409  * 
5410  * Returns %TRUE if the icon pointed to by @path is currently
5411  * selected. If @path does not point to a valid location, %FALSE is returned.
5412  * 
5413  * Return value: %TRUE if @path is selected.
5414  *
5415  * Since: 2.6
5416  **/
5417 gboolean
5418 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5419                                 GtkTreePath *path)
5420 {
5421   GtkIconViewItem *item;
5422   
5423   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5424   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5425   g_return_val_if_fail (path != NULL, FALSE);
5426   
5427   item = g_list_nth_data (icon_view->priv->items,
5428                           gtk_tree_path_get_indices(path)[0]);
5429
5430   if (!item)
5431     return FALSE;
5432   
5433   return item->selected;
5434 }
5435
5436 /**
5437  * gtk_icon_view_get_item_row:
5438  * @icon_view: a #GtkIconView
5439  * @path: the #GtkTreePath of the item
5440  *
5441  * Gets the row in which the item @path is currently
5442  * displayed. Row numbers start at 0.
5443  *
5444  * Returns: The row in which the item is displayed
5445  *
5446  * Since: 2.22
5447  */
5448 gint
5449 gtk_icon_view_get_item_row (GtkIconView *icon_view,
5450                             GtkTreePath *path)
5451 {
5452   GtkIconViewItem *item;
5453
5454   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5455   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5456   g_return_val_if_fail (path != NULL, -1);
5457
5458   item = g_list_nth_data (icon_view->priv->items,
5459                           gtk_tree_path_get_indices(path)[0]);
5460
5461   if (!item)
5462     return -1;
5463
5464   return item->row;
5465 }
5466
5467 /**
5468  * gtk_icon_view_get_item_column:
5469  * @icon_view: a #GtkIconView
5470  * @path: the #GtkTreePath of the item
5471  *
5472  * Gets the column in which the item @path is currently
5473  * displayed. Column numbers start at 0.
5474  *
5475  * Returns: The column in which the item is displayed
5476  *
5477  * Since: 2.22
5478  */
5479 gint
5480 gtk_icon_view_get_item_column (GtkIconView *icon_view,
5481                                GtkTreePath *path)
5482 {
5483   GtkIconViewItem *item;
5484
5485   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5486   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5487   g_return_val_if_fail (path != NULL, -1);
5488
5489   item = g_list_nth_data (icon_view->priv->items,
5490                           gtk_tree_path_get_indices(path)[0]);
5491
5492   if (!item)
5493     return -1;
5494
5495   return item->col;
5496 }
5497
5498 /**
5499  * gtk_icon_view_item_activated:
5500  * @icon_view: A #GtkIconView
5501  * @path: The #GtkTreePath to be activated
5502  * 
5503  * Activates the item determined by @path.
5504  *
5505  * Since: 2.6
5506  **/
5507 void
5508 gtk_icon_view_item_activated (GtkIconView      *icon_view,
5509                               GtkTreePath      *path)
5510 {
5511   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5512   g_return_if_fail (path != NULL);
5513   
5514   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5515 }
5516
5517 /**
5518  * gtk_icon_view_set_item_orientation:
5519  * @icon_view: a #GtkIconView
5520  * @orientation: the relative position of texts and icons 
5521  * 
5522  * Sets the ::item-orientation property which determines whether the labels 
5523  * are drawn beside the icons instead of below.
5524  *
5525  * Since: 2.6
5526  **/
5527 void 
5528 gtk_icon_view_set_item_orientation (GtkIconView    *icon_view,
5529                                     GtkOrientation  orientation)
5530 {
5531   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5532
5533   if (icon_view->priv->item_orientation != orientation)
5534     {
5535       icon_view->priv->item_orientation = orientation;
5536
5537       if (icon_view->priv->cell_area)
5538         {
5539           if (GTK_IS_ORIENTABLE (icon_view->priv->cell_area))
5540             gtk_orientable_set_orientation (GTK_ORIENTABLE (icon_view->priv->cell_area), 
5541                                             icon_view->priv->item_orientation);
5542
5543           gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5544         }
5545
5546       gtk_icon_view_invalidate_sizes (icon_view);
5547
5548       update_text_cell (icon_view);
5549       update_pixbuf_cell (icon_view);
5550       
5551       g_object_notify (G_OBJECT (icon_view), "item-orientation");
5552     }
5553 }
5554
5555 /**
5556  * gtk_icon_view_get_item_orientation:
5557  * @icon_view: a #GtkIconView
5558  * 
5559  * Returns the value of the ::item-orientation property which determines 
5560  * whether the labels are drawn beside the icons instead of below. 
5561  * 
5562  * Return value: the relative position of texts and icons 
5563  *
5564  * Since: 2.6
5565  **/
5566 GtkOrientation
5567 gtk_icon_view_get_item_orientation (GtkIconView *icon_view)
5568 {
5569   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
5570                         GTK_ORIENTATION_VERTICAL);
5571
5572   return icon_view->priv->item_orientation;
5573 }
5574
5575 /**
5576  * gtk_icon_view_set_columns:
5577  * @icon_view: a #GtkIconView
5578  * @columns: the number of columns
5579  * 
5580  * Sets the ::columns property which determines in how
5581  * many columns the icons are arranged. If @columns is
5582  * -1, the number of columns will be chosen automatically 
5583  * to fill the available area. 
5584  *
5585  * Since: 2.6
5586  */
5587 void 
5588 gtk_icon_view_set_columns (GtkIconView *icon_view,
5589                            gint         columns)
5590 {
5591   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5592   
5593   if (icon_view->priv->columns != columns)
5594     {
5595       icon_view->priv->columns = columns;
5596
5597       if (icon_view->priv->cell_area)
5598         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5599
5600       gtk_icon_view_queue_layout (icon_view);
5601       
5602       g_object_notify (G_OBJECT (icon_view), "columns");
5603     }  
5604 }
5605
5606 /**
5607  * gtk_icon_view_get_columns:
5608  * @icon_view: a #GtkIconView
5609  * 
5610  * Returns the value of the ::columns property.
5611  * 
5612  * Return value: the number of columns, or -1
5613  *
5614  * Since: 2.6
5615  */
5616 gint
5617 gtk_icon_view_get_columns (GtkIconView *icon_view)
5618 {
5619   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5620
5621   return icon_view->priv->columns;
5622 }
5623
5624 /**
5625  * gtk_icon_view_set_item_width:
5626  * @icon_view: a #GtkIconView
5627  * @item_width: the width for each item
5628  * 
5629  * Sets the ::item-width property which specifies the width 
5630  * to use for each item. If it is set to -1, the icon view will 
5631  * automatically determine a suitable item size.
5632  *
5633  * Since: 2.6
5634  */
5635 void 
5636 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5637                               gint         item_width)
5638 {
5639   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5640   
5641   if (icon_view->priv->item_width != item_width)
5642     {
5643       icon_view->priv->item_width = item_width;
5644       
5645       if (icon_view->priv->cell_area)
5646         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5647
5648       gtk_icon_view_invalidate_sizes (icon_view);
5649       
5650       update_text_cell (icon_view);
5651
5652       g_object_notify (G_OBJECT (icon_view), "item-width");
5653     }  
5654 }
5655
5656 /**
5657  * gtk_icon_view_get_item_width:
5658  * @icon_view: a #GtkIconView
5659  * 
5660  * Returns the value of the ::item-width property.
5661  * 
5662  * Return value: the width of a single item, or -1
5663  *
5664  * Since: 2.6
5665  */
5666 gint
5667 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5668 {
5669   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5670
5671   return icon_view->priv->item_width;
5672 }
5673
5674
5675 /**
5676  * gtk_icon_view_set_spacing:
5677  * @icon_view: a #GtkIconView
5678  * @spacing: the spacing
5679  * 
5680  * Sets the ::spacing property which specifies the space 
5681  * which is inserted between the cells (i.e. the icon and 
5682  * the text) of an item.
5683  *
5684  * Since: 2.6
5685  */
5686 void 
5687 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5688                            gint         spacing)
5689 {
5690   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5691   
5692   if (icon_view->priv->spacing != spacing)
5693     {
5694       icon_view->priv->spacing = spacing;
5695
5696       if (icon_view->priv->cell_area)
5697         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5698
5699       gtk_icon_view_invalidate_sizes (icon_view);
5700
5701       g_object_notify (G_OBJECT (icon_view), "spacing");
5702     }  
5703 }
5704
5705 /**
5706  * gtk_icon_view_get_spacing:
5707  * @icon_view: a #GtkIconView
5708  * 
5709  * Returns the value of the ::spacing property.
5710  * 
5711  * Return value: the space between cells 
5712  *
5713  * Since: 2.6
5714  */
5715 gint
5716 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5717 {
5718   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5719
5720   return icon_view->priv->spacing;
5721 }
5722
5723 /**
5724  * gtk_icon_view_set_row_spacing:
5725  * @icon_view: a #GtkIconView
5726  * @row_spacing: the row spacing
5727  * 
5728  * Sets the ::row-spacing property which specifies the space 
5729  * which is inserted between the rows of the icon view.
5730  *
5731  * Since: 2.6
5732  */
5733 void 
5734 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5735                                gint         row_spacing)
5736 {
5737   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5738   
5739   if (icon_view->priv->row_spacing != row_spacing)
5740     {
5741       icon_view->priv->row_spacing = row_spacing;
5742
5743       if (icon_view->priv->cell_area)
5744         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5745
5746       gtk_icon_view_invalidate_sizes (icon_view);
5747
5748       g_object_notify (G_OBJECT (icon_view), "row-spacing");
5749     }  
5750 }
5751
5752 /**
5753  * gtk_icon_view_get_row_spacing:
5754  * @icon_view: a #GtkIconView
5755  * 
5756  * Returns the value of the ::row-spacing property.
5757  * 
5758  * Return value: the space between rows
5759  *
5760  * Since: 2.6
5761  */
5762 gint
5763 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5764 {
5765   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5766
5767   return icon_view->priv->row_spacing;
5768 }
5769
5770 /**
5771  * gtk_icon_view_set_column_spacing:
5772  * @icon_view: a #GtkIconView
5773  * @column_spacing: the column spacing
5774  * 
5775  * Sets the ::column-spacing property which specifies the space 
5776  * which is inserted between the columns of the icon view.
5777  *
5778  * Since: 2.6
5779  */
5780 void 
5781 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
5782                                   gint         column_spacing)
5783 {
5784   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5785   
5786   if (icon_view->priv->column_spacing != column_spacing)
5787     {
5788       icon_view->priv->column_spacing = column_spacing;
5789
5790       if (icon_view->priv->cell_area)
5791         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5792
5793       gtk_icon_view_invalidate_sizes (icon_view);
5794
5795       g_object_notify (G_OBJECT (icon_view), "column-spacing");
5796     }  
5797 }
5798
5799 /**
5800  * gtk_icon_view_get_column_spacing:
5801  * @icon_view: a #GtkIconView
5802  * 
5803  * Returns the value of the ::column-spacing property.
5804  * 
5805  * Return value: the space between columns
5806  *
5807  * Since: 2.6
5808  */
5809 gint
5810 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
5811 {
5812   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5813
5814   return icon_view->priv->column_spacing;
5815 }
5816
5817 /**
5818  * gtk_icon_view_set_margin:
5819  * @icon_view: a #GtkIconView
5820  * @margin: the margin
5821  * 
5822  * Sets the ::margin property which specifies the space 
5823  * which is inserted at the top, bottom, left and right 
5824  * of the icon view.
5825  *
5826  * Since: 2.6
5827  */
5828 void 
5829 gtk_icon_view_set_margin (GtkIconView *icon_view,
5830                           gint         margin)
5831 {
5832   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5833   
5834   if (icon_view->priv->margin != margin)
5835     {
5836       icon_view->priv->margin = margin;
5837
5838       if (icon_view->priv->cell_area)
5839         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5840
5841       gtk_icon_view_invalidate_sizes (icon_view);
5842
5843       g_object_notify (G_OBJECT (icon_view), "margin");
5844     }  
5845 }
5846
5847 /**
5848  * gtk_icon_view_get_margin:
5849  * @icon_view: a #GtkIconView
5850  * 
5851  * Returns the value of the ::margin property.
5852  * 
5853  * Return value: the space at the borders 
5854  *
5855  * Since: 2.6
5856  */
5857 gint
5858 gtk_icon_view_get_margin (GtkIconView *icon_view)
5859 {
5860   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5861
5862   return icon_view->priv->margin;
5863 }
5864
5865 /**
5866  * gtk_icon_view_set_item_padding:
5867  * @icon_view: a #GtkIconView
5868  * @item_padding: the item padding
5869  *
5870  * Sets the #GtkIconView:item-padding property which specifies the padding
5871  * around each of the icon view's items.
5872  *
5873  * Since: 2.18
5874  */
5875 void
5876 gtk_icon_view_set_item_padding (GtkIconView *icon_view,
5877                                 gint         item_padding)
5878 {
5879   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5880   
5881   if (icon_view->priv->item_padding != item_padding)
5882     {
5883       icon_view->priv->item_padding = item_padding;
5884
5885       if (icon_view->priv->cell_area)
5886         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5887
5888       gtk_icon_view_invalidate_sizes (icon_view);
5889
5890       g_object_notify (G_OBJECT (icon_view), "item-padding");
5891     }  
5892 }
5893
5894 /**
5895  * gtk_icon_view_get_item_padding:
5896  * @icon_view: a #GtkIconView
5897  * 
5898  * Returns the value of the ::item-padding property.
5899  * 
5900  * Return value: the padding around items
5901  *
5902  * Since: 2.18
5903  */
5904 gint
5905 gtk_icon_view_get_item_padding (GtkIconView *icon_view)
5906 {
5907   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5908
5909   return icon_view->priv->item_padding;
5910 }
5911
5912 /* Get/set whether drag_motion requested the drag data and
5913  * drag_data_received should thus not actually insert the data,
5914  * since the data doesn't result from a drop.
5915  */
5916 static void
5917 set_status_pending (GdkDragContext *context,
5918                     GdkDragAction   suggested_action)
5919 {
5920   g_object_set_data (G_OBJECT (context),
5921                      I_("gtk-icon-view-status-pending"),
5922                      GINT_TO_POINTER (suggested_action));
5923 }
5924
5925 static GdkDragAction
5926 get_status_pending (GdkDragContext *context)
5927 {
5928   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5929                                              "gtk-icon-view-status-pending"));
5930 }
5931
5932 static void
5933 unset_reorderable (GtkIconView *icon_view)
5934 {
5935   if (icon_view->priv->reorderable)
5936     {
5937       icon_view->priv->reorderable = FALSE;
5938       g_object_notify (G_OBJECT (icon_view), "reorderable");
5939     }
5940 }
5941
5942 static void
5943 set_source_row (GdkDragContext *context,
5944                 GtkTreeModel   *model,
5945                 GtkTreePath    *source_row)
5946 {
5947   if (source_row)
5948     g_object_set_data_full (G_OBJECT (context),
5949                             I_("gtk-icon-view-source-row"),
5950                             gtk_tree_row_reference_new (model, source_row),
5951                             (GDestroyNotify) gtk_tree_row_reference_free);
5952   else
5953     g_object_set_data_full (G_OBJECT (context),
5954                             I_("gtk-icon-view-source-row"),
5955                             NULL, NULL);
5956 }
5957
5958 static GtkTreePath*
5959 get_source_row (GdkDragContext *context)
5960 {
5961   GtkTreeRowReference *ref;
5962
5963   ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
5964
5965   if (ref)
5966     return gtk_tree_row_reference_get_path (ref);
5967   else
5968     return NULL;
5969 }
5970
5971 typedef struct
5972 {
5973   GtkTreeRowReference *dest_row;
5974   gboolean             empty_view_drop;
5975   gboolean             drop_append_mode;
5976 } DestRow;
5977
5978 static void
5979 dest_row_free (gpointer data)
5980 {
5981   DestRow *dr = (DestRow *)data;
5982
5983   gtk_tree_row_reference_free (dr->dest_row);
5984   g_free (dr);
5985 }
5986
5987 static void
5988 set_dest_row (GdkDragContext *context,
5989               GtkTreeModel   *model,
5990               GtkTreePath    *dest_row,
5991               gboolean        empty_view_drop,
5992               gboolean        drop_append_mode)
5993 {
5994   DestRow *dr;
5995
5996   if (!dest_row)
5997     {
5998       g_object_set_data_full (G_OBJECT (context),
5999                               I_("gtk-icon-view-dest-row"),
6000                               NULL, NULL);
6001       return;
6002     }
6003   
6004   dr = g_new0 (DestRow, 1);
6005      
6006   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6007   dr->empty_view_drop = empty_view_drop;
6008   dr->drop_append_mode = drop_append_mode;
6009   g_object_set_data_full (G_OBJECT (context),
6010                           I_("gtk-icon-view-dest-row"),
6011                           dr, (GDestroyNotify) dest_row_free);
6012 }
6013
6014 static GtkTreePath*
6015 get_dest_row (GdkDragContext *context)
6016 {
6017   DestRow *dr;
6018
6019   dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
6020
6021   if (dr)
6022     {
6023       GtkTreePath *path = NULL;
6024       
6025       if (dr->dest_row)
6026         path = gtk_tree_row_reference_get_path (dr->dest_row);
6027       else if (dr->empty_view_drop)
6028         path = gtk_tree_path_new_from_indices (0, -1);
6029       else
6030         path = NULL;
6031
6032       if (path && dr->drop_append_mode)
6033         gtk_tree_path_next (path);
6034
6035       return path;
6036     }
6037   else
6038     return NULL;
6039 }
6040
6041 static gboolean
6042 check_model_dnd (GtkTreeModel *model,
6043                  GType         required_iface,
6044                  const gchar  *signal)
6045 {
6046   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6047     {
6048       g_warning ("You must override the default '%s' handler "
6049                  "on GtkIconView when using models that don't support "
6050                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6051                  "is to connect to '%s' and call "
6052                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6053                  "the default handler from running. Look at the source code "
6054                  "for the default handler in gtkiconview.c to get an idea what "
6055                  "your handler should do. (gtkiconview.c is in the GTK+ source "
6056                  "code.) If you're using GTK+ from a language other than C, "
6057                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6058                  signal, g_type_name (required_iface), signal);
6059       return FALSE;
6060     }
6061   else
6062     return TRUE;
6063 }
6064
6065 static void
6066 remove_scroll_timeout (GtkIconView *icon_view)
6067 {
6068   if (icon_view->priv->scroll_timeout_id != 0)
6069     {
6070       g_source_remove (icon_view->priv->scroll_timeout_id);
6071
6072       icon_view->priv->scroll_timeout_id = 0;
6073     }
6074 }
6075
6076 static void
6077 gtk_icon_view_autoscroll (GtkIconView *icon_view,
6078                           GdkDevice   *device)
6079 {
6080   GdkWindow *window;
6081   gint px, py, x, y, width, height;
6082   gint hoffset, voffset;
6083
6084   window = gtk_widget_get_window (GTK_WIDGET (icon_view));
6085
6086   gdk_window_get_device_position (window, device, &px, &py, NULL);
6087   gdk_window_get_geometry (window, &x, &y, &width, &height);
6088
6089   /* see if we are near the edge. */
6090   voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
6091   if (voffset > 0)
6092     voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
6093
6094   hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
6095   if (hoffset > 0)
6096     hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
6097
6098   if (voffset != 0)
6099     gtk_adjustment_set_value (icon_view->priv->vadjustment,
6100                               gtk_adjustment_get_value (icon_view->priv->vadjustment) + voffset);
6101
6102   if (hoffset != 0)
6103     gtk_adjustment_set_value (icon_view->priv->hadjustment,
6104                               gtk_adjustment_get_value (icon_view->priv->hadjustment) + hoffset);
6105 }
6106
6107 typedef struct {
6108   GtkIconView *icon_view;
6109   GdkDevice   *device;
6110 } DragScrollData;
6111
6112 static gboolean
6113 drag_scroll_timeout (gpointer datap)
6114 {
6115   DragScrollData *data = datap;
6116
6117   gtk_icon_view_autoscroll (data->icon_view, data->device);
6118
6119   return TRUE;
6120 }
6121
6122
6123 static gboolean
6124 set_destination (GtkIconView    *icon_view,
6125                  GdkDragContext *context,
6126                  gint            x,
6127                  gint            y,
6128                  GdkDragAction  *suggested_action,
6129                  GdkAtom        *target)
6130 {
6131   GtkWidget *widget;
6132   GtkTreePath *path = NULL;
6133   GtkIconViewDropPosition pos;
6134   GtkIconViewDropPosition old_pos;
6135   GtkTreePath *old_dest_path = NULL;
6136   gboolean can_drop = FALSE;
6137
6138   widget = GTK_WIDGET (icon_view);
6139
6140   *suggested_action = 0;
6141   *target = GDK_NONE;
6142
6143   if (!icon_view->priv->dest_set)
6144     {
6145       /* someone unset us as a drag dest, note that if
6146        * we return FALSE drag_leave isn't called
6147        */
6148
6149       gtk_icon_view_set_drag_dest_item (icon_view,
6150                                         NULL,
6151                                         GTK_ICON_VIEW_DROP_LEFT);
6152
6153       remove_scroll_timeout (GTK_ICON_VIEW (widget));
6154
6155       return FALSE; /* no longer a drop site */
6156     }
6157
6158   *target = gtk_drag_dest_find_target (widget, context,
6159                                        gtk_drag_dest_get_target_list (widget));
6160   if (*target == GDK_NONE)
6161     return FALSE;
6162
6163   if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos)) 
6164     {
6165       gint n_children;
6166       GtkTreeModel *model;
6167       
6168       /* the row got dropped on empty space, let's setup a special case
6169        */
6170
6171       if (path)
6172         gtk_tree_path_free (path);
6173
6174       model = gtk_icon_view_get_model (icon_view);
6175
6176       n_children = gtk_tree_model_iter_n_children (model, NULL);
6177       if (n_children)
6178         {
6179           pos = GTK_ICON_VIEW_DROP_BELOW;
6180           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6181         }
6182       else
6183         {
6184           pos = GTK_ICON_VIEW_DROP_ABOVE;
6185           path = gtk_tree_path_new_from_indices (0, -1);
6186         }
6187
6188       can_drop = TRUE;
6189
6190       goto out;
6191     }
6192
6193   g_assert (path);
6194
6195   gtk_icon_view_get_drag_dest_item (icon_view,
6196                                     &old_dest_path,
6197                                     &old_pos);
6198   
6199   if (old_dest_path)
6200     gtk_tree_path_free (old_dest_path);
6201   
6202   if (TRUE /* FIXME if the location droppable predicate */)
6203     {
6204       can_drop = TRUE;
6205     }
6206
6207 out:
6208   if (can_drop)
6209     {
6210       GtkWidget *source_widget;
6211
6212       *suggested_action = gdk_drag_context_get_suggested_action (context);
6213       source_widget = gtk_drag_get_source_widget (context);
6214
6215       if (source_widget == widget)
6216         {
6217           /* Default to MOVE, unless the user has
6218            * pressed ctrl or shift to affect available actions
6219            */
6220           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
6221             *suggested_action = GDK_ACTION_MOVE;
6222         }
6223
6224       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6225                                         path, pos);
6226     }
6227   else
6228     {
6229       /* can't drop here */
6230       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6231                                         NULL,
6232                                         GTK_ICON_VIEW_DROP_LEFT);
6233     }
6234   
6235   if (path)
6236     gtk_tree_path_free (path);
6237   
6238   return TRUE;
6239 }
6240
6241 static GtkTreePath*
6242 get_logical_destination (GtkIconView *icon_view,
6243                          gboolean    *drop_append_mode)
6244 {
6245   /* adjust path to point to the row the drop goes in front of */
6246   GtkTreePath *path = NULL;
6247   GtkIconViewDropPosition pos;
6248   
6249   *drop_append_mode = FALSE;
6250
6251   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6252
6253   if (path == NULL)
6254     return NULL;
6255
6256   if (pos == GTK_ICON_VIEW_DROP_RIGHT || 
6257       pos == GTK_ICON_VIEW_DROP_BELOW)
6258     {
6259       GtkTreeIter iter;
6260       GtkTreeModel *model = icon_view->priv->model;
6261
6262       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6263           !gtk_tree_model_iter_next (model, &iter))
6264         *drop_append_mode = TRUE;
6265       else
6266         {
6267           *drop_append_mode = FALSE;
6268           gtk_tree_path_next (path);
6269         }      
6270     }
6271
6272   return path;
6273 }
6274
6275 static gboolean
6276 gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
6277                                 GdkEventMotion *event)
6278 {
6279   GtkWidget *widget = GTK_WIDGET (icon_view);
6280   GdkDragContext *context;
6281   GtkTreePath *path = NULL;
6282   gint button;
6283   GtkTreeModel *model;
6284   gboolean retval = FALSE;
6285
6286   if (!icon_view->priv->source_set)
6287     goto out;
6288
6289   if (icon_view->priv->pressed_button < 0)
6290     goto out;
6291
6292   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6293                                  icon_view->priv->press_start_x,
6294                                  icon_view->priv->press_start_y,
6295                                  event->x, event->y))
6296     goto out;
6297
6298   model = gtk_icon_view_get_model (icon_view);
6299
6300   if (model == NULL)
6301     goto out;
6302
6303   button = icon_view->priv->pressed_button;
6304   icon_view->priv->pressed_button = -1;
6305
6306   path = gtk_icon_view_get_path_at_pos (icon_view,
6307                                         icon_view->priv->press_start_x,
6308                                         icon_view->priv->press_start_y);
6309
6310   if (path == NULL)
6311     goto out;
6312
6313   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6314       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6315                                            path))
6316     goto out;
6317
6318   /* FIXME Check whether we're a start button, if not return FALSE and
6319    * free path
6320    */
6321
6322   /* Now we can begin the drag */
6323   
6324   retval = TRUE;
6325
6326   context = gtk_drag_begin (widget,
6327                             gtk_drag_source_get_target_list (widget),
6328                             icon_view->priv->source_actions,
6329                             button,
6330                             (GdkEvent*)event);
6331
6332   set_source_row (context, model, path);
6333   
6334  out:
6335   if (path)
6336     gtk_tree_path_free (path);
6337
6338   return retval;
6339 }
6340
6341 /* Source side drag signals */
6342 static void 
6343 gtk_icon_view_drag_begin (GtkWidget      *widget,
6344                           GdkDragContext *context)
6345 {
6346   GtkIconView *icon_view;
6347   GtkIconViewItem *item;
6348   cairo_surface_t *icon;
6349   gint x, y;
6350   GtkTreePath *path;
6351
6352   icon_view = GTK_ICON_VIEW (widget);
6353
6354   /* if the user uses a custom DnD impl, we don't set the icon here */
6355   if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6356     return;
6357
6358   item = gtk_icon_view_get_item_at_coords (icon_view,
6359                                            icon_view->priv->press_start_x,
6360                                            icon_view->priv->press_start_y,
6361                                            TRUE,
6362                                            NULL);
6363
6364   g_return_if_fail (item != NULL);
6365
6366   x = icon_view->priv->press_start_x - item->cell_area.x + 1;
6367   y = icon_view->priv->press_start_y - item->cell_area.y + 1;
6368   
6369   path = gtk_tree_path_new_from_indices (item->index, -1);
6370   icon = gtk_icon_view_create_drag_icon (icon_view, path);
6371   gtk_tree_path_free (path);
6372
6373   cairo_surface_set_device_offset (icon, -x, -y);
6374
6375   gtk_drag_set_icon_surface (context, icon);
6376
6377   cairo_surface_destroy (icon);
6378 }
6379
6380 static void 
6381 gtk_icon_view_drag_end (GtkWidget      *widget,
6382                         GdkDragContext *context)
6383 {
6384   /* do nothing */
6385 }
6386
6387 static void 
6388 gtk_icon_view_drag_data_get (GtkWidget        *widget,
6389                              GdkDragContext   *context,
6390                              GtkSelectionData *selection_data,
6391                              guint             info,
6392                              guint             time)
6393 {
6394   GtkIconView *icon_view;
6395   GtkTreeModel *model;
6396   GtkTreePath *source_row;
6397
6398   icon_view = GTK_ICON_VIEW (widget);
6399   model = gtk_icon_view_get_model (icon_view);
6400
6401   if (model == NULL)
6402     return;
6403
6404   if (!icon_view->priv->source_set)
6405     return;
6406
6407   source_row = get_source_row (context);
6408
6409   if (source_row == NULL)
6410     return;
6411
6412   /* We can implement the GTK_TREE_MODEL_ROW target generically for
6413    * any model; for DragSource models there are some other targets
6414    * we also support.
6415    */
6416
6417   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6418       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6419                                           source_row,
6420                                           selection_data))
6421     goto done;
6422
6423   /* If drag_data_get does nothing, try providing row data. */
6424   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6425     gtk_tree_set_row_drag_data (selection_data,
6426                                 model,
6427                                 source_row);
6428
6429  done:
6430   gtk_tree_path_free (source_row);
6431 }
6432
6433 static void 
6434 gtk_icon_view_drag_data_delete (GtkWidget      *widget,
6435                                 GdkDragContext *context)
6436 {
6437   GtkTreeModel *model;
6438   GtkIconView *icon_view;
6439   GtkTreePath *source_row;
6440
6441   icon_view = GTK_ICON_VIEW (widget);
6442   model = gtk_icon_view_get_model (icon_view);
6443
6444   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag-data-delete"))
6445     return;
6446
6447   if (!icon_view->priv->source_set)
6448     return;
6449
6450   source_row = get_source_row (context);
6451
6452   if (source_row == NULL)
6453     return;
6454
6455   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6456                                          source_row);
6457
6458   gtk_tree_path_free (source_row);
6459
6460   set_source_row (context, NULL, NULL);
6461 }
6462
6463 /* Target side drag signals */
6464 static void
6465 gtk_icon_view_drag_leave (GtkWidget      *widget,
6466                           GdkDragContext *context,
6467                           guint           time)
6468 {
6469   GtkIconView *icon_view;
6470
6471   icon_view = GTK_ICON_VIEW (widget);
6472
6473   /* unset any highlight row */
6474   gtk_icon_view_set_drag_dest_item (icon_view,
6475                                     NULL,
6476                                     GTK_ICON_VIEW_DROP_LEFT);
6477
6478   remove_scroll_timeout (icon_view);
6479 }
6480
6481 static gboolean 
6482 gtk_icon_view_drag_motion (GtkWidget      *widget,
6483                            GdkDragContext *context,
6484                            gint            x,
6485                            gint            y,
6486                            guint           time)
6487 {
6488   GtkTreePath *path = NULL;
6489   GtkIconViewDropPosition pos;
6490   GtkIconView *icon_view;
6491   GdkDragAction suggested_action = 0;
6492   GdkAtom target;
6493   gboolean empty;
6494
6495   icon_view = GTK_ICON_VIEW (widget);
6496
6497   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6498     return FALSE;
6499
6500   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6501
6502   /* we only know this *after* set_desination_row */
6503   empty = icon_view->priv->empty_view_drop;
6504
6505   if (path == NULL && !empty)
6506     {
6507       /* Can't drop here. */
6508       gdk_drag_status (context, 0, time);
6509     }
6510   else
6511     {
6512       if (icon_view->priv->scroll_timeout_id == 0)
6513         {
6514           DragScrollData *data = g_slice_new (DragScrollData);
6515           data->icon_view = icon_view;
6516           data->device = gdk_drag_context_get_device (context);
6517
6518           icon_view->priv->scroll_timeout_id =
6519             gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT, 50, drag_scroll_timeout, data, g_free);
6520         }
6521
6522       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6523         {
6524           /* Request data so we can use the source row when
6525            * determining whether to accept the drop
6526            */
6527           set_status_pending (context, suggested_action);
6528           gtk_drag_get_data (widget, context, target, time);
6529         }
6530       else
6531         {
6532           set_status_pending (context, 0);
6533           gdk_drag_status (context, suggested_action, time);
6534         }
6535     }
6536
6537   if (path)
6538     gtk_tree_path_free (path);
6539
6540   return TRUE;
6541 }
6542
6543 static gboolean 
6544 gtk_icon_view_drag_drop (GtkWidget      *widget,
6545                          GdkDragContext *context,
6546                          gint            x,
6547                          gint            y,
6548                          guint           time)
6549 {
6550   GtkIconView *icon_view;
6551   GtkTreePath *path;
6552   GdkDragAction suggested_action = 0;
6553   GdkAtom target = GDK_NONE;
6554   GtkTreeModel *model;
6555   gboolean drop_append_mode;
6556
6557   icon_view = GTK_ICON_VIEW (widget);
6558   model = gtk_icon_view_get_model (icon_view);
6559
6560   remove_scroll_timeout (GTK_ICON_VIEW (widget));
6561
6562   if (!icon_view->priv->dest_set)
6563     return FALSE;
6564
6565   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
6566     return FALSE;
6567
6568   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6569     return FALSE;
6570   
6571   path = get_logical_destination (icon_view, &drop_append_mode);
6572
6573   if (target != GDK_NONE && path != NULL)
6574     {
6575       /* in case a motion had requested drag data, change things so we
6576        * treat drag data receives as a drop.
6577        */
6578       set_status_pending (context, 0);
6579       set_dest_row (context, model, path, 
6580                     icon_view->priv->empty_view_drop, drop_append_mode);
6581     }
6582
6583   if (path)
6584     gtk_tree_path_free (path);
6585
6586   /* Unset this thing */
6587   gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6588
6589   if (target != GDK_NONE)
6590     {
6591       gtk_drag_get_data (widget, context, target, time);
6592       return TRUE;
6593     }
6594   else
6595     return FALSE;
6596 }
6597
6598 static void
6599 gtk_icon_view_drag_data_received (GtkWidget        *widget,
6600                                   GdkDragContext   *context,
6601                                   gint              x,
6602                                   gint              y,
6603                                   GtkSelectionData *selection_data,
6604                                   guint             info,
6605                                   guint             time)
6606 {
6607   GtkTreePath *path;
6608   gboolean accepted = FALSE;
6609   GtkTreeModel *model;
6610   GtkIconView *icon_view;
6611   GtkTreePath *dest_row;
6612   GdkDragAction suggested_action;
6613   gboolean drop_append_mode;
6614   
6615   icon_view = GTK_ICON_VIEW (widget);  
6616   model = gtk_icon_view_get_model (icon_view);
6617
6618   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
6619     return;
6620
6621   if (!icon_view->priv->dest_set)
6622     return;
6623
6624   suggested_action = get_status_pending (context);
6625
6626   if (suggested_action)
6627     {
6628       /* We are getting this data due to a request in drag_motion,
6629        * rather than due to a request in drag_drop, so we are just
6630        * supposed to call drag_status, not actually paste in the
6631        * data.
6632        */
6633       path = get_logical_destination (icon_view, &drop_append_mode);
6634
6635       if (path == NULL)
6636         suggested_action = 0;
6637
6638       if (suggested_action)
6639         {
6640           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6641                                                      path,
6642                                                      selection_data))
6643             suggested_action = 0;
6644         }
6645
6646       gdk_drag_status (context, suggested_action, time);
6647
6648       if (path)
6649         gtk_tree_path_free (path);
6650
6651       /* If you can't drop, remove user drop indicator until the next motion */
6652       if (suggested_action == 0)
6653         gtk_icon_view_set_drag_dest_item (icon_view,
6654                                           NULL,
6655                                           GTK_ICON_VIEW_DROP_LEFT);
6656       return;
6657     }
6658   
6659
6660   dest_row = get_dest_row (context);
6661
6662   if (dest_row == NULL)
6663     return;
6664
6665   if (gtk_selection_data_get_length (selection_data) >= 0)
6666     {
6667       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6668                                                  dest_row,
6669                                                  selection_data))
6670         accepted = TRUE;
6671     }
6672
6673   gtk_drag_finish (context,
6674                    accepted,
6675                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
6676                    time);
6677
6678   gtk_tree_path_free (dest_row);
6679
6680   /* drop dest_row */
6681   set_dest_row (context, NULL, NULL, FALSE, FALSE);
6682 }
6683
6684 /* Drag-and-Drop support */
6685 /**
6686  * gtk_icon_view_enable_model_drag_source:
6687  * @icon_view: a #GtkIconTreeView
6688  * @start_button_mask: Mask of allowed buttons to start drag
6689  * @targets: (array length=n_targets): the table of targets that the drag will
6690  *           support
6691  * @n_targets: the number of items in @targets
6692  * @actions: the bitmask of possible actions for a drag from this
6693  *    widget
6694  *
6695  * Turns @icon_view into a drag source for automatic DND. Calling this
6696  * method sets #GtkIconView:reorderable to %FALSE.
6697  *
6698  * Since: 2.8
6699  **/
6700 void
6701 gtk_icon_view_enable_model_drag_source (GtkIconView              *icon_view,
6702                                         GdkModifierType           start_button_mask,
6703                                         const GtkTargetEntry     *targets,
6704                                         gint                      n_targets,
6705                                         GdkDragAction             actions)
6706 {
6707   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6708
6709   gtk_drag_source_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6710
6711   icon_view->priv->start_button_mask = start_button_mask;
6712   icon_view->priv->source_actions = actions;
6713
6714   icon_view->priv->source_set = TRUE;
6715
6716   unset_reorderable (icon_view);
6717 }
6718
6719 /**
6720  * gtk_icon_view_enable_model_drag_dest:
6721  * @icon_view: a #GtkIconView
6722  * @targets: (array length=n_targets): the table of targets that the drag will
6723  *           support
6724  * @n_targets: the number of items in @targets
6725  * @actions: the bitmask of possible actions for a drag to this
6726  *    widget
6727  *
6728  * Turns @icon_view into a drop destination for automatic DND. Calling this
6729  * method sets #GtkIconView:reorderable to %FALSE.
6730  *
6731  * Since: 2.8
6732  **/
6733 void 
6734 gtk_icon_view_enable_model_drag_dest (GtkIconView          *icon_view,
6735                                       const GtkTargetEntry *targets,
6736                                       gint                  n_targets,
6737                                       GdkDragAction         actions)
6738 {
6739   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6740
6741   gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6742
6743   icon_view->priv->dest_actions = actions;
6744
6745   icon_view->priv->dest_set = TRUE;
6746
6747   unset_reorderable (icon_view);  
6748 }
6749
6750 /**
6751  * gtk_icon_view_unset_model_drag_source:
6752  * @icon_view: a #GtkIconView
6753  * 
6754  * Undoes the effect of gtk_icon_view_enable_model_drag_source(). Calling this
6755  * method sets #GtkIconView:reorderable to %FALSE.
6756  *
6757  * Since: 2.8
6758  **/
6759 void
6760 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6761 {
6762   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6763
6764   if (icon_view->priv->source_set)
6765     {
6766       gtk_drag_source_unset (GTK_WIDGET (icon_view));
6767       icon_view->priv->source_set = FALSE;
6768     }
6769
6770   unset_reorderable (icon_view);
6771 }
6772
6773 /**
6774  * gtk_icon_view_unset_model_drag_dest:
6775  * @icon_view: a #GtkIconView
6776  * 
6777  * Undoes the effect of gtk_icon_view_enable_model_drag_dest(). Calling this
6778  * method sets #GtkIconView:reorderable to %FALSE.
6779  *
6780  * Since: 2.8
6781  **/
6782 void
6783 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6784 {
6785   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6786
6787   if (icon_view->priv->dest_set)
6788     {
6789       gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6790       icon_view->priv->dest_set = FALSE;
6791     }
6792
6793   unset_reorderable (icon_view);
6794 }
6795
6796 /* These are useful to implement your own custom stuff. */
6797 /**
6798  * gtk_icon_view_set_drag_dest_item:
6799  * @icon_view: a #GtkIconView
6800  * @path: (allow-none): The path of the item to highlight, or %NULL.
6801  * @pos: Specifies where to drop, relative to the item
6802  *
6803  * Sets the item that is highlighted for feedback.
6804  *
6805  * Since: 2.8
6806  */
6807 void
6808 gtk_icon_view_set_drag_dest_item (GtkIconView              *icon_view,
6809                                   GtkTreePath              *path,
6810                                   GtkIconViewDropPosition   pos)
6811 {
6812   /* Note; this function is exported to allow a custom DND
6813    * implementation, so it can't touch TreeViewDragInfo
6814    */
6815
6816   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6817
6818   if (icon_view->priv->dest_item)
6819     {
6820       GtkTreePath *current_path;
6821       current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6822       gtk_tree_row_reference_free (icon_view->priv->dest_item);
6823       icon_view->priv->dest_item = NULL;      
6824
6825       gtk_icon_view_queue_draw_path (icon_view, current_path);
6826       gtk_tree_path_free (current_path);
6827     }
6828   
6829   /* special case a drop on an empty model */
6830   icon_view->priv->empty_view_drop = FALSE;
6831   if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
6832       && gtk_tree_path_get_depth (path) == 1
6833       && gtk_tree_path_get_indices (path)[0] == 0)
6834     {
6835       gint n_children;
6836
6837       n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
6838                                                    NULL);
6839
6840       if (n_children == 0)
6841         icon_view->priv->empty_view_drop = TRUE;
6842     }
6843
6844   icon_view->priv->dest_pos = pos;
6845
6846   if (path)
6847     {
6848       icon_view->priv->dest_item =
6849         gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), 
6850                                           icon_view->priv->model, path);
6851       
6852       gtk_icon_view_queue_draw_path (icon_view, path);
6853     }
6854 }
6855
6856 /**
6857  * gtk_icon_view_get_drag_dest_item:
6858  * @icon_view: a #GtkIconView
6859  * @path: (out) (allow-none): Return location for the path of
6860  *        the highlighted item, or %NULL.
6861  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6862  * 
6863  * Gets information about the item that is highlighted for feedback.
6864  *
6865  * Since: 2.8
6866  **/
6867 void
6868 gtk_icon_view_get_drag_dest_item (GtkIconView              *icon_view,
6869                                   GtkTreePath             **path,
6870                                   GtkIconViewDropPosition  *pos)
6871 {
6872   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6873
6874   if (path)
6875     {
6876       if (icon_view->priv->dest_item)
6877         *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6878       else
6879         *path = NULL;
6880     }
6881
6882   if (pos)
6883     *pos = icon_view->priv->dest_pos;
6884 }
6885
6886 /**
6887  * gtk_icon_view_get_dest_item_at_pos:
6888  * @icon_view: a #GtkIconView
6889  * @drag_x: the position to determine the destination item for
6890  * @drag_y: the position to determine the destination item for
6891  * @path: (out) (allow-none): Return location for the path of the item,
6892  *    or %NULL.
6893  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6894  * 
6895  * Determines the destination item for a given position.
6896  * 
6897  * Return value: whether there is an item at the given position.
6898  *
6899  * Since: 2.8
6900  **/
6901 gboolean
6902 gtk_icon_view_get_dest_item_at_pos (GtkIconView              *icon_view,
6903                                     gint                      drag_x,
6904                                     gint                      drag_y,
6905                                     GtkTreePath             **path,
6906                                     GtkIconViewDropPosition  *pos)
6907 {
6908   GtkIconViewItem *item;
6909
6910   /* Note; this function is exported to allow a custom DND
6911    * implementation, so it can't touch TreeViewDragInfo
6912    */
6913
6914   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6915   g_return_val_if_fail (drag_x >= 0, FALSE);
6916   g_return_val_if_fail (drag_y >= 0, FALSE);
6917   g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
6918
6919
6920   if (path)
6921     *path = NULL;
6922
6923   item = gtk_icon_view_get_item_at_coords (icon_view, 
6924                                            drag_x + gtk_adjustment_get_value (icon_view->priv->hadjustment), 
6925                                            drag_y + gtk_adjustment_get_value (icon_view->priv->vadjustment),
6926                                            FALSE, NULL);
6927
6928   if (item == NULL)
6929     return FALSE;
6930
6931   if (path)
6932     *path = gtk_tree_path_new_from_indices (item->index, -1);
6933
6934   if (pos)
6935     {
6936       if (drag_x < item->cell_area.x + item->cell_area.width / 4)
6937         *pos = GTK_ICON_VIEW_DROP_LEFT;
6938       else if (drag_x > item->cell_area.x + item->cell_area.width * 3 / 4)
6939         *pos = GTK_ICON_VIEW_DROP_RIGHT;
6940       else if (drag_y < item->cell_area.y + item->cell_area.height / 4)
6941         *pos = GTK_ICON_VIEW_DROP_ABOVE;
6942       else if (drag_y > item->cell_area.y + item->cell_area.height * 3 / 4)
6943         *pos = GTK_ICON_VIEW_DROP_BELOW;
6944       else
6945         *pos = GTK_ICON_VIEW_DROP_INTO;
6946     }
6947
6948   return TRUE;
6949 }
6950
6951 /**
6952  * gtk_icon_view_create_drag_icon:
6953  * @icon_view: a #GtkIconView
6954  * @path: a #GtkTreePath in @icon_view
6955  *
6956  * Creates a #cairo_surface_t representation of the item at @path.  
6957  * This image is used for a drag icon.
6958  *
6959  * Return value: (transfer full): a newly-allocated surface of the drag icon.
6960  * 
6961  * Since: 2.8
6962  **/
6963 cairo_surface_t *
6964 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
6965                                 GtkTreePath *path)
6966 {
6967   GtkWidget *widget;
6968   GtkStyleContext *context;
6969   cairo_t *cr;
6970   cairo_surface_t *surface;
6971   GList *l;
6972   gint index;
6973
6974   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
6975   g_return_val_if_fail (path != NULL, NULL);
6976
6977   widget = GTK_WIDGET (icon_view);
6978   context = gtk_widget_get_style_context (widget);
6979
6980   if (!gtk_widget_get_realized (widget))
6981     return NULL;
6982
6983   index = gtk_tree_path_get_indices (path)[0];
6984
6985   for (l = icon_view->priv->items; l; l = l->next) 
6986     {
6987       GtkIconViewItem *item = l->data;
6988       
6989       if (index == item->index)
6990         {
6991           GdkRectangle rect = { 
6992             item->cell_area.x - icon_view->priv->item_padding, 
6993             item->cell_area.y - icon_view->priv->item_padding, 
6994             item->cell_area.width  + icon_view->priv->item_padding * 2, 
6995             item->cell_area.height + icon_view->priv->item_padding * 2 
6996           };
6997
6998           surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
6999                                                        CAIRO_CONTENT_COLOR,
7000                                                        rect.width + 2,
7001                                                        rect.height + 2);
7002
7003           cr = cairo_create (surface);
7004           cairo_set_line_width (cr, 1.);
7005
7006           gtk_render_background (context, cr, 0, 0,
7007                                  rect.width + 2, rect.height + 2);
7008
7009           cairo_save (cr);
7010
7011           cairo_rectangle (cr, 1, 1, rect.width, rect.height);
7012           cairo_clip (cr);
7013
7014           gtk_icon_view_paint_item (icon_view, cr, item, 
7015                                     icon_view->priv->item_padding + 1, 
7016                                     icon_view->priv->item_padding + 1, FALSE);
7017
7018           cairo_restore (cr);
7019
7020           cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
7021           cairo_rectangle (cr, 0.5, 0.5, rect.width + 1, rect.height + 1);
7022           cairo_stroke (cr);
7023
7024           cairo_destroy (cr);
7025
7026           return surface;
7027         }
7028     }
7029   
7030   return NULL;
7031 }
7032
7033 /**
7034  * gtk_icon_view_get_reorderable:
7035  * @icon_view: a #GtkIconView
7036  *
7037  * Retrieves whether the user can reorder the list via drag-and-drop. 
7038  * See gtk_icon_view_set_reorderable().
7039  *
7040  * Return value: %TRUE if the list can be reordered.
7041  *
7042  * Since: 2.8
7043  **/
7044 gboolean
7045 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
7046 {
7047   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
7048
7049   return icon_view->priv->reorderable;
7050 }
7051
7052 static const GtkTargetEntry item_targets[] = {
7053   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7054 };
7055
7056
7057 /**
7058  * gtk_icon_view_set_reorderable:
7059  * @icon_view: A #GtkIconView.
7060  * @reorderable: %TRUE, if the list of items can be reordered.
7061  *
7062  * This function is a convenience function to allow you to reorder models that
7063  * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface.  Both
7064  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
7065  * the user can reorder the model by dragging and dropping rows.  The
7066  * developer can listen to these changes by connecting to the model's
7067  * row_inserted and row_deleted signals. The reordering is implemented by setting up
7068  * the icon view as a drag source and destination. Therefore, drag and
7069  * drop can not be used in a reorderable view for any other purpose.
7070  *
7071  * This function does not give you any degree of control over the order -- any
7072  * reordering is allowed.  If more control is needed, you should probably
7073  * handle drag and drop manually.
7074  *
7075  * Since: 2.8
7076  **/
7077 void
7078 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
7079                                gboolean     reorderable)
7080 {
7081   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7082
7083   reorderable = reorderable != FALSE;
7084
7085   if (icon_view->priv->reorderable == reorderable)
7086     return;
7087
7088   if (reorderable)
7089     {
7090       gtk_icon_view_enable_model_drag_source (icon_view,
7091                                               GDK_BUTTON1_MASK,
7092                                               item_targets,
7093                                               G_N_ELEMENTS (item_targets),
7094                                               GDK_ACTION_MOVE);
7095       gtk_icon_view_enable_model_drag_dest (icon_view,
7096                                             item_targets,
7097                                             G_N_ELEMENTS (item_targets),
7098                                             GDK_ACTION_MOVE);
7099     }
7100   else
7101     {
7102       gtk_icon_view_unset_model_drag_source (icon_view);
7103       gtk_icon_view_unset_model_drag_dest (icon_view);
7104     }
7105
7106   icon_view->priv->reorderable = reorderable;
7107
7108   g_object_notify (G_OBJECT (icon_view), "reorderable");
7109 }
7110
7111 static gboolean
7112 gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
7113                                           GtkBuilder    *builder,
7114                                           GObject       *child,
7115                                           const gchar   *tagname,
7116                                           GMarkupParser *parser,
7117                                           gpointer      *data)
7118 {
7119   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
7120                                                 tagname, parser, data))
7121     return TRUE;
7122
7123   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
7124                                                       tagname, parser, data);
7125 }
7126
7127 static void
7128 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
7129                                         GtkBuilder   *builder,
7130                                         GObject      *child,
7131                                         const gchar  *tagname,
7132                                         gpointer     *data)
7133 {
7134   if (!_gtk_cell_layout_buildable_custom_tag_end (buildable, builder,
7135                                                   child, tagname, data))
7136     parent_buildable_iface->custom_tag_end (buildable, builder,
7137                                             child, tagname, data);
7138 }
7139
7140 /* Accessibility Support */
7141
7142 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (_gtk_icon_view_item_accessible_get_type ())
7143 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
7144 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
7145
7146 typedef struct
7147 {
7148   AtkObject parent;
7149
7150   GtkIconViewItem *item;
7151   GtkWidget *widget;
7152   AtkStateSet *state_set;
7153   gchar *text;
7154   gchar *action_description;
7155   gchar *image_description;
7156   guint action_idle_handler;
7157 } GtkIconViewItemAccessible;
7158
7159 typedef struct
7160 {
7161   AtkObjectClass parent_class;
7162
7163 } GtkIconViewItemAccessibleClass;
7164
7165 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
7166
7167 static void atk_component_item_interface_init (AtkComponentIface *iface);
7168 static void atk_action_item_interface_init    (AtkActionIface    *iface);
7169 static void atk_text_item_interface_init      (AtkTextIface      *iface);
7170 static void atk_image_item_interface_init     (AtkImageIface     *iface);
7171
7172 G_DEFINE_TYPE_WITH_CODE (GtkIconViewItemAccessible, _gtk_icon_view_item_accessible, ATK_TYPE_OBJECT,
7173                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_item_interface_init)
7174                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_item_interface_init)
7175                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_item_interface_init)
7176                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE, atk_image_item_interface_init))
7177
7178
7179 static gboolean
7180 idle_do_action (gpointer data)
7181 {
7182   GtkIconViewItemAccessible *item;
7183   GtkIconView *icon_view;
7184   GtkTreePath *path;
7185
7186   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
7187   item->action_idle_handler = 0;
7188
7189   if (item->widget != NULL)
7190     {
7191       icon_view = GTK_ICON_VIEW (item->widget);
7192       path = gtk_tree_path_new_from_indices (item->item->index, -1);
7193       gtk_icon_view_item_activated (icon_view, path);
7194       gtk_tree_path_free (path);
7195     }
7196
7197   return FALSE;
7198 }
7199
7200 static gboolean
7201 gtk_icon_view_item_accessible_do_action (AtkAction *action,
7202                                          gint       i)
7203 {
7204   GtkIconViewItemAccessible *item;
7205
7206   if (i != 0)
7207     return FALSE;
7208
7209   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7210
7211   if (!GTK_IS_ICON_VIEW (item->widget))
7212     return FALSE;
7213
7214   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7215     return FALSE;
7216
7217   if (!item->action_idle_handler)
7218     item->action_idle_handler = gdk_threads_add_idle (idle_do_action, item);
7219
7220   return TRUE;
7221 }
7222
7223 static gint
7224 gtk_icon_view_item_accessible_get_n_actions (AtkAction *action)
7225 {
7226         return 1;
7227 }
7228
7229 static const gchar *
7230 gtk_icon_view_item_accessible_get_description (AtkAction *action,
7231                                                gint       i)
7232 {
7233   GtkIconViewItemAccessible *item;
7234
7235   if (i != 0)
7236     return NULL;
7237
7238   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7239
7240   if (item->action_description)
7241     return item->action_description;
7242   else
7243     return "Activate item";
7244 }
7245
7246 static const gchar *
7247 gtk_icon_view_item_accessible_get_name (AtkAction *action,
7248                                         gint       i)
7249 {
7250   if (i != 0)
7251     return NULL;
7252
7253   return "activate";
7254 }
7255
7256 static gboolean
7257 gtk_icon_view_item_accessible_set_description (AtkAction   *action,
7258                                                gint         i,
7259                                                const gchar *description)
7260 {
7261   GtkIconViewItemAccessible *item;
7262
7263   if (i != 0)
7264     return FALSE;
7265
7266   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7267
7268   g_free (item->action_description);
7269   item->action_description = g_strdup (description);
7270
7271   return TRUE;
7272 }
7273
7274 static void
7275 atk_action_item_interface_init (AtkActionIface *iface)
7276 {
7277   iface->do_action = gtk_icon_view_item_accessible_do_action;
7278   iface->set_description = gtk_icon_view_item_accessible_set_description;
7279   iface->get_name = gtk_icon_view_item_accessible_get_name;
7280   iface->get_n_actions = gtk_icon_view_item_accessible_get_n_actions;
7281   iface->get_description = gtk_icon_view_item_accessible_get_description;
7282 }
7283
7284 static const gchar *
7285 gtk_icon_view_item_accessible_get_image_description (AtkImage *image)
7286 {
7287   GtkIconViewItemAccessible *item;
7288
7289   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7290
7291   return item->image_description;
7292 }
7293
7294 static gboolean
7295 gtk_icon_view_item_accessible_set_image_description (AtkImage    *image,
7296                                                      const gchar *description)
7297 {
7298   GtkIconViewItemAccessible *item;
7299
7300   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7301
7302   g_free (item->image_description);
7303   item->image_description = g_strdup (description);
7304
7305   return TRUE;
7306 }
7307
7308 typedef struct {
7309   GdkRectangle box;
7310   gboolean     pixbuf_found;
7311 } GetPixbufBoxData;
7312
7313 static gboolean
7314 get_pixbuf_foreach (GtkCellRenderer    *renderer,
7315                     const GdkRectangle *cell_area,
7316                     const GdkRectangle *cell_background,
7317                     GetPixbufBoxData   *data)
7318 {
7319   if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
7320     {
7321       data->box = *cell_area;
7322       data->pixbuf_found = TRUE;
7323     }
7324   return (data->pixbuf_found != FALSE);
7325 }
7326
7327 static gboolean
7328 get_pixbuf_box (GtkIconView     *icon_view,
7329                 GtkIconViewItem *item,
7330                 GdkRectangle    *box)
7331 {
7332   GetPixbufBoxData data = { { 0, }, FALSE };
7333   GtkCellAreaContext *context;
7334
7335   context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
7336
7337   gtk_icon_view_set_cell_data (icon_view, item);
7338   gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
7339                                GTK_WIDGET (icon_view),
7340                                (GdkRectangle *)item, (GdkRectangle *)item,
7341                                (GtkCellAllocCallback)get_pixbuf_foreach, &data);
7342
7343   return data.pixbuf_found;
7344 }
7345
7346 static gboolean
7347 get_text_foreach (GtkCellRenderer  *renderer,
7348                   gchar           **text)
7349 {
7350   if (GTK_IS_CELL_RENDERER_TEXT (renderer))
7351     {
7352       g_object_get (renderer, "text", text, NULL);
7353       return TRUE;
7354     }
7355   return FALSE;
7356 }
7357
7358 static gchar *
7359 get_text (GtkIconView     *icon_view,
7360           GtkIconViewItem *item)
7361 {
7362   gchar *text = NULL;
7363
7364   gtk_icon_view_set_cell_data (icon_view, item);
7365   gtk_cell_area_foreach (icon_view->priv->cell_area,
7366                          (GtkCellCallback)get_text_foreach, &text);
7367
7368   return text;
7369 }
7370
7371 static void
7372 gtk_icon_view_item_accessible_get_image_size (AtkImage *image,
7373                                               gint     *width,
7374                                               gint     *height)
7375 {
7376   GtkIconViewItemAccessible *item;
7377   GdkRectangle box;
7378
7379   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7380
7381   if (!GTK_IS_ICON_VIEW (item->widget))
7382     return;
7383
7384   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7385     return;
7386
7387   *width = 0;
7388   *height = 0;
7389
7390   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7391     {
7392       *width = box.width;
7393       *height = box.height;
7394     }
7395 }
7396
7397 static void
7398 gtk_icon_view_item_accessible_get_image_position (AtkImage    *image,
7399                                                   gint        *x,
7400                                                   gint        *y,
7401                                                   AtkCoordType coord_type)
7402 {
7403   GtkIconViewItemAccessible *item;
7404   GdkRectangle box;
7405
7406   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7407
7408   if (!GTK_IS_ICON_VIEW (item->widget))
7409     return;
7410
7411   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7412     return;
7413
7414   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7415
7416   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7417     {
7418       *x+= box.x - item->item->cell_area.x;
7419       *y+= box.y - item->item->cell_area.y;
7420     }
7421
7422 }
7423
7424 static void
7425 atk_image_item_interface_init (AtkImageIface *iface)
7426 {
7427   iface->get_image_description = gtk_icon_view_item_accessible_get_image_description;
7428   iface->set_image_description = gtk_icon_view_item_accessible_set_image_description;
7429   iface->get_image_size = gtk_icon_view_item_accessible_get_image_size;
7430   iface->get_image_position = gtk_icon_view_item_accessible_get_image_position;
7431 }
7432
7433 static gchar *
7434 gtk_icon_view_item_accessible_get_text (AtkText *text,
7435                                         gint     start_pos,
7436                                         gint     end_pos)
7437 {
7438   GtkIconViewItemAccessible *item;
7439
7440   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7441   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7442     return NULL;
7443
7444   if (item->text)
7445     return g_utf8_substring (item->text, start_pos, end_pos > -1 ? end_pos : g_utf8_strlen (item->text, -1));
7446   else
7447     return g_strdup ("");
7448 }
7449
7450 static gunichar
7451 gtk_icon_view_item_accessible_get_character_at_offset (AtkText *text,
7452                                                        gint     offset)
7453 {
7454   GtkIconViewItemAccessible *item;
7455   gchar *string;
7456   gchar *index;
7457
7458   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7459   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7460     return '\0';
7461
7462   string = item->text;
7463
7464   if (!string)
7465     return '\0';
7466
7467   if (offset >= g_utf8_strlen (string, -1))
7468     return '\0';
7469
7470   index = g_utf8_offset_to_pointer (string, offset);
7471
7472   return g_utf8_get_char (index);
7473 }
7474
7475 static PangoLayout *
7476 create_pango_layout (GtkIconViewItemAccessible *item)
7477 {
7478   PangoLayout *layout;
7479
7480   layout = gtk_widget_create_pango_layout (item->widget, item->text);
7481
7482   return layout;
7483 }
7484
7485 static gchar *
7486 gtk_icon_view_item_accessible_get_text_before_offset (AtkText         *atk_text,
7487                                                       gint             offset,
7488                                                       AtkTextBoundary  boundary_type,
7489                                                       gint            *start_offset,
7490                                                       gint            *end_offset)
7491 {
7492   GtkIconViewItemAccessible *item;
7493   PangoLayout *layout;
7494   gchar *text;
7495
7496   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (atk_text);
7497   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7498     return NULL;
7499
7500   layout = create_pango_layout (item);
7501   text = _gtk_pango_get_text_before (layout, boundary_type, offset, start_offset, end_offset);
7502   g_object_unref (layout);
7503
7504   return text;
7505 }
7506
7507 static gchar *
7508 gtk_icon_view_item_accessible_get_text_at_offset (AtkText         *atk_text,
7509                                                   gint             offset,
7510                                                   AtkTextBoundary  boundary_type,
7511                                                   gint            *start_offset,
7512                                                   gint            *end_offset)
7513 {
7514   GtkIconViewItemAccessible *item;
7515   PangoLayout *layout;
7516   gchar *text;
7517
7518   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (atk_text);
7519   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7520     return NULL;
7521
7522   layout = create_pango_layout (item);
7523   text = _gtk_pango_get_text_at (layout, boundary_type, offset, start_offset, end_offset);
7524   g_object_unref (layout);
7525
7526   return text;
7527 }
7528
7529 static gchar *
7530 gtk_icon_view_item_accessible_get_text_after_offset (AtkText         *atk_text,
7531                                                      gint             offset,
7532                                                      AtkTextBoundary  boundary_type,
7533                                                      gint            *start_offset,
7534                                                      gint            *end_offset)
7535 {
7536   GtkIconViewItemAccessible *item;
7537   PangoLayout *layout;
7538   gchar *text;
7539
7540   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (atk_text);
7541   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7542     return NULL;
7543
7544   layout = create_pango_layout (item);
7545   text = _gtk_pango_get_text_after (layout, boundary_type, offset, start_offset, end_offset);
7546   g_object_unref (layout);
7547
7548   return text;
7549 }
7550
7551 static gint
7552 gtk_icon_view_item_accessible_get_character_count (AtkText *text)
7553 {
7554   GtkIconViewItemAccessible *item;
7555
7556   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7557   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7558     return 0;
7559
7560   if (item->text)
7561     return g_utf8_strlen (item->text, -1);
7562   else
7563     return 0;
7564 }
7565
7566 static void
7567 gtk_icon_view_item_accessible_get_character_extents (AtkText      *text,
7568                                                      gint         offset,
7569                                                      gint         *x,
7570                                                      gint         *y,
7571                                                      gint         *width,
7572                                                      gint         *height,
7573                                                      AtkCoordType coord_type)
7574 {
7575   GtkIconViewItemAccessible *item;
7576 #if 0
7577   GtkIconView *icon_view;
7578   PangoRectangle char_rect;
7579   const gchar *item_text;
7580   gint index;
7581 #endif
7582
7583   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7584
7585   if (!GTK_IS_ICON_VIEW (item->widget))
7586     return;
7587
7588   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7589     return;
7590
7591 #if 0
7592   icon_view = GTK_ICON_VIEW (item->widget);
7593       /* FIXME we probably have to use GailTextCell to salvage this */
7594   gtk_icon_view_update_item_text (icon_view, item->item);
7595   item_text = pango_layout_get_text (icon_view->priv->layout);
7596   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
7597   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
7598
7599   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
7600   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
7601   /* Look at gtk_icon_view_paint_item() to see where the text is. */
7602   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7603   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
7604   *width = char_rect.width / PANGO_SCALE;
7605   *height = char_rect.height / PANGO_SCALE;
7606 #endif
7607 }
7608
7609 static gint
7610 gtk_icon_view_item_accessible_get_offset_at_point (AtkText      *text,
7611                                                    gint          x,
7612                                                    gint          y,
7613                                                    AtkCoordType coord_type)
7614 {
7615   GtkIconViewItemAccessible *item;
7616   gint offset = 0;
7617 #if 0
7618   GtkIconView *icon_view;
7619   const gchar *item_text;
7620   gint index;
7621   gint l_x, l_y;
7622 #endif
7623
7624   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7625
7626   if (!GTK_IS_ICON_VIEW (item->widget))
7627     return -1;
7628
7629   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7630     return -1;
7631
7632 #if 0
7633   icon_view = GTK_ICON_VIEW (item->widget);
7634       /* FIXME we probably have to use GailTextCell to salvage this */
7635   gtk_icon_view_update_item_text (icon_view, item->item);
7636   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
7637   x -= l_x + item->item->layout_x - item->item->x;
7638   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7639   y -= l_y + item->item->layout_y - item->item->y;
7640   item_text = pango_layout_get_text (icon_view->priv->layout);
7641   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
7642                                 x * PANGO_SCALE,
7643                                 y * PANGO_SCALE,
7644                                 &index, NULL))
7645     {
7646       if (x < 0 || y < 0)
7647         index = 0;
7648       else
7649         index = -1;
7650     } 
7651   if (index == -1)
7652     offset = g_utf8_strlen (item_text, -1);
7653   else
7654     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
7655 #endif
7656   return offset;
7657 }
7658
7659 static void
7660 atk_text_item_interface_init (AtkTextIface *iface)
7661 {
7662   iface->get_text = gtk_icon_view_item_accessible_get_text;
7663   iface->get_character_at_offset = gtk_icon_view_item_accessible_get_character_at_offset;
7664   iface->get_text_before_offset = gtk_icon_view_item_accessible_get_text_before_offset;
7665   iface->get_text_at_offset = gtk_icon_view_item_accessible_get_text_at_offset;
7666   iface->get_text_after_offset = gtk_icon_view_item_accessible_get_text_after_offset;
7667   iface->get_character_count = gtk_icon_view_item_accessible_get_character_count;
7668   iface->get_character_extents = gtk_icon_view_item_accessible_get_character_extents;
7669   iface->get_offset_at_point = gtk_icon_view_item_accessible_get_offset_at_point;
7670 }
7671
7672 static void
7673 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
7674                                            gint         *x,
7675                                            gint         *y,
7676                                            gint         *width,
7677                                            gint         *height,
7678                                            AtkCoordType  coord_type)
7679 {
7680   GtkIconViewItemAccessible *item;
7681   AtkObject *parent_obj;
7682   gint l_x, l_y;
7683
7684   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
7685
7686   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
7687   if (!GTK_IS_WIDGET (item->widget))
7688     return;
7689
7690   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7691     return;
7692
7693   *width = item->item->cell_area.width;
7694   *height = item->item->cell_area.height;
7695   if (gtk_icon_view_item_accessible_is_showing (item))
7696     {
7697       parent_obj = gtk_widget_get_accessible (item->widget);
7698       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
7699       *x = l_x + item->item->cell_area.x;
7700       *y = l_y + item->item->cell_area.y;
7701     }
7702   else
7703     {
7704       *x = G_MININT;
7705       *y = G_MININT;
7706     }
7707 }
7708
7709 static gboolean
7710 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
7711 {
7712   GtkIconViewItemAccessible *item;
7713   GtkWidget *toplevel;
7714
7715   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
7716
7717   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
7718   if (!GTK_IS_WIDGET (item->widget))
7719     return FALSE;
7720
7721   gtk_widget_grab_focus (item->widget);
7722   gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
7723   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
7724   if (gtk_widget_is_toplevel (toplevel))
7725     gtk_window_present (GTK_WINDOW (toplevel));
7726
7727   return TRUE;
7728 }
7729
7730 static void
7731 atk_component_item_interface_init (AtkComponentIface *iface)
7732 {
7733   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
7734   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
7735 }
7736
7737 static gboolean
7738 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
7739                                          AtkStateType               state_type,
7740                                          gboolean                   emit_signal)
7741 {
7742   gboolean rc;
7743
7744   rc = atk_state_set_add_state (item->state_set, state_type);
7745
7746   /* The signal should only be generated if the value changed,
7747    * not when the item is set up. So states that are set
7748    * initially should pass FALSE as the emit_signal argument.
7749    */
7750   if (emit_signal)
7751     {
7752       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
7753       /* If state_type is ATK_STATE_VISIBLE, additional notification */
7754       if (state_type == ATK_STATE_VISIBLE)
7755         g_signal_emit_by_name (item, "visible-data-changed");
7756     }
7757
7758   return rc;
7759 }
7760
7761 static gboolean
7762 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
7763                                             AtkStateType               state_type,
7764                                             gboolean                   emit_signal)
7765 {
7766   if (atk_state_set_contains_state (item->state_set, state_type))
7767     {
7768       gboolean rc;
7769
7770       rc = atk_state_set_remove_state (item->state_set, state_type);
7771
7772       /* The signal should only be generated if the value changed,
7773        * not when the item is set up. So states that are set
7774        * initially should pass FALSE as the emit_signal argument.
7775        */
7776       if (emit_signal)
7777         {
7778           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
7779           /* If state_type is ATK_STATE_VISIBLE, additional notification */
7780           if (state_type == ATK_STATE_VISIBLE)
7781             g_signal_emit_by_name (item, "visible-data-changed");
7782         }
7783
7784       return rc;
7785     }
7786   else
7787     return FALSE;
7788 }
7789
7790 static gboolean
7791 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
7792 {
7793   GtkAllocation allocation;
7794   GtkIconView *icon_view;
7795   GdkRectangle visible_rect;
7796   gboolean is_showing;
7797
7798   /* An item is considered "SHOWING" if any part of the item
7799    * is in the visible rectangle.
7800    */
7801   if (!GTK_IS_ICON_VIEW (item->widget))
7802     return FALSE;
7803
7804   if (item->item == NULL)
7805     return FALSE;
7806
7807   gtk_widget_get_allocation (item->widget, &allocation);
7808
7809   icon_view = GTK_ICON_VIEW (item->widget);
7810   visible_rect.x = 0;
7811   if (icon_view->priv->hadjustment)
7812     visible_rect.x += gtk_adjustment_get_value (icon_view->priv->hadjustment);
7813   visible_rect.y = 0;
7814   if (icon_view->priv->hadjustment)
7815     visible_rect.y += gtk_adjustment_get_value (icon_view->priv->vadjustment);
7816   visible_rect.width = allocation.width;
7817   visible_rect.height = allocation.height;
7818
7819   if (((item->item->cell_area.x + item->item->cell_area.width) < visible_rect.x) ||
7820      ((item->item->cell_area.y + item->item->cell_area.height) < (visible_rect.y)) ||
7821      (item->item->cell_area.x > (visible_rect.x + visible_rect.width)) ||
7822      (item->item->cell_area.y > (visible_rect.y + visible_rect.height)))
7823     is_showing = FALSE;
7824   else
7825     is_showing = TRUE;
7826
7827   return is_showing;
7828 }
7829
7830 static gboolean
7831 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
7832                                               gboolean                   emit_signal)
7833 {
7834   if (gtk_icon_view_item_accessible_is_showing (item))
7835     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
7836                                                     emit_signal);
7837   else
7838     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
7839                                                        emit_signal);
7840 }
7841
7842 static void
7843 _gtk_icon_view_item_accessible_init (GtkIconViewItemAccessible *item)
7844 {
7845   item->state_set = atk_state_set_new ();
7846
7847   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
7848   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
7849   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
7850   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
7851   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
7852
7853   item->action_description = NULL;
7854   item->image_description = NULL;
7855
7856   item->action_idle_handler = 0;
7857 }
7858
7859 static void
7860 gtk_icon_view_item_accessible_finalize (GObject *object)
7861 {
7862   GtkIconViewItemAccessible *item;
7863
7864   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
7865
7866   if (item->widget)
7867     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
7868
7869   if (item->state_set)
7870     g_object_unref (item->state_set);
7871
7872
7873   g_free (item->text);
7874   g_free (item->action_description);
7875   g_free (item->image_description);
7876
7877   if (item->action_idle_handler)
7878     {
7879       g_source_remove (item->action_idle_handler);
7880       item->action_idle_handler = 0;
7881     }
7882
7883   G_OBJECT_CLASS (_gtk_icon_view_item_accessible_parent_class)->finalize (object);
7884 }
7885
7886 static AtkObject*
7887 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
7888 {
7889   GtkIconViewItemAccessible *item;
7890
7891   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
7892   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
7893
7894   if (item->widget)
7895     return gtk_widget_get_accessible (item->widget);
7896   else
7897     return NULL;
7898 }
7899
7900 static gint
7901 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
7902 {
7903   GtkIconViewItemAccessible *item;
7904
7905   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
7906   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
7907
7908   return item->item->index;
7909 }
7910
7911 static AtkStateSet *
7912 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
7913 {
7914   GtkIconViewItemAccessible *item;
7915   GtkIconView *icon_view;
7916
7917   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
7918   g_return_val_if_fail (item->state_set, NULL);
7919
7920   if (!item->widget)
7921     return NULL;
7922
7923   icon_view = GTK_ICON_VIEW (item->widget);
7924   if (icon_view->priv->cursor_item == item->item)
7925     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
7926   else
7927     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
7928   if (item->item->selected)
7929     atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
7930   else
7931     atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
7932
7933   return g_object_ref (item->state_set);
7934 }
7935
7936 static void
7937 _gtk_icon_view_item_accessible_class_init (GtkIconViewItemAccessibleClass *klass)
7938 {
7939   GObjectClass *gobject_class;
7940   AtkObjectClass *atk_class;
7941
7942   gobject_class = (GObjectClass *)klass;
7943   atk_class = (AtkObjectClass *)klass;
7944
7945   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
7946
7947   atk_class->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent;
7948   atk_class->get_parent = gtk_icon_view_item_accessible_get_parent;
7949   atk_class->ref_state_set = gtk_icon_view_item_accessible_ref_state_set;
7950 }
7951
7952 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE      (_gtk_icon_view_accessible_get_type ())
7953 #define GTK_ICON_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
7954 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
7955
7956 typedef struct
7957 {
7958   GtkContainerAccessible parent;
7959
7960   GList *items;
7961   GtkAdjustment *old_hadj;
7962   GtkAdjustment *old_vadj;
7963   GtkTreeModel *model;
7964 } GtkIconViewAccessible;
7965
7966 typedef GtkContainerAccessibleClass GtkIconViewAccessibleClass;
7967
7968 static void atk_component_interface_init (AtkComponentIface *iface);
7969 static void atk_selection_interface_init (AtkSelectionIface *iface);
7970
7971 G_DEFINE_TYPE_WITH_CODE (GtkIconViewAccessible, _gtk_icon_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
7972                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
7973                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
7974
7975 typedef struct
7976 {
7977   AtkObject *item;
7978   gint       index;
7979 } GtkIconViewItemAccessibleInfo;
7980
7981
7982 static void
7983 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
7984                                         AtkObject *item,
7985                                         gint       index)
7986 {
7987   GtkIconViewAccessible *view = (GtkIconViewAccessible *)accessible;
7988   GtkIconViewItemAccessibleInfo *info;
7989   GtkIconViewItemAccessibleInfo *tmp_info;
7990   GList *items;
7991
7992   info = g_new (GtkIconViewItemAccessibleInfo, 1);
7993   info->item = item;
7994   info->index = index;
7995
7996   items = view->items;
7997   while (items)
7998     {
7999       tmp_info = items->data;
8000       if (tmp_info->index > index)
8001         break;
8002       items = items->next;
8003     }
8004   view->items = g_list_insert_before (view->items, items, info);
8005   view->old_hadj = NULL;
8006   view->old_vadj = NULL;
8007 }
8008
8009 static gint
8010 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
8011 {
8012   GtkIconView *icon_view;
8013   GtkWidget *widget;
8014
8015   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8016   if (!widget)
8017       return 0;
8018
8019   icon_view = GTK_ICON_VIEW (widget);
8020
8021   return g_list_length (icon_view->priv->items);
8022 }
8023
8024 static AtkObject *
8025 gtk_icon_view_accessible_find_child (AtkObject *accessible,
8026                                      gint       index)
8027 {
8028   GtkIconViewAccessible *view = (GtkIconViewAccessible*)accessible;
8029   GtkIconViewItemAccessibleInfo *info;
8030   GList *items;
8031
8032   items = view->items;
8033
8034   while (items)
8035     {
8036       info = items->data;
8037       if (info->index == index)
8038         return info->item;
8039       items = items->next;
8040     }
8041
8042   return NULL;
8043 }
8044
8045 static AtkObject *
8046 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
8047                                     gint       index)
8048 {
8049   GtkIconView *icon_view;
8050   GtkWidget *widget;
8051   GList *icons;
8052   AtkObject *obj;
8053   GtkIconViewItemAccessible *a11y_item;
8054
8055   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8056   if (!widget)
8057     return NULL;
8058
8059   icon_view = GTK_ICON_VIEW (widget);
8060   icons = g_list_nth (icon_view->priv->items, index);
8061   obj = NULL;
8062   if (icons)
8063     {
8064       GtkIconViewItem *item = icons->data;
8065
8066       g_return_val_if_fail (item->index == index, NULL);
8067       obj = gtk_icon_view_accessible_find_child (accessible, index);
8068       if (!obj)
8069         {
8070           obj = g_object_new (GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, NULL);
8071           gtk_icon_view_item_accessible_info_new (accessible, obj, index);
8072           obj->role = ATK_ROLE_ICON;
8073           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8074           a11y_item->item = item;
8075           a11y_item->widget = widget;
8076
8077           g_free (a11y_item->text);
8078           a11y_item->text = get_text (icon_view, item);
8079
8080           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
8081           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
8082        }
8083       g_object_ref (obj);
8084     }
8085   return obj;
8086 }
8087
8088 static void
8089 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
8090                                          GList                 *list)
8091 {
8092   GtkIconViewItemAccessibleInfo *info;
8093   GtkIconViewItemAccessible *item;
8094   GList *items;
8095
8096   if (view->items)
8097     {
8098       GtkWidget *widget;
8099       gboolean act_on_item;
8100
8101       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
8102       if (widget == NULL)
8103         return;
8104
8105       items = view->items;
8106
8107       act_on_item = (list == NULL);
8108
8109       while (items)
8110         {
8111
8112           info = (GtkIconViewItemAccessibleInfo *)items->data;
8113           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8114
8115           if (act_on_item == FALSE && list == items)
8116             act_on_item = TRUE;
8117
8118           if (act_on_item)
8119             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
8120
8121           items = items->next;
8122        }
8123    }
8124 }
8125
8126 static void
8127 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment         *adjustment,
8128                                              GtkIconViewAccessible *view)
8129 {
8130   gtk_icon_view_accessible_traverse_items (view, NULL);
8131 }
8132
8133 static void
8134 gtk_icon_view_accessible_set_adjustment (AtkObject      *accessible,
8135                                          GtkOrientation  orientation,
8136                                          GtkAdjustment  *adjustment)
8137 {
8138   GtkIconViewAccessible *view = (GtkIconViewAccessible*)accessible;
8139   GtkAdjustment **old_adj_ptr;
8140
8141   if (orientation == GTK_ORIENTATION_HORIZONTAL)
8142     {
8143       if (view->old_hadj == adjustment)
8144         return;
8145
8146       old_adj_ptr = &view->old_hadj;
8147     }
8148   else
8149     {
8150       if (view->old_vadj == adjustment)
8151         return;
8152
8153       old_adj_ptr = &view->old_vadj;
8154     }
8155
8156   /* Disconnect signal handlers */
8157   if (*old_adj_ptr)
8158     {
8159       g_object_remove_weak_pointer (G_OBJECT (*old_adj_ptr),
8160                                     (gpointer *)old_adj_ptr);
8161       g_signal_handlers_disconnect_by_func (*old_adj_ptr,
8162                                             gtk_icon_view_accessible_adjustment_changed,
8163                                             accessible);
8164     }
8165
8166   /* Connect signal */
8167   *old_adj_ptr = adjustment;
8168   g_object_add_weak_pointer (G_OBJECT (adjustment), (gpointer *)old_adj_ptr);
8169   g_signal_connect (adjustment, "value-changed",
8170                     G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8171                     accessible);
8172 }
8173
8174 static void
8175 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
8176                                             GtkTreePath  *path,
8177                                             GtkTreeIter  *iter,
8178                                             gpointer      user_data)
8179 {
8180   AtkObject *atk_obj;
8181   gint index;
8182   GtkWidget *widget;
8183   GtkIconView *icon_view;
8184   GtkIconViewItem *item;
8185   GtkIconViewItemAccessible *a11y_item;
8186   const gchar *name;
8187
8188   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8189   index = gtk_tree_path_get_indices(path)[0];
8190   a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
8191       gtk_icon_view_accessible_find_child (atk_obj, index));
8192
8193   if (a11y_item)
8194     {
8195       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
8196       icon_view = GTK_ICON_VIEW (widget);
8197       item = a11y_item->item;
8198
8199       name = atk_object_get_name (ATK_OBJECT (a11y_item));
8200       if (!name || strcmp (name, "") == 0)
8201         {
8202           g_free (a11y_item->text);
8203           a11y_item->text = get_text (icon_view, item);
8204         }
8205     }
8206
8207   g_signal_emit_by_name (atk_obj, "visible-data-changed");
8208
8209   return;
8210 }
8211
8212 static void
8213 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
8214                                              GtkTreePath  *path,
8215                                              GtkTreeIter  *iter,
8216                                              gpointer     user_data)
8217 {
8218   GtkIconViewItemAccessibleInfo *info;
8219   GtkIconViewAccessible *view;
8220   GtkIconViewItemAccessible *item;
8221   GList *items;
8222   GList *tmp_list;
8223   AtkObject *atk_obj;
8224   gint index;
8225
8226   index = gtk_tree_path_get_indices(path)[0];
8227   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8228   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8229
8230   items = view->items;
8231   tmp_list = NULL;
8232   while (items)
8233     {
8234       info = items->data;
8235       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8236       if (info->index != item->item->index)
8237         {
8238           if (info->index < index)
8239             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
8240
8241           if (tmp_list == NULL)
8242             tmp_list = items;
8243
8244           info->index = item->item->index;
8245         }
8246
8247       items = items->next;
8248     }
8249   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8250   g_signal_emit_by_name (atk_obj, "children-changed::add",
8251                          index, NULL, NULL);
8252   return;
8253 }
8254
8255 static void
8256 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
8257                                             GtkTreePath  *path,
8258                                             gpointer     user_data)
8259 {
8260   GtkIconViewItemAccessibleInfo *info;
8261   GtkIconViewAccessible *view;
8262   GtkIconViewItemAccessible *item;
8263   GList *items;
8264   GList *tmp_list;
8265   GList *deleted_item;
8266   AtkObject *atk_obj;
8267   gint index;
8268
8269   index = gtk_tree_path_get_indices(path)[0];
8270   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8271   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8272
8273   items = view->items;
8274   tmp_list = NULL;
8275   deleted_item = NULL;
8276   info = NULL;
8277   while (items)
8278     {
8279       info = items->data;
8280       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8281       if (info->index == index)
8282         {
8283           deleted_item = items;
8284         }
8285       if (info->index != item->item->index)
8286         {
8287           if (tmp_list == NULL)
8288             tmp_list = items;
8289
8290           info->index = item->item->index;
8291         }
8292
8293       items = items->next;
8294     }
8295   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8296   if (deleted_item)
8297     {
8298       info = deleted_item->data;
8299       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
8300       g_signal_emit_by_name (atk_obj, "children-changed::remove",
8301                              index, NULL, NULL);
8302       view->items = g_list_remove_link (view->items, deleted_item);
8303       g_free (info);
8304     }
8305
8306   return;
8307 }
8308
8309 static gint
8310 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
8311                                        GtkIconViewItemAccessibleInfo *i2)
8312 {
8313   return i1->index - i2->index;
8314 }
8315
8316 static void
8317 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
8318                                                GtkTreePath  *path,
8319                                                GtkTreeIter  *iter,
8320                                                gint         *new_order,
8321                                                gpointer     user_data)
8322 {
8323   GtkIconViewAccessible *view;
8324   GtkIconViewItemAccessibleInfo *info;
8325   GtkIconView *icon_view;
8326   GtkIconViewItemAccessible *item;
8327   GList *items;
8328   AtkObject *atk_obj;
8329   gint *order;
8330   gint length, i;
8331
8332   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8333   icon_view = GTK_ICON_VIEW (user_data);
8334   view = (GtkIconViewAccessible*)atk_obj;
8335
8336   length = gtk_tree_model_iter_n_children (tree_model, NULL);
8337
8338   order = g_new (gint, length);
8339   for (i = 0; i < length; i++)
8340     order [new_order[i]] = i;
8341
8342   items = view->items;
8343   while (items)
8344     {
8345       info = items->data;
8346       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8347       info->index = order[info->index];
8348       item->item = g_list_nth_data (icon_view->priv->items, info->index);
8349       items = items->next;
8350     }
8351   g_free (order);
8352   view->items = g_list_sort (view->items,
8353                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
8354
8355   return;
8356 }
8357
8358 static void
8359 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
8360                                                    GtkWidget *widget)
8361 {
8362   GObject *obj;
8363
8364   obj = G_OBJECT (model);
8365   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
8366   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
8367   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
8368   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
8369 }
8370
8371 static void
8372 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
8373 {
8374   GObject *obj;
8375
8376   obj = G_OBJECT (icon_view->priv->model);
8377   g_signal_connect_data (obj, "row-changed",
8378                          (GCallback) gtk_icon_view_accessible_model_row_changed,
8379                          icon_view, NULL, 0);
8380   g_signal_connect_data (obj, "row-inserted",
8381                          (GCallback) gtk_icon_view_accessible_model_row_inserted,
8382                          icon_view, NULL, G_CONNECT_AFTER);
8383   g_signal_connect_data (obj, "row-deleted",
8384                          (GCallback) gtk_icon_view_accessible_model_row_deleted,
8385                          icon_view, NULL, G_CONNECT_AFTER);
8386   g_signal_connect_data (obj, "rows-reordered",
8387                          (GCallback) gtk_icon_view_accessible_model_rows_reordered,
8388                          icon_view, NULL, G_CONNECT_AFTER);
8389 }
8390
8391 static void
8392 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessible *view)
8393 {
8394   GtkIconViewItemAccessibleInfo *info;
8395   GList *items;
8396
8397   items = view->items;
8398   while (items)
8399     {
8400       info = (GtkIconViewItemAccessibleInfo *) items->data;
8401       g_object_unref (info->item);
8402       g_free (items->data);
8403       items = items->next;
8404     }
8405   g_list_free (view->items);
8406   view->items = NULL;
8407 }
8408
8409 static void
8410 gtk_icon_view_accessible_notify_gtk (GObject    *obj,
8411                                      GParamSpec *pspec)
8412 {
8413   GtkIconView *icon_view;
8414   GtkWidget *widget;
8415   AtkObject *atk_obj;
8416   GtkIconViewAccessible *view;
8417
8418   if (strcmp (pspec->name, "model") == 0)
8419     {
8420       widget = GTK_WIDGET (obj);
8421       atk_obj = gtk_widget_get_accessible (widget);
8422       view = (GtkIconViewAccessible*)atk_obj;
8423       if (view->model)
8424         {
8425           g_object_remove_weak_pointer (G_OBJECT (view->model),
8426                                         (gpointer *)&view->model);
8427           gtk_icon_view_accessible_disconnect_model_signals (view->model, widget);
8428         }
8429       gtk_icon_view_accessible_clear_cache (view);
8430
8431       icon_view = GTK_ICON_VIEW (obj);
8432       view->model = icon_view->priv->model;
8433       /* If there is no model the GtkIconView is probably being destroyed */
8434       if (view->model)
8435         {
8436           g_object_add_weak_pointer (G_OBJECT (view->model), (gpointer *)&view->model);
8437           gtk_icon_view_accessible_connect_model_signals (icon_view);
8438         }
8439     }
8440
8441   return;
8442 }
8443
8444 static void
8445 gtk_icon_view_accessible_initialize (AtkObject *accessible,
8446                                      gpointer   data)
8447 {
8448   GtkIconViewAccessible *view;
8449   GtkIconView *icon_view;
8450
8451   if (ATK_OBJECT_CLASS (_gtk_icon_view_accessible_parent_class)->initialize)
8452     ATK_OBJECT_CLASS (_gtk_icon_view_accessible_parent_class)->initialize (accessible, data);
8453
8454   icon_view = (GtkIconView*)data;
8455   view = (GtkIconViewAccessible*)accessible;
8456
8457   if (icon_view->priv->hadjustment)
8458     gtk_icon_view_accessible_set_adjustment (accessible,
8459                                              GTK_ORIENTATION_HORIZONTAL,
8460                                              icon_view->priv->hadjustment);
8461   if (icon_view->priv->vadjustment)
8462     gtk_icon_view_accessible_set_adjustment (accessible,
8463                                              GTK_ORIENTATION_VERTICAL,
8464                                              icon_view->priv->vadjustment);
8465   g_signal_connect (data, "notify",
8466                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk), NULL);
8467
8468   view->model = icon_view->priv->model;
8469   if (view->model)
8470     {
8471       g_object_add_weak_pointer (G_OBJECT (view->model), (gpointer *)&view->model);
8472       gtk_icon_view_accessible_connect_model_signals (icon_view);
8473     }
8474
8475   accessible->role = ATK_ROLE_LAYERED_PANE;
8476 }
8477
8478 static void
8479 gtk_icon_view_accessible_finalize (GObject *object)
8480 {
8481   GtkIconViewAccessible *view = (GtkIconViewAccessible*)object;
8482
8483   gtk_icon_view_accessible_clear_cache (view);
8484
8485   G_OBJECT_CLASS (_gtk_icon_view_accessible_parent_class)->finalize (object);
8486 }
8487
8488 static void
8489 gtk_icon_view_accessible_destroyed (GtkWidget     *widget,
8490                                     GtkAccessible *accessible)
8491 {
8492   AtkObject *atk_obj;
8493   GtkIconViewAccessible *view;
8494
8495   atk_obj = ATK_OBJECT (accessible);
8496   view = (GtkIconViewAccessible*)atk_obj;
8497   if (view->old_hadj)
8498     {
8499       g_object_remove_weak_pointer (G_OBJECT (view->old_hadj),
8500                                     (gpointer *)&view->old_hadj);
8501
8502       g_signal_handlers_disconnect_by_func (view->old_hadj,
8503                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
8504                                             accessible);
8505       view->old_hadj = NULL;
8506     }
8507   if (view->old_vadj)
8508     {
8509       g_object_remove_weak_pointer (G_OBJECT (view->old_vadj),
8510                                     (gpointer *)&view->old_vadj);
8511
8512       g_signal_handlers_disconnect_by_func (view->old_vadj,
8513                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
8514                                             accessible);
8515       view->old_vadj = NULL;
8516     }
8517 }
8518
8519 static void
8520 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
8521 {
8522   GtkWidget *widget;
8523
8524   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8525   if (widget)
8526     {
8527       g_signal_connect_after (widget, "destroy",
8528                               G_CALLBACK (gtk_icon_view_accessible_destroyed), accessible);
8529     }
8530   GTK_ACCESSIBLE_CLASS (_gtk_icon_view_accessible_parent_class)->connect_widget_destroyed (accessible);
8531 }
8532
8533 static void
8534 _gtk_icon_view_accessible_class_init (GtkIconViewAccessibleClass *klass)
8535 {
8536   GObjectClass *gobject_class;
8537   GtkAccessibleClass *accessible_class;
8538   AtkObjectClass *atk_class;
8539
8540   gobject_class = (GObjectClass *)klass;
8541   accessible_class = (GtkAccessibleClass *)klass;
8542   atk_class = (AtkObjectClass *)klass;
8543
8544   gobject_class->finalize = gtk_icon_view_accessible_finalize;
8545
8546   atk_class->get_n_children = gtk_icon_view_accessible_get_n_children;
8547   atk_class->ref_child = gtk_icon_view_accessible_ref_child;
8548   atk_class->initialize = gtk_icon_view_accessible_initialize;
8549
8550   accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
8551 }
8552
8553 static void
8554 _gtk_icon_view_accessible_init (GtkIconViewAccessible *accessible)
8555 {
8556 }
8557
8558 static AtkObject*
8559 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
8560                                                   gint          x,
8561                                                   gint          y,
8562                                                   AtkCoordType  coord_type)
8563 {
8564   GtkWidget *widget;
8565   GtkIconView *icon_view;
8566   GtkIconViewItem *item;
8567   gint x_pos, y_pos;
8568
8569   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
8570   if (widget == NULL)
8571     return NULL;
8572
8573   icon_view = GTK_ICON_VIEW (widget);
8574   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
8575   item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
8576   if (item)
8577     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
8578
8579   return NULL;
8580 }
8581
8582 static void
8583 atk_component_interface_init (AtkComponentIface *iface)
8584 {
8585   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
8586 }
8587
8588 static gboolean
8589 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
8590                                         gint          i)
8591 {
8592   GtkWidget *widget;
8593   GtkIconView *icon_view;
8594   GtkIconViewItem *item;
8595
8596   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8597   if (widget == NULL)
8598     return FALSE;
8599
8600   icon_view = GTK_ICON_VIEW (widget);
8601
8602   item = g_list_nth_data (icon_view->priv->items, i);
8603   if (!item)
8604     return FALSE;
8605
8606   gtk_icon_view_select_item (icon_view, item);
8607
8608   return TRUE;
8609 }
8610
8611 static gboolean
8612 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
8613 {
8614   GtkWidget *widget;
8615   GtkIconView *icon_view;
8616
8617   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8618   if (widget == NULL)
8619     return FALSE;
8620
8621   icon_view = GTK_ICON_VIEW (widget);
8622   gtk_icon_view_unselect_all (icon_view);
8623
8624   return TRUE;
8625 }
8626
8627 static AtkObject*
8628 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
8629                                         gint          i)
8630 {
8631   GList *l;
8632   GtkWidget *widget;
8633   GtkIconView *icon_view;
8634   GtkIconViewItem *item;
8635
8636   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8637   if (widget == NULL)
8638     return NULL;
8639
8640   icon_view = GTK_ICON_VIEW (widget);
8641
8642   l = icon_view->priv->items;
8643   while (l)
8644     {
8645       item = l->data;
8646       if (item->selected)
8647         {
8648           if (i == 0)
8649             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
8650           else
8651             i--;
8652         }
8653       l = l->next;
8654     }
8655
8656   return NULL;
8657 }
8658
8659 static gint
8660 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
8661 {
8662   GtkWidget *widget;
8663   GtkIconView *icon_view;
8664   GtkIconViewItem *item;
8665   GList *l;
8666   gint count;
8667
8668   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8669   if (widget == NULL)
8670     return 0;
8671
8672   icon_view = GTK_ICON_VIEW (widget);
8673
8674   l = icon_view->priv->items;
8675   count = 0;
8676   while (l)
8677     {
8678       item = l->data;
8679
8680       if (item->selected)
8681         count++;
8682
8683       l = l->next;
8684     }
8685
8686   return count;
8687 }
8688
8689 static gboolean
8690 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
8691                                             gint          i)
8692 {
8693   GtkWidget *widget;
8694   GtkIconView *icon_view;
8695   GtkIconViewItem *item;
8696
8697   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8698   if (widget == NULL)
8699     return FALSE;
8700
8701   icon_view = GTK_ICON_VIEW (widget);
8702
8703   item = g_list_nth_data (icon_view->priv->items, i);
8704   if (!item)
8705     return FALSE;
8706
8707   return item->selected;
8708 }
8709
8710 static gboolean
8711 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
8712                                            gint          i)
8713 {
8714   GtkWidget *widget;
8715   GtkIconView *icon_view;
8716   GtkIconViewItem *item;
8717   GList *l;
8718   gint count;
8719
8720   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8721   if (widget == NULL)
8722     return FALSE;
8723
8724   icon_view = GTK_ICON_VIEW (widget);
8725   l = icon_view->priv->items;
8726   count = 0;
8727   while (l)
8728     {
8729       item = l->data;
8730       if (item->selected)
8731         {
8732           if (count == i)
8733             {
8734               gtk_icon_view_unselect_item (icon_view, item);
8735               return TRUE;
8736             }
8737           count++;
8738         }
8739       l = l->next;
8740     }
8741
8742   return FALSE;
8743 }
8744  
8745 static gboolean
8746 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
8747 {
8748   GtkWidget *widget;
8749   GtkIconView *icon_view;
8750
8751   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
8752   if (widget == NULL)
8753     return FALSE;
8754
8755   icon_view = GTK_ICON_VIEW (widget);
8756   gtk_icon_view_select_all (icon_view);
8757   return TRUE;
8758 }
8759
8760 static void
8761 atk_selection_interface_init (AtkSelectionIface *iface)
8762 {
8763   iface->add_selection = gtk_icon_view_accessible_add_selection;
8764   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
8765   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
8766   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
8767   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
8768   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
8769   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
8770 }