]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
iconview: Don't cache iters
[~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   GList *list;
3190
3191   /* ignore changes in branches */
3192   if (gtk_tree_path_get_depth (path) > 1)
3193     return;
3194
3195   index = gtk_tree_path_get_indices(path)[0];
3196
3197   item = gtk_icon_view_item_new ();
3198
3199   item->index = index;
3200
3201   /* FIXME: We can be more efficient here,
3202      we can store a tail pointer and use that when
3203      appending (which is a rather common operation)
3204   */
3205   icon_view->priv->items = g_list_insert (icon_view->priv->items,
3206                                          item, index);
3207   
3208   list = g_list_nth (icon_view->priv->items, index + 1);
3209   for (; list; list = list->next)
3210     {
3211       item = list->data;
3212
3213       item->index++;
3214     }
3215     
3216   verify_items (icon_view);
3217
3218   gtk_icon_view_queue_layout (icon_view);
3219 }
3220
3221 static void
3222 gtk_icon_view_row_deleted (GtkTreeModel *model,
3223                            GtkTreePath  *path,
3224                            gpointer      data)
3225 {
3226   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3227   gint index;
3228   GtkIconViewItem *item;
3229   GList *list, *next;
3230   gboolean emit = FALSE;
3231
3232   /* ignore changes in branches */
3233   if (gtk_tree_path_get_depth (path) > 1)
3234     return;
3235
3236   index = gtk_tree_path_get_indices(path)[0];
3237
3238   list = g_list_nth (icon_view->priv->items, index);
3239   item = list->data;
3240
3241   if (icon_view->priv->cell_area)
3242     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3243
3244   if (item == icon_view->priv->anchor_item)
3245     icon_view->priv->anchor_item = NULL;
3246
3247   if (item == icon_view->priv->cursor_item)
3248     icon_view->priv->cursor_item = NULL;
3249
3250   if (item == icon_view->priv->last_prelight)
3251     icon_view->priv->last_prelight = NULL;
3252
3253   if (item->selected)
3254     emit = TRUE;
3255   
3256   gtk_icon_view_item_free (item);
3257
3258   for (next = list->next; next; next = next->next)
3259     {
3260       item = next->data;
3261
3262       item->index--;
3263     }
3264   
3265   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3266
3267   verify_items (icon_view);  
3268   
3269   gtk_icon_view_queue_layout (icon_view);
3270
3271   if (emit)
3272     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3273 }
3274
3275 static void
3276 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3277                               GtkTreePath  *parent,
3278                               GtkTreeIter  *iter,
3279                               gint         *new_order,
3280                               gpointer      data)
3281 {
3282   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3283   int i;
3284   int length;
3285   GList *items = NULL, *list;
3286   GtkIconViewItem **item_array;
3287   gint *order;
3288
3289   /* ignore changes in branches */
3290   if (iter != NULL)
3291     return;
3292
3293   if (icon_view->priv->cell_area)
3294     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3295
3296   length = gtk_tree_model_iter_n_children (model, NULL);
3297
3298   order = g_new (gint, length);
3299   for (i = 0; i < length; i++)
3300     order [new_order[i]] = i;
3301
3302   item_array = g_new (GtkIconViewItem *, length);
3303   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3304     item_array[order[i]] = list->data;
3305   g_free (order);
3306
3307   for (i = length - 1; i >= 0; i--)
3308     {
3309       item_array[i]->index = i;
3310       items = g_list_prepend (items, item_array[i]);
3311     }
3312   
3313   g_free (item_array);
3314   g_list_free (icon_view->priv->items);
3315   icon_view->priv->items = items;
3316
3317   gtk_icon_view_queue_layout (icon_view);
3318
3319   verify_items (icon_view);  
3320 }
3321
3322 static void
3323 gtk_icon_view_build_items (GtkIconView *icon_view)
3324 {
3325   GtkTreeIter iter;
3326   int i;
3327   GList *items = NULL;
3328
3329   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3330                                       &iter))
3331     return;
3332
3333   i = 0;
3334   
3335   do
3336     {
3337       GtkIconViewItem *item = gtk_icon_view_item_new ();
3338
3339       item->index = i;
3340       
3341       i++;
3342
3343       items = g_list_prepend (items, item);
3344       
3345     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3346
3347   icon_view->priv->items = g_list_reverse (items);
3348 }
3349
3350 static void
3351 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
3352                                 guint           keyval,
3353                                 guint           modmask,
3354                                 GtkMovementStep step,
3355                                 gint            count)
3356 {
3357   
3358   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3359                                 I_("move-cursor"), 2,
3360                                 G_TYPE_ENUM, step,
3361                                 G_TYPE_INT, count);
3362
3363   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3364                                 "move-cursor", 2,
3365                                 G_TYPE_ENUM, step,
3366                                 G_TYPE_INT, count);
3367
3368   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3369    return;
3370
3371   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3372                                 "move-cursor", 2,
3373                                 G_TYPE_ENUM, step,
3374                                 G_TYPE_INT, count);
3375
3376   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3377                                 "move-cursor", 2,
3378                                 G_TYPE_ENUM, step,
3379                                 G_TYPE_INT, count);
3380 }
3381
3382 static gboolean
3383 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
3384                                 GtkMovementStep  step,
3385                                 gint             count)
3386 {
3387   GdkModifierType state;
3388
3389   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3390   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3391                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3392                         step == GTK_MOVEMENT_DISPLAY_LINES ||
3393                         step == GTK_MOVEMENT_PAGES ||
3394                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3395
3396   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3397     return FALSE;
3398
3399   gtk_cell_area_stop_editing (icon_view->priv->cell_area, FALSE);
3400   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3401
3402   if (gtk_get_current_event_state (&state))
3403     {
3404       GdkModifierType extend_mod_mask;
3405       GdkModifierType modify_mod_mask;
3406
3407       extend_mod_mask =
3408         gtk_widget_get_modifier_mask (GTK_WIDGET (icon_view),
3409                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3410       modify_mod_mask =
3411         gtk_widget_get_modifier_mask (GTK_WIDGET (icon_view),
3412                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3413
3414       if ((state & modify_mod_mask) == modify_mod_mask)
3415         icon_view->priv->modify_selection_pressed = TRUE;
3416       if ((state & extend_mod_mask) == extend_mod_mask)
3417         icon_view->priv->extend_selection_pressed = TRUE;
3418     }
3419   /* else we assume not pressed */
3420
3421   switch (step)
3422     {
3423     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3424     case GTK_MOVEMENT_VISUAL_POSITIONS:
3425       gtk_icon_view_move_cursor_left_right (icon_view, count);
3426       break;
3427     case GTK_MOVEMENT_DISPLAY_LINES:
3428       gtk_icon_view_move_cursor_up_down (icon_view, count);
3429       break;
3430     case GTK_MOVEMENT_PAGES:
3431       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3432       break;
3433     case GTK_MOVEMENT_BUFFER_ENDS:
3434       gtk_icon_view_move_cursor_start_end (icon_view, count);
3435       break;
3436     default:
3437       g_assert_not_reached ();
3438     }
3439
3440   icon_view->priv->modify_selection_pressed = FALSE;
3441   icon_view->priv->extend_selection_pressed = FALSE;
3442
3443   icon_view->priv->draw_focus = TRUE;
3444
3445   return TRUE;
3446 }
3447
3448 static GtkIconViewItem *
3449 find_item (GtkIconView     *icon_view,
3450            GtkIconViewItem *current,
3451            gint             row_ofs,
3452            gint             col_ofs)
3453 {
3454   gint row, col;
3455   GList *items;
3456   GtkIconViewItem *item;
3457
3458   /* FIXME: this could be more efficient 
3459    */
3460   row = current->row + row_ofs;
3461   col = current->col + col_ofs;
3462
3463   for (items = icon_view->priv->items; items; items = items->next)
3464     {
3465       item = items->data;
3466       if (item->row == row && item->col == col)
3467         return item;
3468     }
3469   
3470   return NULL;
3471 }
3472
3473 static GtkIconViewItem *
3474 find_item_page_up_down (GtkIconView     *icon_view,
3475                         GtkIconViewItem *current,
3476                         gint             count)
3477 {
3478   GList *item, *next;
3479   gint y, col;
3480   
3481   col = current->col;
3482   y = current->cell_area.y + count * gtk_adjustment_get_page_size (icon_view->priv->vadjustment);
3483
3484   item = g_list_find (icon_view->priv->items, current);
3485   if (count > 0)
3486     {
3487       while (item)
3488         {
3489           for (next = item->next; next; next = next->next)
3490             {
3491               if (((GtkIconViewItem *)next->data)->col == col)
3492                 break;
3493             }
3494           if (!next || ((GtkIconViewItem *)next->data)->cell_area.y > y)
3495             break;
3496
3497           item = next;
3498         }
3499     }
3500   else 
3501     {
3502       while (item)
3503         {
3504           for (next = item->prev; next; next = next->prev)
3505             {
3506               if (((GtkIconViewItem *)next->data)->col == col)
3507                 break;
3508             }
3509           if (!next || ((GtkIconViewItem *)next->data)->cell_area.y < y)
3510             break;
3511
3512           item = next;
3513         }
3514     }
3515
3516   if (item)
3517     return item->data;
3518
3519   return NULL;
3520 }
3521
3522 static gboolean
3523 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
3524                                   GtkIconViewItem *anchor,
3525                                   GtkIconViewItem *cursor)
3526 {
3527   GList *items;
3528   GtkIconViewItem *item;
3529   gint row1, row2, col1, col2;
3530   gboolean dirty = FALSE;
3531   
3532   if (anchor->row < cursor->row)
3533     {
3534       row1 = anchor->row;
3535       row2 = cursor->row;
3536     }
3537   else
3538     {
3539       row1 = cursor->row;
3540       row2 = anchor->row;
3541     }
3542
3543   if (anchor->col < cursor->col)
3544     {
3545       col1 = anchor->col;
3546       col2 = cursor->col;
3547     }
3548   else
3549     {
3550       col1 = cursor->col;
3551       col2 = anchor->col;
3552     }
3553
3554   for (items = icon_view->priv->items; items; items = items->next)
3555     {
3556       item = items->data;
3557
3558       if (row1 <= item->row && item->row <= row2 &&
3559           col1 <= item->col && item->col <= col2)
3560         {
3561           if (!item->selected)
3562             {
3563               dirty = TRUE;
3564               item->selected = TRUE;
3565               gtk_icon_view_item_selected_changed (icon_view, item);
3566             }
3567           gtk_icon_view_queue_draw_item (icon_view, item);
3568         }
3569     }
3570
3571   return dirty;
3572 }
3573
3574 static void 
3575 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3576                                    gint         count)
3577 {
3578   GtkIconViewItem *item;
3579   GtkCellRenderer *cell = NULL;
3580   gboolean dirty = FALSE;
3581   gint step;
3582   GtkDirectionType direction;
3583
3584   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3585     return;
3586
3587   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
3588
3589   if (!icon_view->priv->cursor_item)
3590     {
3591       GList *list;
3592
3593       if (count > 0)
3594         list = icon_view->priv->items;
3595       else
3596         list = g_list_last (icon_view->priv->items);
3597
3598       if (list)
3599         {
3600           item = list->data;
3601
3602           /* Give focus to the first cell initially */
3603           _gtk_icon_view_set_cell_data (icon_view, item);
3604           gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3605         }
3606       else
3607         {
3608           item = NULL;
3609         }
3610     }
3611   else
3612     {
3613       item = icon_view->priv->cursor_item;
3614       step = count > 0 ? 1 : -1;      
3615
3616       /* Save the current focus cell in case we hit the edge */
3617       cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3618
3619       while (item)
3620         {
3621           _gtk_icon_view_set_cell_data (icon_view, item);
3622
3623           if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3624             break;
3625
3626           item = find_item (icon_view, item, step, 0);
3627         }
3628     }
3629
3630   if (!item)
3631     {
3632       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3633         {
3634           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3635           if (toplevel)
3636             gtk_widget_child_focus (toplevel,
3637                                     direction == GTK_DIR_UP ?
3638                                     GTK_DIR_TAB_BACKWARD :
3639                                     GTK_DIR_TAB_FORWARD);
3640
3641         }
3642
3643       gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3644       return;
3645     }
3646
3647   if (icon_view->priv->modify_selection_pressed ||
3648       !icon_view->priv->extend_selection_pressed ||
3649       !icon_view->priv->anchor_item ||
3650       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3651     icon_view->priv->anchor_item = item;
3652
3653   cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3654   _gtk_icon_view_set_cursor_item (icon_view, item, cell);
3655
3656   if (!icon_view->priv->modify_selection_pressed &&
3657       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3658     {
3659       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3660       dirty = gtk_icon_view_select_all_between (icon_view, 
3661                                                 icon_view->priv->anchor_item,
3662                                                 item) || dirty;
3663     }
3664
3665   gtk_icon_view_scroll_to_item (icon_view, item);
3666
3667   if (dirty)
3668     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3669 }
3670
3671 static void 
3672 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3673                                         gint         count)
3674 {
3675   GtkIconViewItem *item;
3676   gboolean dirty = FALSE;
3677   
3678   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3679     return;
3680   
3681   if (!icon_view->priv->cursor_item)
3682     {
3683       GList *list;
3684
3685       if (count > 0)
3686         list = icon_view->priv->items;
3687       else
3688         list = g_list_last (icon_view->priv->items);
3689
3690       item = list ? list->data : NULL;
3691     }
3692   else
3693     item = find_item_page_up_down (icon_view, 
3694                                    icon_view->priv->cursor_item,
3695                                    count);
3696
3697   if (item == icon_view->priv->cursor_item)
3698     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3699
3700   if (!item)
3701     return;
3702
3703   if (icon_view->priv->modify_selection_pressed ||
3704       !icon_view->priv->extend_selection_pressed ||
3705       !icon_view->priv->anchor_item ||
3706       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3707     icon_view->priv->anchor_item = item;
3708
3709   _gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3710
3711   if (!icon_view->priv->modify_selection_pressed &&
3712       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3713     {
3714       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3715       dirty = gtk_icon_view_select_all_between (icon_view, 
3716                                                 icon_view->priv->anchor_item,
3717                                                 item) || dirty;
3718     }
3719
3720   gtk_icon_view_scroll_to_item (icon_view, item);
3721
3722   if (dirty)
3723     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
3724 }
3725
3726 static void 
3727 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
3728                                       gint         count)
3729 {
3730   GtkIconViewItem *item;
3731   GtkCellRenderer *cell = NULL;
3732   gboolean dirty = FALSE;
3733   gint step;
3734   GtkDirectionType direction;
3735
3736   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3737     return;
3738
3739   direction = count < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
3740
3741   if (!icon_view->priv->cursor_item)
3742     {
3743       GList *list;
3744
3745       if (count > 0)
3746         list = icon_view->priv->items;
3747       else
3748         list = g_list_last (icon_view->priv->items);
3749
3750       if (list)
3751         {
3752           item = list->data;
3753
3754           /* Give focus to the first cell initially */
3755           _gtk_icon_view_set_cell_data (icon_view, item);
3756           gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3757         }
3758       else
3759         {
3760           item = NULL;
3761         }
3762     }
3763   else
3764     {
3765       item = icon_view->priv->cursor_item;
3766       step = count > 0 ? 1 : -1;
3767
3768       /* Save the current focus cell in case we hit the edge */
3769       cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3770
3771       while (item)
3772         {
3773           _gtk_icon_view_set_cell_data (icon_view, item);
3774
3775           if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3776             break;
3777           
3778           item = find_item (icon_view, item, 0, step);
3779         }
3780     }
3781
3782   if (!item)
3783     {
3784       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3785         {
3786           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3787           if (toplevel)
3788             gtk_widget_child_focus (toplevel,
3789                                     direction == GTK_DIR_LEFT ?
3790                                     GTK_DIR_TAB_BACKWARD :
3791                                     GTK_DIR_TAB_FORWARD);
3792
3793         }
3794
3795       gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3796       return;
3797     }
3798
3799   if (icon_view->priv->modify_selection_pressed ||
3800       !icon_view->priv->extend_selection_pressed ||
3801       !icon_view->priv->anchor_item ||
3802       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3803     icon_view->priv->anchor_item = item;
3804
3805   cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3806   _gtk_icon_view_set_cursor_item (icon_view, item, cell);
3807
3808   if (!icon_view->priv->modify_selection_pressed &&
3809       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3810     {
3811       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3812       dirty = gtk_icon_view_select_all_between (icon_view, 
3813                                                 icon_view->priv->anchor_item,
3814                                                 item) || dirty;
3815     }
3816
3817   gtk_icon_view_scroll_to_item (icon_view, item);
3818
3819   if (dirty)
3820     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3821 }
3822
3823 static void 
3824 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
3825                                      gint         count)
3826 {
3827   GtkIconViewItem *item;
3828   GList *list;
3829   gboolean dirty = FALSE;
3830   
3831   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3832     return;
3833   
3834   if (count < 0)
3835     list = icon_view->priv->items;
3836   else
3837     list = g_list_last (icon_view->priv->items);
3838   
3839   item = list ? list->data : NULL;
3840
3841   if (item == icon_view->priv->cursor_item)
3842     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3843
3844   if (!item)
3845     return;
3846
3847   if (icon_view->priv->modify_selection_pressed ||
3848       !icon_view->priv->extend_selection_pressed ||
3849       !icon_view->priv->anchor_item ||
3850       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3851     icon_view->priv->anchor_item = item;
3852
3853   _gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3854
3855   if (!icon_view->priv->modify_selection_pressed &&
3856       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3857     {
3858       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3859       dirty = gtk_icon_view_select_all_between (icon_view, 
3860                                                 icon_view->priv->anchor_item,
3861                                                 item) || dirty;
3862     }
3863
3864   gtk_icon_view_scroll_to_item (icon_view, item);
3865
3866   if (dirty)
3867     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3868 }
3869
3870 /**
3871  * gtk_icon_view_scroll_to_path:
3872  * @icon_view: A #GtkIconView.
3873  * @path: The path of the item to move to.
3874  * @use_align: whether to use alignment arguments, or %FALSE.
3875  * @row_align: The vertical alignment of the item specified by @path.
3876  * @col_align: The horizontal alignment of the item specified by @path.
3877  *
3878  * Moves the alignments of @icon_view to the position specified by @path.  
3879  * @row_align determines where the row is placed, and @col_align determines 
3880  * where @column is placed.  Both are expected to be between 0.0 and 1.0. 
3881  * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means 
3882  * center.
3883  *
3884  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
3885  * tree does the minimum amount of work to scroll the item onto the screen.
3886  * This means that the item will be scrolled to the edge closest to its current
3887  * position.  If the item is currently visible on the screen, nothing is done.
3888  *
3889  * This function only works if the model is set, and @path is a valid row on 
3890  * the model. If the model changes before the @icon_view is realized, the 
3891  * centered path will be modified to reflect this change.
3892  *
3893  * Since: 2.8
3894  **/
3895 void
3896 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
3897                               GtkTreePath *path,
3898                               gboolean     use_align,
3899                               gfloat       row_align,
3900                               gfloat       col_align)
3901 {
3902   GtkIconViewItem *item = NULL;
3903   GtkWidget *widget;
3904
3905   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3906   g_return_if_fail (path != NULL);
3907   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
3908   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
3909
3910   widget = GTK_WIDGET (icon_view);
3911
3912   if (gtk_tree_path_get_depth (path) > 0)
3913     item = g_list_nth_data (icon_view->priv->items,
3914                             gtk_tree_path_get_indices(path)[0]);
3915   
3916   if (!item || item->cell_area.width < 0 ||
3917       !gtk_widget_get_realized (widget))
3918     {
3919       if (icon_view->priv->scroll_to_path)
3920         gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
3921
3922       icon_view->priv->scroll_to_path = NULL;
3923
3924       if (path)
3925         icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
3926
3927       icon_view->priv->scroll_to_use_align = use_align;
3928       icon_view->priv->scroll_to_row_align = row_align;
3929       icon_view->priv->scroll_to_col_align = col_align;
3930
3931       return;
3932     }
3933
3934   if (use_align)
3935     {
3936       GtkAllocation allocation;
3937       gint x, y;
3938       gfloat offset;
3939       GdkRectangle item_area = 
3940         { 
3941           item->cell_area.x - icon_view->priv->item_padding, 
3942           item->cell_area.y - icon_view->priv->item_padding, 
3943           item->cell_area.width  + icon_view->priv->item_padding * 2, 
3944           item->cell_area.height + icon_view->priv->item_padding * 2 
3945         };
3946
3947       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
3948
3949       gtk_widget_get_allocation (widget, &allocation);
3950
3951       offset = y + item_area.y - row_align * (allocation.height - item_area.height);
3952
3953       gtk_adjustment_set_value (icon_view->priv->vadjustment,
3954                                 gtk_adjustment_get_value (icon_view->priv->vadjustment) + offset);
3955
3956       offset = x + item_area.x - col_align * (allocation.width - item_area.width);
3957
3958       gtk_adjustment_set_value (icon_view->priv->hadjustment,
3959                                 gtk_adjustment_get_value (icon_view->priv->hadjustment) + offset);
3960
3961       gtk_adjustment_changed (icon_view->priv->hadjustment);
3962       gtk_adjustment_changed (icon_view->priv->vadjustment);
3963     }
3964   else
3965     gtk_icon_view_scroll_to_item (icon_view, item);
3966 }
3967
3968
3969 static void
3970 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view,
3971                               GtkIconViewItem *item)
3972 {
3973   GtkIconViewPrivate *priv = icon_view->priv;
3974   GtkWidget *widget = GTK_WIDGET (icon_view);
3975   GtkAdjustment *hadj, *vadj;
3976   GtkAllocation allocation;
3977   gint x, y;
3978   GdkRectangle item_area;
3979
3980   item_area.x = item->cell_area.x - priv->item_padding;
3981   item_area.y = item->cell_area.y - priv->item_padding;
3982   item_area.width = item->cell_area.width  + priv->item_padding * 2;
3983   item_area.height = item->cell_area.height + priv->item_padding * 2;
3984
3985   gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
3986   gtk_widget_get_allocation (widget, &allocation);
3987
3988   hadj = icon_view->priv->hadjustment;
3989   vadj = icon_view->priv->vadjustment;
3990
3991   if (y + item_area.y < 0)
3992     gtk_adjustment_set_value (vadj,
3993                               gtk_adjustment_get_value (vadj)
3994                                 + y + item_area.y);
3995   else if (y + item_area.y + item_area.height > allocation.height)
3996     gtk_adjustment_set_value (vadj,
3997                               gtk_adjustment_get_value (vadj)
3998                                 + y + item_area.y + item_area.height - allocation.height);
3999
4000   if (x + item_area.x < 0)
4001     gtk_adjustment_set_value (hadj,
4002                               gtk_adjustment_get_value (hadj)
4003                                 + x + item_area.x);
4004   else if (x + item_area.x + item_area.width > allocation.width)
4005     gtk_adjustment_set_value (hadj,
4006                               gtk_adjustment_get_value (hadj)
4007                                 + x + item_area.x + item_area.width - allocation.width);
4008
4009   gtk_adjustment_changed (hadj);
4010   gtk_adjustment_changed (vadj);
4011 }
4012
4013 /* GtkCellLayout implementation */
4014
4015 static void
4016 gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
4017                                 GtkCellArea *cell_area)
4018 {
4019   GtkIconViewPrivate *priv = icon_view->priv;
4020
4021   if (priv->cell_area)
4022     return;
4023
4024   if (cell_area)
4025     priv->cell_area = cell_area;
4026   else
4027     priv->cell_area = gtk_cell_area_box_new ();
4028
4029   g_object_ref_sink (priv->cell_area);
4030
4031   if (GTK_IS_ORIENTABLE (priv->cell_area))
4032     gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
4033
4034   priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
4035
4036   priv->add_editable_id =
4037     g_signal_connect (priv->cell_area, "add-editable",
4038                       G_CALLBACK (gtk_icon_view_add_editable), icon_view);
4039   priv->remove_editable_id =
4040     g_signal_connect (priv->cell_area, "remove-editable",
4041                       G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
4042   priv->context_changed_id =
4043     g_signal_connect (priv->cell_area_context, "notify",
4044                       G_CALLBACK (gtk_icon_view_context_changed), icon_view);
4045
4046   update_text_cell (icon_view);
4047   update_pixbuf_cell (icon_view);
4048 }
4049
4050 static GtkCellArea *
4051 gtk_icon_view_cell_layout_get_area (GtkCellLayout *cell_layout)
4052 {
4053   GtkIconView *icon_view = GTK_ICON_VIEW (cell_layout);
4054   GtkIconViewPrivate *priv = icon_view->priv;
4055
4056   if (G_UNLIKELY (!priv->cell_area))
4057     gtk_icon_view_ensure_cell_area (icon_view, NULL);
4058
4059   return icon_view->priv->cell_area;
4060 }
4061
4062 void
4063 _gtk_icon_view_set_cell_data (GtkIconView     *icon_view,
4064                               GtkIconViewItem *item)
4065 {
4066   GtkTreeIter iter;
4067   GtkTreePath *path;
4068
4069   path = gtk_tree_path_new_from_indices (item->index, -1);
4070   if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4071     return;
4072   gtk_tree_path_free (path);
4073
4074   gtk_cell_area_apply_attributes (icon_view->priv->cell_area, 
4075                                   icon_view->priv->model,
4076                                   &iter, FALSE, FALSE);
4077 }
4078
4079
4080
4081 /* Public API */
4082
4083
4084 /**
4085  * gtk_icon_view_new:
4086  * 
4087  * Creates a new #GtkIconView widget
4088  * 
4089  * Return value: A newly created #GtkIconView widget
4090  *
4091  * Since: 2.6
4092  **/
4093 GtkWidget *
4094 gtk_icon_view_new (void)
4095 {
4096   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4097 }
4098
4099 /**
4100  * gtk_icon_view_new_with_area:
4101  * @area: the #GtkCellArea to use to layout cells
4102  * 
4103  * Creates a new #GtkIconView widget using the
4104  * specified @area to layout cells inside the icons.
4105  * 
4106  * Return value: A newly created #GtkIconView widget
4107  *
4108  * Since: 3.0
4109  **/
4110 GtkWidget *
4111 gtk_icon_view_new_with_area (GtkCellArea *area)
4112 {
4113   return g_object_new (GTK_TYPE_ICON_VIEW, "cell-area", area, NULL);
4114 }
4115
4116 /**
4117  * gtk_icon_view_new_with_model:
4118  * @model: The model.
4119  * 
4120  * Creates a new #GtkIconView widget with the model @model.
4121  * 
4122  * Return value: A newly created #GtkIconView widget.
4123  *
4124  * Since: 2.6 
4125  **/
4126 GtkWidget *
4127 gtk_icon_view_new_with_model (GtkTreeModel *model)
4128 {
4129   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4130 }
4131
4132 /**
4133  * gtk_icon_view_convert_widget_to_bin_window_coords:
4134  * @icon_view: a #GtkIconView 
4135  * @wx: X coordinate relative to the widget
4136  * @wy: Y coordinate relative to the widget
4137  * @bx: (out): return location for bin_window X coordinate
4138  * @by: (out): return location for bin_window Y coordinate
4139  * 
4140  * Converts widget coordinates to coordinates for the bin_window,
4141  * as expected by e.g. gtk_icon_view_get_path_at_pos(). 
4142  *
4143  * Since: 2.12
4144  */
4145 void
4146 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4147                                                    gint         wx,
4148                                                    gint         wy, 
4149                                                    gint        *bx,
4150                                                    gint        *by)
4151 {
4152   gint x, y;
4153
4154   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4155
4156   if (icon_view->priv->bin_window) 
4157     gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4158   else
4159     x = y = 0;
4160  
4161   if (bx)
4162     *bx = wx - x;
4163   if (by)
4164     *by = wy - y;
4165 }
4166
4167 /**
4168  * gtk_icon_view_get_path_at_pos:
4169  * @icon_view: A #GtkIconView.
4170  * @x: The x position to be identified
4171  * @y: The y position to be identified
4172  * 
4173  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4174  * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4175  * the cell at the specified position. 
4176  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4177  * widget coordinates to bin_window coordinates.
4178  * 
4179  * Return value: The #GtkTreePath corresponding to the icon or %NULL
4180  * if no icon exists at that position.
4181  *
4182  * Since: 2.6 
4183  **/
4184 GtkTreePath *
4185 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4186                                gint         x,
4187                                gint         y)
4188 {
4189   GtkIconViewItem *item;
4190   GtkTreePath *path;
4191   
4192   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4193
4194   item = _gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4195
4196   if (!item)
4197     return NULL;
4198
4199   path = gtk_tree_path_new_from_indices (item->index, -1);
4200
4201   return path;
4202 }
4203
4204 /**
4205  * gtk_icon_view_get_item_at_pos:
4206  * @icon_view: A #GtkIconView.
4207  * @x: The x position to be identified
4208  * @y: The y position to be identified
4209  * @path: (out) (allow-none): Return location for the path, or %NULL
4210  * @cell: (out) (allow-none): Return location for the renderer
4211  *   responsible for the cell at (@x, @y), or %NULL
4212  * 
4213  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4214  * In contrast to gtk_icon_view_get_path_at_pos(), this function also 
4215  * obtains the cell at the specified position. The returned path should
4216  * be freed with gtk_tree_path_free().
4217  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4218  * widget coordinates to bin_window coordinates.
4219  * 
4220  * Return value: %TRUE if an item exists at the specified position
4221  *
4222  * Since: 2.8
4223  **/
4224 gboolean 
4225 gtk_icon_view_get_item_at_pos (GtkIconView      *icon_view,
4226                                gint              x,
4227                                gint              y,
4228                                GtkTreePath     **path,
4229                                GtkCellRenderer **cell)
4230 {
4231   GtkIconViewItem *item;
4232   GtkCellRenderer *renderer = NULL;
4233   
4234   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4235
4236   item = _gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &renderer);
4237
4238   if (path != NULL)
4239     {
4240       if (item != NULL)
4241         *path = gtk_tree_path_new_from_indices (item->index, -1);
4242       else
4243         *path = NULL;
4244     }
4245
4246   if (cell != NULL)
4247     *cell = renderer;
4248
4249   return (item != NULL);
4250 }
4251
4252 /**
4253  * gtk_icon_view_set_tooltip_item:
4254  * @icon_view: a #GtkIconView
4255  * @tooltip: a #GtkTooltip
4256  * @path: a #GtkTreePath
4257  * 
4258  * Sets the tip area of @tooltip to be the area covered by the item at @path.
4259  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4260  * See also gtk_tooltip_set_tip_area().
4261  * 
4262  * Since: 2.12
4263  */
4264 void 
4265 gtk_icon_view_set_tooltip_item (GtkIconView     *icon_view,
4266                                 GtkTooltip      *tooltip,
4267                                 GtkTreePath     *path)
4268 {
4269   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4270   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4271
4272   gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
4273 }
4274
4275 /**
4276  * gtk_icon_view_set_tooltip_cell:
4277  * @icon_view: a #GtkIconView
4278  * @tooltip: a #GtkTooltip
4279  * @path: a #GtkTreePath
4280  * @cell: (allow-none): a #GtkCellRenderer or %NULL
4281  *
4282  * Sets the tip area of @tooltip to the area which @cell occupies in
4283  * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
4284  *
4285  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4286  *
4287  * Since: 2.12
4288  */
4289 void
4290 gtk_icon_view_set_tooltip_cell (GtkIconView     *icon_view,
4291                                 GtkTooltip      *tooltip,
4292                                 GtkTreePath     *path,
4293                                 GtkCellRenderer *cell)
4294 {
4295   GdkRectangle rect;
4296   GtkIconViewItem *item = NULL;
4297   gint x, y;
4298  
4299   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4300   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4301   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
4302
4303   if (gtk_tree_path_get_depth (path) > 0)
4304     item = g_list_nth_data (icon_view->priv->items,
4305                             gtk_tree_path_get_indices(path)[0]);
4306  
4307   if (!item)
4308     return;
4309
4310   if (cell)
4311     {
4312       GtkCellAreaContext *context;
4313
4314       context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
4315       _gtk_icon_view_set_cell_data (icon_view, item);
4316       gtk_cell_area_get_cell_allocation (icon_view->priv->cell_area, context,
4317                                          GTK_WIDGET (icon_view),
4318                                          cell, &item->cell_area, &rect);
4319     }
4320   else
4321     {
4322       rect.x = item->cell_area.x - icon_view->priv->item_padding;
4323       rect.y = item->cell_area.y - icon_view->priv->item_padding;
4324       rect.width  = item->cell_area.width  + icon_view->priv->item_padding * 2;
4325       rect.height = item->cell_area.height + icon_view->priv->item_padding * 2;
4326     }
4327   
4328   if (icon_view->priv->bin_window)
4329     {
4330       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4331       rect.x += x;
4332       rect.y += y; 
4333     }
4334
4335   gtk_tooltip_set_tip_area (tooltip, &rect); 
4336 }
4337
4338
4339 /**
4340  * gtk_icon_view_get_tooltip_context:
4341  * @icon_view: an #GtkIconView
4342  * @x: (inout): the x coordinate (relative to widget coordinates)
4343  * @y: (inout): the y coordinate (relative to widget coordinates)
4344  * @keyboard_tip: whether this is a keyboard tooltip or not
4345  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
4346  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
4347  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
4348  *
4349  * This function is supposed to be used in a #GtkWidget::query-tooltip
4350  * signal handler for #GtkIconView.  The @x, @y and @keyboard_tip values
4351  * which are received in the signal handler, should be passed to this
4352  * function without modification.
4353  *
4354  * The return value indicates whether there is an icon view item at the given
4355  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
4356  * tooltips the item returned will be the cursor item. When %TRUE, then any of
4357  * @model, @path and @iter which have been provided will be set to point to
4358  * that row and the corresponding model. @x and @y will always be converted
4359  * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
4360  *
4361  * Return value: whether or not the given tooltip context points to a item
4362  *
4363  * Since: 2.12
4364  */
4365 gboolean
4366 gtk_icon_view_get_tooltip_context (GtkIconView   *icon_view,
4367                                    gint          *x,
4368                                    gint          *y,
4369                                    gboolean       keyboard_tip,
4370                                    GtkTreeModel **model,
4371                                    GtkTreePath  **path,
4372                                    GtkTreeIter   *iter)
4373 {
4374   GtkTreePath *tmppath = NULL;
4375
4376   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4377   g_return_val_if_fail (x != NULL, FALSE);
4378   g_return_val_if_fail (y != NULL, FALSE);
4379
4380   if (keyboard_tip)
4381     {
4382       gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
4383
4384       if (!tmppath)
4385         return FALSE;
4386     }
4387   else
4388     {
4389       gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
4390                                                          x, y);
4391
4392       if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
4393         return FALSE;
4394     }
4395
4396   if (model)
4397     *model = gtk_icon_view_get_model (icon_view);
4398
4399   if (iter)
4400     gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
4401                              iter, tmppath);
4402
4403   if (path)
4404     *path = tmppath;
4405   else
4406     gtk_tree_path_free (tmppath);
4407
4408   return TRUE;
4409 }
4410
4411 static gboolean
4412 gtk_icon_view_set_tooltip_query_cb (GtkWidget  *widget,
4413                                     gint        x,
4414                                     gint        y,
4415                                     gboolean    keyboard_tip,
4416                                     GtkTooltip *tooltip,
4417                                     gpointer    data)
4418 {
4419   gchar *str;
4420   GtkTreeIter iter;
4421   GtkTreePath *path;
4422   GtkTreeModel *model;
4423   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
4424
4425   if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
4426                                           &x, &y,
4427                                           keyboard_tip,
4428                                           &model, &path, &iter))
4429     return FALSE;
4430
4431   gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
4432
4433   if (!str)
4434     {
4435       gtk_tree_path_free (path);
4436       return FALSE;
4437     }
4438
4439   gtk_tooltip_set_markup (tooltip, str);
4440   gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
4441
4442   gtk_tree_path_free (path);
4443   g_free (str);
4444
4445   return TRUE;
4446 }
4447
4448
4449 /**
4450  * gtk_icon_view_set_tooltip_column:
4451  * @icon_view: a #GtkIconView
4452  * @column: an integer, which is a valid column number for @icon_view's model
4453  *
4454  * If you only plan to have simple (text-only) tooltips on full items, you
4455  * can use this function to have #GtkIconView handle these automatically
4456  * for you. @column should be set to the column in @icon_view's model
4457  * containing the tooltip texts, or -1 to disable this feature.
4458  *
4459  * When enabled, #GtkWidget:has-tooltip will be set to %TRUE and
4460  * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
4461  *
4462  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
4463  * so &amp;, &lt;, etc have to be escaped in the text.
4464  *
4465  * Since: 2.12
4466  */
4467 void
4468 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
4469                                   gint         column)
4470 {
4471   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4472
4473   if (column == icon_view->priv->tooltip_column)
4474     return;
4475
4476   if (column == -1)
4477     {
4478       g_signal_handlers_disconnect_by_func (icon_view,
4479                                             gtk_icon_view_set_tooltip_query_cb,
4480                                             NULL);
4481       gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
4482     }
4483   else
4484     {
4485       if (icon_view->priv->tooltip_column == -1)
4486         {
4487           g_signal_connect (icon_view, "query-tooltip",
4488                             G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
4489           gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
4490         }
4491     }
4492
4493   icon_view->priv->tooltip_column = column;
4494   g_object_notify (G_OBJECT (icon_view), "tooltip-column");
4495 }
4496
4497 /**
4498  * gtk_icon_view_get_tooltip_column:
4499  * @icon_view: a #GtkIconView
4500  *
4501  * Returns the column of @icon_view's model which is being used for
4502  * displaying tooltips on @icon_view's rows.
4503  *
4504  * Return value: the index of the tooltip column that is currently being
4505  * used, or -1 if this is disabled.
4506  *
4507  * Since: 2.12
4508  */
4509 gint
4510 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
4511 {
4512   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
4513
4514   return icon_view->priv->tooltip_column;
4515 }
4516
4517 /**
4518  * gtk_icon_view_get_visible_range:
4519  * @icon_view: A #GtkIconView
4520  * @start_path: (out) (allow-none): Return location for start of region,
4521  *              or %NULL
4522  * @end_path: (out) (allow-none): Return location for end of region, or %NULL
4523  * 
4524  * Sets @start_path and @end_path to be the first and last visible path. 
4525  * Note that there may be invisible paths in between.
4526  * 
4527  * Both paths should be freed with gtk_tree_path_free() after use.
4528  * 
4529  * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4530  *
4531  * Since: 2.8
4532  **/
4533 gboolean
4534 gtk_icon_view_get_visible_range (GtkIconView  *icon_view,
4535                                  GtkTreePath **start_path,
4536                                  GtkTreePath **end_path)
4537 {
4538   gint start_index = -1;
4539   gint end_index = -1;
4540   GList *icons;
4541
4542   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4543
4544   if (icon_view->priv->hadjustment == NULL ||
4545       icon_view->priv->vadjustment == NULL)
4546     return FALSE;
4547
4548   if (start_path == NULL && end_path == NULL)
4549     return FALSE;
4550   
4551   for (icons = icon_view->priv->items; icons; icons = icons->next) 
4552     {
4553       GtkIconViewItem *item = icons->data;
4554       GdkRectangle    *item_area = &item->cell_area;
4555
4556       if ((item_area->x + item_area->width >= (int)gtk_adjustment_get_value (icon_view->priv->hadjustment)) &&
4557           (item_area->y + item_area->height >= (int)gtk_adjustment_get_value (icon_view->priv->vadjustment)) &&
4558           (item_area->x <= 
4559            (int) (gtk_adjustment_get_value (icon_view->priv->hadjustment) + 
4560                   gtk_adjustment_get_page_size (icon_view->priv->hadjustment))) &&
4561           (item_area->y <= 
4562            (int) (gtk_adjustment_get_value (icon_view->priv->vadjustment) + 
4563                   gtk_adjustment_get_page_size (icon_view->priv->vadjustment))))
4564         {
4565           if (start_index == -1)
4566             start_index = item->index;
4567           end_index = item->index;
4568         }
4569     }
4570
4571   if (start_path && start_index != -1)
4572     *start_path = gtk_tree_path_new_from_indices (start_index, -1);
4573   if (end_path && end_index != -1)
4574     *end_path = gtk_tree_path_new_from_indices (end_index, -1);
4575   
4576   return start_index != -1;
4577 }
4578
4579 /**
4580  * gtk_icon_view_selected_foreach:
4581  * @icon_view: A #GtkIconView.
4582  * @func: (scope call): The function to call for each selected icon.
4583  * @data: User data to pass to the function.
4584  * 
4585  * Calls a function for each selected icon. Note that the model or
4586  * selection cannot be modified from within this function.
4587  *
4588  * Since: 2.6 
4589  **/
4590 void
4591 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
4592                                 GtkIconViewForeachFunc func,
4593                                 gpointer               data)
4594 {
4595   GList *list;
4596   
4597   for (list = icon_view->priv->items; list; list = list->next)
4598     {
4599       GtkIconViewItem *item = list->data;
4600       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
4601
4602       if (item->selected)
4603         (* func) (icon_view, path, data);
4604
4605       gtk_tree_path_free (path);
4606     }
4607 }
4608
4609 /**
4610  * gtk_icon_view_set_selection_mode:
4611  * @icon_view: A #GtkIconView.
4612  * @mode: The selection mode
4613  * 
4614  * Sets the selection mode of the @icon_view.
4615  *
4616  * Since: 2.6 
4617  **/
4618 void
4619 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
4620                                   GtkSelectionMode  mode)
4621 {
4622   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4623
4624   if (mode == icon_view->priv->selection_mode)
4625     return;
4626   
4627   if (mode == GTK_SELECTION_NONE ||
4628       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
4629     gtk_icon_view_unselect_all (icon_view);
4630   
4631   icon_view->priv->selection_mode = mode;
4632
4633   g_object_notify (G_OBJECT (icon_view), "selection-mode");
4634 }
4635
4636 /**
4637  * gtk_icon_view_get_selection_mode:
4638  * @icon_view: A #GtkIconView.
4639  * 
4640  * Gets the selection mode of the @icon_view.
4641  *
4642  * Return value: the current selection mode
4643  *
4644  * Since: 2.6 
4645  **/
4646 GtkSelectionMode
4647 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
4648 {
4649   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
4650
4651   return icon_view->priv->selection_mode;
4652 }
4653
4654 /**
4655  * gtk_icon_view_set_model:
4656  * @icon_view: A #GtkIconView.
4657  * @model: (allow-none): The model.
4658  *
4659  * Sets the model for a #GtkIconView.
4660  * If the @icon_view already has a model set, it will remove
4661  * it before setting the new model.  If @model is %NULL, then
4662  * it will unset the old model.
4663  *
4664  * Since: 2.6 
4665  **/
4666 void
4667 gtk_icon_view_set_model (GtkIconView *icon_view,
4668                          GtkTreeModel *model)
4669 {
4670   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4671   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
4672   
4673   if (icon_view->priv->model == model)
4674     return;
4675
4676   if (icon_view->priv->scroll_to_path)
4677     {
4678       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4679       icon_view->priv->scroll_to_path = NULL;
4680     }
4681
4682   /* The area can be NULL while disposing */
4683   if (icon_view->priv->cell_area)
4684     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4685
4686   if (model)
4687     {
4688       GType column_type;
4689
4690       if (icon_view->priv->pixbuf_column != -1)
4691         {
4692           column_type = gtk_tree_model_get_column_type (model,
4693                                                         icon_view->priv->pixbuf_column);          
4694
4695           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
4696         }
4697
4698       if (icon_view->priv->text_column != -1)
4699         {
4700           column_type = gtk_tree_model_get_column_type (model,
4701                                                         icon_view->priv->text_column);    
4702
4703           g_return_if_fail (column_type == G_TYPE_STRING);
4704         }
4705
4706       if (icon_view->priv->markup_column != -1)
4707         {
4708           column_type = gtk_tree_model_get_column_type (model,
4709                                                         icon_view->priv->markup_column);          
4710
4711           g_return_if_fail (column_type == G_TYPE_STRING);
4712         }
4713       
4714     }
4715   
4716   if (icon_view->priv->model)
4717     {
4718       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4719                                             gtk_icon_view_row_changed,
4720                                             icon_view);
4721       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4722                                             gtk_icon_view_row_inserted,
4723                                             icon_view);
4724       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4725                                             gtk_icon_view_row_deleted,
4726                                             icon_view);
4727       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4728                                             gtk_icon_view_rows_reordered,
4729                                             icon_view);
4730
4731       g_object_unref (icon_view->priv->model);
4732       
4733       g_list_free_full (icon_view->priv->items, (GDestroyNotify) gtk_icon_view_item_free);
4734       icon_view->priv->items = NULL;
4735       icon_view->priv->anchor_item = NULL;
4736       icon_view->priv->cursor_item = NULL;
4737       icon_view->priv->last_single_clicked = NULL;
4738       icon_view->priv->last_prelight = NULL;
4739       icon_view->priv->width = 0;
4740       icon_view->priv->height = 0;
4741     }
4742
4743   icon_view->priv->model = model;
4744
4745   if (icon_view->priv->model)
4746     {
4747       g_object_ref (icon_view->priv->model);
4748       g_signal_connect (icon_view->priv->model,
4749                         "row-changed",
4750                         G_CALLBACK (gtk_icon_view_row_changed),
4751                         icon_view);
4752       g_signal_connect (icon_view->priv->model,
4753                         "row-inserted",
4754                         G_CALLBACK (gtk_icon_view_row_inserted),
4755                         icon_view);
4756       g_signal_connect (icon_view->priv->model,
4757                         "row-deleted",
4758                         G_CALLBACK (gtk_icon_view_row_deleted),
4759                         icon_view);
4760       g_signal_connect (icon_view->priv->model,
4761                         "rows-reordered",
4762                         G_CALLBACK (gtk_icon_view_rows_reordered),
4763                         icon_view);
4764
4765       gtk_icon_view_build_items (icon_view);
4766
4767       gtk_icon_view_layout (icon_view);
4768     }
4769
4770   g_object_notify (G_OBJECT (icon_view), "model");  
4771
4772   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
4773     gtk_widget_queue_resize (GTK_WIDGET (icon_view));
4774 }
4775
4776 /**
4777  * gtk_icon_view_get_model:
4778  * @icon_view: a #GtkIconView
4779  *
4780  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
4781  * model is unset.
4782  *
4783  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is
4784  *     currently being used.
4785  *
4786  * Since: 2.6 
4787  **/
4788 GtkTreeModel *
4789 gtk_icon_view_get_model (GtkIconView *icon_view)
4790 {
4791   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4792
4793   return icon_view->priv->model;
4794 }
4795
4796 static void
4797 update_text_cell (GtkIconView *icon_view)
4798 {
4799   if (!icon_view->priv->cell_area)
4800     return;
4801
4802   if (icon_view->priv->text_column == -1 &&
4803       icon_view->priv->markup_column == -1)
4804     {
4805       if (icon_view->priv->text_cell != NULL)
4806         {
4807           gtk_cell_area_remove (icon_view->priv->cell_area, 
4808                                 icon_view->priv->text_cell);
4809           icon_view->priv->text_cell = NULL;
4810         }
4811     }
4812   else 
4813     {
4814       if (icon_view->priv->text_cell == NULL)
4815         {
4816           icon_view->priv->text_cell = gtk_cell_renderer_text_new ();
4817
4818           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), icon_view->priv->text_cell, FALSE);
4819         }
4820
4821       if (icon_view->priv->markup_column != -1)
4822         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4823                                         icon_view->priv->text_cell, 
4824                                         "markup", icon_view->priv->markup_column, 
4825                                         NULL);
4826       else
4827         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4828                                         icon_view->priv->text_cell, 
4829                                         "text", icon_view->priv->text_column, 
4830                                         NULL);
4831
4832       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4833         g_object_set (icon_view->priv->text_cell,
4834                       "alignment", PANGO_ALIGN_CENTER,
4835                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
4836                       "xalign", 0.5,
4837                       "yalign", 0.0,
4838                       NULL);
4839       else
4840         g_object_set (icon_view->priv->text_cell,
4841                       "alignment", PANGO_ALIGN_LEFT,
4842                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
4843                       "xalign", 0.0,
4844                       "yalign", 0.5,
4845                       NULL);
4846     }
4847 }
4848
4849 static void
4850 update_pixbuf_cell (GtkIconView *icon_view)
4851 {
4852   if (!icon_view->priv->cell_area)
4853     return;
4854
4855   if (icon_view->priv->pixbuf_column == -1)
4856     {
4857       if (icon_view->priv->pixbuf_cell != NULL)
4858         {
4859           gtk_cell_area_remove (icon_view->priv->cell_area, 
4860                                 icon_view->priv->pixbuf_cell);
4861
4862           icon_view->priv->pixbuf_cell = NULL;
4863         }
4864     }
4865   else 
4866     {
4867       if (icon_view->priv->pixbuf_cell == NULL)
4868         {
4869           icon_view->priv->pixbuf_cell = gtk_cell_renderer_pixbuf_new ();
4870           
4871           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), icon_view->priv->pixbuf_cell, FALSE);
4872         }
4873       
4874       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4875                                       icon_view->priv->pixbuf_cell, 
4876                                       "pixbuf", icon_view->priv->pixbuf_column, 
4877                                       NULL);
4878
4879       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4880         g_object_set (icon_view->priv->pixbuf_cell,
4881                       "xalign", 0.5,
4882                       "yalign", 1.0,
4883                       NULL);
4884       else
4885         g_object_set (icon_view->priv->pixbuf_cell,
4886                       "xalign", 0.0,
4887                       "yalign", 0.0,
4888                       NULL);
4889     }
4890 }
4891
4892 /**
4893  * gtk_icon_view_set_text_column:
4894  * @icon_view: A #GtkIconView.
4895  * @column: A column in the currently used model, or -1 to display no text
4896  * 
4897  * Sets the column with text for @icon_view to be @column. The text
4898  * column must be of type #G_TYPE_STRING.
4899  *
4900  * Since: 2.6 
4901  **/
4902 void
4903 gtk_icon_view_set_text_column (GtkIconView *icon_view,
4904                                gint          column)
4905 {
4906   if (column == icon_view->priv->text_column)
4907     return;
4908   
4909   if (column == -1)
4910     icon_view->priv->text_column = -1;
4911   else
4912     {
4913       if (icon_view->priv->model != NULL)
4914         {
4915           GType column_type;
4916           
4917           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
4918
4919           g_return_if_fail (column_type == G_TYPE_STRING);
4920         }
4921       
4922       icon_view->priv->text_column = column;
4923     }
4924
4925   if (icon_view->priv->cell_area)
4926     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4927
4928   update_text_cell (icon_view);
4929
4930   gtk_icon_view_invalidate_sizes (icon_view);
4931   
4932   g_object_notify (G_OBJECT (icon_view), "text-column");
4933 }
4934
4935 /**
4936  * gtk_icon_view_get_text_column:
4937  * @icon_view: A #GtkIconView.
4938  *
4939  * Returns the column with text for @icon_view.
4940  *
4941  * Returns: the text column, or -1 if it's unset.
4942  *
4943  * Since: 2.6
4944  */
4945 gint
4946 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
4947 {
4948   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
4949
4950   return icon_view->priv->text_column;
4951 }
4952
4953 /**
4954  * gtk_icon_view_set_markup_column:
4955  * @icon_view: A #GtkIconView.
4956  * @column: A column in the currently used model, or -1 to display no text
4957  * 
4958  * Sets the column with markup information for @icon_view to be
4959  * @column. The markup column must be of type #G_TYPE_STRING.
4960  * If the markup column is set to something, it overrides
4961  * the text column set by gtk_icon_view_set_text_column().
4962  *
4963  * Since: 2.6
4964  **/
4965 void
4966 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
4967                                  gint         column)
4968 {
4969   if (column == icon_view->priv->markup_column)
4970     return;
4971   
4972   if (column == -1)
4973     icon_view->priv->markup_column = -1;
4974   else
4975     {
4976       if (icon_view->priv->model != NULL)
4977         {
4978           GType column_type;
4979           
4980           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
4981
4982           g_return_if_fail (column_type == G_TYPE_STRING);
4983         }
4984       
4985       icon_view->priv->markup_column = column;
4986     }
4987
4988   if (icon_view->priv->cell_area)
4989     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4990
4991   update_text_cell (icon_view);
4992
4993   gtk_icon_view_invalidate_sizes (icon_view);
4994   
4995   g_object_notify (G_OBJECT (icon_view), "markup-column");
4996 }
4997
4998 /**
4999  * gtk_icon_view_get_markup_column:
5000  * @icon_view: A #GtkIconView.
5001  *
5002  * Returns the column with markup text for @icon_view.
5003  *
5004  * Returns: the markup column, or -1 if it's unset.
5005  *
5006  * Since: 2.6
5007  */
5008 gint
5009 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
5010 {
5011   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5012
5013   return icon_view->priv->markup_column;
5014 }
5015
5016 /**
5017  * gtk_icon_view_set_pixbuf_column:
5018  * @icon_view: A #GtkIconView.
5019  * @column: A column in the currently used model, or -1 to disable
5020  * 
5021  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5022  * column must be of type #GDK_TYPE_PIXBUF
5023  *
5024  * Since: 2.6 
5025  **/
5026 void
5027 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5028                                  gint         column)
5029 {
5030   if (column == icon_view->priv->pixbuf_column)
5031     return;
5032   
5033   if (column == -1)
5034     icon_view->priv->pixbuf_column = -1;
5035   else
5036     {
5037       if (icon_view->priv->model != NULL)
5038         {
5039           GType column_type;
5040           
5041           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5042
5043           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5044         }
5045       
5046       icon_view->priv->pixbuf_column = column;
5047     }
5048
5049   if (icon_view->priv->cell_area)
5050     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5051
5052   update_pixbuf_cell (icon_view);
5053
5054   gtk_icon_view_invalidate_sizes (icon_view);
5055   
5056   g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5057   
5058 }
5059
5060 /**
5061  * gtk_icon_view_get_pixbuf_column:
5062  * @icon_view: A #GtkIconView.
5063  *
5064  * Returns the column with pixbufs for @icon_view.
5065  *
5066  * Returns: the pixbuf column, or -1 if it's unset.
5067  *
5068  * Since: 2.6
5069  */
5070 gint
5071 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
5072 {
5073   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5074
5075   return icon_view->priv->pixbuf_column;
5076 }
5077
5078 /**
5079  * gtk_icon_view_select_path:
5080  * @icon_view: A #GtkIconView.
5081  * @path: The #GtkTreePath to be selected.
5082  * 
5083  * Selects the row at @path.
5084  *
5085  * Since: 2.6
5086  **/
5087 void
5088 gtk_icon_view_select_path (GtkIconView *icon_view,
5089                            GtkTreePath *path)
5090 {
5091   GtkIconViewItem *item = NULL;
5092
5093   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5094   g_return_if_fail (icon_view->priv->model != NULL);
5095   g_return_if_fail (path != NULL);
5096
5097   if (gtk_tree_path_get_depth (path) > 0)
5098     item = g_list_nth_data (icon_view->priv->items,
5099                             gtk_tree_path_get_indices(path)[0]);
5100
5101   if (item)
5102     _gtk_icon_view_select_item (icon_view, item);
5103 }
5104
5105 /**
5106  * gtk_icon_view_unselect_path:
5107  * @icon_view: A #GtkIconView.
5108  * @path: The #GtkTreePath to be unselected.
5109  * 
5110  * Unselects the row at @path.
5111  *
5112  * Since: 2.6
5113  **/
5114 void
5115 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5116                              GtkTreePath *path)
5117 {
5118   GtkIconViewItem *item;
5119   
5120   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5121   g_return_if_fail (icon_view->priv->model != NULL);
5122   g_return_if_fail (path != NULL);
5123
5124   item = g_list_nth_data (icon_view->priv->items,
5125                           gtk_tree_path_get_indices(path)[0]);
5126
5127   if (!item)
5128     return;
5129   
5130   _gtk_icon_view_unselect_item (icon_view, item);
5131 }
5132
5133 /**
5134  * gtk_icon_view_get_selected_items:
5135  * @icon_view: A #GtkIconView.
5136  *
5137  * Creates a list of paths of all selected items. Additionally, if you are
5138  * planning on modifying the model after calling this function, you may
5139  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5140  * To do this, you can use gtk_tree_row_reference_new().
5141  *
5142  * To free the return value, use:
5143  * |[
5144  * g_list_free_full (list, (GDestroyNotify) gtk_tree_patch_free);
5145  * ]|
5146  *
5147  * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
5148  *
5149  * Since: 2.6
5150  **/
5151 GList *
5152 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5153 {
5154   GList *list;
5155   GList *selected = NULL;
5156   
5157   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5158   
5159   for (list = icon_view->priv->items; list != NULL; list = list->next)
5160     {
5161       GtkIconViewItem *item = list->data;
5162
5163       if (item->selected)
5164         {
5165           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5166
5167           selected = g_list_prepend (selected, path);
5168         }
5169     }
5170
5171   return selected;
5172 }
5173
5174 /**
5175  * gtk_icon_view_select_all:
5176  * @icon_view: A #GtkIconView.
5177  * 
5178  * Selects all the icons. @icon_view must has its selection mode set
5179  * to #GTK_SELECTION_MULTIPLE.
5180  *
5181  * Since: 2.6
5182  **/
5183 void
5184 gtk_icon_view_select_all (GtkIconView *icon_view)
5185 {
5186   GList *items;
5187   gboolean dirty = FALSE;
5188   
5189   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5190
5191   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5192     return;
5193
5194   for (items = icon_view->priv->items; items; items = items->next)
5195     {
5196       GtkIconViewItem *item = items->data;
5197       
5198       if (!item->selected)
5199         {
5200           dirty = TRUE;
5201           item->selected = TRUE;
5202           gtk_icon_view_queue_draw_item (icon_view, item);
5203         }
5204     }
5205
5206   if (dirty)
5207     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5208 }
5209
5210 /**
5211  * gtk_icon_view_unselect_all:
5212  * @icon_view: A #GtkIconView.
5213  * 
5214  * Unselects all the icons.
5215  *
5216  * Since: 2.6
5217  **/
5218 void
5219 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5220 {
5221   gboolean dirty = FALSE;
5222   
5223   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5224
5225   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5226     return;
5227
5228   dirty = gtk_icon_view_unselect_all_internal (icon_view);
5229
5230   if (dirty)
5231     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5232 }
5233
5234 /**
5235  * gtk_icon_view_path_is_selected:
5236  * @icon_view: A #GtkIconView.
5237  * @path: A #GtkTreePath to check selection on.
5238  * 
5239  * Returns %TRUE if the icon pointed to by @path is currently
5240  * selected. If @path does not point to a valid location, %FALSE is returned.
5241  * 
5242  * Return value: %TRUE if @path is selected.
5243  *
5244  * Since: 2.6
5245  **/
5246 gboolean
5247 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5248                                 GtkTreePath *path)
5249 {
5250   GtkIconViewItem *item;
5251   
5252   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5253   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5254   g_return_val_if_fail (path != NULL, FALSE);
5255   
5256   item = g_list_nth_data (icon_view->priv->items,
5257                           gtk_tree_path_get_indices(path)[0]);
5258
5259   if (!item)
5260     return FALSE;
5261   
5262   return item->selected;
5263 }
5264
5265 /**
5266  * gtk_icon_view_get_item_row:
5267  * @icon_view: a #GtkIconView
5268  * @path: the #GtkTreePath of the item
5269  *
5270  * Gets the row in which the item @path is currently
5271  * displayed. Row numbers start at 0.
5272  *
5273  * Returns: The row in which the item is displayed
5274  *
5275  * Since: 2.22
5276  */
5277 gint
5278 gtk_icon_view_get_item_row (GtkIconView *icon_view,
5279                             GtkTreePath *path)
5280 {
5281   GtkIconViewItem *item;
5282
5283   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5284   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5285   g_return_val_if_fail (path != NULL, -1);
5286
5287   item = g_list_nth_data (icon_view->priv->items,
5288                           gtk_tree_path_get_indices(path)[0]);
5289
5290   if (!item)
5291     return -1;
5292
5293   return item->row;
5294 }
5295
5296 /**
5297  * gtk_icon_view_get_item_column:
5298  * @icon_view: a #GtkIconView
5299  * @path: the #GtkTreePath of the item
5300  *
5301  * Gets the column in which the item @path is currently
5302  * displayed. Column numbers start at 0.
5303  *
5304  * Returns: The column in which the item is displayed
5305  *
5306  * Since: 2.22
5307  */
5308 gint
5309 gtk_icon_view_get_item_column (GtkIconView *icon_view,
5310                                GtkTreePath *path)
5311 {
5312   GtkIconViewItem *item;
5313
5314   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5315   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5316   g_return_val_if_fail (path != NULL, -1);
5317
5318   item = g_list_nth_data (icon_view->priv->items,
5319                           gtk_tree_path_get_indices(path)[0]);
5320
5321   if (!item)
5322     return -1;
5323
5324   return item->col;
5325 }
5326
5327 /**
5328  * gtk_icon_view_item_activated:
5329  * @icon_view: A #GtkIconView
5330  * @path: The #GtkTreePath to be activated
5331  * 
5332  * Activates the item determined by @path.
5333  *
5334  * Since: 2.6
5335  **/
5336 void
5337 gtk_icon_view_item_activated (GtkIconView      *icon_view,
5338                               GtkTreePath      *path)
5339 {
5340   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5341   g_return_if_fail (path != NULL);
5342   
5343   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5344 }
5345
5346 /**
5347  * gtk_icon_view_set_item_orientation:
5348  * @icon_view: a #GtkIconView
5349  * @orientation: the relative position of texts and icons 
5350  * 
5351  * Sets the ::item-orientation property which determines whether the labels 
5352  * are drawn beside the icons instead of below.
5353  *
5354  * Since: 2.6
5355  **/
5356 void 
5357 gtk_icon_view_set_item_orientation (GtkIconView    *icon_view,
5358                                     GtkOrientation  orientation)
5359 {
5360   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5361
5362   if (icon_view->priv->item_orientation != orientation)
5363     {
5364       icon_view->priv->item_orientation = orientation;
5365
5366       if (icon_view->priv->cell_area)
5367         {
5368           if (GTK_IS_ORIENTABLE (icon_view->priv->cell_area))
5369             gtk_orientable_set_orientation (GTK_ORIENTABLE (icon_view->priv->cell_area), 
5370                                             icon_view->priv->item_orientation);
5371
5372           gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5373         }
5374
5375       gtk_icon_view_invalidate_sizes (icon_view);
5376
5377       update_text_cell (icon_view);
5378       update_pixbuf_cell (icon_view);
5379       
5380       g_object_notify (G_OBJECT (icon_view), "item-orientation");
5381     }
5382 }
5383
5384 /**
5385  * gtk_icon_view_get_item_orientation:
5386  * @icon_view: a #GtkIconView
5387  * 
5388  * Returns the value of the ::item-orientation property which determines 
5389  * whether the labels are drawn beside the icons instead of below. 
5390  * 
5391  * Return value: the relative position of texts and icons 
5392  *
5393  * Since: 2.6
5394  **/
5395 GtkOrientation
5396 gtk_icon_view_get_item_orientation (GtkIconView *icon_view)
5397 {
5398   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
5399                         GTK_ORIENTATION_VERTICAL);
5400
5401   return icon_view->priv->item_orientation;
5402 }
5403
5404 /**
5405  * gtk_icon_view_set_columns:
5406  * @icon_view: a #GtkIconView
5407  * @columns: the number of columns
5408  * 
5409  * Sets the ::columns property which determines in how
5410  * many columns the icons are arranged. If @columns is
5411  * -1, the number of columns will be chosen automatically 
5412  * to fill the available area. 
5413  *
5414  * Since: 2.6
5415  */
5416 void 
5417 gtk_icon_view_set_columns (GtkIconView *icon_view,
5418                            gint         columns)
5419 {
5420   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5421   
5422   if (icon_view->priv->columns != columns)
5423     {
5424       icon_view->priv->columns = columns;
5425
5426       if (icon_view->priv->cell_area)
5427         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5428
5429       gtk_icon_view_queue_layout (icon_view);
5430       
5431       g_object_notify (G_OBJECT (icon_view), "columns");
5432     }  
5433 }
5434
5435 /**
5436  * gtk_icon_view_get_columns:
5437  * @icon_view: a #GtkIconView
5438  * 
5439  * Returns the value of the ::columns property.
5440  * 
5441  * Return value: the number of columns, or -1
5442  *
5443  * Since: 2.6
5444  */
5445 gint
5446 gtk_icon_view_get_columns (GtkIconView *icon_view)
5447 {
5448   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5449
5450   return icon_view->priv->columns;
5451 }
5452
5453 /**
5454  * gtk_icon_view_set_item_width:
5455  * @icon_view: a #GtkIconView
5456  * @item_width: the width for each item
5457  * 
5458  * Sets the ::item-width property which specifies the width 
5459  * to use for each item. If it is set to -1, the icon view will 
5460  * automatically determine a suitable item size.
5461  *
5462  * Since: 2.6
5463  */
5464 void 
5465 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5466                               gint         item_width)
5467 {
5468   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5469   
5470   if (icon_view->priv->item_width != item_width)
5471     {
5472       icon_view->priv->item_width = item_width;
5473       
5474       if (icon_view->priv->cell_area)
5475         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5476
5477       gtk_icon_view_invalidate_sizes (icon_view);
5478       
5479       update_text_cell (icon_view);
5480
5481       g_object_notify (G_OBJECT (icon_view), "item-width");
5482     }  
5483 }
5484
5485 /**
5486  * gtk_icon_view_get_item_width:
5487  * @icon_view: a #GtkIconView
5488  * 
5489  * Returns the value of the ::item-width property.
5490  * 
5491  * Return value: the width of a single item, or -1
5492  *
5493  * Since: 2.6
5494  */
5495 gint
5496 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5497 {
5498   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5499
5500   return icon_view->priv->item_width;
5501 }
5502
5503
5504 /**
5505  * gtk_icon_view_set_spacing:
5506  * @icon_view: a #GtkIconView
5507  * @spacing: the spacing
5508  * 
5509  * Sets the ::spacing property which specifies the space 
5510  * which is inserted between the cells (i.e. the icon and 
5511  * the text) of an item.
5512  *
5513  * Since: 2.6
5514  */
5515 void 
5516 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5517                            gint         spacing)
5518 {
5519   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5520   
5521   if (icon_view->priv->spacing != spacing)
5522     {
5523       icon_view->priv->spacing = spacing;
5524
5525       if (icon_view->priv->cell_area)
5526         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5527
5528       gtk_icon_view_invalidate_sizes (icon_view);
5529
5530       g_object_notify (G_OBJECT (icon_view), "spacing");
5531     }  
5532 }
5533
5534 /**
5535  * gtk_icon_view_get_spacing:
5536  * @icon_view: a #GtkIconView
5537  * 
5538  * Returns the value of the ::spacing property.
5539  * 
5540  * Return value: the space between cells 
5541  *
5542  * Since: 2.6
5543  */
5544 gint
5545 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5546 {
5547   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5548
5549   return icon_view->priv->spacing;
5550 }
5551
5552 /**
5553  * gtk_icon_view_set_row_spacing:
5554  * @icon_view: a #GtkIconView
5555  * @row_spacing: the row spacing
5556  * 
5557  * Sets the ::row-spacing property which specifies the space 
5558  * which is inserted between the rows of the icon view.
5559  *
5560  * Since: 2.6
5561  */
5562 void 
5563 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5564                                gint         row_spacing)
5565 {
5566   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5567   
5568   if (icon_view->priv->row_spacing != row_spacing)
5569     {
5570       icon_view->priv->row_spacing = row_spacing;
5571
5572       if (icon_view->priv->cell_area)
5573         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5574
5575       gtk_icon_view_invalidate_sizes (icon_view);
5576
5577       g_object_notify (G_OBJECT (icon_view), "row-spacing");
5578     }  
5579 }
5580
5581 /**
5582  * gtk_icon_view_get_row_spacing:
5583  * @icon_view: a #GtkIconView
5584  * 
5585  * Returns the value of the ::row-spacing property.
5586  * 
5587  * Return value: the space between rows
5588  *
5589  * Since: 2.6
5590  */
5591 gint
5592 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5593 {
5594   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5595
5596   return icon_view->priv->row_spacing;
5597 }
5598
5599 /**
5600  * gtk_icon_view_set_column_spacing:
5601  * @icon_view: a #GtkIconView
5602  * @column_spacing: the column spacing
5603  * 
5604  * Sets the ::column-spacing property which specifies the space 
5605  * which is inserted between the columns of the icon view.
5606  *
5607  * Since: 2.6
5608  */
5609 void 
5610 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
5611                                   gint         column_spacing)
5612 {
5613   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5614   
5615   if (icon_view->priv->column_spacing != column_spacing)
5616     {
5617       icon_view->priv->column_spacing = column_spacing;
5618
5619       if (icon_view->priv->cell_area)
5620         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5621
5622       gtk_icon_view_invalidate_sizes (icon_view);
5623
5624       g_object_notify (G_OBJECT (icon_view), "column-spacing");
5625     }  
5626 }
5627
5628 /**
5629  * gtk_icon_view_get_column_spacing:
5630  * @icon_view: a #GtkIconView
5631  * 
5632  * Returns the value of the ::column-spacing property.
5633  * 
5634  * Return value: the space between columns
5635  *
5636  * Since: 2.6
5637  */
5638 gint
5639 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
5640 {
5641   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5642
5643   return icon_view->priv->column_spacing;
5644 }
5645
5646 /**
5647  * gtk_icon_view_set_margin:
5648  * @icon_view: a #GtkIconView
5649  * @margin: the margin
5650  * 
5651  * Sets the ::margin property which specifies the space 
5652  * which is inserted at the top, bottom, left and right 
5653  * of the icon view.
5654  *
5655  * Since: 2.6
5656  */
5657 void 
5658 gtk_icon_view_set_margin (GtkIconView *icon_view,
5659                           gint         margin)
5660 {
5661   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5662   
5663   if (icon_view->priv->margin != margin)
5664     {
5665       icon_view->priv->margin = margin;
5666
5667       if (icon_view->priv->cell_area)
5668         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5669
5670       gtk_icon_view_invalidate_sizes (icon_view);
5671
5672       g_object_notify (G_OBJECT (icon_view), "margin");
5673     }  
5674 }
5675
5676 /**
5677  * gtk_icon_view_get_margin:
5678  * @icon_view: a #GtkIconView
5679  * 
5680  * Returns the value of the ::margin property.
5681  * 
5682  * Return value: the space at the borders 
5683  *
5684  * Since: 2.6
5685  */
5686 gint
5687 gtk_icon_view_get_margin (GtkIconView *icon_view)
5688 {
5689   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5690
5691   return icon_view->priv->margin;
5692 }
5693
5694 /**
5695  * gtk_icon_view_set_item_padding:
5696  * @icon_view: a #GtkIconView
5697  * @item_padding: the item padding
5698  *
5699  * Sets the #GtkIconView:item-padding property which specifies the padding
5700  * around each of the icon view's items.
5701  *
5702  * Since: 2.18
5703  */
5704 void
5705 gtk_icon_view_set_item_padding (GtkIconView *icon_view,
5706                                 gint         item_padding)
5707 {
5708   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5709   
5710   if (icon_view->priv->item_padding != item_padding)
5711     {
5712       icon_view->priv->item_padding = item_padding;
5713
5714       if (icon_view->priv->cell_area)
5715         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5716
5717       gtk_icon_view_invalidate_sizes (icon_view);
5718
5719       g_object_notify (G_OBJECT (icon_view), "item-padding");
5720     }  
5721 }
5722
5723 /**
5724  * gtk_icon_view_get_item_padding:
5725  * @icon_view: a #GtkIconView
5726  * 
5727  * Returns the value of the ::item-padding property.
5728  * 
5729  * Return value: the padding around items
5730  *
5731  * Since: 2.18
5732  */
5733 gint
5734 gtk_icon_view_get_item_padding (GtkIconView *icon_view)
5735 {
5736   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5737
5738   return icon_view->priv->item_padding;
5739 }
5740
5741 /* Get/set whether drag_motion requested the drag data and
5742  * drag_data_received should thus not actually insert the data,
5743  * since the data doesn't result from a drop.
5744  */
5745 static void
5746 set_status_pending (GdkDragContext *context,
5747                     GdkDragAction   suggested_action)
5748 {
5749   g_object_set_data (G_OBJECT (context),
5750                      I_("gtk-icon-view-status-pending"),
5751                      GINT_TO_POINTER (suggested_action));
5752 }
5753
5754 static GdkDragAction
5755 get_status_pending (GdkDragContext *context)
5756 {
5757   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5758                                              "gtk-icon-view-status-pending"));
5759 }
5760
5761 static void
5762 unset_reorderable (GtkIconView *icon_view)
5763 {
5764   if (icon_view->priv->reorderable)
5765     {
5766       icon_view->priv->reorderable = FALSE;
5767       g_object_notify (G_OBJECT (icon_view), "reorderable");
5768     }
5769 }
5770
5771 static void
5772 set_source_row (GdkDragContext *context,
5773                 GtkTreeModel   *model,
5774                 GtkTreePath    *source_row)
5775 {
5776   if (source_row)
5777     g_object_set_data_full (G_OBJECT (context),
5778                             I_("gtk-icon-view-source-row"),
5779                             gtk_tree_row_reference_new (model, source_row),
5780                             (GDestroyNotify) gtk_tree_row_reference_free);
5781   else
5782     g_object_set_data_full (G_OBJECT (context),
5783                             I_("gtk-icon-view-source-row"),
5784                             NULL, NULL);
5785 }
5786
5787 static GtkTreePath*
5788 get_source_row (GdkDragContext *context)
5789 {
5790   GtkTreeRowReference *ref;
5791
5792   ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
5793
5794   if (ref)
5795     return gtk_tree_row_reference_get_path (ref);
5796   else
5797     return NULL;
5798 }
5799
5800 typedef struct
5801 {
5802   GtkTreeRowReference *dest_row;
5803   gboolean             empty_view_drop;
5804   gboolean             drop_append_mode;
5805 } DestRow;
5806
5807 static void
5808 dest_row_free (gpointer data)
5809 {
5810   DestRow *dr = (DestRow *)data;
5811
5812   gtk_tree_row_reference_free (dr->dest_row);
5813   g_free (dr);
5814 }
5815
5816 static void
5817 set_dest_row (GdkDragContext *context,
5818               GtkTreeModel   *model,
5819               GtkTreePath    *dest_row,
5820               gboolean        empty_view_drop,
5821               gboolean        drop_append_mode)
5822 {
5823   DestRow *dr;
5824
5825   if (!dest_row)
5826     {
5827       g_object_set_data_full (G_OBJECT (context),
5828                               I_("gtk-icon-view-dest-row"),
5829                               NULL, NULL);
5830       return;
5831     }
5832   
5833   dr = g_new0 (DestRow, 1);
5834      
5835   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
5836   dr->empty_view_drop = empty_view_drop;
5837   dr->drop_append_mode = drop_append_mode;
5838   g_object_set_data_full (G_OBJECT (context),
5839                           I_("gtk-icon-view-dest-row"),
5840                           dr, (GDestroyNotify) dest_row_free);
5841 }
5842
5843 static GtkTreePath*
5844 get_dest_row (GdkDragContext *context)
5845 {
5846   DestRow *dr;
5847
5848   dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
5849
5850   if (dr)
5851     {
5852       GtkTreePath *path = NULL;
5853       
5854       if (dr->dest_row)
5855         path = gtk_tree_row_reference_get_path (dr->dest_row);
5856       else if (dr->empty_view_drop)
5857         path = gtk_tree_path_new_from_indices (0, -1);
5858       else
5859         path = NULL;
5860
5861       if (path && dr->drop_append_mode)
5862         gtk_tree_path_next (path);
5863
5864       return path;
5865     }
5866   else
5867     return NULL;
5868 }
5869
5870 static gboolean
5871 check_model_dnd (GtkTreeModel *model,
5872                  GType         required_iface,
5873                  const gchar  *signal)
5874 {
5875   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
5876     {
5877       g_warning ("You must override the default '%s' handler "
5878                  "on GtkIconView when using models that don't support "
5879                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
5880                  "is to connect to '%s' and call "
5881                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
5882                  "the default handler from running. Look at the source code "
5883                  "for the default handler in gtkiconview.c to get an idea what "
5884                  "your handler should do. (gtkiconview.c is in the GTK+ source "
5885                  "code.) If you're using GTK+ from a language other than C, "
5886                  "there may be a more natural way to override default handlers, e.g. via derivation.",
5887                  signal, g_type_name (required_iface), signal);
5888       return FALSE;
5889     }
5890   else
5891     return TRUE;
5892 }
5893
5894 static void
5895 remove_scroll_timeout (GtkIconView *icon_view)
5896 {
5897   if (icon_view->priv->scroll_timeout_id != 0)
5898     {
5899       g_source_remove (icon_view->priv->scroll_timeout_id);
5900
5901       icon_view->priv->scroll_timeout_id = 0;
5902     }
5903 }
5904
5905 static void
5906 gtk_icon_view_autoscroll (GtkIconView *icon_view,
5907                           GdkDevice   *device)
5908 {
5909   GdkWindow *window;
5910   gint px, py, width, height;
5911   gint hoffset, voffset;
5912
5913   window = gtk_widget_get_window (GTK_WIDGET (icon_view));
5914
5915   gdk_window_get_device_position (window, device, &px, &py, NULL);
5916   gdk_window_get_geometry (window, NULL, NULL, &width, &height);
5917
5918   /* see if we are near the edge. */
5919   voffset = py - 2 * SCROLL_EDGE_SIZE;
5920   if (voffset > 0)
5921     voffset = MAX (py - (height - 2 * SCROLL_EDGE_SIZE), 0);
5922
5923   hoffset = px - 2 * SCROLL_EDGE_SIZE;
5924   if (hoffset > 0)
5925     hoffset = MAX (px - (width - 2 * SCROLL_EDGE_SIZE), 0);
5926
5927   if (voffset != 0)
5928     gtk_adjustment_set_value (icon_view->priv->vadjustment,
5929                               gtk_adjustment_get_value (icon_view->priv->vadjustment) + voffset);
5930
5931   if (hoffset != 0)
5932     gtk_adjustment_set_value (icon_view->priv->hadjustment,
5933                               gtk_adjustment_get_value (icon_view->priv->hadjustment) + hoffset);
5934 }
5935
5936 typedef struct {
5937   GtkIconView *icon_view;
5938   GdkDevice   *device;
5939 } DragScrollData;
5940
5941 static gboolean
5942 drag_scroll_timeout (gpointer datap)
5943 {
5944   DragScrollData *data = datap;
5945
5946   gtk_icon_view_autoscroll (data->icon_view, data->device);
5947
5948   return TRUE;
5949 }
5950
5951 static void
5952 drag_scroll_data_free (DragScrollData *data)
5953 {
5954   g_slice_free (DragScrollData, data);
5955 }
5956
5957 static gboolean
5958 set_destination (GtkIconView    *icon_view,
5959                  GdkDragContext *context,
5960                  gint            x,
5961                  gint            y,
5962                  GdkDragAction  *suggested_action,
5963                  GdkAtom        *target)
5964 {
5965   GtkWidget *widget;
5966   GtkTreePath *path = NULL;
5967   GtkIconViewDropPosition pos;
5968   GtkIconViewDropPosition old_pos;
5969   GtkTreePath *old_dest_path = NULL;
5970   gboolean can_drop = FALSE;
5971
5972   widget = GTK_WIDGET (icon_view);
5973
5974   *suggested_action = 0;
5975   *target = GDK_NONE;
5976
5977   if (!icon_view->priv->dest_set)
5978     {
5979       /* someone unset us as a drag dest, note that if
5980        * we return FALSE drag_leave isn't called
5981        */
5982
5983       gtk_icon_view_set_drag_dest_item (icon_view,
5984                                         NULL,
5985                                         GTK_ICON_VIEW_DROP_LEFT);
5986
5987       remove_scroll_timeout (GTK_ICON_VIEW (widget));
5988
5989       return FALSE; /* no longer a drop site */
5990     }
5991
5992   *target = gtk_drag_dest_find_target (widget, context,
5993                                        gtk_drag_dest_get_target_list (widget));
5994   if (*target == GDK_NONE)
5995     return FALSE;
5996
5997   if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos)) 
5998     {
5999       gint n_children;
6000       GtkTreeModel *model;
6001       
6002       /* the row got dropped on empty space, let's setup a special case
6003        */
6004
6005       if (path)
6006         gtk_tree_path_free (path);
6007
6008       model = gtk_icon_view_get_model (icon_view);
6009
6010       n_children = gtk_tree_model_iter_n_children (model, NULL);
6011       if (n_children)
6012         {
6013           pos = GTK_ICON_VIEW_DROP_BELOW;
6014           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6015         }
6016       else
6017         {
6018           pos = GTK_ICON_VIEW_DROP_ABOVE;
6019           path = gtk_tree_path_new_from_indices (0, -1);
6020         }
6021
6022       can_drop = TRUE;
6023
6024       goto out;
6025     }
6026
6027   g_assert (path);
6028
6029   gtk_icon_view_get_drag_dest_item (icon_view,
6030                                     &old_dest_path,
6031                                     &old_pos);
6032   
6033   if (old_dest_path)
6034     gtk_tree_path_free (old_dest_path);
6035   
6036   if (TRUE /* FIXME if the location droppable predicate */)
6037     {
6038       can_drop = TRUE;
6039     }
6040
6041 out:
6042   if (can_drop)
6043     {
6044       GtkWidget *source_widget;
6045
6046       *suggested_action = gdk_drag_context_get_suggested_action (context);
6047       source_widget = gtk_drag_get_source_widget (context);
6048
6049       if (source_widget == widget)
6050         {
6051           /* Default to MOVE, unless the user has
6052            * pressed ctrl or shift to affect available actions
6053            */
6054           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
6055             *suggested_action = GDK_ACTION_MOVE;
6056         }
6057
6058       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6059                                         path, pos);
6060     }
6061   else
6062     {
6063       /* can't drop here */
6064       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6065                                         NULL,
6066                                         GTK_ICON_VIEW_DROP_LEFT);
6067     }
6068   
6069   if (path)
6070     gtk_tree_path_free (path);
6071   
6072   return TRUE;
6073 }
6074
6075 static GtkTreePath*
6076 get_logical_destination (GtkIconView *icon_view,
6077                          gboolean    *drop_append_mode)
6078 {
6079   /* adjust path to point to the row the drop goes in front of */
6080   GtkTreePath *path = NULL;
6081   GtkIconViewDropPosition pos;
6082   
6083   *drop_append_mode = FALSE;
6084
6085   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6086
6087   if (path == NULL)
6088     return NULL;
6089
6090   if (pos == GTK_ICON_VIEW_DROP_RIGHT || 
6091       pos == GTK_ICON_VIEW_DROP_BELOW)
6092     {
6093       GtkTreeIter iter;
6094       GtkTreeModel *model = icon_view->priv->model;
6095
6096       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6097           !gtk_tree_model_iter_next (model, &iter))
6098         *drop_append_mode = TRUE;
6099       else
6100         {
6101           *drop_append_mode = FALSE;
6102           gtk_tree_path_next (path);
6103         }      
6104     }
6105
6106   return path;
6107 }
6108
6109 static gboolean
6110 gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
6111                                 GdkEventMotion *event)
6112 {
6113   GtkWidget *widget = GTK_WIDGET (icon_view);
6114   GdkDragContext *context;
6115   GtkTreePath *path = NULL;
6116   gint button;
6117   GtkTreeModel *model;
6118   gboolean retval = FALSE;
6119
6120   if (!icon_view->priv->source_set)
6121     goto out;
6122
6123   if (icon_view->priv->pressed_button < 0)
6124     goto out;
6125
6126   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6127                                  icon_view->priv->press_start_x,
6128                                  icon_view->priv->press_start_y,
6129                                  event->x, event->y))
6130     goto out;
6131
6132   model = gtk_icon_view_get_model (icon_view);
6133
6134   if (model == NULL)
6135     goto out;
6136
6137   button = icon_view->priv->pressed_button;
6138   icon_view->priv->pressed_button = -1;
6139
6140   path = gtk_icon_view_get_path_at_pos (icon_view,
6141                                         icon_view->priv->press_start_x,
6142                                         icon_view->priv->press_start_y);
6143
6144   if (path == NULL)
6145     goto out;
6146
6147   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6148       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6149                                            path))
6150     goto out;
6151
6152   /* FIXME Check whether we're a start button, if not return FALSE and
6153    * free path
6154    */
6155
6156   /* Now we can begin the drag */
6157   
6158   retval = TRUE;
6159
6160   context = gtk_drag_begin (widget,
6161                             gtk_drag_source_get_target_list (widget),
6162                             icon_view->priv->source_actions,
6163                             button,
6164                             (GdkEvent*)event);
6165
6166   set_source_row (context, model, path);
6167   
6168  out:
6169   if (path)
6170     gtk_tree_path_free (path);
6171
6172   return retval;
6173 }
6174
6175 /* Source side drag signals */
6176 static void 
6177 gtk_icon_view_drag_begin (GtkWidget      *widget,
6178                           GdkDragContext *context)
6179 {
6180   GtkIconView *icon_view;
6181   GtkIconViewItem *item;
6182   cairo_surface_t *icon;
6183   gint x, y;
6184   GtkTreePath *path;
6185
6186   icon_view = GTK_ICON_VIEW (widget);
6187
6188   /* if the user uses a custom DnD impl, we don't set the icon here */
6189   if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6190     return;
6191
6192   item = _gtk_icon_view_get_item_at_coords (icon_view,
6193                                            icon_view->priv->press_start_x,
6194                                            icon_view->priv->press_start_y,
6195                                            TRUE,
6196                                            NULL);
6197
6198   g_return_if_fail (item != NULL);
6199
6200   x = icon_view->priv->press_start_x - item->cell_area.x + 1;
6201   y = icon_view->priv->press_start_y - item->cell_area.y + 1;
6202   
6203   path = gtk_tree_path_new_from_indices (item->index, -1);
6204   icon = gtk_icon_view_create_drag_icon (icon_view, path);
6205   gtk_tree_path_free (path);
6206
6207   cairo_surface_set_device_offset (icon, -x, -y);
6208
6209   gtk_drag_set_icon_surface (context, icon);
6210
6211   cairo_surface_destroy (icon);
6212 }
6213
6214 static void 
6215 gtk_icon_view_drag_end (GtkWidget      *widget,
6216                         GdkDragContext *context)
6217 {
6218   /* do nothing */
6219 }
6220
6221 static void 
6222 gtk_icon_view_drag_data_get (GtkWidget        *widget,
6223                              GdkDragContext   *context,
6224                              GtkSelectionData *selection_data,
6225                              guint             info,
6226                              guint             time)
6227 {
6228   GtkIconView *icon_view;
6229   GtkTreeModel *model;
6230   GtkTreePath *source_row;
6231
6232   icon_view = GTK_ICON_VIEW (widget);
6233   model = gtk_icon_view_get_model (icon_view);
6234
6235   if (model == NULL)
6236     return;
6237
6238   if (!icon_view->priv->source_set)
6239     return;
6240
6241   source_row = get_source_row (context);
6242
6243   if (source_row == NULL)
6244     return;
6245
6246   /* We can implement the GTK_TREE_MODEL_ROW target generically for
6247    * any model; for DragSource models there are some other targets
6248    * we also support.
6249    */
6250
6251   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6252       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6253                                           source_row,
6254                                           selection_data))
6255     goto done;
6256
6257   /* If drag_data_get does nothing, try providing row data. */
6258   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6259     gtk_tree_set_row_drag_data (selection_data,
6260                                 model,
6261                                 source_row);
6262
6263  done:
6264   gtk_tree_path_free (source_row);
6265 }
6266
6267 static void 
6268 gtk_icon_view_drag_data_delete (GtkWidget      *widget,
6269                                 GdkDragContext *context)
6270 {
6271   GtkTreeModel *model;
6272   GtkIconView *icon_view;
6273   GtkTreePath *source_row;
6274
6275   icon_view = GTK_ICON_VIEW (widget);
6276   model = gtk_icon_view_get_model (icon_view);
6277
6278   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag-data-delete"))
6279     return;
6280
6281   if (!icon_view->priv->source_set)
6282     return;
6283
6284   source_row = get_source_row (context);
6285
6286   if (source_row == NULL)
6287     return;
6288
6289   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6290                                          source_row);
6291
6292   gtk_tree_path_free (source_row);
6293
6294   set_source_row (context, NULL, NULL);
6295 }
6296
6297 /* Target side drag signals */
6298 static void
6299 gtk_icon_view_drag_leave (GtkWidget      *widget,
6300                           GdkDragContext *context,
6301                           guint           time)
6302 {
6303   GtkIconView *icon_view;
6304
6305   icon_view = GTK_ICON_VIEW (widget);
6306
6307   /* unset any highlight row */
6308   gtk_icon_view_set_drag_dest_item (icon_view,
6309                                     NULL,
6310                                     GTK_ICON_VIEW_DROP_LEFT);
6311
6312   remove_scroll_timeout (icon_view);
6313 }
6314
6315 static gboolean 
6316 gtk_icon_view_drag_motion (GtkWidget      *widget,
6317                            GdkDragContext *context,
6318                            gint            x,
6319                            gint            y,
6320                            guint           time)
6321 {
6322   GtkTreePath *path = NULL;
6323   GtkIconViewDropPosition pos;
6324   GtkIconView *icon_view;
6325   GdkDragAction suggested_action = 0;
6326   GdkAtom target;
6327   gboolean empty;
6328
6329   icon_view = GTK_ICON_VIEW (widget);
6330
6331   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6332     return FALSE;
6333
6334   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6335
6336   /* we only know this *after* set_desination_row */
6337   empty = icon_view->priv->empty_view_drop;
6338
6339   if (path == NULL && !empty)
6340     {
6341       /* Can't drop here. */
6342       gdk_drag_status (context, 0, time);
6343     }
6344   else
6345     {
6346       if (icon_view->priv->scroll_timeout_id == 0)
6347         {
6348           DragScrollData *data = g_slice_new (DragScrollData);
6349           data->icon_view = icon_view;
6350           data->device = gdk_drag_context_get_device (context);
6351
6352           icon_view->priv->scroll_timeout_id =
6353             gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT, 50, drag_scroll_timeout, data, (GDestroyNotify) drag_scroll_data_free);
6354         }
6355
6356       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6357         {
6358           /* Request data so we can use the source row when
6359            * determining whether to accept the drop
6360            */
6361           set_status_pending (context, suggested_action);
6362           gtk_drag_get_data (widget, context, target, time);
6363         }
6364       else
6365         {
6366           set_status_pending (context, 0);
6367           gdk_drag_status (context, suggested_action, time);
6368         }
6369     }
6370
6371   if (path)
6372     gtk_tree_path_free (path);
6373
6374   return TRUE;
6375 }
6376
6377 static gboolean 
6378 gtk_icon_view_drag_drop (GtkWidget      *widget,
6379                          GdkDragContext *context,
6380                          gint            x,
6381                          gint            y,
6382                          guint           time)
6383 {
6384   GtkIconView *icon_view;
6385   GtkTreePath *path;
6386   GdkDragAction suggested_action = 0;
6387   GdkAtom target = GDK_NONE;
6388   GtkTreeModel *model;
6389   gboolean drop_append_mode;
6390
6391   icon_view = GTK_ICON_VIEW (widget);
6392   model = gtk_icon_view_get_model (icon_view);
6393
6394   remove_scroll_timeout (GTK_ICON_VIEW (widget));
6395
6396   if (!icon_view->priv->dest_set)
6397     return FALSE;
6398
6399   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
6400     return FALSE;
6401
6402   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6403     return FALSE;
6404   
6405   path = get_logical_destination (icon_view, &drop_append_mode);
6406
6407   if (target != GDK_NONE && path != NULL)
6408     {
6409       /* in case a motion had requested drag data, change things so we
6410        * treat drag data receives as a drop.
6411        */
6412       set_status_pending (context, 0);
6413       set_dest_row (context, model, path, 
6414                     icon_view->priv->empty_view_drop, drop_append_mode);
6415     }
6416
6417   if (path)
6418     gtk_tree_path_free (path);
6419
6420   /* Unset this thing */
6421   gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6422
6423   if (target != GDK_NONE)
6424     {
6425       gtk_drag_get_data (widget, context, target, time);
6426       return TRUE;
6427     }
6428   else
6429     return FALSE;
6430 }
6431
6432 static void
6433 gtk_icon_view_drag_data_received (GtkWidget        *widget,
6434                                   GdkDragContext   *context,
6435                                   gint              x,
6436                                   gint              y,
6437                                   GtkSelectionData *selection_data,
6438                                   guint             info,
6439                                   guint             time)
6440 {
6441   GtkTreePath *path;
6442   gboolean accepted = FALSE;
6443   GtkTreeModel *model;
6444   GtkIconView *icon_view;
6445   GtkTreePath *dest_row;
6446   GdkDragAction suggested_action;
6447   gboolean drop_append_mode;
6448   
6449   icon_view = GTK_ICON_VIEW (widget);  
6450   model = gtk_icon_view_get_model (icon_view);
6451
6452   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
6453     return;
6454
6455   if (!icon_view->priv->dest_set)
6456     return;
6457
6458   suggested_action = get_status_pending (context);
6459
6460   if (suggested_action)
6461     {
6462       /* We are getting this data due to a request in drag_motion,
6463        * rather than due to a request in drag_drop, so we are just
6464        * supposed to call drag_status, not actually paste in the
6465        * data.
6466        */
6467       path = get_logical_destination (icon_view, &drop_append_mode);
6468
6469       if (path == NULL)
6470         suggested_action = 0;
6471
6472       if (suggested_action)
6473         {
6474           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6475                                                      path,
6476                                                      selection_data))
6477             suggested_action = 0;
6478         }
6479
6480       gdk_drag_status (context, suggested_action, time);
6481
6482       if (path)
6483         gtk_tree_path_free (path);
6484
6485       /* If you can't drop, remove user drop indicator until the next motion */
6486       if (suggested_action == 0)
6487         gtk_icon_view_set_drag_dest_item (icon_view,
6488                                           NULL,
6489                                           GTK_ICON_VIEW_DROP_LEFT);
6490       return;
6491     }
6492   
6493
6494   dest_row = get_dest_row (context);
6495
6496   if (dest_row == NULL)
6497     return;
6498
6499   if (gtk_selection_data_get_length (selection_data) >= 0)
6500     {
6501       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6502                                                  dest_row,
6503                                                  selection_data))
6504         accepted = TRUE;
6505     }
6506
6507   gtk_drag_finish (context,
6508                    accepted,
6509                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
6510                    time);
6511
6512   gtk_tree_path_free (dest_row);
6513
6514   /* drop dest_row */
6515   set_dest_row (context, NULL, NULL, FALSE, FALSE);
6516 }
6517
6518 /* Drag-and-Drop support */
6519 /**
6520  * gtk_icon_view_enable_model_drag_source:
6521  * @icon_view: a #GtkIconTreeView
6522  * @start_button_mask: Mask of allowed buttons to start drag
6523  * @targets: (array length=n_targets): the table of targets that the drag will
6524  *           support
6525  * @n_targets: the number of items in @targets
6526  * @actions: the bitmask of possible actions for a drag from this
6527  *    widget
6528  *
6529  * Turns @icon_view into a drag source for automatic DND. Calling this
6530  * method sets #GtkIconView:reorderable to %FALSE.
6531  *
6532  * Since: 2.8
6533  **/
6534 void
6535 gtk_icon_view_enable_model_drag_source (GtkIconView              *icon_view,
6536                                         GdkModifierType           start_button_mask,
6537                                         const GtkTargetEntry     *targets,
6538                                         gint                      n_targets,
6539                                         GdkDragAction             actions)
6540 {
6541   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6542
6543   gtk_drag_source_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6544
6545   icon_view->priv->start_button_mask = start_button_mask;
6546   icon_view->priv->source_actions = actions;
6547
6548   icon_view->priv->source_set = TRUE;
6549
6550   unset_reorderable (icon_view);
6551 }
6552
6553 /**
6554  * gtk_icon_view_enable_model_drag_dest:
6555  * @icon_view: a #GtkIconView
6556  * @targets: (array length=n_targets): the table of targets that the drag will
6557  *           support
6558  * @n_targets: the number of items in @targets
6559  * @actions: the bitmask of possible actions for a drag to this
6560  *    widget
6561  *
6562  * Turns @icon_view into a drop destination for automatic DND. Calling this
6563  * method sets #GtkIconView:reorderable to %FALSE.
6564  *
6565  * Since: 2.8
6566  **/
6567 void 
6568 gtk_icon_view_enable_model_drag_dest (GtkIconView          *icon_view,
6569                                       const GtkTargetEntry *targets,
6570                                       gint                  n_targets,
6571                                       GdkDragAction         actions)
6572 {
6573   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6574
6575   gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6576
6577   icon_view->priv->dest_actions = actions;
6578
6579   icon_view->priv->dest_set = TRUE;
6580
6581   unset_reorderable (icon_view);  
6582 }
6583
6584 /**
6585  * gtk_icon_view_unset_model_drag_source:
6586  * @icon_view: a #GtkIconView
6587  * 
6588  * Undoes the effect of gtk_icon_view_enable_model_drag_source(). Calling this
6589  * method sets #GtkIconView:reorderable to %FALSE.
6590  *
6591  * Since: 2.8
6592  **/
6593 void
6594 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6595 {
6596   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6597
6598   if (icon_view->priv->source_set)
6599     {
6600       gtk_drag_source_unset (GTK_WIDGET (icon_view));
6601       icon_view->priv->source_set = FALSE;
6602     }
6603
6604   unset_reorderable (icon_view);
6605 }
6606
6607 /**
6608  * gtk_icon_view_unset_model_drag_dest:
6609  * @icon_view: a #GtkIconView
6610  * 
6611  * Undoes the effect of gtk_icon_view_enable_model_drag_dest(). Calling this
6612  * method sets #GtkIconView:reorderable to %FALSE.
6613  *
6614  * Since: 2.8
6615  **/
6616 void
6617 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6618 {
6619   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6620
6621   if (icon_view->priv->dest_set)
6622     {
6623       gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6624       icon_view->priv->dest_set = FALSE;
6625     }
6626
6627   unset_reorderable (icon_view);
6628 }
6629
6630 /* These are useful to implement your own custom stuff. */
6631 /**
6632  * gtk_icon_view_set_drag_dest_item:
6633  * @icon_view: a #GtkIconView
6634  * @path: (allow-none): The path of the item to highlight, or %NULL.
6635  * @pos: Specifies where to drop, relative to the item
6636  *
6637  * Sets the item that is highlighted for feedback.
6638  *
6639  * Since: 2.8
6640  */
6641 void
6642 gtk_icon_view_set_drag_dest_item (GtkIconView              *icon_view,
6643                                   GtkTreePath              *path,
6644                                   GtkIconViewDropPosition   pos)
6645 {
6646   /* Note; this function is exported to allow a custom DND
6647    * implementation, so it can't touch TreeViewDragInfo
6648    */
6649
6650   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6651
6652   if (icon_view->priv->dest_item)
6653     {
6654       GtkTreePath *current_path;
6655       current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6656       gtk_tree_row_reference_free (icon_view->priv->dest_item);
6657       icon_view->priv->dest_item = NULL;      
6658
6659       gtk_icon_view_queue_draw_path (icon_view, current_path);
6660       gtk_tree_path_free (current_path);
6661     }
6662   
6663   /* special case a drop on an empty model */
6664   icon_view->priv->empty_view_drop = FALSE;
6665   if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
6666       && gtk_tree_path_get_depth (path) == 1
6667       && gtk_tree_path_get_indices (path)[0] == 0)
6668     {
6669       gint n_children;
6670
6671       n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
6672                                                    NULL);
6673
6674       if (n_children == 0)
6675         icon_view->priv->empty_view_drop = TRUE;
6676     }
6677
6678   icon_view->priv->dest_pos = pos;
6679
6680   if (path)
6681     {
6682       icon_view->priv->dest_item =
6683         gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), 
6684                                           icon_view->priv->model, path);
6685       
6686       gtk_icon_view_queue_draw_path (icon_view, path);
6687     }
6688 }
6689
6690 /**
6691  * gtk_icon_view_get_drag_dest_item:
6692  * @icon_view: a #GtkIconView
6693  * @path: (out) (allow-none): Return location for the path of
6694  *        the highlighted item, or %NULL.
6695  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6696  * 
6697  * Gets information about the item that is highlighted for feedback.
6698  *
6699  * Since: 2.8
6700  **/
6701 void
6702 gtk_icon_view_get_drag_dest_item (GtkIconView              *icon_view,
6703                                   GtkTreePath             **path,
6704                                   GtkIconViewDropPosition  *pos)
6705 {
6706   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6707
6708   if (path)
6709     {
6710       if (icon_view->priv->dest_item)
6711         *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6712       else
6713         *path = NULL;
6714     }
6715
6716   if (pos)
6717     *pos = icon_view->priv->dest_pos;
6718 }
6719
6720 /**
6721  * gtk_icon_view_get_dest_item_at_pos:
6722  * @icon_view: a #GtkIconView
6723  * @drag_x: the position to determine the destination item for
6724  * @drag_y: the position to determine the destination item for
6725  * @path: (out) (allow-none): Return location for the path of the item,
6726  *    or %NULL.
6727  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6728  * 
6729  * Determines the destination item for a given position.
6730  * 
6731  * Return value: whether there is an item at the given position.
6732  *
6733  * Since: 2.8
6734  **/
6735 gboolean
6736 gtk_icon_view_get_dest_item_at_pos (GtkIconView              *icon_view,
6737                                     gint                      drag_x,
6738                                     gint                      drag_y,
6739                                     GtkTreePath             **path,
6740                                     GtkIconViewDropPosition  *pos)
6741 {
6742   GtkIconViewItem *item;
6743
6744   /* Note; this function is exported to allow a custom DND
6745    * implementation, so it can't touch TreeViewDragInfo
6746    */
6747
6748   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6749   g_return_val_if_fail (drag_x >= 0, FALSE);
6750   g_return_val_if_fail (drag_y >= 0, FALSE);
6751   g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
6752
6753
6754   if (path)
6755     *path = NULL;
6756
6757   item = _gtk_icon_view_get_item_at_coords (icon_view, 
6758                                            drag_x + gtk_adjustment_get_value (icon_view->priv->hadjustment), 
6759                                            drag_y + gtk_adjustment_get_value (icon_view->priv->vadjustment),
6760                                            FALSE, NULL);
6761
6762   if (item == NULL)
6763     return FALSE;
6764
6765   if (path)
6766     *path = gtk_tree_path_new_from_indices (item->index, -1);
6767
6768   if (pos)
6769     {
6770       if (drag_x < item->cell_area.x + item->cell_area.width / 4)
6771         *pos = GTK_ICON_VIEW_DROP_LEFT;
6772       else if (drag_x > item->cell_area.x + item->cell_area.width * 3 / 4)
6773         *pos = GTK_ICON_VIEW_DROP_RIGHT;
6774       else if (drag_y < item->cell_area.y + item->cell_area.height / 4)
6775         *pos = GTK_ICON_VIEW_DROP_ABOVE;
6776       else if (drag_y > item->cell_area.y + item->cell_area.height * 3 / 4)
6777         *pos = GTK_ICON_VIEW_DROP_BELOW;
6778       else
6779         *pos = GTK_ICON_VIEW_DROP_INTO;
6780     }
6781
6782   return TRUE;
6783 }
6784
6785 /**
6786  * gtk_icon_view_create_drag_icon:
6787  * @icon_view: a #GtkIconView
6788  * @path: a #GtkTreePath in @icon_view
6789  *
6790  * Creates a #cairo_surface_t representation of the item at @path.  
6791  * This image is used for a drag icon.
6792  *
6793  * Return value: (transfer full): a newly-allocated surface of the drag icon.
6794  * 
6795  * Since: 2.8
6796  **/
6797 cairo_surface_t *
6798 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
6799                                 GtkTreePath *path)
6800 {
6801   GtkWidget *widget;
6802   GtkStyleContext *context;
6803   cairo_t *cr;
6804   cairo_surface_t *surface;
6805   GList *l;
6806   gint index;
6807
6808   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
6809   g_return_val_if_fail (path != NULL, NULL);
6810
6811   widget = GTK_WIDGET (icon_view);
6812   context = gtk_widget_get_style_context (widget);
6813
6814   if (!gtk_widget_get_realized (widget))
6815     return NULL;
6816
6817   index = gtk_tree_path_get_indices (path)[0];
6818
6819   for (l = icon_view->priv->items; l; l = l->next) 
6820     {
6821       GtkIconViewItem *item = l->data;
6822       
6823       if (index == item->index)
6824         {
6825           GdkRectangle rect = { 
6826             item->cell_area.x - icon_view->priv->item_padding, 
6827             item->cell_area.y - icon_view->priv->item_padding, 
6828             item->cell_area.width  + icon_view->priv->item_padding * 2, 
6829             item->cell_area.height + icon_view->priv->item_padding * 2 
6830           };
6831
6832           surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
6833                                                        CAIRO_CONTENT_COLOR,
6834                                                        rect.width + 2,
6835                                                        rect.height + 2);
6836
6837           cr = cairo_create (surface);
6838           cairo_set_line_width (cr, 1.);
6839
6840           gtk_render_background (context, cr, 0, 0,
6841                                  rect.width + 2, rect.height + 2);
6842
6843           cairo_save (cr);
6844
6845           cairo_rectangle (cr, 1, 1, rect.width, rect.height);
6846           cairo_clip (cr);
6847
6848           gtk_icon_view_paint_item (icon_view, cr, item, 
6849                                     icon_view->priv->item_padding + 1, 
6850                                     icon_view->priv->item_padding + 1, FALSE);
6851
6852           cairo_restore (cr);
6853
6854           cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
6855           cairo_rectangle (cr, 0.5, 0.5, rect.width + 1, rect.height + 1);
6856           cairo_stroke (cr);
6857
6858           cairo_destroy (cr);
6859
6860           return surface;
6861         }
6862     }
6863   
6864   return NULL;
6865 }
6866
6867 /**
6868  * gtk_icon_view_get_reorderable:
6869  * @icon_view: a #GtkIconView
6870  *
6871  * Retrieves whether the user can reorder the list via drag-and-drop. 
6872  * See gtk_icon_view_set_reorderable().
6873  *
6874  * Return value: %TRUE if the list can be reordered.
6875  *
6876  * Since: 2.8
6877  **/
6878 gboolean
6879 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
6880 {
6881   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6882
6883   return icon_view->priv->reorderable;
6884 }
6885
6886 static const GtkTargetEntry item_targets[] = {
6887   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
6888 };
6889
6890
6891 /**
6892  * gtk_icon_view_set_reorderable:
6893  * @icon_view: A #GtkIconView.
6894  * @reorderable: %TRUE, if the list of items can be reordered.
6895  *
6896  * This function is a convenience function to allow you to reorder models that
6897  * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface.  Both
6898  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
6899  * the user can reorder the model by dragging and dropping rows.  The
6900  * developer can listen to these changes by connecting to the model's
6901  * row_inserted and row_deleted signals. The reordering is implemented by setting up
6902  * the icon view as a drag source and destination. Therefore, drag and
6903  * drop can not be used in a reorderable view for any other purpose.
6904  *
6905  * This function does not give you any degree of control over the order -- any
6906  * reordering is allowed.  If more control is needed, you should probably
6907  * handle drag and drop manually.
6908  *
6909  * Since: 2.8
6910  **/
6911 void
6912 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
6913                                gboolean     reorderable)
6914 {
6915   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6916
6917   reorderable = reorderable != FALSE;
6918
6919   if (icon_view->priv->reorderable == reorderable)
6920     return;
6921
6922   if (reorderable)
6923     {
6924       gtk_icon_view_enable_model_drag_source (icon_view,
6925                                               GDK_BUTTON1_MASK,
6926                                               item_targets,
6927                                               G_N_ELEMENTS (item_targets),
6928                                               GDK_ACTION_MOVE);
6929       gtk_icon_view_enable_model_drag_dest (icon_view,
6930                                             item_targets,
6931                                             G_N_ELEMENTS (item_targets),
6932                                             GDK_ACTION_MOVE);
6933     }
6934   else
6935     {
6936       gtk_icon_view_unset_model_drag_source (icon_view);
6937       gtk_icon_view_unset_model_drag_dest (icon_view);
6938     }
6939
6940   icon_view->priv->reorderable = reorderable;
6941
6942   g_object_notify (G_OBJECT (icon_view), "reorderable");
6943 }
6944
6945 static gboolean
6946 gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
6947                                           GtkBuilder    *builder,
6948                                           GObject       *child,
6949                                           const gchar   *tagname,
6950                                           GMarkupParser *parser,
6951                                           gpointer      *data)
6952 {
6953   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
6954                                                 tagname, parser, data))
6955     return TRUE;
6956
6957   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
6958                                                       tagname, parser, data);
6959 }
6960
6961 static void
6962 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
6963                                         GtkBuilder   *builder,
6964                                         GObject      *child,
6965                                         const gchar  *tagname,
6966                                         gpointer     *data)
6967 {
6968   if (!_gtk_cell_layout_buildable_custom_tag_end (buildable, builder,
6969                                                   child, tagname, data))
6970     parent_buildable_iface->custom_tag_end (buildable, builder,
6971                                             child, tagname, data);
6972 }