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