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