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