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