]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
GtkApplication: Add window-added/-removed signals
[~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 <atk/atk.h>
25
26 #include "gtkaccessibleprivate.h"
27 #include "gtkiconview.h"
28 #include "gtkcelllayout.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkcellareabox.h"
31 #include "gtkcellareacontext.h"
32 #include "gtkcellrenderertext.h"
33 #include "gtkcellrendererpixbuf.h"
34 #include "gtkorientable.h"
35 #include "gtkmarshalers.h"
36 #include "gtkbindings.h"
37 #include "gtkdnd.h"
38 #include "gtkmain.h"
39 #include "gtkintl.h"
40 #include "gtkaccessible.h"
41 #include "gtkwindow.h"
42 #include "gtkentry.h"
43 #include "gtkcombobox.h"
44 #include "gtktextbuffer.h"
45 #include "gtkscrollable.h"
46 #include "gtksizerequest.h"
47 #include "gtktreednd.h"
48 #include "gtktypebuiltins.h"
49 #include "gtkprivate.h"
50
51 /**
52  * SECTION:gtkiconview
53  * @title: GtkIconView
54  * @short_description: A widget which displays a list of icons in a grid
55  *
56  * #GtkIconView provides an alternative view on a #GtkTreeModel.
57  * It displays the model as a grid of icons with labels. Like
58  * #GtkTreeView, it allows to select one or multiple items
59  * (depending on the selection mode, see gtk_icon_view_set_selection_mode()).
60  * In addition to selection with the arrow keys, #GtkIconView supports
61  * rubberband selection, which is controlled by dragging the pointer.
62  *
63  * Note that if the tree model is backed by an actual tree store (as
64  * opposed to a flat list where the mapping to icons is obvious),
65  * #GtkIconView will only display the first level of the tree and
66  * ignore the tree's branches.
67  */
68
69 #define SCROLL_EDGE_SIZE 15
70
71 #define GTK_ICON_VIEW_PRIORITY_LAYOUT (GDK_PRIORITY_REDRAW + 5)
72
73 typedef struct _GtkIconViewItem GtkIconViewItem;
74 struct _GtkIconViewItem
75 {
76   /* First member is always the rectangle so it 
77    * can be cast to a rectangle. */
78   GdkRectangle cell_area;
79
80   GtkTreeIter iter;
81   gint index;
82   
83   gint row, col;
84
85   guint selected : 1;
86   guint selected_before_rubberbanding : 1;
87
88 };
89
90 typedef struct _GtkIconViewChild GtkIconViewChild;
91 struct _GtkIconViewChild
92 {
93   GtkWidget    *widget;
94   GdkRectangle  area;
95 };
96
97 struct _GtkIconViewPrivate
98 {
99   GtkCellArea        *cell_area;
100   GtkCellAreaContext *cell_area_context;
101
102   gulong              add_editable_id;
103   gulong              remove_editable_id;
104   gulong              context_changed_id;
105
106   GPtrArray          *row_contexts;
107
108   gint width, height;
109
110   GtkSelectionMode selection_mode;
111
112   guint layout_idle_id;
113
114   GdkWindow *bin_window;
115
116   GList *children;
117
118   GtkTreeModel *model;
119
120   GList *items;
121
122   GtkAdjustment *hadjustment;
123   GtkAdjustment *vadjustment;
124
125   gint rubberband_x1, rubberband_y1;
126   gint rubberband_x2, rubberband_y2;
127   GdkDevice *rubberband_device;
128
129   guint scroll_timeout_id;
130   gint scroll_value_diff;
131   gint event_last_x, event_last_y;
132
133   GtkIconViewItem *anchor_item;
134   GtkIconViewItem *cursor_item;
135
136   GtkIconViewItem *last_single_clicked;
137
138   GtkOrientation item_orientation;
139
140   gint columns;
141   gint item_width;
142   gint spacing;
143   gint row_spacing;
144   gint column_spacing;
145   gint margin;
146   gint item_padding;
147
148   gint text_column;
149   gint markup_column;
150   gint pixbuf_column;
151   gint tooltip_column;
152
153   GtkCellRenderer *pixbuf_cell;
154   GtkCellRenderer *text_cell;
155
156   /* Drag-and-drop. */
157   GdkModifierType start_button_mask;
158   gint pressed_button;
159   gint press_start_x;
160   gint press_start_y;
161
162   GdkDragAction source_actions;
163   GdkDragAction dest_actions;
164
165   GtkTreeRowReference *dest_item;
166   GtkIconViewDropPosition dest_pos;
167
168   /* scroll to */
169   GtkTreeRowReference *scroll_to_path;
170   gfloat scroll_to_row_align;
171   gfloat scroll_to_col_align;
172   guint scroll_to_use_align : 1;
173
174   guint source_set : 1;
175   guint dest_set : 1;
176   guint reorderable : 1;
177   guint empty_view_drop :1;
178
179   guint ctrl_pressed : 1;
180   guint shift_pressed : 1;
181
182   guint draw_focus : 1;
183
184   /* GtkScrollablePolicy needs to be checked when
185    * driving the scrollable adjustment values */
186   guint hscroll_policy : 1;
187   guint vscroll_policy : 1;
188
189   guint doing_rubberband : 1;
190
191 };
192
193 /* Signals */
194 enum
195 {
196   ITEM_ACTIVATED,
197   SELECTION_CHANGED,
198   SELECT_ALL,
199   UNSELECT_ALL,
200   SELECT_CURSOR_ITEM,
201   TOGGLE_CURSOR_ITEM,
202   MOVE_CURSOR,
203   ACTIVATE_CURSOR_ITEM,
204   LAST_SIGNAL
205 };
206
207 /* Properties */
208 enum
209 {
210   PROP_0,
211   PROP_PIXBUF_COLUMN,
212   PROP_TEXT_COLUMN,
213   PROP_MARKUP_COLUMN,
214   PROP_SELECTION_MODE,
215   PROP_ITEM_ORIENTATION,
216   PROP_MODEL,
217   PROP_COLUMNS,
218   PROP_ITEM_WIDTH,
219   PROP_SPACING,
220   PROP_ROW_SPACING,
221   PROP_COLUMN_SPACING,
222   PROP_MARGIN,
223   PROP_REORDERABLE,
224   PROP_TOOLTIP_COLUMN,
225   PROP_ITEM_PADDING,
226   PROP_CELL_AREA,
227
228   /* For scrollable interface */
229   PROP_HADJUSTMENT,
230   PROP_VADJUSTMENT,
231   PROP_HSCROLL_POLICY,
232   PROP_VSCROLL_POLICY
233 };
234
235 /* GObject vfuncs */
236 static void             gtk_icon_view_cell_layout_init          (GtkCellLayoutIface *iface);
237 static void             gtk_icon_view_dispose                   (GObject            *object);
238 static GObject         *gtk_icon_view_constructor               (GType               type,
239                                                                  guint               n_construct_properties,
240                                                                  GObjectConstructParam *construct_properties);
241 static void             gtk_icon_view_set_property              (GObject            *object,
242                                                                  guint               prop_id,
243                                                                  const GValue       *value,
244                                                                  GParamSpec         *pspec);
245 static void             gtk_icon_view_get_property              (GObject            *object,
246                                                                  guint               prop_id,
247                                                                  GValue             *value,
248                                                                  GParamSpec         *pspec);
249 /* GtkWidget vfuncs */
250 static void             gtk_icon_view_destroy                   (GtkWidget          *widget);
251 static void             gtk_icon_view_realize                   (GtkWidget          *widget);
252 static void             gtk_icon_view_unrealize                 (GtkWidget          *widget);
253 static void             gtk_icon_view_style_updated             (GtkWidget          *widget);
254 static void             gtk_icon_view_state_flags_changed       (GtkWidget          *widget,
255                                                                  GtkStateFlags       previous_state);
256 static void             gtk_icon_view_get_preferred_width       (GtkWidget          *widget,
257                                                                  gint               *minimum,
258                                                                  gint               *natural);
259 static void             gtk_icon_view_get_preferred_height      (GtkWidget          *widget,
260                                                                  gint               *minimum,
261                                                                  gint               *natural);
262 static void             gtk_icon_view_size_allocate             (GtkWidget          *widget,
263                                                                  GtkAllocation      *allocation);
264 static gboolean         gtk_icon_view_draw                      (GtkWidget          *widget,
265                                                                  cairo_t            *cr);
266 static gboolean         gtk_icon_view_motion                    (GtkWidget          *widget,
267                                                                  GdkEventMotion     *event);
268 static gboolean         gtk_icon_view_button_press              (GtkWidget          *widget,
269                                                                  GdkEventButton     *event);
270 static gboolean         gtk_icon_view_button_release            (GtkWidget          *widget,
271                                                                  GdkEventButton     *event);
272 static gboolean         gtk_icon_view_key_press                 (GtkWidget          *widget,
273                                                                  GdkEventKey        *event);
274 static gboolean         gtk_icon_view_key_release               (GtkWidget          *widget,
275                                                                  GdkEventKey        *event);
276 static AtkObject       *gtk_icon_view_get_accessible            (GtkWidget          *widget);
277
278
279 /* GtkContainer vfuncs */
280 static void             gtk_icon_view_remove                    (GtkContainer       *container,
281                                                                  GtkWidget          *widget);
282 static void             gtk_icon_view_forall                    (GtkContainer       *container,
283                                                                  gboolean            include_internals,
284                                                                  GtkCallback         callback,
285                                                                  gpointer            callback_data);
286
287 /* GtkIconView vfuncs */
288 static void             gtk_icon_view_real_select_all           (GtkIconView        *icon_view);
289 static void             gtk_icon_view_real_unselect_all         (GtkIconView        *icon_view);
290 static void             gtk_icon_view_real_select_cursor_item   (GtkIconView        *icon_view);
291 static void             gtk_icon_view_real_toggle_cursor_item   (GtkIconView        *icon_view);
292 static gboolean         gtk_icon_view_real_activate_cursor_item (GtkIconView        *icon_view);
293
294  /* Internal functions */
295 static void                 gtk_icon_view_set_hadjustment_values         (GtkIconView            *icon_view);
296 static void                 gtk_icon_view_set_vadjustment_values         (GtkIconView            *icon_view);
297 static void                 gtk_icon_view_set_hadjustment                (GtkIconView            *icon_view,
298                                                                           GtkAdjustment          *adjustment);
299 static void                 gtk_icon_view_set_vadjustment                (GtkIconView            *icon_view,
300                                                                           GtkAdjustment          *adjustment);
301 static void                 gtk_icon_view_accessible_set_adjustment      (AtkObject              *accessible,
302                                                                           GtkOrientation          orientation,
303                                                                           GtkAdjustment          *adjustment);
304 static void                 gtk_icon_view_adjustment_changed             (GtkAdjustment          *adjustment,
305                                                                           GtkIconView            *icon_view);
306 static void                 gtk_icon_view_layout                         (GtkIconView            *icon_view);
307 static void                 gtk_icon_view_paint_item                     (GtkIconView            *icon_view,
308                                                                           cairo_t                *cr,
309                                                                           GtkIconViewItem        *item,
310                                                                           gint                    x,
311                                                                           gint                    y,
312                                                                           gboolean                draw_focus);
313 static void                 gtk_icon_view_paint_rubberband               (GtkIconView            *icon_view,
314                                                                           cairo_t                *cr);
315 static void                 gtk_icon_view_queue_draw_path                (GtkIconView *icon_view,
316                                                                           GtkTreePath *path);
317 static void                 gtk_icon_view_queue_draw_item                (GtkIconView            *icon_view,
318                                                                           GtkIconViewItem        *item);
319 static void                 gtk_icon_view_queue_layout                   (GtkIconView            *icon_view);
320 static void                 gtk_icon_view_set_cursor_item                (GtkIconView            *icon_view,
321                                                                           GtkIconViewItem        *item,
322                                                                           GtkCellRenderer        *cursor_cell);
323 static void                 gtk_icon_view_start_rubberbanding            (GtkIconView            *icon_view,
324                                                                           GdkDevice              *device,
325                                                                           gint                    x,
326                                                                           gint                    y);
327 static void                 gtk_icon_view_stop_rubberbanding             (GtkIconView            *icon_view);
328 static void                 gtk_icon_view_update_rubberband_selection    (GtkIconView            *icon_view);
329 static gboolean             gtk_icon_view_item_hit_test                  (GtkIconView            *icon_view,
330                                                                           GtkIconViewItem        *item,
331                                                                           gint                    x,
332                                                                           gint                    y,
333                                                                           gint                    width,
334                                                                           gint                    height);
335 static gboolean             gtk_icon_view_unselect_all_internal          (GtkIconView            *icon_view);
336 static void                 gtk_icon_view_cache_widths                   (GtkIconView            *icon_view);
337 static void                 gtk_icon_view_update_rubberband              (gpointer                data);
338 static void                 gtk_icon_view_item_invalidate_size           (GtkIconViewItem        *item);
339 static void                 gtk_icon_view_invalidate_sizes               (GtkIconView            *icon_view);
340 static void                 gtk_icon_view_add_move_binding               (GtkBindingSet          *binding_set,
341                                                                           guint                   keyval,
342                                                                           guint                   modmask,
343                                                                           GtkMovementStep         step,
344                                                                           gint                    count);
345 static gboolean             gtk_icon_view_real_move_cursor               (GtkIconView            *icon_view,
346                                                                           GtkMovementStep         step,
347                                                                           gint                    count);
348 static void                 gtk_icon_view_move_cursor_up_down            (GtkIconView            *icon_view,
349                                                                           gint                    count);
350 static void                 gtk_icon_view_move_cursor_page_up_down       (GtkIconView            *icon_view,
351                                                                           gint                    count);
352 static void                 gtk_icon_view_move_cursor_left_right         (GtkIconView            *icon_view,
353                                                                           gint                    count);
354 static void                 gtk_icon_view_move_cursor_start_end          (GtkIconView            *icon_view,
355                                                                           gint                    count);
356 static void                 gtk_icon_view_scroll_to_item                 (GtkIconView            *icon_view,
357                                                                           GtkIconViewItem        *item);
358 static void                 gtk_icon_view_select_item                    (GtkIconView            *icon_view,
359                                                                           GtkIconViewItem        *item);
360 static void                 gtk_icon_view_unselect_item                  (GtkIconView            *icon_view,
361                                                                           GtkIconViewItem        *item);
362 static gboolean             gtk_icon_view_select_all_between             (GtkIconView            *icon_view,
363                                                                           GtkIconViewItem        *anchor,
364                                                                           GtkIconViewItem        *cursor);
365 static GtkIconViewItem *    gtk_icon_view_get_item_at_coords             (GtkIconView            *icon_view,
366                                                                           gint                    x,
367                                                                           gint                    y,
368                                                                           gboolean                only_in_cell,
369                                                                           GtkCellRenderer       **cell_at_pos);
370 static void                 gtk_icon_view_set_cell_data                  (GtkIconView            *icon_view,
371                                                                           GtkIconViewItem        *item);
372
373 static void                 gtk_icon_view_ensure_cell_area               (GtkIconView            *icon_view,
374                                                                           GtkCellArea            *cell_area);
375
376 static GtkCellArea         *gtk_icon_view_cell_layout_get_area           (GtkCellLayout          *layout);
377
378 static void                 gtk_icon_view_item_selected_changed          (GtkIconView            *icon_view,
379                                                                           GtkIconViewItem        *item);
380
381 static void                 gtk_icon_view_add_editable                   (GtkCellArea            *area,
382                                                                           GtkCellRenderer        *renderer,
383                                                                           GtkCellEditable        *editable,
384                                                                           GdkRectangle           *cell_area,
385                                                                           const gchar            *path,
386                                                                           GtkIconView            *icon_view);
387 static void                 gtk_icon_view_remove_editable                (GtkCellArea            *area,
388                                                                           GtkCellRenderer        *renderer,
389                                                                           GtkCellEditable        *editable,
390                                                                           GtkIconView            *icon_view);
391 static void                 gtk_icon_view_context_changed                (GtkCellAreaContext     *context,
392                                                                           GParamSpec             *pspec,
393                                                                           GtkIconView            *icon_view);
394 static void                 update_text_cell                             (GtkIconView            *icon_view);
395 static void                 update_pixbuf_cell                           (GtkIconView            *icon_view);
396
397 /* Source side drag signals */
398 static void gtk_icon_view_drag_begin       (GtkWidget        *widget,
399                                             GdkDragContext   *context);
400 static void gtk_icon_view_drag_end         (GtkWidget        *widget,
401                                             GdkDragContext   *context);
402 static void gtk_icon_view_drag_data_get    (GtkWidget        *widget,
403                                             GdkDragContext   *context,
404                                             GtkSelectionData *selection_data,
405                                             guint             info,
406                                             guint             time);
407 static void gtk_icon_view_drag_data_delete (GtkWidget        *widget,
408                                             GdkDragContext   *context);
409
410 /* Target side drag signals */
411 static void     gtk_icon_view_drag_leave         (GtkWidget        *widget,
412                                                   GdkDragContext   *context,
413                                                   guint             time);
414 static gboolean gtk_icon_view_drag_motion        (GtkWidget        *widget,
415                                                   GdkDragContext   *context,
416                                                   gint              x,
417                                                   gint              y,
418                                                   guint             time);
419 static gboolean gtk_icon_view_drag_drop          (GtkWidget        *widget,
420                                                   GdkDragContext   *context,
421                                                   gint              x,
422                                                   gint              y,
423                                                   guint             time);
424 static void     gtk_icon_view_drag_data_received (GtkWidget        *widget,
425                                                   GdkDragContext   *context,
426                                                   gint              x,
427                                                   gint              y,
428                                                   GtkSelectionData *selection_data,
429                                                   guint             info,
430                                                   guint             time);
431 static gboolean gtk_icon_view_maybe_begin_drag   (GtkIconView             *icon_view,
432                                                   GdkEventMotion          *event);
433
434 static void     remove_scroll_timeout            (GtkIconView *icon_view);
435
436 /* GtkBuildable */
437 static GtkBuildableIface *parent_buildable_iface;
438 static void     gtk_icon_view_buildable_init             (GtkBuildableIface *iface);
439 static gboolean gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
440                                                           GtkBuilder    *builder,
441                                                           GObject       *child,
442                                                           const gchar   *tagname,
443                                                           GMarkupParser *parser,
444                                                           gpointer      *data);
445 static void     gtk_icon_view_buildable_custom_tag_end   (GtkBuildable  *buildable,
446                                                           GtkBuilder    *builder,
447                                                           GObject       *child,
448                                                           const gchar   *tagname,
449                                                           gpointer      *data);
450
451 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
452
453 G_DEFINE_TYPE_WITH_CODE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER,
454                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
455                                                 gtk_icon_view_cell_layout_init)
456                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
457                                                 gtk_icon_view_buildable_init)
458                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
459
460 static void
461 gtk_icon_view_class_init (GtkIconViewClass *klass)
462 {
463   GObjectClass *gobject_class;
464   GtkWidgetClass *widget_class;
465   GtkContainerClass *container_class;
466   GtkBindingSet *binding_set;
467   
468   binding_set = gtk_binding_set_by_class (klass);
469
470   g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
471
472   gobject_class = (GObjectClass *) klass;
473   widget_class = (GtkWidgetClass *) klass;
474   container_class = (GtkContainerClass *) klass;
475
476   gobject_class->constructor = gtk_icon_view_constructor;
477   gobject_class->dispose = gtk_icon_view_dispose;
478   gobject_class->set_property = gtk_icon_view_set_property;
479   gobject_class->get_property = gtk_icon_view_get_property;
480
481   widget_class->destroy = gtk_icon_view_destroy;
482   widget_class->realize = gtk_icon_view_realize;
483   widget_class->unrealize = gtk_icon_view_unrealize;
484   widget_class->style_updated = gtk_icon_view_style_updated;
485   widget_class->get_accessible = gtk_icon_view_get_accessible;
486   widget_class->get_preferred_width = gtk_icon_view_get_preferred_width;
487   widget_class->get_preferred_height = gtk_icon_view_get_preferred_height;
488   widget_class->size_allocate = gtk_icon_view_size_allocate;
489   widget_class->draw = gtk_icon_view_draw;
490   widget_class->motion_notify_event = gtk_icon_view_motion;
491   widget_class->button_press_event = gtk_icon_view_button_press;
492   widget_class->button_release_event = gtk_icon_view_button_release;
493   widget_class->key_press_event = gtk_icon_view_key_press;
494   widget_class->key_release_event = gtk_icon_view_key_release;
495   widget_class->drag_begin = gtk_icon_view_drag_begin;
496   widget_class->drag_end = gtk_icon_view_drag_end;
497   widget_class->drag_data_get = gtk_icon_view_drag_data_get;
498   widget_class->drag_data_delete = gtk_icon_view_drag_data_delete;
499   widget_class->drag_leave = gtk_icon_view_drag_leave;
500   widget_class->drag_motion = gtk_icon_view_drag_motion;
501   widget_class->drag_drop = gtk_icon_view_drag_drop;
502   widget_class->drag_data_received = gtk_icon_view_drag_data_received;
503   widget_class->state_flags_changed = gtk_icon_view_state_flags_changed;
504
505   container_class->remove = gtk_icon_view_remove;
506   container_class->forall = gtk_icon_view_forall;
507
508   klass->select_all = gtk_icon_view_real_select_all;
509   klass->unselect_all = gtk_icon_view_real_unselect_all;
510   klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
511   klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
512   klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;  
513   klass->move_cursor = gtk_icon_view_real_move_cursor;
514   
515   /* Properties */
516   /**
517    * GtkIconView:selection-mode:
518    * 
519    * The ::selection-mode property specifies the selection mode of
520    * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
521    * is enabled, for the other modes, only keyboard selection is possible.
522    *
523    * Since: 2.6
524    */
525   g_object_class_install_property (gobject_class,
526                                    PROP_SELECTION_MODE,
527                                    g_param_spec_enum ("selection-mode",
528                                                       P_("Selection mode"),
529                                                       P_("The selection mode"),
530                                                       GTK_TYPE_SELECTION_MODE,
531                                                       GTK_SELECTION_SINGLE,
532                                                       GTK_PARAM_READWRITE));
533
534   /**
535    * GtkIconView:pixbuf-column:
536    *
537    * The ::pixbuf-column property contains the number of the model column
538    * containing the pixbufs which are displayed. The pixbuf column must be 
539    * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
540    * display of pixbufs.
541    *
542    * Since: 2.6
543    */
544   g_object_class_install_property (gobject_class,
545                                    PROP_PIXBUF_COLUMN,
546                                    g_param_spec_int ("pixbuf-column",
547                                                      P_("Pixbuf column"),
548                                                      P_("Model column used to retrieve the icon pixbuf from"),
549                                                      -1, G_MAXINT, -1,
550                                                      GTK_PARAM_READWRITE));
551
552   /**
553    * GtkIconView:text-column:
554    *
555    * The ::text-column property contains the number of the model column
556    * containing the texts which are displayed. The text column must be 
557    * of type #G_TYPE_STRING. If this property and the :markup-column 
558    * property are both set to -1, no texts are displayed.   
559    *
560    * Since: 2.6
561    */
562   g_object_class_install_property (gobject_class,
563                                    PROP_TEXT_COLUMN,
564                                    g_param_spec_int ("text-column",
565                                                      P_("Text column"),
566                                                      P_("Model column used to retrieve the text from"),
567                                                      -1, G_MAXINT, -1,
568                                                      GTK_PARAM_READWRITE));
569
570   
571   /**
572    * GtkIconView:markup-column:
573    *
574    * The ::markup-column property contains the number of the model column
575    * containing markup information to be displayed. The markup column must be 
576    * of type #G_TYPE_STRING. If this property and the :text-column property 
577    * are both set to column numbers, it overrides the text column.
578    * If both are set to -1, no texts are displayed.   
579    *
580    * Since: 2.6
581    */
582   g_object_class_install_property (gobject_class,
583                                    PROP_MARKUP_COLUMN,
584                                    g_param_spec_int ("markup-column",
585                                                      P_("Markup column"),
586                                                      P_("Model column used to retrieve the text if using Pango markup"),
587                                                      -1, G_MAXINT, -1,
588                                                      GTK_PARAM_READWRITE));
589   
590   g_object_class_install_property (gobject_class,
591                                    PROP_MODEL,
592                                    g_param_spec_object ("model",
593                                                         P_("Icon View Model"),
594                                                         P_("The model for the icon view"),
595                                                         GTK_TYPE_TREE_MODEL,
596                                                         GTK_PARAM_READWRITE));
597   
598   /**
599    * GtkIconView:columns:
600    *
601    * The columns property contains the number of the columns in which the
602    * items should be displayed. If it is -1, the number of columns will
603    * be chosen automatically to fill the available area.
604    *
605    * Since: 2.6
606    */
607   g_object_class_install_property (gobject_class,
608                                    PROP_COLUMNS,
609                                    g_param_spec_int ("columns",
610                                                      P_("Number of columns"),
611                                                      P_("Number of columns to display"),
612                                                      -1, G_MAXINT, -1,
613                                                      GTK_PARAM_READWRITE));
614   
615
616   /**
617    * GtkIconView:item-width:
618    *
619    * The item-width property specifies the width to use for each item. 
620    * If it is set to -1, the icon view will automatically determine a 
621    * suitable item size.
622    *
623    * Since: 2.6
624    */
625   g_object_class_install_property (gobject_class,
626                                    PROP_ITEM_WIDTH,
627                                    g_param_spec_int ("item-width",
628                                                      P_("Width for each item"),
629                                                      P_("The width used for each item"),
630                                                      -1, G_MAXINT, -1,
631                                                      GTK_PARAM_READWRITE));  
632
633   /**
634    * GtkIconView:spacing:
635    *
636    * The spacing property specifies the space which is inserted between
637    * the cells (i.e. the icon and the text) of an item.
638    *
639    * Since: 2.6
640    */
641   g_object_class_install_property (gobject_class,
642                                    PROP_SPACING,
643                                    g_param_spec_int ("spacing",
644                                                      P_("Spacing"),
645                                                      P_("Space which is inserted between cells of an item"),
646                                                      0, G_MAXINT, 0,
647                                                      GTK_PARAM_READWRITE));
648
649   /**
650    * GtkIconView:row-spacing:
651    *
652    * The row-spacing property specifies the space which is inserted between
653    * the rows of the icon view.
654    *
655    * Since: 2.6
656    */
657   g_object_class_install_property (gobject_class,
658                                    PROP_ROW_SPACING,
659                                    g_param_spec_int ("row-spacing",
660                                                      P_("Row Spacing"),
661                                                      P_("Space which is inserted between grid rows"),
662                                                      0, G_MAXINT, 6,
663                                                      GTK_PARAM_READWRITE));
664
665   /**
666    * GtkIconView:column-spacing:
667    *
668    * The column-spacing property specifies the space which is inserted between
669    * the columns of the icon view.
670    *
671    * Since: 2.6
672    */
673   g_object_class_install_property (gobject_class,
674                                    PROP_COLUMN_SPACING,
675                                    g_param_spec_int ("column-spacing",
676                                                      P_("Column Spacing"),
677                                                      P_("Space which is inserted between grid columns"),
678                                                      0, G_MAXINT, 6,
679                                                      GTK_PARAM_READWRITE));
680
681   /**
682    * GtkIconView:margin:
683    *
684    * The margin property specifies the space which is inserted 
685    * at the edges of the icon view.
686    *
687    * Since: 2.6
688    */
689   g_object_class_install_property (gobject_class,
690                                    PROP_MARGIN,
691                                    g_param_spec_int ("margin",
692                                                      P_("Margin"),
693                                                      P_("Space which is inserted at the edges of the icon view"),
694                                                      0, G_MAXINT, 6,
695                                                      GTK_PARAM_READWRITE));
696
697   /**
698    * GtkIconView:item-orientation:
699    *
700    * The item-orientation property specifies how the cells (i.e. the icon and
701    * the text) of the item are positioned relative to each other.
702    *
703    * Since: 2.6
704    */
705   g_object_class_install_property (gobject_class,
706                                    PROP_ITEM_ORIENTATION,
707                                    g_param_spec_enum ("item-orientation",
708                                                       P_("Item Orientation"),
709                                                       P_("How the text and icon of each item are positioned relative to each other"),
710                                                       GTK_TYPE_ORIENTATION,
711                                                       GTK_ORIENTATION_VERTICAL,
712                                                       GTK_PARAM_READWRITE));
713
714   /**
715    * GtkIconView:reorderable:
716    *
717    * The reorderable property specifies if the items can be reordered
718    * by DND.
719    *
720    * Since: 2.8
721    */
722   g_object_class_install_property (gobject_class,
723                                    PROP_REORDERABLE,
724                                    g_param_spec_boolean ("reorderable",
725                                                          P_("Reorderable"),
726                                                          P_("View is reorderable"),
727                                                          FALSE,
728                                                          G_PARAM_READWRITE));
729
730     g_object_class_install_property (gobject_class,
731                                      PROP_TOOLTIP_COLUMN,
732                                      g_param_spec_int ("tooltip-column",
733                                                        P_("Tooltip Column"),
734                                                        P_("The column in the model containing the tooltip texts for the items"),
735                                                        -1,
736                                                        G_MAXINT,
737                                                        -1,
738                                                        GTK_PARAM_READWRITE));
739
740   /**
741    * GtkIconView:item-padding:
742    *
743    * The item-padding property specifies the padding around each
744    * of the icon view's item.
745    *
746    * Since: 2.18
747    */
748   g_object_class_install_property (gobject_class,
749                                    PROP_ITEM_PADDING,
750                                    g_param_spec_int ("item-padding",
751                                                      P_("Item Padding"),
752                                                      P_("Padding around icon view items"),
753                                                      0, G_MAXINT, 6,
754                                                      GTK_PARAM_READWRITE));
755
756   /**
757    * GtkIconView:cell-area:
758    *
759    * The #GtkCellArea used to layout cell renderers for this view.
760    *
761    * If no area is specified when creating the icon view with gtk_icon_view_new_with_area() 
762    * a #GtkCellAreaBox will be used.
763    *
764    * Since: 3.0
765    */
766   g_object_class_install_property (gobject_class,
767                                    PROP_CELL_AREA,
768                                    g_param_spec_object ("cell-area",
769                                                         P_("Cell Area"),
770                                                         P_("The GtkCellArea used to layout cells"),
771                                                         GTK_TYPE_CELL_AREA,
772                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
773
774   /* Scrollable interface properties */
775   g_object_class_override_property (gobject_class, PROP_HADJUSTMENT,    "hadjustment");
776   g_object_class_override_property (gobject_class, PROP_VADJUSTMENT,    "vadjustment");
777   g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
778   g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
779
780   /* Style properties */
781   gtk_widget_class_install_style_property (widget_class,
782                                            g_param_spec_boxed ("selection-box-color",
783                                                                P_("Selection Box Color"),
784                                                                P_("Color of the selection box"),
785                                                                GDK_TYPE_COLOR,
786                                                                GTK_PARAM_READABLE));
787
788   gtk_widget_class_install_style_property (widget_class,
789                                            g_param_spec_uchar ("selection-box-alpha",
790                                                                P_("Selection Box Alpha"),
791                                                                P_("Opacity of the selection box"),
792                                                                0, 0xff,
793                                                                0x40,
794                                                                GTK_PARAM_READABLE));
795
796   /* Signals */
797   /**
798    * GtkIconView::item-activated:
799    * @iconview: the object on which the signal is emitted
800    * @path: the #GtkTreePath for the activated item
801    *
802    * The ::item-activated signal is emitted when the method
803    * gtk_icon_view_item_activated() is called or the user double 
804    * clicks an item. It is also emitted when a non-editable item
805    * is selected and one of the keys: Space, Return or Enter is
806    * pressed.
807    */
808   icon_view_signals[ITEM_ACTIVATED] =
809     g_signal_new (I_("item-activated"),
810                   G_TYPE_FROM_CLASS (gobject_class),
811                   G_SIGNAL_RUN_LAST,
812                   G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
813                   NULL, NULL,
814                   g_cclosure_marshal_VOID__BOXED,
815                   G_TYPE_NONE, 1,
816                   GTK_TYPE_TREE_PATH);
817
818   /**
819    * GtkIconView::selection-changed:
820    * @iconview: the object on which the signal is emitted
821    *
822    * The ::selection-changed signal is emitted when the selection
823    * (i.e. the set of selected items) changes.
824    */
825   icon_view_signals[SELECTION_CHANGED] =
826     g_signal_new (I_("selection-changed"),
827                   G_TYPE_FROM_CLASS (gobject_class),
828                   G_SIGNAL_RUN_FIRST,
829                   G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
830                   NULL, NULL,
831                   g_cclosure_marshal_VOID__VOID,
832                   G_TYPE_NONE, 0);
833   
834   /**
835    * GtkIconView::select-all:
836    * @iconview: the object on which the signal is emitted
837    *
838    * A <link linkend="keybinding-signals">keybinding signal</link>
839    * which gets emitted when the user selects all items.
840    *
841    * Applications should not connect to it, but may emit it with
842    * g_signal_emit_by_name() if they need to control selection
843    * programmatically.
844    * 
845    * The default binding for this signal is Ctrl-a.
846    */
847   icon_view_signals[SELECT_ALL] =
848     g_signal_new (I_("select-all"),
849                   G_TYPE_FROM_CLASS (gobject_class),
850                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
851                   G_STRUCT_OFFSET (GtkIconViewClass, select_all),
852                   NULL, NULL,
853                   g_cclosure_marshal_VOID__VOID,
854                   G_TYPE_NONE, 0);
855   
856   /**
857    * GtkIconView::unselect-all:
858    * @iconview: the object on which the signal is emitted
859    *
860    * A <link linkend="keybinding-signals">keybinding signal</link>
861    * which gets emitted when the user unselects all items.
862    *
863    * Applications should not connect to it, but may emit it with
864    * g_signal_emit_by_name() if they need to control selection
865    * programmatically.
866    * 
867    * The default binding for this signal is Ctrl-Shift-a. 
868    */
869   icon_view_signals[UNSELECT_ALL] =
870     g_signal_new (I_("unselect-all"),
871                   G_TYPE_FROM_CLASS (gobject_class),
872                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
873                   G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
874                   NULL, NULL,
875                   g_cclosure_marshal_VOID__VOID,
876                   G_TYPE_NONE, 0);
877
878   /**
879    * GtkIconView::select-cursor-item:
880    * @iconview: the object on which the signal is emitted
881    *
882    * A <link linkend="keybinding-signals">keybinding signal</link>
883    * which gets emitted when the user selects the item that is currently
884    * focused.
885    *
886    * Applications should not connect to it, but may emit it with
887    * g_signal_emit_by_name() if they need to control selection
888    * programmatically.
889    * 
890    * There is no default binding for this signal.
891    */
892   icon_view_signals[SELECT_CURSOR_ITEM] =
893     g_signal_new (I_("select-cursor-item"),
894                   G_TYPE_FROM_CLASS (gobject_class),
895                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
896                   G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
897                   NULL, NULL,
898                   g_cclosure_marshal_VOID__VOID,
899                   G_TYPE_NONE, 0);
900
901   /**
902    * GtkIconView::toggle-cursor-item:
903    * @iconview: the object on which the signal is emitted
904    *
905    * A <link linkend="keybinding-signals">keybinding signal</link>
906    * which gets emitted when the user toggles whether the currently
907    * focused item is selected or not. The exact effect of this 
908    * depend on the selection mode.
909    *
910    * Applications should not connect to it, but may emit it with
911    * g_signal_emit_by_name() if they need to control selection
912    * programmatically.
913    * 
914    * There is no default binding for this signal is Ctrl-Space.
915    */
916   icon_view_signals[TOGGLE_CURSOR_ITEM] =
917     g_signal_new (I_("toggle-cursor-item"),
918                   G_TYPE_FROM_CLASS (gobject_class),
919                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
920                   G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
921                   NULL, NULL,
922                   g_cclosure_marshal_VOID__VOID,
923                   G_TYPE_NONE, 0);
924
925   /**
926    * GtkIconView::activate-cursor-item:
927    * @iconview: the object on which the signal is emitted
928    *
929    * A <link linkend="keybinding-signals">keybinding signal</link>
930    * which gets emitted when the user activates the currently 
931    * focused item. 
932    *
933    * Applications should not connect to it, but may emit it with
934    * g_signal_emit_by_name() if they need to control activation
935    * programmatically.
936    * 
937    * The default bindings for this signal are Space, Return and Enter.
938    */
939   icon_view_signals[ACTIVATE_CURSOR_ITEM] =
940     g_signal_new (I_("activate-cursor-item"),
941                   G_TYPE_FROM_CLASS (gobject_class),
942                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
943                   G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
944                   NULL, NULL,
945                   _gtk_marshal_BOOLEAN__VOID,
946                   G_TYPE_BOOLEAN, 0);
947   
948   /**
949    * GtkIconView::move-cursor:
950    * @iconview: the object which received the signal
951    * @step: the granularity of the move, as a #GtkMovementStep
952    * @count: the number of @step units to move
953    *
954    * The ::move-cursor signal is a
955    * <link linkend="keybinding-signals">keybinding signal</link>
956    * which gets emitted when the user initiates a cursor movement.
957    *
958    * Applications should not connect to it, but may emit it with
959    * g_signal_emit_by_name() if they need to control the cursor
960    * programmatically.
961    *
962    * The default bindings for this signal include
963    * <itemizedlist>
964    * <listitem>Arrow keys which move by individual steps</listitem>
965    * <listitem>Home/End keys which move to the first/last item</listitem>
966    * <listitem>PageUp/PageDown which move by "pages"</listitem>
967    * </itemizedlist>
968    *
969    * All of these will extend the selection when combined with
970    * the Shift modifier.
971    */
972   icon_view_signals[MOVE_CURSOR] =
973     g_signal_new (I_("move-cursor"),
974                   G_TYPE_FROM_CLASS (gobject_class),
975                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
976                   G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
977                   NULL, NULL,
978                   _gtk_marshal_BOOLEAN__ENUM_INT,
979                   G_TYPE_BOOLEAN, 2,
980                   GTK_TYPE_MOVEMENT_STEP,
981                   G_TYPE_INT);
982
983   /* Key bindings */
984   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, 
985                                 "select-all", 0);
986   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, 
987                                 "unselect-all", 0);
988   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, 
989                                 "toggle-cursor-item", 0);
990   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
991                                 "toggle-cursor-item", 0);
992
993   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, 
994                                 "activate-cursor-item", 0);
995   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
996                                 "activate-cursor-item", 0);
997   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, 
998                                 "activate-cursor-item", 0);
999   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, 
1000                                 "activate-cursor-item", 0);
1001   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, 
1002                                 "activate-cursor-item", 0);
1003
1004   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Up, 0,
1005                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1006   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0,
1007                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1008
1009   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Down, 0,
1010                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1011   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0,
1012                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1013
1014   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK,
1015                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1016
1017   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK,
1018                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1019
1020   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Home, 0,
1021                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1022   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
1023                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1024
1025   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_End, 0,
1026                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1027   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0,
1028                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1029
1030   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0,
1031                                   GTK_MOVEMENT_PAGES, -1);
1032   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0,
1033                                   GTK_MOVEMENT_PAGES, -1);
1034
1035   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0,
1036                                   GTK_MOVEMENT_PAGES, 1);
1037   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0,
1038                                   GTK_MOVEMENT_PAGES, 1);
1039
1040   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Right, 0, 
1041                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1042   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_Left, 0, 
1043                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1044
1045   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Right, 0, 
1046                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1047   gtk_icon_view_add_move_binding (binding_set, GDK_KEY_KP_Left, 0, 
1048                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1049 }
1050
1051 static void
1052 gtk_icon_view_buildable_init (GtkBuildableIface *iface)
1053 {
1054   parent_buildable_iface = g_type_interface_peek_parent (iface);
1055   iface->add_child = _gtk_cell_layout_buildable_add_child;
1056   iface->custom_tag_start = gtk_icon_view_buildable_custom_tag_start;
1057   iface->custom_tag_end = gtk_icon_view_buildable_custom_tag_end;
1058 }
1059
1060 static void
1061 gtk_icon_view_cell_layout_init (GtkCellLayoutIface *iface)
1062 {
1063   iface->get_area = gtk_icon_view_cell_layout_get_area;
1064 }
1065
1066 static void
1067 gtk_icon_view_init (GtkIconView *icon_view)
1068 {
1069   icon_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon_view,
1070                                                  GTK_TYPE_ICON_VIEW,
1071                                                  GtkIconViewPrivate);
1072
1073   icon_view->priv->width = 0;
1074   icon_view->priv->height = 0;
1075   icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
1076   icon_view->priv->pressed_button = -1;
1077   icon_view->priv->press_start_x = -1;
1078   icon_view->priv->press_start_y = -1;
1079   icon_view->priv->text_column = -1;
1080   icon_view->priv->markup_column = -1;  
1081   icon_view->priv->pixbuf_column = -1;
1082   icon_view->priv->text_cell = NULL;
1083   icon_view->priv->pixbuf_cell = NULL;  
1084   icon_view->priv->tooltip_column = -1;  
1085
1086   gtk_widget_set_can_focus (GTK_WIDGET (icon_view), TRUE);
1087
1088   icon_view->priv->item_orientation = GTK_ORIENTATION_VERTICAL;
1089
1090   icon_view->priv->columns = -1;
1091   icon_view->priv->item_width = -1;
1092   icon_view->priv->spacing = 0;
1093   icon_view->priv->row_spacing = 6;
1094   icon_view->priv->column_spacing = 6;
1095   icon_view->priv->margin = 6;
1096   icon_view->priv->item_padding = 6;
1097
1098   icon_view->priv->draw_focus = TRUE;
1099
1100   icon_view->priv->row_contexts = 
1101     g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
1102 }
1103
1104 /* GObject methods */
1105 static GObject *
1106 gtk_icon_view_constructor (GType               type,
1107                            guint               n_construct_properties,
1108                            GObjectConstructParam *construct_properties)
1109 {
1110   GtkIconView        *icon_view;
1111   GObject            *object;
1112
1113   object = G_OBJECT_CLASS (gtk_icon_view_parent_class)->constructor
1114     (type, n_construct_properties, construct_properties);
1115
1116   icon_view = (GtkIconView *) object;
1117
1118   gtk_icon_view_ensure_cell_area (icon_view, NULL);
1119
1120   return object;
1121 }
1122
1123 static void
1124 gtk_icon_view_dispose (GObject *object)
1125 {
1126   GtkIconView *icon_view;
1127   GtkIconViewPrivate *priv;
1128
1129   icon_view = GTK_ICON_VIEW (object);
1130   priv      = icon_view->priv;
1131
1132   if (priv->cell_area_context)
1133     {
1134       g_signal_handler_disconnect (priv->cell_area_context, priv->context_changed_id);
1135       priv->context_changed_id = 0;
1136
1137       g_object_unref (priv->cell_area_context);
1138       priv->cell_area_context = NULL;
1139     }
1140
1141   if (priv->row_contexts)
1142     {
1143       g_ptr_array_free (priv->row_contexts, TRUE);
1144       priv->row_contexts = NULL;
1145     }
1146
1147   if (priv->cell_area)
1148     {
1149       gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
1150
1151       g_signal_handler_disconnect (priv->cell_area, priv->add_editable_id);
1152       g_signal_handler_disconnect (priv->cell_area, priv->remove_editable_id);
1153       priv->add_editable_id = 0;
1154       priv->remove_editable_id = 0;
1155
1156       g_object_unref (priv->cell_area);
1157       priv->cell_area = NULL;
1158     }
1159
1160   G_OBJECT_CLASS (gtk_icon_view_parent_class)->dispose (object);
1161 }
1162
1163 static void
1164 gtk_icon_view_set_property (GObject      *object,
1165                             guint         prop_id,
1166                             const GValue *value,
1167                             GParamSpec   *pspec)
1168 {
1169   GtkIconView *icon_view;
1170   GtkCellArea *area;
1171
1172   icon_view = GTK_ICON_VIEW (object);
1173
1174   switch (prop_id)
1175     {
1176     case PROP_SELECTION_MODE:
1177       gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
1178       break;
1179     case PROP_PIXBUF_COLUMN:
1180       gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
1181       break;
1182     case PROP_TEXT_COLUMN:
1183       gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
1184       break;
1185     case PROP_MARKUP_COLUMN:
1186       gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
1187       break;
1188     case PROP_MODEL:
1189       gtk_icon_view_set_model (icon_view, g_value_get_object (value));
1190       break;
1191     case PROP_ITEM_ORIENTATION:
1192       gtk_icon_view_set_item_orientation (icon_view, g_value_get_enum (value));
1193       break;
1194     case PROP_COLUMNS:
1195       gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
1196       break;
1197     case PROP_ITEM_WIDTH:
1198       gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
1199       break;
1200     case PROP_SPACING:
1201       gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
1202       break;
1203     case PROP_ROW_SPACING:
1204       gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
1205       break;
1206     case PROP_COLUMN_SPACING:
1207       gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
1208       break;
1209     case PROP_MARGIN:
1210       gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
1211       break;
1212     case PROP_REORDERABLE:
1213       gtk_icon_view_set_reorderable (icon_view, g_value_get_boolean (value));
1214       break;
1215       
1216     case PROP_TOOLTIP_COLUMN:
1217       gtk_icon_view_set_tooltip_column (icon_view, g_value_get_int (value));
1218       break;
1219
1220     case PROP_ITEM_PADDING:
1221       gtk_icon_view_set_item_padding (icon_view, g_value_get_int (value));
1222       break;
1223
1224     case PROP_CELL_AREA:
1225       /* Construct-only, can only be assigned once */
1226       area = g_value_get_object (value);
1227       if (area)
1228         {
1229           if (icon_view->priv->cell_area != NULL)
1230             {
1231               g_warning ("cell-area has already been set, ignoring construct property");
1232               g_object_ref_sink (area);
1233               g_object_unref (area);
1234             }
1235           else
1236             gtk_icon_view_ensure_cell_area (icon_view, area);
1237         }
1238       break;
1239
1240     case PROP_HADJUSTMENT:
1241       gtk_icon_view_set_hadjustment (icon_view, g_value_get_object (value));
1242       break;
1243     case PROP_VADJUSTMENT:
1244       gtk_icon_view_set_vadjustment (icon_view, g_value_get_object (value));
1245       break;
1246     case PROP_HSCROLL_POLICY:
1247       icon_view->priv->hscroll_policy = g_value_get_enum (value);
1248       gtk_widget_queue_resize (GTK_WIDGET (icon_view));
1249       break;
1250     case PROP_VSCROLL_POLICY:
1251       icon_view->priv->vscroll_policy = g_value_get_enum (value);
1252       gtk_widget_queue_resize (GTK_WIDGET (icon_view));
1253       break;
1254
1255     default:
1256       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1257       break;
1258     }
1259 }
1260
1261 static void
1262 gtk_icon_view_get_property (GObject      *object,
1263                             guint         prop_id,
1264                             GValue       *value,
1265                             GParamSpec   *pspec)
1266 {
1267   GtkIconView *icon_view;
1268
1269   icon_view = GTK_ICON_VIEW (object);
1270
1271   switch (prop_id)
1272     {
1273     case PROP_SELECTION_MODE:
1274       g_value_set_enum (value, icon_view->priv->selection_mode);
1275       break;
1276     case PROP_PIXBUF_COLUMN:
1277       g_value_set_int (value, icon_view->priv->pixbuf_column);
1278       break;
1279     case PROP_TEXT_COLUMN:
1280       g_value_set_int (value, icon_view->priv->text_column);
1281       break;
1282     case PROP_MARKUP_COLUMN:
1283       g_value_set_int (value, icon_view->priv->markup_column);
1284       break;
1285     case PROP_MODEL:
1286       g_value_set_object (value, icon_view->priv->model);
1287       break;
1288     case PROP_ITEM_ORIENTATION:
1289       g_value_set_enum (value, icon_view->priv->item_orientation);
1290       break;
1291     case PROP_COLUMNS:
1292       g_value_set_int (value, icon_view->priv->columns);
1293       break;
1294     case PROP_ITEM_WIDTH:
1295       g_value_set_int (value, icon_view->priv->item_width);
1296       break;
1297     case PROP_SPACING:
1298       g_value_set_int (value, icon_view->priv->spacing);
1299       break;
1300     case PROP_ROW_SPACING:
1301       g_value_set_int (value, icon_view->priv->row_spacing);
1302       break;
1303     case PROP_COLUMN_SPACING:
1304       g_value_set_int (value, icon_view->priv->column_spacing);
1305       break;
1306     case PROP_MARGIN:
1307       g_value_set_int (value, icon_view->priv->margin);
1308       break;
1309     case PROP_REORDERABLE:
1310       g_value_set_boolean (value, icon_view->priv->reorderable);
1311       break;
1312     case PROP_TOOLTIP_COLUMN:
1313       g_value_set_int (value, icon_view->priv->tooltip_column);
1314       break;
1315
1316     case PROP_ITEM_PADDING:
1317       g_value_set_int (value, icon_view->priv->item_padding);
1318       break;
1319
1320     case PROP_CELL_AREA:
1321       g_value_set_object (value, icon_view->priv->cell_area);
1322       break;
1323
1324     case PROP_HADJUSTMENT:
1325       g_value_set_object (value, icon_view->priv->hadjustment);
1326       break;
1327     case PROP_VADJUSTMENT:
1328       g_value_set_object (value, icon_view->priv->vadjustment);
1329       break;
1330     case PROP_HSCROLL_POLICY:
1331       g_value_set_enum (value, icon_view->priv->hscroll_policy);
1332       break;
1333     case PROP_VSCROLL_POLICY:
1334       g_value_set_enum (value, icon_view->priv->vscroll_policy);
1335       break;
1336
1337     default:
1338       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1339       break;
1340     }
1341 }
1342
1343 /* GtkWidget methods */
1344 static void
1345 gtk_icon_view_destroy (GtkWidget *widget)
1346 {
1347   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1348
1349   gtk_icon_view_set_model (icon_view, NULL);
1350
1351   if (icon_view->priv->layout_idle_id != 0)
1352     {
1353       g_source_remove (icon_view->priv->layout_idle_id);
1354       icon_view->priv->layout_idle_id = 0;
1355     }
1356
1357   if (icon_view->priv->scroll_to_path != NULL)
1358     {
1359       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1360       icon_view->priv->scroll_to_path = NULL;
1361     }
1362
1363   remove_scroll_timeout (icon_view);
1364
1365   if (icon_view->priv->hadjustment != NULL)
1366     {
1367       g_object_unref (icon_view->priv->hadjustment);
1368       icon_view->priv->hadjustment = NULL;
1369     }
1370
1371   if (icon_view->priv->vadjustment != NULL)
1372     {
1373       g_object_unref (icon_view->priv->vadjustment);
1374       icon_view->priv->vadjustment = NULL;
1375     }
1376
1377   GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->destroy (widget);
1378 }
1379
1380 static void
1381 gtk_icon_view_realize (GtkWidget *widget)
1382 {
1383   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1384   GtkAllocation allocation;
1385   GdkWindow *window;
1386   GdkWindowAttr attributes;
1387   gint attributes_mask;
1388   GtkStyleContext *context;
1389
1390   gtk_widget_set_realized (widget, TRUE);
1391
1392   gtk_widget_get_allocation (widget, &allocation);
1393
1394   /* Make the main, clipping window */
1395   attributes.window_type = GDK_WINDOW_CHILD;
1396   attributes.x = allocation.x;
1397   attributes.y = allocation.y;
1398   attributes.width = allocation.width;
1399   attributes.height = allocation.height;
1400   attributes.wclass = GDK_INPUT_OUTPUT;
1401   attributes.visual = gtk_widget_get_visual (widget);
1402   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1403
1404   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1405
1406   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1407                            &attributes, attributes_mask);
1408   gtk_widget_set_window (widget, window);
1409   gdk_window_set_user_data (window, widget);
1410
1411   gtk_widget_get_allocation (widget, &allocation);
1412
1413   /* Make the window for the icon view */
1414   attributes.x = 0;
1415   attributes.y = 0;
1416   attributes.width = MAX (icon_view->priv->width, allocation.width);
1417   attributes.height = MAX (icon_view->priv->height, allocation.height);
1418   attributes.event_mask = (GDK_EXPOSURE_MASK |
1419                            GDK_SCROLL_MASK |
1420                            GDK_POINTER_MOTION_MASK |
1421                            GDK_BUTTON_PRESS_MASK |
1422                            GDK_BUTTON_RELEASE_MASK |
1423                            GDK_KEY_PRESS_MASK |
1424                            GDK_KEY_RELEASE_MASK) |
1425     gtk_widget_get_events (widget);
1426   
1427   icon_view->priv->bin_window = gdk_window_new (window,
1428                                                 &attributes, attributes_mask);
1429   gdk_window_set_user_data (icon_view->priv->bin_window, widget);
1430
1431   context = gtk_widget_get_style_context (widget);
1432
1433   gtk_style_context_save (context);
1434   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
1435   gtk_style_context_set_background (context, icon_view->priv->bin_window);
1436   gtk_style_context_restore (context);
1437
1438   gdk_window_show (icon_view->priv->bin_window);
1439 }
1440
1441 static void
1442 gtk_icon_view_unrealize (GtkWidget *widget)
1443 {
1444   GtkIconView *icon_view;
1445
1446   icon_view = GTK_ICON_VIEW (widget);
1447
1448   gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
1449   gdk_window_destroy (icon_view->priv->bin_window);
1450   icon_view->priv->bin_window = NULL;
1451
1452   GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->unrealize (widget);
1453 }
1454
1455 static void
1456 _gtk_icon_view_update_background (GtkIconView *icon_view)
1457 {
1458   GtkWidget *widget = GTK_WIDGET (icon_view);
1459
1460   if (gtk_widget_get_realized (widget))
1461     {
1462       GtkStyleContext *context;
1463
1464       context = gtk_widget_get_style_context (widget);
1465
1466       gtk_style_context_save (context);
1467       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
1468
1469       gtk_style_context_set_background (context, gtk_widget_get_window (widget));
1470       gtk_style_context_set_background (context, icon_view->priv->bin_window);
1471
1472       gtk_style_context_restore (context);
1473     }
1474 }
1475
1476 static void
1477 gtk_icon_view_state_flags_changed (GtkWidget     *widget,
1478                                    GtkStateFlags  previous_state)
1479 {
1480   _gtk_icon_view_update_background (GTK_ICON_VIEW (widget));
1481   gtk_widget_queue_draw (widget);
1482 }
1483
1484 static void
1485 gtk_icon_view_style_updated (GtkWidget *widget)
1486 {
1487   GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->style_updated (widget);
1488
1489   _gtk_icon_view_update_background (GTK_ICON_VIEW (widget));
1490   gtk_widget_queue_resize (widget);
1491 }
1492
1493 static void
1494 gtk_icon_view_get_preferred_width (GtkWidget      *widget,
1495                                    gint           *minimum,
1496                                    gint           *natural)
1497 {
1498   *minimum = *natural = GTK_ICON_VIEW (widget)->priv->width;
1499 }
1500
1501 static void
1502 gtk_icon_view_get_preferred_height (GtkWidget      *widget,
1503                                    gint           *minimum,
1504                                    gint           *natural)
1505 {
1506   *minimum = *natural = GTK_ICON_VIEW (widget)->priv->height;
1507 }
1508
1509 static void
1510 gtk_icon_view_allocate_children (GtkIconView *icon_view)
1511 {
1512   GList *list;
1513
1514   for (list = icon_view->priv->children; list; list = list->next)
1515     {
1516       GtkIconViewChild *child = list->data;
1517
1518       /* totally ignore our child's requisition */
1519       gtk_widget_size_allocate (child->widget, &child->area);
1520     }
1521 }
1522
1523 static void
1524 gtk_icon_view_size_allocate (GtkWidget      *widget,
1525                              GtkAllocation  *allocation)
1526 {
1527   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
1528
1529   gtk_widget_set_allocation (widget, allocation);
1530
1531   if (gtk_widget_get_realized (widget))
1532     {
1533       gdk_window_move_resize (gtk_widget_get_window (widget),
1534                               allocation->x, allocation->y,
1535                               allocation->width, allocation->height);
1536       gdk_window_resize (icon_view->priv->bin_window,
1537                          MAX (icon_view->priv->width, allocation->width),
1538                          MAX (icon_view->priv->height, allocation->height));
1539     }
1540
1541   gtk_icon_view_layout (icon_view);
1542   
1543   gtk_icon_view_allocate_children (icon_view);
1544
1545   /* Delay signal emission */
1546   g_object_freeze_notify (G_OBJECT (icon_view->priv->hadjustment));
1547   g_object_freeze_notify (G_OBJECT (icon_view->priv->vadjustment));
1548
1549   gtk_icon_view_set_hadjustment_values (icon_view);
1550   gtk_icon_view_set_vadjustment_values (icon_view);
1551
1552   if (gtk_widget_get_realized (widget) &&
1553       icon_view->priv->scroll_to_path)
1554     {
1555       GtkTreePath *path;
1556       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
1557       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
1558       icon_view->priv->scroll_to_path = NULL;
1559
1560       gtk_icon_view_scroll_to_path (icon_view, path,
1561                                     icon_view->priv->scroll_to_use_align,
1562                                     icon_view->priv->scroll_to_row_align,
1563                                     icon_view->priv->scroll_to_col_align);
1564       gtk_tree_path_free (path);
1565     }
1566
1567   /* Emit any pending signals now */
1568   g_object_thaw_notify (G_OBJECT (icon_view->priv->hadjustment));
1569   g_object_thaw_notify (G_OBJECT (icon_view->priv->vadjustment));
1570 }
1571
1572 static gboolean
1573 gtk_icon_view_draw (GtkWidget *widget,
1574                     cairo_t   *cr)
1575 {
1576   GtkIconView *icon_view;
1577   GList *icons;
1578   GtkTreePath *path;
1579   gint dest_index;
1580   GtkIconViewDropPosition dest_pos;
1581   GtkIconViewItem *dest_item = NULL;
1582
1583   icon_view = GTK_ICON_VIEW (widget);
1584
1585   if (!gtk_cairo_should_draw_window (cr, icon_view->priv->bin_window))
1586     return FALSE;
1587
1588   cairo_save (cr);
1589
1590   gtk_cairo_transform_to_window (cr, widget, icon_view->priv->bin_window);
1591       
1592   cairo_set_line_width (cr, 1.);
1593
1594   gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
1595
1596   if (path)
1597     {
1598       dest_index = gtk_tree_path_get_indices (path)[0];
1599       gtk_tree_path_free (path);
1600     }
1601   else
1602     dest_index = -1;
1603
1604   for (icons = icon_view->priv->items; icons; icons = icons->next) 
1605     {
1606       GtkIconViewItem *item = icons->data;
1607       GdkRectangle paint_area;
1608
1609       paint_area.x      = ((GdkRectangle *)item)->x      - icon_view->priv->item_padding;
1610       paint_area.y      = ((GdkRectangle *)item)->y      - icon_view->priv->item_padding;
1611       paint_area.width  = ((GdkRectangle *)item)->width  + icon_view->priv->item_padding * 2;
1612       paint_area.height = ((GdkRectangle *)item)->height + icon_view->priv->item_padding * 2;
1613       
1614       cairo_save (cr);
1615
1616       cairo_rectangle (cr, paint_area.x, paint_area.y, paint_area.width, paint_area.height);
1617       cairo_clip (cr);
1618
1619       if (gdk_cairo_get_clip_rectangle (cr, NULL))
1620         {
1621           gtk_icon_view_paint_item (icon_view, cr, item,
1622                                     ((GdkRectangle *)item)->x, ((GdkRectangle *)item)->y,
1623                                     icon_view->priv->draw_focus); 
1624      
1625           if (dest_index == item->index)
1626             dest_item = item;
1627         }
1628
1629       cairo_restore (cr);
1630     }
1631
1632   if (dest_item &&
1633       dest_pos != GTK_ICON_VIEW_NO_DROP)
1634     {
1635       GtkStyleContext *context;
1636       GtkStateFlags state;
1637       GdkRectangle rect = { 0 };
1638
1639       context = gtk_widget_get_style_context (widget);
1640       state = gtk_widget_get_state_flags (widget);
1641
1642       switch (dest_pos)
1643         {
1644         case GTK_ICON_VIEW_DROP_INTO:
1645           rect = dest_item->cell_area;
1646           break;
1647         case GTK_ICON_VIEW_DROP_ABOVE:
1648           rect.x = dest_item->cell_area.x;
1649           rect.y = dest_item->cell_area.y - 1;
1650           rect.width = dest_item->cell_area.width;
1651           rect.height = 2;
1652           break;
1653         case GTK_ICON_VIEW_DROP_LEFT:
1654           rect.x = dest_item->cell_area.x - 1;
1655           rect.y = dest_item->cell_area.y;
1656           rect.width = 2;
1657           rect.height = dest_item->cell_area.height;
1658           break;
1659         case GTK_ICON_VIEW_DROP_BELOW:
1660           rect.x = dest_item->cell_area.x;
1661           rect.y = dest_item->cell_area.y + dest_item->cell_area.height - 1;
1662           rect.width = dest_item->cell_area.width;
1663           rect.height = 2;
1664           break;
1665         case GTK_ICON_VIEW_DROP_RIGHT:
1666           rect.x = dest_item->cell_area.x + dest_item->cell_area.width - 1;
1667           rect.y = dest_item->cell_area.y;
1668           rect.width = 2;
1669           rect.height = dest_item->cell_area.height;
1670         case GTK_ICON_VIEW_NO_DROP: ;
1671           break;
1672         }
1673
1674       gtk_style_context_set_state (context, state);
1675       gtk_render_focus (context, cr,
1676                         rect.x, rect.y,
1677                         rect.width, rect.height);
1678     }
1679   
1680   if (icon_view->priv->doing_rubberband)
1681     gtk_icon_view_paint_rubberband (icon_view, cr);
1682
1683   cairo_restore (cr);
1684
1685   GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->draw (widget, cr);
1686
1687   return TRUE;
1688 }
1689
1690 static gboolean
1691 rubberband_scroll_timeout (gpointer data)
1692 {
1693   GtkIconView *icon_view = data;
1694
1695   gtk_adjustment_set_value (icon_view->priv->vadjustment,
1696                             gtk_adjustment_get_value (icon_view->priv->vadjustment) +
1697                             icon_view->priv->scroll_value_diff);
1698
1699   gtk_icon_view_update_rubberband (icon_view);
1700   
1701   return TRUE;
1702 }
1703
1704 static gboolean
1705 gtk_icon_view_motion (GtkWidget      *widget,
1706                       GdkEventMotion *event)
1707 {
1708   GtkAllocation allocation;
1709   GtkIconView *icon_view;
1710   gint abs_y;
1711   
1712   icon_view = GTK_ICON_VIEW (widget);
1713
1714   gtk_icon_view_maybe_begin_drag (icon_view, event);
1715
1716   if (icon_view->priv->doing_rubberband)
1717     {
1718       gtk_icon_view_update_rubberband (widget);
1719       
1720       abs_y = event->y - icon_view->priv->height *
1721         (gtk_adjustment_get_value (icon_view->priv->vadjustment) /
1722          (gtk_adjustment_get_upper (icon_view->priv->vadjustment) -
1723           gtk_adjustment_get_lower (icon_view->priv->vadjustment)));
1724
1725       gtk_widget_get_allocation (widget, &allocation);
1726
1727       if (abs_y < 0 || abs_y > allocation.height)
1728         {
1729           if (abs_y < 0)
1730             icon_view->priv->scroll_value_diff = abs_y;
1731           else
1732             icon_view->priv->scroll_value_diff = abs_y - allocation.height;
1733
1734           icon_view->priv->event_last_x = event->x;
1735           icon_view->priv->event_last_y = event->y;
1736
1737           if (icon_view->priv->scroll_timeout_id == 0)
1738             icon_view->priv->scroll_timeout_id = gdk_threads_add_timeout (30, rubberband_scroll_timeout, 
1739                                                                 icon_view);
1740         }
1741       else 
1742         remove_scroll_timeout (icon_view);
1743     }
1744   
1745   return TRUE;
1746 }
1747
1748 static void
1749 gtk_icon_view_remove (GtkContainer *container,
1750                       GtkWidget    *widget)
1751 {
1752   GtkIconView *icon_view;
1753   GtkIconViewChild *child = NULL;
1754   GList *tmp_list;
1755
1756   icon_view = GTK_ICON_VIEW (container);
1757   
1758   tmp_list = icon_view->priv->children;
1759   while (tmp_list)
1760     {
1761       child = tmp_list->data;
1762       if (child->widget == widget)
1763         {
1764           gtk_widget_unparent (widget);
1765
1766           icon_view->priv->children = g_list_remove_link (icon_view->priv->children, tmp_list);
1767           g_list_free_1 (tmp_list);
1768           g_free (child);
1769           return;
1770         }
1771
1772       tmp_list = tmp_list->next;
1773     }
1774 }
1775
1776 static void
1777 gtk_icon_view_forall (GtkContainer *container,
1778                       gboolean      include_internals,
1779                       GtkCallback   callback,
1780                       gpointer      callback_data)
1781 {
1782   GtkIconView *icon_view;
1783   GtkIconViewChild *child = NULL;
1784   GList *tmp_list;
1785
1786   icon_view = GTK_ICON_VIEW (container);
1787
1788   tmp_list = icon_view->priv->children;
1789   while (tmp_list)
1790     {
1791       child = tmp_list->data;
1792       tmp_list = tmp_list->next;
1793
1794       (* callback) (child->widget, callback_data);
1795     }
1796 }
1797
1798 static void 
1799 gtk_icon_view_item_selected_changed (GtkIconView      *icon_view,
1800                                      GtkIconViewItem  *item)
1801 {
1802   AtkObject *obj;
1803   AtkObject *item_obj;
1804
1805   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
1806   if (obj != NULL)
1807     {
1808       item_obj = atk_object_ref_accessible_child (obj, item->index);
1809       if (item_obj != NULL)
1810         {
1811           atk_object_notify_state_change (item_obj, ATK_STATE_SELECTED, item->selected);
1812           g_object_unref (item_obj);
1813         }
1814     }
1815 }
1816
1817 static void
1818 gtk_icon_view_add_editable (GtkCellArea            *area,
1819                             GtkCellRenderer        *renderer,
1820                             GtkCellEditable        *editable,
1821                             GdkRectangle           *cell_area,
1822                             const gchar            *path,
1823                             GtkIconView            *icon_view)
1824 {
1825   GtkIconViewChild *child;
1826   GtkWidget *widget = GTK_WIDGET (editable);
1827   
1828   child = g_new (GtkIconViewChild, 1);
1829   
1830   child->widget      = widget;
1831   child->area.x      = cell_area->x;
1832   child->area.y      = cell_area->y;
1833   child->area.width  = cell_area->width;
1834   child->area.height = cell_area->height;
1835
1836   icon_view->priv->children = g_list_append (icon_view->priv->children, child);
1837
1838   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
1839     gtk_widget_set_parent_window (child->widget, icon_view->priv->bin_window);
1840   
1841   gtk_widget_set_parent (widget, GTK_WIDGET (icon_view));
1842 }
1843
1844 static void
1845 gtk_icon_view_remove_editable (GtkCellArea            *area,
1846                                GtkCellRenderer        *renderer,
1847                                GtkCellEditable        *editable,
1848                                GtkIconView            *icon_view)
1849 {
1850   GtkTreePath *path;
1851
1852   if (gtk_widget_has_focus (GTK_WIDGET (editable)))
1853     gtk_widget_grab_focus (GTK_WIDGET (icon_view));
1854   
1855   gtk_container_remove (GTK_CONTAINER (icon_view),
1856                         GTK_WIDGET (editable));  
1857
1858   path = gtk_tree_path_new_from_string (gtk_cell_area_get_current_path_string (area));
1859   gtk_icon_view_queue_draw_path (icon_view, path);
1860   gtk_tree_path_free (path);
1861 }
1862
1863 static void
1864 gtk_icon_view_context_changed (GtkCellAreaContext     *context,
1865                                GParamSpec             *pspec,
1866                                GtkIconView            *icon_view)
1867 {
1868   if (!strcmp (pspec->name, "minimum-width") ||
1869       !strcmp (pspec->name, "natural-width") ||
1870       !strcmp (pspec->name, "minimum-height") ||
1871       !strcmp (pspec->name, "natural-height"))
1872     gtk_icon_view_invalidate_sizes (icon_view);
1873 }
1874
1875 /**
1876  * gtk_icon_view_set_cursor:
1877  * @icon_view: A #GtkIconView
1878  * @path: A #GtkTreePath
1879  * @cell: (allow-none): One of the cell renderers of @icon_view, or %NULL
1880  * @start_editing: %TRUE if the specified cell should start being edited.
1881  *
1882  * Sets the current keyboard focus to be at @path, and selects it.  This is
1883  * useful when you want to focus the user's attention on a particular item.
1884  * If @cell is not %NULL, then focus is given to the cell specified by 
1885  * it. Additionally, if @start_editing is %TRUE, then editing should be 
1886  * started in the specified cell.  
1887  *
1888  * This function is often followed by <literal>gtk_widget_grab_focus 
1889  * (icon_view)</literal> in order to give keyboard focus to the widget.  
1890  * Please note that editing can only happen when the widget is realized.
1891  *
1892  * Since: 2.8
1893  **/
1894 void
1895 gtk_icon_view_set_cursor (GtkIconView     *icon_view,
1896                           GtkTreePath     *path,
1897                           GtkCellRenderer *cell,
1898                           gboolean         start_editing)
1899 {
1900   GtkIconViewItem *item = NULL;
1901
1902   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
1903   g_return_if_fail (path != NULL);
1904   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
1905
1906   if (icon_view->priv->cell_area)
1907     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
1908
1909   if (gtk_tree_path_get_depth (path) == 1)
1910     item = g_list_nth_data (icon_view->priv->items,
1911                             gtk_tree_path_get_indices(path)[0]);
1912   
1913   if (!item)
1914     return;
1915   
1916   gtk_icon_view_set_cursor_item (icon_view, item, cell);
1917   gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
1918
1919   if (start_editing && 
1920       icon_view->priv->cell_area)
1921     {
1922       GtkCellAreaContext *context;
1923
1924       context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
1925       gtk_icon_view_set_cell_data (icon_view, item);
1926       gtk_cell_area_activate (icon_view->priv->cell_area, context, 
1927                               GTK_WIDGET (icon_view), (GdkRectangle *)item, 
1928                               0 /* XXX flags */, TRUE);
1929     }
1930 }
1931
1932 /**
1933  * gtk_icon_view_get_cursor:
1934  * @icon_view: A #GtkIconView
1935  * @path: (out) (allow-none): Return location for the current cursor path,
1936  *        or %NULL
1937  * @cell: (out) (allow-none): Return location the current focus cell, or %NULL
1938  *
1939  * Fills in @path and @cell with the current cursor path and cell. 
1940  * If the cursor isn't currently set, then *@path will be %NULL.  
1941  * If no cell currently has focus, then *@cell will be %NULL.
1942  *
1943  * The returned #GtkTreePath must be freed with gtk_tree_path_free().
1944  *
1945  * Return value: %TRUE if the cursor is set.
1946  *
1947  * Since: 2.8
1948  **/
1949 gboolean
1950 gtk_icon_view_get_cursor (GtkIconView      *icon_view,
1951                           GtkTreePath     **path,
1952                           GtkCellRenderer **cell)
1953 {
1954   GtkIconViewItem *item;
1955
1956   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
1957
1958   item = icon_view->priv->cursor_item;
1959
1960   if (path != NULL)
1961     {
1962       if (item != NULL)
1963         *path = gtk_tree_path_new_from_indices (item->index, -1);
1964       else
1965         *path = NULL;
1966     }
1967
1968   if (cell != NULL && item != NULL && icon_view->priv->cell_area != NULL)
1969     *cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
1970
1971   return (item != NULL);
1972 }
1973
1974 static gboolean
1975 gtk_icon_view_button_press (GtkWidget      *widget,
1976                             GdkEventButton *event)
1977 {
1978   GtkIconView *icon_view;
1979   GtkIconViewItem *item;
1980   gboolean dirty = FALSE;
1981   GtkCellRenderer *cell = NULL, *cursor_cell = NULL;
1982
1983   icon_view = GTK_ICON_VIEW (widget);
1984
1985   if (event->window != icon_view->priv->bin_window)
1986     return FALSE;
1987
1988   if (!gtk_widget_has_focus (widget))
1989     gtk_widget_grab_focus (widget);
1990
1991   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1992     {
1993       item = gtk_icon_view_get_item_at_coords (icon_view, 
1994                                                event->x, event->y,
1995                                                FALSE,
1996                                                &cell);
1997
1998       /*
1999        * We consider only the the cells' area as the item area if the
2000        * item is not selected, but if it *is* selected, the complete
2001        * selection rectangle is considered to be part of the item.
2002        */
2003       if (item != NULL && (cell != NULL || item->selected))
2004         {
2005           if (cell != NULL)
2006             {
2007               if (gtk_cell_renderer_is_activatable (cell))
2008                 cursor_cell = cell;
2009             }
2010
2011           gtk_icon_view_scroll_to_item (icon_view, item);
2012           
2013           if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2014             {
2015               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2016             }
2017           else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
2018                    (event->state & GDK_SHIFT_MASK))
2019             {
2020               gtk_icon_view_unselect_all_internal (icon_view);
2021
2022               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2023               if (!icon_view->priv->anchor_item)
2024                 icon_view->priv->anchor_item = item;
2025               else 
2026                 gtk_icon_view_select_all_between (icon_view,
2027                                                   icon_view->priv->anchor_item,
2028                                                   item);
2029               dirty = TRUE;
2030             }
2031           else 
2032             {
2033               if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
2034                   ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
2035                   (event->state & GDK_CONTROL_MASK))
2036                 {
2037                   item->selected = !item->selected;
2038                   gtk_icon_view_queue_draw_item (icon_view, item);
2039                   dirty = TRUE;
2040                 }
2041               else
2042                 {
2043                   gtk_icon_view_unselect_all_internal (icon_view);
2044
2045                   item->selected = TRUE;
2046                   gtk_icon_view_queue_draw_item (icon_view, item);
2047                   dirty = TRUE;
2048                 }
2049               gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
2050               icon_view->priv->anchor_item = item;
2051             }
2052
2053           /* Save press to possibly begin a drag */
2054           if (icon_view->priv->pressed_button < 0)
2055             {
2056               icon_view->priv->pressed_button = event->button;
2057               icon_view->priv->press_start_x = event->x;
2058               icon_view->priv->press_start_y = event->y;
2059             }
2060
2061           if (!icon_view->priv->last_single_clicked)
2062             icon_view->priv->last_single_clicked = item;
2063
2064           /* cancel the current editing, if it exists */
2065           gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
2066
2067           if (cell != NULL && gtk_cell_renderer_is_activatable (cell))
2068             {
2069               GtkCellAreaContext *context;
2070
2071               context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
2072
2073               gtk_icon_view_set_cell_data (icon_view, item);
2074               gtk_cell_area_activate (icon_view->priv->cell_area, context,
2075                                       GTK_WIDGET (icon_view),
2076                                       (GdkRectangle *)item, 0/* XXX flags */, FALSE);
2077             }
2078         }
2079       else
2080         {
2081           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
2082               !(event->state & GDK_CONTROL_MASK))
2083             {
2084               dirty = gtk_icon_view_unselect_all_internal (icon_view);
2085             }
2086           
2087           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
2088             gtk_icon_view_start_rubberbanding (icon_view, event->device, event->x, event->y);
2089         }
2090
2091       /* don't draw keyboard focus around an clicked-on item */
2092       icon_view->priv->draw_focus = FALSE;
2093     }
2094
2095   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
2096     {
2097       item = gtk_icon_view_get_item_at_coords (icon_view,
2098                                                event->x, event->y,
2099                                                FALSE,
2100                                                NULL);
2101
2102       if (item && item == icon_view->priv->last_single_clicked)
2103         {
2104           GtkTreePath *path;
2105
2106           path = gtk_tree_path_new_from_indices (item->index, -1);
2107           gtk_icon_view_item_activated (icon_view, path);
2108           gtk_tree_path_free (path);
2109         }
2110
2111       icon_view->priv->last_single_clicked = NULL;
2112       icon_view->priv->pressed_button = -1;
2113     }
2114   
2115   if (dirty)
2116     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2117
2118   return event->button == 1;
2119 }
2120
2121 static gboolean
2122 gtk_icon_view_button_release (GtkWidget      *widget,
2123                               GdkEventButton *event)
2124 {
2125   GtkIconView *icon_view;
2126
2127   icon_view = GTK_ICON_VIEW (widget);
2128   
2129   if (icon_view->priv->pressed_button == event->button)
2130     icon_view->priv->pressed_button = -1;
2131
2132   gtk_icon_view_stop_rubberbanding (icon_view);
2133
2134   remove_scroll_timeout (icon_view);
2135
2136   return TRUE;
2137 }
2138
2139 static gboolean
2140 gtk_icon_view_key_press (GtkWidget      *widget,
2141                          GdkEventKey    *event)
2142 {
2143   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2144
2145   if (icon_view->priv->doing_rubberband)
2146     {
2147       if (event->keyval == GDK_KEY_Escape)
2148         gtk_icon_view_stop_rubberbanding (icon_view);
2149
2150       return TRUE;
2151     }
2152
2153   return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event (widget, event);
2154 }
2155
2156 static gboolean
2157 gtk_icon_view_key_release (GtkWidget      *widget,
2158                            GdkEventKey    *event)
2159 {
2160   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
2161
2162   if (icon_view->priv->doing_rubberband)
2163     return TRUE;
2164
2165   return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->key_press_event (widget, event);
2166 }
2167
2168 static void
2169 gtk_icon_view_update_rubberband (gpointer data)
2170 {
2171   GtkIconView *icon_view;
2172   gint x, y;
2173   GdkRectangle old_area;
2174   GdkRectangle new_area;
2175   GdkRectangle common;
2176   cairo_region_t *invalid_region;
2177   
2178   icon_view = GTK_ICON_VIEW (data);
2179
2180   gdk_window_get_device_position (icon_view->priv->bin_window,
2181                                   icon_view->priv->rubberband_device,
2182                                   &x, &y, NULL);
2183
2184   x = MAX (x, 0);
2185   y = MAX (y, 0);
2186
2187   old_area.x = MIN (icon_view->priv->rubberband_x1,
2188                     icon_view->priv->rubberband_x2);
2189   old_area.y = MIN (icon_view->priv->rubberband_y1,
2190                     icon_view->priv->rubberband_y2);
2191   old_area.width = ABS (icon_view->priv->rubberband_x2 -
2192                         icon_view->priv->rubberband_x1) + 1;
2193   old_area.height = ABS (icon_view->priv->rubberband_y2 -
2194                          icon_view->priv->rubberband_y1) + 1;
2195   
2196   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
2197   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
2198   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
2199   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
2200
2201   invalid_region = cairo_region_create_rectangle (&old_area);
2202   cairo_region_union_rectangle (invalid_region, &new_area);
2203
2204   gdk_rectangle_intersect (&old_area, &new_area, &common);
2205   if (common.width > 2 && common.height > 2)
2206     {
2207       cairo_region_t *common_region;
2208
2209       /* make sure the border is invalidated */
2210       common.x += 1;
2211       common.y += 1;
2212       common.width -= 2;
2213       common.height -= 2;
2214       
2215       common_region = cairo_region_create_rectangle (&common);
2216
2217       cairo_region_subtract (invalid_region, common_region);
2218       cairo_region_destroy (common_region);
2219     }
2220   
2221   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
2222     
2223   cairo_region_destroy (invalid_region);
2224
2225   icon_view->priv->rubberband_x2 = x;
2226   icon_view->priv->rubberband_y2 = y;  
2227
2228   gtk_icon_view_update_rubberband_selection (icon_view);
2229 }
2230
2231 static void
2232 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
2233                                    GdkDevice    *device,
2234                                    gint          x,
2235                                    gint          y)
2236 {
2237   GList *items;
2238
2239   if (icon_view->priv->rubberband_device)
2240     return;
2241
2242   for (items = icon_view->priv->items; items; items = items->next)
2243     {
2244       GtkIconViewItem *item = items->data;
2245
2246       item->selected_before_rubberbanding = item->selected;
2247     }
2248   
2249   icon_view->priv->rubberband_x1 = x;
2250   icon_view->priv->rubberband_y1 = y;
2251   icon_view->priv->rubberband_x2 = x;
2252   icon_view->priv->rubberband_y2 = y;
2253
2254   icon_view->priv->doing_rubberband = TRUE;
2255   icon_view->priv->rubberband_device = device;
2256
2257   gtk_device_grab_add (GTK_WIDGET (icon_view), device, TRUE);
2258 }
2259
2260 static void
2261 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
2262 {
2263   if (!icon_view->priv->doing_rubberband)
2264     return;
2265
2266   gtk_device_grab_remove (GTK_WIDGET (icon_view),
2267                           icon_view->priv->rubberband_device);
2268
2269   icon_view->priv->doing_rubberband = FALSE;
2270   icon_view->priv->rubberband_device = NULL;
2271
2272   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
2273 }
2274
2275 static void
2276 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
2277 {
2278   GList *items;
2279   gint x, y, width, height;
2280   gboolean dirty = FALSE;
2281   
2282   x = MIN (icon_view->priv->rubberband_x1,
2283            icon_view->priv->rubberband_x2);
2284   y = MIN (icon_view->priv->rubberband_y1,
2285            icon_view->priv->rubberband_y2);
2286   width = ABS (icon_view->priv->rubberband_x1 - 
2287                icon_view->priv->rubberband_x2);
2288   height = ABS (icon_view->priv->rubberband_y1 - 
2289                 icon_view->priv->rubberband_y2);
2290   
2291   for (items = icon_view->priv->items; items; items = items->next)
2292     {
2293       GtkIconViewItem *item = items->data;
2294       gboolean is_in;
2295       gboolean selected;
2296       
2297       is_in = gtk_icon_view_item_hit_test (icon_view, item, 
2298                                            x, y, width, height);
2299
2300       selected = is_in ^ item->selected_before_rubberbanding;
2301
2302       if (item->selected != selected)
2303         {
2304           item->selected = selected;
2305           dirty = TRUE;
2306           gtk_icon_view_queue_draw_item (icon_view, item);
2307         }
2308     }
2309
2310   if (dirty)
2311     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2312 }
2313
2314
2315 typedef struct {
2316   GdkRectangle hit_rect;
2317   gboolean     hit;
2318 } HitTestData;
2319
2320 static gboolean 
2321 hit_test (GtkCellRenderer    *renderer,
2322           const GdkRectangle *cell_area,
2323           const GdkRectangle *cell_background,
2324           HitTestData        *data)
2325 {
2326   if (MIN (data->hit_rect.x + data->hit_rect.width, cell_area->x + cell_area->width) - 
2327       MAX (data->hit_rect.x, cell_area->x) > 0 &&
2328       MIN (data->hit_rect.y + data->hit_rect.height, cell_area->y + cell_area->height) - 
2329       MAX (data->hit_rect.y, cell_area->y) > 0)
2330     data->hit = TRUE;
2331   
2332   return (data->hit != FALSE);
2333 }
2334
2335 static gboolean
2336 gtk_icon_view_item_hit_test (GtkIconView      *icon_view,
2337                              GtkIconViewItem  *item,
2338                              gint              x,
2339                              gint              y,
2340                              gint              width,
2341                              gint              height)
2342 {
2343   HitTestData data = { { x, y, width, height }, FALSE };
2344   GtkCellAreaContext *context;
2345   GdkRectangle *item_area = (GdkRectangle *)item;
2346    
2347   if (MIN (x + width, item_area->x + item_area->width) - MAX (x, item_area->x) <= 0 ||
2348       MIN (y + height, item_area->y + item_area->height) - MAX (y, item_area->y) <= 0)
2349     return FALSE;
2350
2351   context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
2352
2353   gtk_icon_view_set_cell_data (icon_view, item);
2354   gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
2355                                GTK_WIDGET (icon_view),
2356                                item_area, item_area,
2357                                (GtkCellAllocCallback)hit_test, &data);
2358
2359   return data.hit;
2360 }
2361
2362 static gboolean
2363 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
2364 {
2365   gboolean dirty = FALSE;
2366   GList *items;
2367
2368   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2369     return FALSE;
2370
2371   for (items = icon_view->priv->items; items; items = items->next)
2372     {
2373       GtkIconViewItem *item = items->data;
2374
2375       if (item->selected)
2376         {
2377           item->selected = FALSE;
2378           dirty = TRUE;
2379           gtk_icon_view_queue_draw_item (icon_view, item);
2380           gtk_icon_view_item_selected_changed (icon_view, item);
2381         }
2382     }
2383
2384   return dirty;
2385 }
2386
2387
2388 /* GtkIconView signals */
2389 static void
2390 gtk_icon_view_real_select_all (GtkIconView *icon_view)
2391 {
2392   gtk_icon_view_select_all (icon_view);
2393 }
2394
2395 static void
2396 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
2397 {
2398   gtk_icon_view_unselect_all (icon_view);
2399 }
2400
2401 static void
2402 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
2403 {
2404   gtk_icon_view_unselect_all (icon_view);
2405
2406   if (icon_view->priv->cursor_item != NULL)
2407     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2408 }
2409
2410 static gboolean
2411 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
2412 {
2413   GtkTreePath *path;
2414   GtkCellAreaContext *context;
2415
2416   if (!icon_view->priv->cursor_item)
2417     return FALSE;
2418
2419   context = g_ptr_array_index (icon_view->priv->row_contexts, icon_view->priv->cursor_item->row);
2420
2421   gtk_icon_view_set_cell_data (icon_view, icon_view->priv->cursor_item);
2422   gtk_cell_area_activate (icon_view->priv->cell_area, context,
2423                           GTK_WIDGET (icon_view),
2424                           (GdkRectangle *)icon_view->priv->cursor_item,
2425                           0 /* XXX flags */,
2426                           FALSE);
2427
2428   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
2429   gtk_icon_view_item_activated (icon_view, path);
2430   gtk_tree_path_free (path);
2431
2432   return TRUE;
2433 }
2434
2435 static void
2436 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
2437 {
2438   if (!icon_view->priv->cursor_item)
2439     return;
2440
2441   switch (icon_view->priv->selection_mode)
2442     {
2443     case GTK_SELECTION_NONE:
2444       break;
2445     case GTK_SELECTION_BROWSE:
2446       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2447       break;
2448     case GTK_SELECTION_SINGLE:
2449       if (icon_view->priv->cursor_item->selected)
2450         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
2451       else
2452         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
2453       break;
2454     case GTK_SELECTION_MULTIPLE:
2455       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
2456       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
2457       
2458       gtk_icon_view_item_selected_changed (icon_view, icon_view->priv->cursor_item);      
2459       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2460       break;
2461     }
2462 }
2463
2464 /* Internal functions */
2465 static void
2466 gtk_icon_view_process_updates (GtkIconView *icon_view)
2467 {
2468   /* Prior to drawing, we check if a layout has been scheduled.  If so,
2469    * do it now that all cell view items have valid sizes before we proceeed
2470    * (and resize the bin_window if required).
2471    */
2472   if (icon_view->priv->layout_idle_id != 0)
2473     gtk_icon_view_layout (icon_view);
2474
2475   gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
2476 }
2477
2478 static void
2479 gtk_icon_view_set_hadjustment_values (GtkIconView *icon_view)
2480 {
2481   GtkAllocation  allocation;
2482   GtkAdjustment *adj = icon_view->priv->hadjustment;
2483   gdouble old_page_size;
2484   gdouble old_upper;
2485   gdouble old_value;
2486   gdouble new_value;
2487   gdouble new_upper;
2488
2489   gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
2490
2491   old_value = gtk_adjustment_get_value (adj);
2492   old_upper = gtk_adjustment_get_upper (adj);
2493   old_page_size = gtk_adjustment_get_page_size (adj);
2494   new_upper = MAX (allocation.width, icon_view->priv->width);
2495
2496   if (gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL)
2497     {
2498       /* Make sure no scrolling occurs for RTL locales also (if possible) */
2499       /* Quick explanation:
2500        *   In LTR locales, leftmost portion of visible rectangle should stay
2501        *   fixed, which means left edge of scrollbar thumb should remain fixed
2502        *   and thus adjustment's value should stay the same.
2503        *
2504        *   In RTL locales, we want to keep rightmost portion of visible
2505        *   rectangle fixed. This means right edge of thumb should remain fixed.
2506        *   In this case, upper - value - page_size should remain constant.
2507        */
2508       new_value = (new_upper - allocation.width) -
2509                   (old_upper - old_value - old_page_size);
2510       new_value = CLAMP (new_value, 0, new_upper - allocation.width);
2511     }
2512   else
2513     new_value = CLAMP (old_value, 0, new_upper - allocation.width);
2514
2515   gtk_adjustment_configure (adj,
2516                             new_value,
2517                             0.0,
2518                             new_upper,
2519                             allocation.width * 0.1,
2520                             allocation.width * 0.9,
2521                             allocation.width);
2522 }
2523
2524 static void
2525 gtk_icon_view_set_vadjustment_values (GtkIconView *icon_view)
2526 {
2527   GtkAllocation  allocation;
2528   GtkAdjustment *adj = icon_view->priv->vadjustment;
2529
2530   gtk_widget_get_allocation (GTK_WIDGET (icon_view), &allocation);
2531
2532   gtk_adjustment_configure (adj,
2533                             gtk_adjustment_get_value (adj),
2534                             0.0,
2535                             MAX (allocation.height, icon_view->priv->height),
2536                             allocation.height * 0.1,
2537                             allocation.height * 0.9,
2538                             allocation.height);
2539 }
2540
2541 static void
2542 gtk_icon_view_set_hadjustment (GtkIconView   *icon_view,
2543                                GtkAdjustment *adjustment)
2544 {
2545   GtkIconViewPrivate *priv = icon_view->priv;
2546   AtkObject *atk_obj;
2547
2548   if (adjustment && priv->hadjustment == adjustment)
2549     return;
2550
2551   if (priv->hadjustment != NULL)
2552     {
2553       g_signal_handlers_disconnect_matched (priv->hadjustment,
2554                                             G_SIGNAL_MATCH_DATA,
2555                                             0, 0, NULL, NULL, icon_view);
2556       g_object_unref (priv->hadjustment);
2557     }
2558
2559   if (!adjustment)
2560     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2561                                      0.0, 0.0, 0.0);
2562
2563   g_signal_connect (adjustment, "value-changed",
2564                     G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2565   priv->hadjustment = g_object_ref_sink (adjustment);
2566   gtk_icon_view_set_hadjustment_values (icon_view);
2567
2568   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2569   gtk_icon_view_accessible_set_adjustment (atk_obj,
2570                                            GTK_ORIENTATION_HORIZONTAL,
2571                                            adjustment);
2572
2573   g_object_notify (G_OBJECT (icon_view), "hadjustment");
2574 }
2575
2576 static void
2577 gtk_icon_view_set_vadjustment (GtkIconView   *icon_view,
2578                                GtkAdjustment *adjustment)
2579 {
2580   GtkIconViewPrivate *priv = icon_view->priv;
2581   AtkObject *atk_obj;
2582
2583   if (adjustment && priv->vadjustment == adjustment)
2584     return;
2585
2586   if (priv->vadjustment != NULL)
2587     {
2588       g_signal_handlers_disconnect_matched (priv->vadjustment,
2589                                             G_SIGNAL_MATCH_DATA,
2590                                             0, 0, NULL, NULL, icon_view);
2591       g_object_unref (priv->vadjustment);
2592     }
2593
2594   if (!adjustment)
2595     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2596                                      0.0, 0.0, 0.0);
2597
2598   g_signal_connect (adjustment, "value-changed",
2599                     G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2600   priv->vadjustment = g_object_ref_sink (adjustment);
2601   gtk_icon_view_set_vadjustment_values (icon_view);
2602
2603   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2604   gtk_icon_view_accessible_set_adjustment (atk_obj,
2605                                            GTK_ORIENTATION_VERTICAL,
2606                                            adjustment);
2607
2608   g_object_notify (G_OBJECT (icon_view), "vadjustment");
2609 }
2610
2611 static void
2612 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
2613                                   GtkIconView   *icon_view)
2614 {
2615   GtkIconViewPrivate *priv = icon_view->priv;
2616
2617   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2618     {
2619       gdk_window_move (priv->bin_window,
2620                        - gtk_adjustment_get_value (priv->hadjustment),
2621                        - gtk_adjustment_get_value (priv->vadjustment));
2622
2623       if (icon_view->priv->doing_rubberband)
2624         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
2625
2626       gtk_icon_view_process_updates (icon_view);
2627     }
2628 }
2629
2630 static GList *
2631 gtk_icon_view_layout_single_row (GtkIconView *icon_view, 
2632                                  GList       *first_item, 
2633                                  gint         item_width,
2634                                  gint         row,
2635                                  gint        *y, 
2636                                  gint        *maximum_width)
2637 {
2638   GtkAllocation allocation;
2639   GtkCellAreaContext *context;
2640   GtkIconViewPrivate *priv = icon_view->priv;
2641   GtkWidget *widget = GTK_WIDGET (icon_view);
2642   gint x, current_width;
2643   GList *items, *last_item;
2644   gint col;
2645   gint max_height = 0;
2646   gboolean rtl;
2647
2648   rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2649
2650   x = 0;
2651   col = 0;
2652   items = first_item;
2653   current_width = 0;
2654
2655   x += priv->margin;
2656   current_width += 2 * priv->margin;
2657
2658   gtk_widget_get_allocation (widget, &allocation);
2659
2660   context = gtk_cell_area_copy_context (priv->cell_area, priv->cell_area_context);
2661   g_ptr_array_add (priv->row_contexts, context);
2662
2663   /* In the first loop we iterate horizontally until we hit allocation width
2664    * and collect the aligned height-for-width */
2665   items = first_item;
2666   while (items)
2667     {
2668       GtkIconViewItem *item = items->data;
2669       GdkRectangle    *item_area = (GdkRectangle *)item;
2670
2671       item_area->width = item_width;
2672
2673       current_width += item_area->width + icon_view->priv->item_padding * 2;
2674
2675       if (items != first_item)
2676         {
2677           if ((icon_view->priv->columns <= 0 && current_width > allocation.width) ||
2678               (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
2679             break;
2680         }
2681
2682       /* Get this item's particular width & height (all alignments are cached by now) */
2683       gtk_icon_view_set_cell_data (icon_view, item);
2684       gtk_cell_area_get_preferred_height_for_width (priv->cell_area,
2685                                                     context,
2686                                                     widget, item_width, 
2687                                                     NULL, NULL);
2688
2689       current_width += icon_view->priv->column_spacing;
2690
2691       item_area->y = *y + icon_view->priv->item_padding;
2692       item_area->x = x  + icon_view->priv->item_padding;
2693
2694       x = current_width - icon_view->priv->margin; 
2695               
2696       if (current_width > *maximum_width)
2697         *maximum_width = current_width;
2698
2699       item->row = row;
2700       item->col = col;
2701
2702       col ++;
2703       items = items->next;
2704     }
2705
2706   last_item = items;
2707
2708   gtk_cell_area_context_get_preferred_height_for_width (context, item_width, &max_height, NULL);
2709   gtk_cell_area_context_allocate (context, item_width, max_height);
2710
2711   /* In the second loop the item height has been aligned and derived and
2712    * we just set the height and handle rtl layout */
2713   for (items = first_item; items != last_item; items = items->next)
2714     {
2715       GtkIconViewItem *item = items->data;
2716       GdkRectangle    *item_area = (GdkRectangle *)item;
2717
2718       if (rtl)
2719         {
2720           item_area->x = *maximum_width - item_area->width - item_area->x;
2721           item->col = col - 1 - item->col;
2722         }
2723
2724       /* All items in the same row get the same height */
2725       item_area->height = max_height;
2726     }
2727
2728   /* Adjust the new y coordinate. */
2729   *y += max_height + icon_view->priv->row_spacing + icon_view->priv->item_padding * 2;
2730   
2731   return last_item;
2732 }
2733
2734 static void
2735 adjust_wrap_width (GtkIconView *icon_view)
2736 {
2737   if (icon_view->priv->text_cell)
2738     {
2739       gint wrap_width = 50;
2740
2741       /* Here we go with the same old guess, try the icon size and set double
2742        * the size of the first icon found in the list, naive but works much
2743        * of the time */
2744       if (icon_view->priv->items && icon_view->priv->pixbuf_cell)
2745         {
2746           gtk_icon_view_set_cell_data (icon_view, icon_view->priv->items->data);
2747           gtk_cell_renderer_get_preferred_width (icon_view->priv->pixbuf_cell,
2748                                                  GTK_WIDGET (icon_view),
2749                                                  &wrap_width, NULL);
2750           
2751           wrap_width = MAX (wrap_width * 2, 50);
2752         }
2753       
2754       g_object_set (icon_view->priv->text_cell, "wrap-width", wrap_width, NULL);
2755       g_object_set (icon_view->priv->text_cell, "width", wrap_width, NULL);
2756     }
2757 }
2758
2759 static void
2760 gtk_icon_view_layout (GtkIconView *icon_view)
2761 {
2762   GtkAllocation allocation;
2763   GtkWidget *widget;
2764   GList *icons;
2765   gint y = 0, maximum_width = 0;
2766   gint row;
2767   gint item_width;
2768   gboolean size_changed = FALSE;
2769
2770   if (icon_view->priv->layout_idle_id != 0)
2771     {
2772       g_source_remove (icon_view->priv->layout_idle_id);
2773       icon_view->priv->layout_idle_id = 0;
2774     }
2775   
2776   if (icon_view->priv->model == NULL)
2777     return;
2778
2779   widget = GTK_WIDGET (icon_view);
2780
2781   item_width = icon_view->priv->item_width;
2782
2783   /* Update the wrap width for the text cell before going and requesting sizes */
2784   adjust_wrap_width (icon_view);
2785
2786   /* Update the context widths for any invalidated items */
2787   gtk_icon_view_cache_widths (icon_view);
2788
2789   /* Fetch the new item width if needed */
2790   if (item_width < 0)
2791     gtk_cell_area_context_get_preferred_width (icon_view->priv->cell_area_context, 
2792                                                &item_width, NULL);
2793
2794   gtk_cell_area_context_allocate (icon_view->priv->cell_area_context, item_width, -1);
2795
2796   icons = icon_view->priv->items;
2797   y += icon_view->priv->margin;
2798   row = 0;
2799
2800   /* Clear the per row contexts */
2801   g_ptr_array_set_size (icon_view->priv->row_contexts, 0);
2802   
2803   do
2804     {
2805       icons = gtk_icon_view_layout_single_row (icon_view, icons, 
2806                                                item_width, row,
2807                                                &y, &maximum_width);
2808       row++;
2809     }
2810   while (icons != NULL);
2811
2812   if (maximum_width != icon_view->priv->width)
2813     {
2814       icon_view->priv->width = maximum_width;
2815       size_changed = TRUE;
2816     }
2817
2818   y += icon_view->priv->margin;
2819   
2820   if (y != icon_view->priv->height)
2821     {
2822       icon_view->priv->height = y;
2823       size_changed = TRUE;
2824     }
2825
2826   gtk_icon_view_set_hadjustment_values (icon_view);
2827   gtk_icon_view_set_vadjustment_values (icon_view);
2828
2829   if (size_changed)
2830     gtk_widget_queue_resize_no_redraw (widget);
2831
2832   gtk_widget_get_allocation (widget, &allocation);
2833   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2834     gdk_window_resize (icon_view->priv->bin_window,
2835                        MAX (icon_view->priv->width, allocation.width),
2836                        MAX (icon_view->priv->height, allocation.height));
2837
2838   if (icon_view->priv->scroll_to_path)
2839     {
2840       GtkTreePath *path;
2841
2842       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
2843       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
2844       icon_view->priv->scroll_to_path = NULL;
2845       
2846       gtk_icon_view_scroll_to_path (icon_view, path,
2847                                     icon_view->priv->scroll_to_use_align,
2848                                     icon_view->priv->scroll_to_row_align,
2849                                     icon_view->priv->scroll_to_col_align);
2850       gtk_tree_path_free (path);
2851     }
2852   
2853   gtk_widget_queue_draw (widget);
2854 }
2855
2856 /* This ensures that all widths have been cached in the
2857  * context and we have proper alignments to go on.
2858  */
2859 static void
2860 gtk_icon_view_cache_widths (GtkIconView *icon_view)
2861 {
2862   GList *items;
2863
2864   g_signal_handler_block (icon_view->priv->cell_area_context, 
2865                           icon_view->priv->context_changed_id);
2866
2867   for (items = icon_view->priv->items; items; items = items->next)
2868     {
2869       GtkIconViewItem *item = items->data;
2870
2871       /* Only fetch the width of items with invalidated sizes */
2872       if (item->cell_area.width < 0)
2873         {
2874           gtk_icon_view_set_cell_data (icon_view, item);
2875           gtk_cell_area_get_preferred_width (icon_view->priv->cell_area, 
2876                                              icon_view->priv->cell_area_context,
2877                                              GTK_WIDGET (icon_view), NULL, NULL);
2878         }
2879     }
2880
2881   g_signal_handler_unblock (icon_view->priv->cell_area_context, 
2882                             icon_view->priv->context_changed_id);
2883 }
2884
2885 static void
2886 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
2887 {
2888   /* Clear all item sizes */
2889   g_list_foreach (icon_view->priv->items,
2890                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
2891
2892   /* Reset the context */
2893   if (icon_view->priv->cell_area_context)
2894     {
2895       g_signal_handler_block (icon_view->priv->cell_area_context, 
2896                               icon_view->priv->context_changed_id);
2897       gtk_cell_area_context_reset (icon_view->priv->cell_area_context);
2898       g_signal_handler_unblock (icon_view->priv->cell_area_context, 
2899                                 icon_view->priv->context_changed_id);
2900     }
2901
2902   /* Re-layout the items */
2903   gtk_icon_view_queue_layout (icon_view);
2904 }
2905
2906 static void
2907 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
2908 {
2909   item->cell_area.width = -1;
2910   item->cell_area.height = -1;
2911 }
2912
2913 static void
2914 gtk_icon_view_paint_item (GtkIconView     *icon_view,
2915                           cairo_t         *cr,
2916                           GtkIconViewItem *item,
2917                           gint             x,
2918                           gint             y,
2919                           gboolean         draw_focus)
2920 {
2921   GdkRectangle cell_area;
2922   GtkStateFlags state = 0;
2923   GtkCellRendererState flags = 0;
2924   GtkStyleContext *style_context;
2925   GtkWidget *widget = GTK_WIDGET (icon_view);
2926   GtkIconViewPrivate *priv = icon_view->priv;
2927   GtkCellAreaContext *context;
2928
2929   if (priv->model == NULL)
2930     return;
2931
2932   gtk_icon_view_set_cell_data (icon_view, item);
2933
2934   style_context = gtk_widget_get_style_context (widget);
2935
2936   gtk_style_context_save (style_context);
2937   gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_VIEW);
2938   gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_CELL);
2939
2940   if (item->selected)
2941     {
2942       if (gtk_widget_has_focus (widget) &&
2943           item == icon_view->priv->cursor_item)
2944         {
2945           state |= GTK_STATE_FLAG_FOCUSED;
2946           flags |= GTK_CELL_RENDERER_FOCUSED;
2947         }
2948
2949       state |= GTK_STATE_FLAG_SELECTED;
2950       flags |= GTK_CELL_RENDERER_SELECTED;
2951
2952       gtk_style_context_set_state (style_context, state);
2953       gtk_render_background (style_context, cr,
2954                              x - icon_view->priv->item_padding,
2955                              y - icon_view->priv->item_padding,
2956                              item->cell_area.width  + icon_view->priv->item_padding * 2,
2957                              item->cell_area.height + icon_view->priv->item_padding * 2);
2958     }
2959
2960   cell_area.x      = x;
2961   cell_area.y      = y;
2962   cell_area.width  = item->cell_area.width;
2963   cell_area.height = item->cell_area.height;
2964
2965   context = g_ptr_array_index (priv->row_contexts, item->row);
2966   gtk_cell_area_render (priv->cell_area, context,
2967                         widget, cr, &cell_area, &cell_area, flags,
2968                         draw_focus);
2969
2970   gtk_style_context_restore (style_context);
2971 }
2972
2973 static void
2974 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
2975                                 cairo_t         *cr)
2976 {
2977   GtkStyleContext *context;
2978   GdkRectangle rect;
2979
2980   cairo_save (cr);
2981
2982   rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
2983   rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
2984   rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
2985   rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
2986
2987   context = gtk_widget_get_style_context (GTK_WIDGET (icon_view));
2988
2989   gtk_style_context_save (context);
2990   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
2991
2992   gdk_cairo_rectangle (cr, &rect);
2993   cairo_clip (cr);
2994
2995   gtk_render_background (context, cr,
2996                          rect.x, rect.y,
2997                          rect.width, rect.height);
2998   gtk_render_frame (context, cr,
2999                     rect.x, rect.y,
3000                     rect.width, rect.height);
3001
3002   gtk_style_context_restore (context);
3003   cairo_restore (cr);
3004 }
3005
3006 static void
3007 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3008                                GtkTreePath *path)
3009 {
3010   GList *l;
3011   gint index;
3012
3013   index = gtk_tree_path_get_indices (path)[0];
3014
3015   for (l = icon_view->priv->items; l; l = l->next) 
3016     {
3017       GtkIconViewItem *item = l->data;
3018
3019       if (item->index == index)
3020         {
3021           gtk_icon_view_queue_draw_item (icon_view, item);
3022           break;
3023         }
3024     }
3025 }
3026
3027 static void
3028 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
3029                                GtkIconViewItem *item)
3030 {
3031   GdkRectangle  rect;
3032   GdkRectangle *item_area = (GdkRectangle *)item;
3033
3034   rect.x      = item_area->x - icon_view->priv->item_padding;
3035   rect.y      = item_area->y - icon_view->priv->item_padding;
3036   rect.width  = item_area->width  + icon_view->priv->item_padding * 2;
3037   rect.height = item_area->height + icon_view->priv->item_padding * 2;
3038
3039   if (icon_view->priv->bin_window)
3040     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3041 }
3042
3043 static gboolean
3044 layout_callback (gpointer user_data)
3045 {
3046   GtkIconView *icon_view;
3047
3048   icon_view = GTK_ICON_VIEW (user_data);
3049   
3050   icon_view->priv->layout_idle_id = 0;
3051
3052   gtk_icon_view_layout (icon_view);
3053   
3054   return FALSE;
3055 }
3056
3057 static void
3058 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3059 {
3060   if (icon_view->priv->layout_idle_id != 0)
3061     return;
3062
3063   icon_view->priv->layout_idle_id =
3064       gdk_threads_add_idle_full (GTK_ICON_VIEW_PRIORITY_LAYOUT,
3065                                  layout_callback, icon_view, NULL);
3066 }
3067
3068 static void
3069 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
3070                                GtkIconViewItem *item,
3071                                GtkCellRenderer *cursor_cell)
3072 {
3073   AtkObject *obj;
3074   AtkObject *item_obj;
3075   AtkObject *cursor_item_obj;
3076
3077   /* When hitting this path from keynav, the focus cell is
3078    * already set, we dont need to notify the atk object
3079    * but we still need to queue the draw here (in the case
3080    * that the focus cell changes but not the cursor item).
3081    */
3082   gtk_icon_view_queue_draw_item (icon_view, item);
3083
3084   if (icon_view->priv->cursor_item == item &&
3085       (cursor_cell == NULL || cursor_cell == gtk_cell_area_get_focus_cell (icon_view->priv->cell_area)))
3086     return;
3087
3088   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3089   if (icon_view->priv->cursor_item != NULL)
3090     {
3091       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3092       if (obj != NULL)
3093         {
3094           cursor_item_obj = atk_object_ref_accessible_child (obj, icon_view->priv->cursor_item->index);
3095           if (cursor_item_obj != NULL)
3096             atk_object_notify_state_change (cursor_item_obj, ATK_STATE_FOCUSED, FALSE);
3097         }
3098     }
3099   icon_view->priv->cursor_item = item;
3100
3101   if (cursor_cell)
3102     gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cursor_cell);
3103   else
3104     {
3105       /* Make sure there is a cell in focus initially */
3106       if (!gtk_cell_area_get_focus_cell (icon_view->priv->cell_area))
3107         gtk_cell_area_focus (icon_view->priv->cell_area, GTK_DIR_TAB_FORWARD);
3108     }
3109   
3110   /* Notify that accessible focus object has changed */
3111   item_obj = atk_object_ref_accessible_child (obj, item->index);
3112
3113   if (item_obj != NULL)
3114     {
3115       atk_focus_tracker_notify (item_obj);
3116       atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
3117       g_object_unref (item_obj); 
3118     }
3119 }
3120
3121
3122 static GtkIconViewItem *
3123 gtk_icon_view_item_new (void)
3124 {
3125   GtkIconViewItem *item;
3126
3127   item = g_slice_new0 (GtkIconViewItem);
3128
3129   item->cell_area.width  = -1;
3130   item->cell_area.height = -1;
3131   
3132   return item;
3133 }
3134
3135 static void
3136 gtk_icon_view_item_free (GtkIconViewItem *item)
3137 {
3138   g_return_if_fail (item != NULL);
3139
3140   g_slice_free (GtkIconViewItem, item);
3141 }
3142
3143 static GtkIconViewItem *
3144 gtk_icon_view_get_item_at_coords (GtkIconView          *icon_view,
3145                                   gint                  x,
3146                                   gint                  y,
3147                                   gboolean              only_in_cell,
3148                                   GtkCellRenderer     **cell_at_pos)
3149 {
3150   GList *items;
3151
3152   if (cell_at_pos)
3153     *cell_at_pos = NULL;
3154
3155   for (items = icon_view->priv->items; items; items = items->next)
3156     {
3157       GtkIconViewItem *item = items->data;
3158       GdkRectangle    *item_area = (GdkRectangle *)item;
3159
3160       if (x >= item_area->x - icon_view->priv->column_spacing/2 && 
3161           x <= item_area->x + item_area->width + icon_view->priv->column_spacing/2 &&
3162           y >= item_area->y - icon_view->priv->row_spacing/2 && 
3163           y <= item_area->y + item_area->height + icon_view->priv->row_spacing/2)
3164         {
3165           if (only_in_cell || cell_at_pos)
3166             {
3167               GtkCellRenderer *cell = NULL;
3168               GtkCellAreaContext *context;
3169
3170               context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
3171               gtk_icon_view_set_cell_data (icon_view, item);
3172
3173               if (x >= item_area->x && x <= item_area->x + item_area->width &&
3174                   y >= item_area->y && y <= item_area->y + item_area->height)
3175                 cell = gtk_cell_area_get_cell_at_position (icon_view->priv->cell_area, context,
3176                                                            GTK_WIDGET (icon_view),
3177                                                            item_area,
3178                                                            x, y, NULL);
3179
3180               if (cell_at_pos)
3181                 *cell_at_pos = cell;
3182
3183               if (only_in_cell)
3184                 return cell != NULL ? item : NULL;
3185               else
3186                 return item;
3187             }
3188           return item;
3189         }
3190     }
3191   return NULL;
3192 }
3193
3194 static void
3195 gtk_icon_view_select_item (GtkIconView      *icon_view,
3196                            GtkIconViewItem  *item)
3197 {
3198   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3199   g_return_if_fail (item != NULL);
3200
3201   if (item->selected)
3202     return;
3203   
3204   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3205     return;
3206   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3207     gtk_icon_view_unselect_all_internal (icon_view);
3208
3209   item->selected = TRUE;
3210
3211   gtk_icon_view_item_selected_changed (icon_view, item);
3212   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3213
3214   gtk_icon_view_queue_draw_item (icon_view, item);
3215 }
3216
3217
3218 static void
3219 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
3220                              GtkIconViewItem  *item)
3221 {
3222   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3223   g_return_if_fail (item != NULL);
3224
3225   if (!item->selected)
3226     return;
3227   
3228   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3229       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3230     return;
3231   
3232   item->selected = FALSE;
3233
3234   gtk_icon_view_item_selected_changed (icon_view, item);
3235   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3236
3237   gtk_icon_view_queue_draw_item (icon_view, item);
3238 }
3239
3240 static void
3241 verify_items (GtkIconView *icon_view)
3242 {
3243   GList *items;
3244   int i = 0;
3245
3246   for (items = icon_view->priv->items; items; items = items->next)
3247     {
3248       GtkIconViewItem *item = items->data;
3249
3250       if (item->index != i)
3251         g_error ("List item does not match its index: "
3252                  "item index %d and list index %d\n", item->index, i);
3253
3254       i++;
3255     }
3256 }
3257
3258 static void
3259 gtk_icon_view_row_changed (GtkTreeModel *model,
3260                            GtkTreePath  *path,
3261                            GtkTreeIter  *iter,
3262                            gpointer      data)
3263 {
3264   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3265
3266   /* ignore changes in branches */
3267   if (gtk_tree_path_get_depth (path) > 1)
3268     return;
3269
3270   /* An icon view subclass might add it's own model and populate
3271    * things at init() time instead of waiting for the constructor() 
3272    * to be called 
3273    */
3274   if (icon_view->priv->cell_area)
3275     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3276
3277   /* Here we can use a "grow-only" strategy for optimization
3278    * and only invalidate a single item and queue a relayout
3279    * instead of invalidating the whole thing.
3280    *
3281    * For now GtkIconView still cant deal with huge models
3282    * so just invalidate the whole thing when the model
3283    * changes.
3284    */
3285   gtk_icon_view_invalidate_sizes (icon_view);
3286
3287   verify_items (icon_view);
3288 }
3289
3290 static void
3291 gtk_icon_view_row_inserted (GtkTreeModel *model,
3292                             GtkTreePath  *path,
3293                             GtkTreeIter  *iter,
3294                             gpointer      data)
3295 {
3296   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3297   gint index;
3298   GtkIconViewItem *item;
3299   gboolean iters_persist;
3300   GList *list;
3301
3302   /* ignore changes in branches */
3303   if (gtk_tree_path_get_depth (path) > 1)
3304     return;
3305
3306   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3307   
3308   index = gtk_tree_path_get_indices(path)[0];
3309
3310   item = gtk_icon_view_item_new ();
3311
3312   if (iters_persist)
3313     item->iter = *iter;
3314
3315   item->index = index;
3316
3317   /* FIXME: We can be more efficient here,
3318      we can store a tail pointer and use that when
3319      appending (which is a rather common operation)
3320   */
3321   icon_view->priv->items = g_list_insert (icon_view->priv->items,
3322                                          item, index);
3323   
3324   list = g_list_nth (icon_view->priv->items, index + 1);
3325   for (; list; list = list->next)
3326     {
3327       item = list->data;
3328
3329       item->index++;
3330     }
3331     
3332   verify_items (icon_view);
3333
3334   gtk_icon_view_queue_layout (icon_view);
3335 }
3336
3337 static void
3338 gtk_icon_view_row_deleted (GtkTreeModel *model,
3339                            GtkTreePath  *path,
3340                            gpointer      data)
3341 {
3342   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3343   gint index;
3344   GtkIconViewItem *item;
3345   GList *list, *next;
3346   gboolean emit = FALSE;
3347
3348   /* ignore changes in branches */
3349   if (gtk_tree_path_get_depth (path) > 1)
3350     return;
3351
3352   index = gtk_tree_path_get_indices(path)[0];
3353
3354   list = g_list_nth (icon_view->priv->items, index);
3355   item = list->data;
3356
3357   if (icon_view->priv->cell_area)
3358     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3359
3360   if (item == icon_view->priv->anchor_item)
3361     icon_view->priv->anchor_item = NULL;
3362
3363   if (item == icon_view->priv->cursor_item)
3364     icon_view->priv->cursor_item = NULL;
3365
3366   if (item->selected)
3367     emit = TRUE;
3368   
3369   gtk_icon_view_item_free (item);
3370
3371   for (next = list->next; next; next = next->next)
3372     {
3373       item = next->data;
3374
3375       item->index--;
3376     }
3377   
3378   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3379
3380   verify_items (icon_view);  
3381   
3382   gtk_icon_view_queue_layout (icon_view);
3383
3384   if (emit)
3385     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3386 }
3387
3388 static void
3389 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3390                               GtkTreePath  *parent,
3391                               GtkTreeIter  *iter,
3392                               gint         *new_order,
3393                               gpointer      data)
3394 {
3395   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3396   int i;
3397   int length;
3398   GList *items = NULL, *list;
3399   GtkIconViewItem **item_array;
3400   gint *order;
3401
3402   /* ignore changes in branches */
3403   if (iter != NULL)
3404     return;
3405
3406   if (icon_view->priv->cell_area)
3407     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
3408
3409   length = gtk_tree_model_iter_n_children (model, NULL);
3410
3411   order = g_new (gint, length);
3412   for (i = 0; i < length; i++)
3413     order [new_order[i]] = i;
3414
3415   item_array = g_new (GtkIconViewItem *, length);
3416   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3417     item_array[order[i]] = list->data;
3418   g_free (order);
3419
3420   for (i = length - 1; i >= 0; i--)
3421     {
3422       item_array[i]->index = i;
3423       items = g_list_prepend (items, item_array[i]);
3424     }
3425   
3426   g_free (item_array);
3427   g_list_free (icon_view->priv->items);
3428   icon_view->priv->items = items;
3429
3430   gtk_icon_view_queue_layout (icon_view);
3431
3432   verify_items (icon_view);  
3433 }
3434
3435 static void
3436 gtk_icon_view_build_items (GtkIconView *icon_view)
3437 {
3438   GtkTreeIter iter;
3439   int i;
3440   gboolean iters_persist;
3441   GList *items = NULL;
3442
3443   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3444   
3445   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3446                                       &iter))
3447     return;
3448
3449   i = 0;
3450   
3451   do
3452     {
3453       GtkIconViewItem *item = gtk_icon_view_item_new ();
3454
3455       if (iters_persist)
3456         item->iter = iter;
3457
3458       item->index = i;
3459       
3460       i++;
3461
3462       items = g_list_prepend (items, item);
3463       
3464     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3465
3466   icon_view->priv->items = g_list_reverse (items);
3467 }
3468
3469 static void
3470 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
3471                                 guint           keyval,
3472                                 guint           modmask,
3473                                 GtkMovementStep step,
3474                                 gint            count)
3475 {
3476   
3477   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3478                                 I_("move-cursor"), 2,
3479                                 G_TYPE_ENUM, step,
3480                                 G_TYPE_INT, count);
3481
3482   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3483                                 "move-cursor", 2,
3484                                 G_TYPE_ENUM, step,
3485                                 G_TYPE_INT, count);
3486
3487   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3488    return;
3489
3490   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3491                                 "move-cursor", 2,
3492                                 G_TYPE_ENUM, step,
3493                                 G_TYPE_INT, count);
3494
3495   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3496                                 "move-cursor", 2,
3497                                 G_TYPE_ENUM, step,
3498                                 G_TYPE_INT, count);
3499 }
3500
3501 static gboolean
3502 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
3503                                 GtkMovementStep  step,
3504                                 gint             count)
3505 {
3506   GdkModifierType state;
3507
3508   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3509   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3510                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3511                         step == GTK_MOVEMENT_DISPLAY_LINES ||
3512                         step == GTK_MOVEMENT_PAGES ||
3513                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3514
3515   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3516     return FALSE;
3517
3518   gtk_cell_area_stop_editing (icon_view->priv->cell_area, FALSE);
3519   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3520
3521   if (gtk_get_current_event_state (&state))
3522     {
3523       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3524         icon_view->priv->ctrl_pressed = TRUE;
3525       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3526         icon_view->priv->shift_pressed = TRUE;
3527     }
3528   /* else we assume not pressed */
3529
3530   switch (step)
3531     {
3532     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3533     case GTK_MOVEMENT_VISUAL_POSITIONS:
3534       gtk_icon_view_move_cursor_left_right (icon_view, count);
3535       break;
3536     case GTK_MOVEMENT_DISPLAY_LINES:
3537       gtk_icon_view_move_cursor_up_down (icon_view, count);
3538       break;
3539     case GTK_MOVEMENT_PAGES:
3540       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3541       break;
3542     case GTK_MOVEMENT_BUFFER_ENDS:
3543       gtk_icon_view_move_cursor_start_end (icon_view, count);
3544       break;
3545     default:
3546       g_assert_not_reached ();
3547     }
3548
3549   icon_view->priv->ctrl_pressed = FALSE;
3550   icon_view->priv->shift_pressed = FALSE;
3551
3552   icon_view->priv->draw_focus = TRUE;
3553
3554   return TRUE;
3555 }
3556
3557 static GtkIconViewItem *
3558 find_item (GtkIconView     *icon_view,
3559            GtkIconViewItem *current,
3560            gint             row_ofs,
3561            gint             col_ofs)
3562 {
3563   gint row, col;
3564   GList *items;
3565   GtkIconViewItem *item;
3566
3567   /* FIXME: this could be more efficient 
3568    */
3569   row = current->row + row_ofs;
3570   col = current->col + col_ofs;
3571
3572   for (items = icon_view->priv->items; items; items = items->next)
3573     {
3574       item = items->data;
3575       if (item->row == row && item->col == col)
3576         return item;
3577     }
3578   
3579   return NULL;
3580 }
3581
3582 static GtkIconViewItem *
3583 find_item_page_up_down (GtkIconView     *icon_view,
3584                         GtkIconViewItem *current,
3585                         gint             count)
3586 {
3587   GList *item, *next;
3588   gint y, col;
3589   
3590   col = current->col;
3591   y = current->cell_area.y + count * gtk_adjustment_get_page_size (icon_view->priv->vadjustment);
3592
3593   item = g_list_find (icon_view->priv->items, current);
3594   if (count > 0)
3595     {
3596       while (item)
3597         {
3598           for (next = item->next; next; next = next->next)
3599             {
3600               if (((GtkIconViewItem *)next->data)->col == col)
3601                 break;
3602             }
3603           if (!next || ((GtkIconViewItem *)next->data)->cell_area.y > y)
3604             break;
3605
3606           item = next;
3607         }
3608     }
3609   else 
3610     {
3611       while (item)
3612         {
3613           for (next = item->prev; next; next = next->prev)
3614             {
3615               if (((GtkIconViewItem *)next->data)->col == col)
3616                 break;
3617             }
3618           if (!next || ((GtkIconViewItem *)next->data)->cell_area.y < y)
3619             break;
3620
3621           item = next;
3622         }
3623     }
3624
3625   if (item)
3626     return item->data;
3627
3628   return NULL;
3629 }
3630
3631 static gboolean
3632 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
3633                                   GtkIconViewItem *anchor,
3634                                   GtkIconViewItem *cursor)
3635 {
3636   GList *items;
3637   GtkIconViewItem *item;
3638   gint row1, row2, col1, col2;
3639   gboolean dirty = FALSE;
3640   
3641   if (anchor->row < cursor->row)
3642     {
3643       row1 = anchor->row;
3644       row2 = cursor->row;
3645     }
3646   else
3647     {
3648       row1 = cursor->row;
3649       row2 = anchor->row;
3650     }
3651
3652   if (anchor->col < cursor->col)
3653     {
3654       col1 = anchor->col;
3655       col2 = cursor->col;
3656     }
3657   else
3658     {
3659       col1 = cursor->col;
3660       col2 = anchor->col;
3661     }
3662
3663   for (items = icon_view->priv->items; items; items = items->next)
3664     {
3665       item = items->data;
3666
3667       if (row1 <= item->row && item->row <= row2 &&
3668           col1 <= item->col && item->col <= col2)
3669         {
3670           if (!item->selected)
3671             {
3672               dirty = TRUE;
3673               item->selected = TRUE;
3674               gtk_icon_view_item_selected_changed (icon_view, item);
3675             }
3676           gtk_icon_view_queue_draw_item (icon_view, item);
3677         }
3678     }
3679
3680   return dirty;
3681 }
3682
3683 static void 
3684 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
3685                                    gint         count)
3686 {
3687   GtkIconViewItem *item;
3688   GtkCellRenderer *cell;
3689   gboolean dirty = FALSE;
3690   gint step;
3691   GtkDirectionType direction;
3692
3693   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3694     return;
3695
3696   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
3697
3698   if (!icon_view->priv->cursor_item)
3699     {
3700       GList *list;
3701
3702       if (count > 0)
3703         list = icon_view->priv->items;
3704       else
3705         list = g_list_last (icon_view->priv->items);
3706
3707       item = list ? list->data : NULL;
3708
3709       /* Give focus to the first cell initially */
3710       gtk_icon_view_set_cell_data (icon_view, item);
3711       gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3712     }
3713   else
3714     {
3715       item = icon_view->priv->cursor_item;
3716       step = count > 0 ? 1 : -1;      
3717
3718       /* Save the current focus cell in case we hit the edge */
3719       cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3720
3721       while (item)
3722         {
3723           gtk_icon_view_set_cell_data (icon_view, item);
3724
3725           if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3726             break;
3727
3728           item = find_item (icon_view, item, step, 0);
3729         }
3730     }
3731
3732   if (!item)
3733     {
3734       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3735         {
3736           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3737           if (toplevel)
3738             gtk_widget_child_focus (toplevel,
3739                                     direction == GTK_DIR_UP ?
3740                                     GTK_DIR_TAB_BACKWARD :
3741                                     GTK_DIR_TAB_FORWARD);
3742
3743         }
3744
3745       gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3746       return;
3747     }
3748
3749   if (icon_view->priv->ctrl_pressed ||
3750       !icon_view->priv->shift_pressed ||
3751       !icon_view->priv->anchor_item ||
3752       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3753     icon_view->priv->anchor_item = item;
3754
3755   cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3756   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3757
3758   if (!icon_view->priv->ctrl_pressed &&
3759       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3760     {
3761       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3762       dirty = gtk_icon_view_select_all_between (icon_view, 
3763                                                 icon_view->priv->anchor_item,
3764                                                 item) || dirty;
3765     }
3766
3767   gtk_icon_view_scroll_to_item (icon_view, item);
3768
3769   if (dirty)
3770     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3771 }
3772
3773 static void 
3774 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
3775                                         gint         count)
3776 {
3777   GtkIconViewItem *item;
3778   gboolean dirty = FALSE;
3779   
3780   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3781     return;
3782   
3783   if (!icon_view->priv->cursor_item)
3784     {
3785       GList *list;
3786
3787       if (count > 0)
3788         list = icon_view->priv->items;
3789       else
3790         list = g_list_last (icon_view->priv->items);
3791
3792       item = list ? list->data : NULL;
3793     }
3794   else
3795     item = find_item_page_up_down (icon_view, 
3796                                    icon_view->priv->cursor_item,
3797                                    count);
3798
3799   if (item == icon_view->priv->cursor_item)
3800     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3801
3802   if (!item)
3803     return;
3804
3805   if (icon_view->priv->ctrl_pressed ||
3806       !icon_view->priv->shift_pressed ||
3807       !icon_view->priv->anchor_item ||
3808       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3809     icon_view->priv->anchor_item = item;
3810
3811   gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3812
3813   if (!icon_view->priv->ctrl_pressed &&
3814       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3815     {
3816       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3817       dirty = gtk_icon_view_select_all_between (icon_view, 
3818                                                 icon_view->priv->anchor_item,
3819                                                 item) || dirty;
3820     }
3821
3822   gtk_icon_view_scroll_to_item (icon_view, item);
3823
3824   if (dirty)
3825     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
3826 }
3827
3828 static void 
3829 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
3830                                       gint         count)
3831 {
3832   GtkIconViewItem *item;
3833   GtkCellRenderer *cell = NULL;
3834   gboolean dirty = FALSE;
3835   gint step;
3836   GtkDirectionType direction;
3837
3838   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3839     return;
3840
3841   direction = count < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
3842
3843   if (!icon_view->priv->cursor_item)
3844     {
3845       GList *list;
3846
3847       if (count > 0)
3848         list = icon_view->priv->items;
3849       else
3850         list = g_list_last (icon_view->priv->items);
3851
3852       item = list ? list->data : NULL;
3853
3854       /* Give focus to the first cell initially */
3855       gtk_icon_view_set_cell_data (icon_view, item);
3856       gtk_cell_area_focus (icon_view->priv->cell_area, direction);
3857     }
3858   else
3859     {
3860       item = icon_view->priv->cursor_item;
3861       step = count > 0 ? 1 : -1;
3862
3863       /* Save the current focus cell in case we hit the edge */
3864       cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3865
3866       while (item)
3867         {
3868           gtk_icon_view_set_cell_data (icon_view, item);
3869
3870           if (gtk_cell_area_focus (icon_view->priv->cell_area, direction))
3871             break;
3872           
3873           item = find_item (icon_view, item, 0, step);
3874         }
3875     }
3876
3877   if (!item)
3878     {
3879       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
3880         {
3881           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
3882           if (toplevel)
3883             gtk_widget_child_focus (toplevel,
3884                                     direction == GTK_DIR_LEFT ?
3885                                     GTK_DIR_TAB_BACKWARD :
3886                                     GTK_DIR_TAB_FORWARD);
3887
3888         }
3889
3890       gtk_cell_area_set_focus_cell (icon_view->priv->cell_area, cell);
3891       return;
3892     }
3893
3894   if (icon_view->priv->ctrl_pressed ||
3895       !icon_view->priv->shift_pressed ||
3896       !icon_view->priv->anchor_item ||
3897       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3898     icon_view->priv->anchor_item = item;
3899
3900   cell = gtk_cell_area_get_focus_cell (icon_view->priv->cell_area);
3901   gtk_icon_view_set_cursor_item (icon_view, item, cell);
3902
3903   if (!icon_view->priv->ctrl_pressed &&
3904       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3905     {
3906       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3907       dirty = gtk_icon_view_select_all_between (icon_view, 
3908                                                 icon_view->priv->anchor_item,
3909                                                 item) || dirty;
3910     }
3911
3912   gtk_icon_view_scroll_to_item (icon_view, item);
3913
3914   if (dirty)
3915     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3916 }
3917
3918 static void 
3919 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
3920                                      gint         count)
3921 {
3922   GtkIconViewItem *item;
3923   GList *list;
3924   gboolean dirty = FALSE;
3925   
3926   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3927     return;
3928   
3929   if (count < 0)
3930     list = icon_view->priv->items;
3931   else
3932     list = g_list_last (icon_view->priv->items);
3933   
3934   item = list ? list->data : NULL;
3935
3936   if (item == icon_view->priv->cursor_item)
3937     gtk_widget_error_bell (GTK_WIDGET (icon_view));
3938
3939   if (!item)
3940     return;
3941
3942   if (icon_view->priv->ctrl_pressed ||
3943       !icon_view->priv->shift_pressed ||
3944       !icon_view->priv->anchor_item ||
3945       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3946     icon_view->priv->anchor_item = item;
3947
3948   gtk_icon_view_set_cursor_item (icon_view, item, NULL);
3949
3950   if (!icon_view->priv->ctrl_pressed &&
3951       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
3952     {
3953       dirty = gtk_icon_view_unselect_all_internal (icon_view);
3954       dirty = gtk_icon_view_select_all_between (icon_view, 
3955                                                 icon_view->priv->anchor_item,
3956                                                 item) || dirty;
3957     }
3958
3959   gtk_icon_view_scroll_to_item (icon_view, item);
3960
3961   if (dirty)
3962     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3963 }
3964
3965 /**
3966  * gtk_icon_view_scroll_to_path:
3967  * @icon_view: A #GtkIconView.
3968  * @path: The path of the item to move to.
3969  * @use_align: whether to use alignment arguments, or %FALSE.
3970  * @row_align: The vertical alignment of the item specified by @path.
3971  * @col_align: The horizontal alignment of the item specified by @path.
3972  *
3973  * Moves the alignments of @icon_view to the position specified by @path.  
3974  * @row_align determines where the row is placed, and @col_align determines 
3975  * where @column is placed.  Both are expected to be between 0.0 and 1.0. 
3976  * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means 
3977  * center.
3978  *
3979  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
3980  * tree does the minimum amount of work to scroll the item onto the screen.
3981  * This means that the item will be scrolled to the edge closest to its current
3982  * position.  If the item is currently visible on the screen, nothing is done.
3983  *
3984  * This function only works if the model is set, and @path is a valid row on 
3985  * the model. If the model changes before the @icon_view is realized, the 
3986  * centered path will be modified to reflect this change.
3987  *
3988  * Since: 2.8
3989  **/
3990 void
3991 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
3992                               GtkTreePath *path,
3993                               gboolean     use_align,
3994                               gfloat       row_align,
3995                               gfloat       col_align)
3996 {
3997   GtkIconViewItem *item = NULL;
3998   GtkWidget *widget;
3999
4000   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4001   g_return_if_fail (path != NULL);
4002   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
4003   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
4004
4005   widget = GTK_WIDGET (icon_view);
4006
4007   if (gtk_tree_path_get_depth (path) > 0)
4008     item = g_list_nth_data (icon_view->priv->items,
4009                             gtk_tree_path_get_indices(path)[0]);
4010   
4011   if (!item || item->cell_area.width < 0 ||
4012       !gtk_widget_get_realized (widget))
4013     {
4014       if (icon_view->priv->scroll_to_path)
4015         gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4016
4017       icon_view->priv->scroll_to_path = NULL;
4018
4019       if (path)
4020         icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4021
4022       icon_view->priv->scroll_to_use_align = use_align;
4023       icon_view->priv->scroll_to_row_align = row_align;
4024       icon_view->priv->scroll_to_col_align = col_align;
4025
4026       return;
4027     }
4028
4029   if (use_align)
4030     {
4031       GtkAllocation allocation;
4032       gint x, y;
4033       gfloat offset;
4034       GdkRectangle item_area = 
4035         { 
4036           item->cell_area.x - icon_view->priv->item_padding, 
4037           item->cell_area.y - icon_view->priv->item_padding, 
4038           item->cell_area.width  + icon_view->priv->item_padding * 2, 
4039           item->cell_area.height + icon_view->priv->item_padding * 2 
4040         };
4041
4042       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4043
4044       gtk_widget_get_allocation (widget, &allocation);
4045
4046       offset = y + item_area.y - row_align * (allocation.height - item_area.height);
4047
4048       gtk_adjustment_set_value (icon_view->priv->vadjustment,
4049                                 gtk_adjustment_get_value (icon_view->priv->vadjustment) + offset);
4050
4051       offset = x + item_area.x - col_align * (allocation.width - item_area.width);
4052
4053       gtk_adjustment_set_value (icon_view->priv->hadjustment,
4054                                 gtk_adjustment_get_value (icon_view->priv->hadjustment) + offset);
4055
4056       gtk_adjustment_changed (icon_view->priv->hadjustment);
4057       gtk_adjustment_changed (icon_view->priv->vadjustment);
4058     }
4059   else
4060     gtk_icon_view_scroll_to_item (icon_view, item);
4061 }
4062
4063
4064 static void
4065 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view,
4066                               GtkIconViewItem *item)
4067 {
4068   GtkIconViewPrivate *priv = icon_view->priv;
4069   GtkWidget *widget = GTK_WIDGET (icon_view);
4070   GtkAdjustment *hadj, *vadj;
4071   GtkAllocation allocation;
4072   gint x, y;
4073   GdkRectangle item_area;
4074
4075   item_area.x = item->cell_area.x - priv->item_padding;
4076   item_area.y = item->cell_area.y - priv->item_padding;
4077   item_area.width = item->cell_area.width  + priv->item_padding * 2;
4078   item_area.height = item->cell_area.height + priv->item_padding * 2;
4079
4080   gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4081   gtk_widget_get_allocation (widget, &allocation);
4082
4083   hadj = icon_view->priv->hadjustment;
4084   vadj = icon_view->priv->vadjustment;
4085
4086   if (y + item_area.y < 0)
4087     gtk_adjustment_set_value (vadj,
4088                               gtk_adjustment_get_value (vadj)
4089                                 + y + item_area.y);
4090   else if (y + item_area.y + item_area.height > allocation.height)
4091     gtk_adjustment_set_value (vadj,
4092                               gtk_adjustment_get_value (vadj)
4093                                 + y + item_area.y + item_area.height - allocation.height);
4094
4095   if (x + item_area.x < 0)
4096     gtk_adjustment_set_value (hadj,
4097                               gtk_adjustment_get_value (hadj)
4098                                 + x + item_area.x);
4099   else if (x + item_area.x + item_area.width > allocation.width)
4100     gtk_adjustment_set_value (hadj,
4101                               gtk_adjustment_get_value (hadj)
4102                                 + x + item_area.x + item_area.width - allocation.width);
4103
4104   gtk_adjustment_changed (hadj);
4105   gtk_adjustment_changed (vadj);
4106 }
4107
4108 /* GtkCellLayout implementation */
4109
4110 static void
4111 gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
4112                                 GtkCellArea *cell_area)
4113 {
4114   GtkIconViewPrivate *priv = icon_view->priv;
4115
4116   if (priv->cell_area)
4117     return;
4118
4119   if (cell_area)
4120     priv->cell_area = cell_area;
4121   else
4122     priv->cell_area = gtk_cell_area_box_new ();
4123
4124   g_object_ref_sink (priv->cell_area);
4125
4126   if (GTK_IS_ORIENTABLE (priv->cell_area))
4127     gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
4128
4129   priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
4130
4131   priv->add_editable_id =
4132     g_signal_connect (priv->cell_area, "add-editable",
4133                       G_CALLBACK (gtk_icon_view_add_editable), icon_view);
4134   priv->remove_editable_id =
4135     g_signal_connect (priv->cell_area, "remove-editable",
4136                       G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
4137   priv->context_changed_id =
4138     g_signal_connect (priv->cell_area_context, "notify",
4139                       G_CALLBACK (gtk_icon_view_context_changed), icon_view);
4140
4141   update_text_cell (icon_view);
4142   update_pixbuf_cell (icon_view);
4143 }
4144
4145 static GtkCellArea *
4146 gtk_icon_view_cell_layout_get_area (GtkCellLayout *cell_layout)
4147 {
4148   GtkIconView *icon_view = GTK_ICON_VIEW (cell_layout);
4149   GtkIconViewPrivate *priv = icon_view->priv;
4150
4151   if (G_UNLIKELY (!priv->cell_area))
4152     gtk_icon_view_ensure_cell_area (icon_view, NULL);
4153
4154   return icon_view->priv->cell_area;
4155 }
4156
4157 static void
4158 gtk_icon_view_set_cell_data (GtkIconView     *icon_view,
4159                              GtkIconViewItem *item)
4160 {
4161   gboolean iters_persist;
4162   GtkTreeIter iter;
4163
4164   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4165   
4166   if (!iters_persist)
4167     {
4168       GtkTreePath *path;
4169
4170       path = gtk_tree_path_new_from_indices (item->index, -1);
4171       if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4172         return;
4173       gtk_tree_path_free (path);
4174     }
4175   else
4176     iter = item->iter;
4177
4178   gtk_cell_area_apply_attributes (icon_view->priv->cell_area, 
4179                                   icon_view->priv->model,
4180                                   &iter, FALSE, FALSE);
4181 }
4182
4183
4184
4185 /* Public API */
4186
4187
4188 /**
4189  * gtk_icon_view_new:
4190  * 
4191  * Creates a new #GtkIconView widget
4192  * 
4193  * Return value: A newly created #GtkIconView widget
4194  *
4195  * Since: 2.6
4196  **/
4197 GtkWidget *
4198 gtk_icon_view_new (void)
4199 {
4200   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4201 }
4202
4203 /**
4204  * gtk_icon_view_new_with_area:
4205  * @area: the #GtkCellArea to use to layout cells
4206  * 
4207  * Creates a new #GtkIconView widget using the
4208  * specified @area to layout cells inside the icons.
4209  * 
4210  * Return value: A newly created #GtkIconView widget
4211  *
4212  * Since: 3.0
4213  **/
4214 GtkWidget *
4215 gtk_icon_view_new_with_area (GtkCellArea *area)
4216 {
4217   return g_object_new (GTK_TYPE_ICON_VIEW, "cell-area", area, NULL);
4218 }
4219
4220 /**
4221  * gtk_icon_view_new_with_model:
4222  * @model: The model.
4223  * 
4224  * Creates a new #GtkIconView widget with the model @model.
4225  * 
4226  * Return value: A newly created #GtkIconView widget.
4227  *
4228  * Since: 2.6 
4229  **/
4230 GtkWidget *
4231 gtk_icon_view_new_with_model (GtkTreeModel *model)
4232 {
4233   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4234 }
4235
4236 /**
4237  * gtk_icon_view_convert_widget_to_bin_window_coords:
4238  * @icon_view: a #GtkIconView 
4239  * @wx: X coordinate relative to the widget
4240  * @wy: Y coordinate relative to the widget
4241  * @bx: (out): return location for bin_window X coordinate
4242  * @by: (out): return location for bin_window Y coordinate
4243  * 
4244  * Converts widget coordinates to coordinates for the bin_window,
4245  * as expected by e.g. gtk_icon_view_get_path_at_pos(). 
4246  *
4247  * Since: 2.12
4248  */
4249 void
4250 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4251                                                    gint         wx,
4252                                                    gint         wy, 
4253                                                    gint        *bx,
4254                                                    gint        *by)
4255 {
4256   gint x, y;
4257
4258   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4259
4260   if (icon_view->priv->bin_window) 
4261     gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4262   else
4263     x = y = 0;
4264  
4265   if (bx)
4266     *bx = wx - x;
4267   if (by)
4268     *by = wy - y;
4269 }
4270
4271 /**
4272  * gtk_icon_view_get_path_at_pos:
4273  * @icon_view: A #GtkIconView.
4274  * @x: The x position to be identified
4275  * @y: The y position to be identified
4276  * 
4277  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4278  * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4279  * the cell at the specified position. 
4280  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4281  * widget coordinates to bin_window coordinates.
4282  * 
4283  * Return value: The #GtkTreePath corresponding to the icon or %NULL
4284  * if no icon exists at that position.
4285  *
4286  * Since: 2.6 
4287  **/
4288 GtkTreePath *
4289 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4290                                gint         x,
4291                                gint         y)
4292 {
4293   GtkIconViewItem *item;
4294   GtkTreePath *path;
4295   
4296   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4297
4298   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4299
4300   if (!item)
4301     return NULL;
4302
4303   path = gtk_tree_path_new_from_indices (item->index, -1);
4304
4305   return path;
4306 }
4307
4308 /**
4309  * gtk_icon_view_get_item_at_pos:
4310  * @icon_view: A #GtkIconView.
4311  * @x: The x position to be identified
4312  * @y: The y position to be identified
4313  * @path: (out) (allow-none): Return location for the path, or %NULL
4314  * @cell: (out) (allow-none): Return location for the renderer
4315  *   responsible for the cell at (@x, @y), or %NULL
4316  * 
4317  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4318  * In contrast to gtk_icon_view_get_path_at_pos(), this function also 
4319  * obtains the cell at the specified position. The returned path should
4320  * be freed with gtk_tree_path_free().
4321  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4322  * widget coordinates to bin_window coordinates.
4323  * 
4324  * Return value: %TRUE if an item exists at the specified position
4325  *
4326  * Since: 2.8
4327  **/
4328 gboolean 
4329 gtk_icon_view_get_item_at_pos (GtkIconView      *icon_view,
4330                                gint              x,
4331                                gint              y,
4332                                GtkTreePath     **path,
4333                                GtkCellRenderer **cell)
4334 {
4335   GtkIconViewItem *item;
4336   GtkCellRenderer *renderer = NULL;
4337   
4338   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4339
4340   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &renderer);
4341
4342   if (path != NULL)
4343     {
4344       if (item != NULL)
4345         *path = gtk_tree_path_new_from_indices (item->index, -1);
4346       else
4347         *path = NULL;
4348     }
4349
4350   if (cell != NULL)
4351     *cell = renderer;
4352
4353   return (item != NULL);
4354 }
4355
4356 /**
4357  * gtk_icon_view_set_tooltip_item:
4358  * @icon_view: a #GtkIconView
4359  * @tooltip: a #GtkTooltip
4360  * @path: a #GtkTreePath
4361  * 
4362  * Sets the tip area of @tooltip to be the area covered by the item at @path.
4363  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4364  * See also gtk_tooltip_set_tip_area().
4365  * 
4366  * Since: 2.12
4367  */
4368 void 
4369 gtk_icon_view_set_tooltip_item (GtkIconView     *icon_view,
4370                                 GtkTooltip      *tooltip,
4371                                 GtkTreePath     *path)
4372 {
4373   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4374   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4375
4376   gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
4377 }
4378
4379 /**
4380  * gtk_icon_view_set_tooltip_cell:
4381  * @icon_view: a #GtkIconView
4382  * @tooltip: a #GtkTooltip
4383  * @path: a #GtkTreePath
4384  * @cell: (allow-none): a #GtkCellRenderer or %NULL
4385  *
4386  * Sets the tip area of @tooltip to the area which @cell occupies in
4387  * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
4388  *
4389  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
4390  *
4391  * Since: 2.12
4392  */
4393 void
4394 gtk_icon_view_set_tooltip_cell (GtkIconView     *icon_view,
4395                                 GtkTooltip      *tooltip,
4396                                 GtkTreePath     *path,
4397                                 GtkCellRenderer *cell)
4398 {
4399   GdkRectangle rect;
4400   GtkIconViewItem *item = NULL;
4401   gint x, y;
4402  
4403   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4404   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
4405   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
4406
4407   if (gtk_tree_path_get_depth (path) > 0)
4408     item = g_list_nth_data (icon_view->priv->items,
4409                             gtk_tree_path_get_indices(path)[0]);
4410  
4411   if (!item)
4412     return;
4413
4414   if (cell)
4415     {
4416       GtkCellAreaContext *context;
4417
4418       context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
4419       gtk_icon_view_set_cell_data (icon_view, item);
4420       gtk_cell_area_get_cell_allocation (icon_view->priv->cell_area, context,
4421                                          GTK_WIDGET (icon_view),
4422                                          cell, (GdkRectangle *)item, &rect);
4423     }
4424   else
4425     {
4426       rect.x = item->cell_area.x - icon_view->priv->item_padding;
4427       rect.y = item->cell_area.y - icon_view->priv->item_padding;
4428       rect.width  = item->cell_area.width  + icon_view->priv->item_padding * 2;
4429       rect.height = item->cell_area.height + icon_view->priv->item_padding * 2;
4430     }
4431   
4432   if (icon_view->priv->bin_window)
4433     {
4434       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4435       rect.x += x;
4436       rect.y += y; 
4437     }
4438
4439   gtk_tooltip_set_tip_area (tooltip, &rect); 
4440 }
4441
4442
4443 /**
4444  * gtk_icon_view_get_tooltip_context:
4445  * @icon_view: an #GtkIconView
4446  * @x: (inout): the x coordinate (relative to widget coordinates)
4447  * @y: (inout): the y coordinate (relative to widget coordinates)
4448  * @keyboard_tip: whether this is a keyboard tooltip or not
4449  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
4450  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
4451  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
4452  *
4453  * This function is supposed to be used in a #GtkWidget::query-tooltip
4454  * signal handler for #GtkIconView.  The @x, @y and @keyboard_tip values
4455  * which are received in the signal handler, should be passed to this
4456  * function without modification.
4457  *
4458  * The return value indicates whether there is an icon view item at the given
4459  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
4460  * tooltips the item returned will be the cursor item. When %TRUE, then any of
4461  * @model, @path and @iter which have been provided will be set to point to
4462  * that row and the corresponding model. @x and @y will always be converted
4463  * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
4464  *
4465  * Return value: whether or not the given tooltip context points to a item
4466  *
4467  * Since: 2.12
4468  */
4469 gboolean
4470 gtk_icon_view_get_tooltip_context (GtkIconView   *icon_view,
4471                                    gint          *x,
4472                                    gint          *y,
4473                                    gboolean       keyboard_tip,
4474                                    GtkTreeModel **model,
4475                                    GtkTreePath  **path,
4476                                    GtkTreeIter   *iter)
4477 {
4478   GtkTreePath *tmppath = NULL;
4479
4480   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4481   g_return_val_if_fail (x != NULL, FALSE);
4482   g_return_val_if_fail (y != NULL, FALSE);
4483
4484   if (keyboard_tip)
4485     {
4486       gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
4487
4488       if (!tmppath)
4489         return FALSE;
4490     }
4491   else
4492     {
4493       gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
4494                                                          x, y);
4495
4496       if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
4497         return FALSE;
4498     }
4499
4500   if (model)
4501     *model = gtk_icon_view_get_model (icon_view);
4502
4503   if (iter)
4504     gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
4505                              iter, tmppath);
4506
4507   if (path)
4508     *path = tmppath;
4509   else
4510     gtk_tree_path_free (tmppath);
4511
4512   return TRUE;
4513 }
4514
4515 static gboolean
4516 gtk_icon_view_set_tooltip_query_cb (GtkWidget  *widget,
4517                                     gint        x,
4518                                     gint        y,
4519                                     gboolean    keyboard_tip,
4520                                     GtkTooltip *tooltip,
4521                                     gpointer    data)
4522 {
4523   gchar *str;
4524   GtkTreeIter iter;
4525   GtkTreePath *path;
4526   GtkTreeModel *model;
4527   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
4528
4529   if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
4530                                           &x, &y,
4531                                           keyboard_tip,
4532                                           &model, &path, &iter))
4533     return FALSE;
4534
4535   gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
4536
4537   if (!str)
4538     {
4539       gtk_tree_path_free (path);
4540       return FALSE;
4541     }
4542
4543   gtk_tooltip_set_markup (tooltip, str);
4544   gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
4545
4546   gtk_tree_path_free (path);
4547   g_free (str);
4548
4549   return TRUE;
4550 }
4551
4552
4553 /**
4554  * gtk_icon_view_set_tooltip_column:
4555  * @icon_view: a #GtkIconView
4556  * @column: an integer, which is a valid column number for @icon_view's model
4557  *
4558  * If you only plan to have simple (text-only) tooltips on full items, you
4559  * can use this function to have #GtkIconView handle these automatically
4560  * for you. @column should be set to the column in @icon_view's model
4561  * containing the tooltip texts, or -1 to disable this feature.
4562  *
4563  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
4564  * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
4565  *
4566  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
4567  * so &amp;, &lt;, etc have to be escaped in the text.
4568  *
4569  * Since: 2.12
4570  */
4571 void
4572 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
4573                                   gint         column)
4574 {
4575   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4576
4577   if (column == icon_view->priv->tooltip_column)
4578     return;
4579
4580   if (column == -1)
4581     {
4582       g_signal_handlers_disconnect_by_func (icon_view,
4583                                             gtk_icon_view_set_tooltip_query_cb,
4584                                             NULL);
4585       gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
4586     }
4587   else
4588     {
4589       if (icon_view->priv->tooltip_column == -1)
4590         {
4591           g_signal_connect (icon_view, "query-tooltip",
4592                             G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
4593           gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
4594         }
4595     }
4596
4597   icon_view->priv->tooltip_column = column;
4598   g_object_notify (G_OBJECT (icon_view), "tooltip-column");
4599 }
4600
4601 /**
4602  * gtk_icon_view_get_tooltip_column:
4603  * @icon_view: a #GtkIconView
4604  *
4605  * Returns the column of @icon_view's model which is being used for
4606  * displaying tooltips on @icon_view's rows.
4607  *
4608  * Return value: the index of the tooltip column that is currently being
4609  * used, or -1 if this is disabled.
4610  *
4611  * Since: 2.12
4612  */
4613 gint
4614 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
4615 {
4616   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
4617
4618   return icon_view->priv->tooltip_column;
4619 }
4620
4621 /**
4622  * gtk_icon_view_get_visible_range:
4623  * @icon_view: A #GtkIconView
4624  * @start_path: (out) (allow-none): Return location for start of region,
4625  *              or %NULL
4626  * @end_path: (out) (allow-none): Return location for end of region, or %NULL
4627  * 
4628  * Sets @start_path and @end_path to be the first and last visible path. 
4629  * Note that there may be invisible paths in between.
4630  * 
4631  * Both paths should be freed with gtk_tree_path_free() after use.
4632  * 
4633  * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
4634  *
4635  * Since: 2.8
4636  **/
4637 gboolean
4638 gtk_icon_view_get_visible_range (GtkIconView  *icon_view,
4639                                  GtkTreePath **start_path,
4640                                  GtkTreePath **end_path)
4641 {
4642   gint start_index = -1;
4643   gint end_index = -1;
4644   GList *icons;
4645
4646   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
4647
4648   if (icon_view->priv->hadjustment == NULL ||
4649       icon_view->priv->vadjustment == NULL)
4650     return FALSE;
4651
4652   if (start_path == NULL && end_path == NULL)
4653     return FALSE;
4654   
4655   for (icons = icon_view->priv->items; icons; icons = icons->next) 
4656     {
4657       GtkIconViewItem *item = icons->data;
4658       GdkRectangle    *item_area = (GdkRectangle *)item;
4659
4660       if ((item_area->x + item_area->width >= (int)gtk_adjustment_get_value (icon_view->priv->hadjustment)) &&
4661           (item_area->y + item_area->height >= (int)gtk_adjustment_get_value (icon_view->priv->vadjustment)) &&
4662           (item_area->x <= 
4663            (int) (gtk_adjustment_get_value (icon_view->priv->hadjustment) + 
4664                   gtk_adjustment_get_page_size (icon_view->priv->hadjustment))) &&
4665           (item_area->y <= 
4666            (int) (gtk_adjustment_get_value (icon_view->priv->vadjustment) + 
4667                   gtk_adjustment_get_page_size (icon_view->priv->vadjustment))))
4668         {
4669           if (start_index == -1)
4670             start_index = item->index;
4671           end_index = item->index;
4672         }
4673     }
4674
4675   if (start_path && start_index != -1)
4676     *start_path = gtk_tree_path_new_from_indices (start_index, -1);
4677   if (end_path && end_index != -1)
4678     *end_path = gtk_tree_path_new_from_indices (end_index, -1);
4679   
4680   return start_index != -1;
4681 }
4682
4683 /**
4684  * gtk_icon_view_selected_foreach:
4685  * @icon_view: A #GtkIconView.
4686  * @func: (scope call): The function to call for each selected icon.
4687  * @data: User data to pass to the function.
4688  * 
4689  * Calls a function for each selected icon. Note that the model or
4690  * selection cannot be modified from within this function.
4691  *
4692  * Since: 2.6 
4693  **/
4694 void
4695 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
4696                                 GtkIconViewForeachFunc func,
4697                                 gpointer               data)
4698 {
4699   GList *list;
4700   
4701   for (list = icon_view->priv->items; list; list = list->next)
4702     {
4703       GtkIconViewItem *item = list->data;
4704       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
4705
4706       if (item->selected)
4707         (* func) (icon_view, path, data);
4708
4709       gtk_tree_path_free (path);
4710     }
4711 }
4712
4713 /**
4714  * gtk_icon_view_set_selection_mode:
4715  * @icon_view: A #GtkIconView.
4716  * @mode: The selection mode
4717  * 
4718  * Sets the selection mode of the @icon_view.
4719  *
4720  * Since: 2.6 
4721  **/
4722 void
4723 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
4724                                   GtkSelectionMode  mode)
4725 {
4726   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4727
4728   if (mode == icon_view->priv->selection_mode)
4729     return;
4730   
4731   if (mode == GTK_SELECTION_NONE ||
4732       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
4733     gtk_icon_view_unselect_all (icon_view);
4734   
4735   icon_view->priv->selection_mode = mode;
4736
4737   g_object_notify (G_OBJECT (icon_view), "selection-mode");
4738 }
4739
4740 /**
4741  * gtk_icon_view_get_selection_mode:
4742  * @icon_view: A #GtkIconView.
4743  * 
4744  * Gets the selection mode of the @icon_view.
4745  *
4746  * Return value: the current selection mode
4747  *
4748  * Since: 2.6 
4749  **/
4750 GtkSelectionMode
4751 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
4752 {
4753   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
4754
4755   return icon_view->priv->selection_mode;
4756 }
4757
4758 /**
4759  * gtk_icon_view_set_model:
4760  * @icon_view: A #GtkIconView.
4761  * @model: (allow-none): The model.
4762  *
4763  * Sets the model for a #GtkIconView.
4764  * If the @icon_view already has a model set, it will remove
4765  * it before setting the new model.  If @model is %NULL, then
4766  * it will unset the old model.
4767  *
4768  * Since: 2.6 
4769  **/
4770 void
4771 gtk_icon_view_set_model (GtkIconView *icon_view,
4772                          GtkTreeModel *model)
4773 {
4774   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4775   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
4776   
4777   if (icon_view->priv->model == model)
4778     return;
4779
4780   if (icon_view->priv->scroll_to_path)
4781     {
4782       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4783       icon_view->priv->scroll_to_path = NULL;
4784     }
4785
4786   /* The area can be NULL while disposing */
4787   if (icon_view->priv->cell_area)
4788     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
4789
4790   if (model)
4791     {
4792       GType column_type;
4793
4794       if (icon_view->priv->pixbuf_column != -1)
4795         {
4796           column_type = gtk_tree_model_get_column_type (model,
4797                                                         icon_view->priv->pixbuf_column);          
4798
4799           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
4800         }
4801
4802       if (icon_view->priv->text_column != -1)
4803         {
4804           column_type = gtk_tree_model_get_column_type (model,
4805                                                         icon_view->priv->text_column);    
4806
4807           g_return_if_fail (column_type == G_TYPE_STRING);
4808         }
4809
4810       if (icon_view->priv->markup_column != -1)
4811         {
4812           column_type = gtk_tree_model_get_column_type (model,
4813                                                         icon_view->priv->markup_column);          
4814
4815           g_return_if_fail (column_type == G_TYPE_STRING);
4816         }
4817       
4818     }
4819   
4820   if (icon_view->priv->model)
4821     {
4822       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4823                                             gtk_icon_view_row_changed,
4824                                             icon_view);
4825       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4826                                             gtk_icon_view_row_inserted,
4827                                             icon_view);
4828       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4829                                             gtk_icon_view_row_deleted,
4830                                             icon_view);
4831       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
4832                                             gtk_icon_view_rows_reordered,
4833                                             icon_view);
4834
4835       g_object_unref (icon_view->priv->model);
4836       
4837       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
4838       g_list_free (icon_view->priv->items);
4839       icon_view->priv->items = NULL;
4840       icon_view->priv->anchor_item = NULL;
4841       icon_view->priv->cursor_item = NULL;
4842       icon_view->priv->last_single_clicked = NULL;
4843       icon_view->priv->width = 0;
4844       icon_view->priv->height = 0;
4845     }
4846
4847   icon_view->priv->model = model;
4848
4849   if (icon_view->priv->model)
4850     {
4851       g_object_ref (icon_view->priv->model);
4852       g_signal_connect (icon_view->priv->model,
4853                         "row-changed",
4854                         G_CALLBACK (gtk_icon_view_row_changed),
4855                         icon_view);
4856       g_signal_connect (icon_view->priv->model,
4857                         "row-inserted",
4858                         G_CALLBACK (gtk_icon_view_row_inserted),
4859                         icon_view);
4860       g_signal_connect (icon_view->priv->model,
4861                         "row-deleted",
4862                         G_CALLBACK (gtk_icon_view_row_deleted),
4863                         icon_view);
4864       g_signal_connect (icon_view->priv->model,
4865                         "rows-reordered",
4866                         G_CALLBACK (gtk_icon_view_rows_reordered),
4867                         icon_view);
4868
4869       gtk_icon_view_build_items (icon_view);
4870
4871       gtk_icon_view_queue_layout (icon_view);
4872     }
4873
4874   g_object_notify (G_OBJECT (icon_view), "model");  
4875
4876   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
4877     gtk_widget_queue_resize (GTK_WIDGET (icon_view));
4878 }
4879
4880 /**
4881  * gtk_icon_view_get_model:
4882  * @icon_view: a #GtkIconView
4883  *
4884  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
4885  * model is unset.
4886  *
4887  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is
4888  *     currently being used.
4889  *
4890  * Since: 2.6 
4891  **/
4892 GtkTreeModel *
4893 gtk_icon_view_get_model (GtkIconView *icon_view)
4894 {
4895   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4896
4897   return icon_view->priv->model;
4898 }
4899
4900 static void
4901 update_text_cell (GtkIconView *icon_view)
4902 {
4903   if (!icon_view->priv->cell_area)
4904     return;
4905
4906   if (icon_view->priv->text_column == -1 &&
4907       icon_view->priv->markup_column == -1)
4908     {
4909       if (icon_view->priv->text_cell != NULL)
4910         {
4911           gtk_cell_area_remove (icon_view->priv->cell_area, 
4912                                 icon_view->priv->text_cell);
4913           icon_view->priv->text_cell = NULL;
4914         }
4915     }
4916   else 
4917     {
4918       if (icon_view->priv->text_cell == NULL)
4919         {
4920           icon_view->priv->text_cell = gtk_cell_renderer_text_new ();
4921
4922           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), icon_view->priv->text_cell, FALSE);
4923         }
4924
4925       if (icon_view->priv->markup_column != -1)
4926         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4927                                         icon_view->priv->text_cell, 
4928                                         "markup", icon_view->priv->markup_column, 
4929                                         NULL);
4930       else
4931         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4932                                         icon_view->priv->text_cell, 
4933                                         "text", icon_view->priv->text_column, 
4934                                         NULL);
4935
4936       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4937         g_object_set (icon_view->priv->text_cell,
4938                       "alignment", PANGO_ALIGN_CENTER,
4939                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
4940                       "xalign", 0.5,
4941                       "yalign", 0.0,
4942                       NULL);
4943       else
4944         g_object_set (icon_view->priv->text_cell,
4945                       "alignment", PANGO_ALIGN_LEFT,
4946                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
4947                       "xalign", 0.0,
4948                       "yalign", 0.5,
4949                       NULL);
4950     }
4951 }
4952
4953 static void
4954 update_pixbuf_cell (GtkIconView *icon_view)
4955 {
4956   if (!icon_view->priv->cell_area)
4957     return;
4958
4959   if (icon_view->priv->pixbuf_column == -1)
4960     {
4961       if (icon_view->priv->pixbuf_cell != NULL)
4962         {
4963           gtk_cell_area_remove (icon_view->priv->cell_area, 
4964                                 icon_view->priv->pixbuf_cell);
4965
4966           icon_view->priv->pixbuf_cell = NULL;
4967         }
4968     }
4969   else 
4970     {
4971       if (icon_view->priv->pixbuf_cell == NULL)
4972         {
4973           icon_view->priv->pixbuf_cell = gtk_cell_renderer_pixbuf_new ();
4974           
4975           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), icon_view->priv->pixbuf_cell, FALSE);
4976         }
4977       
4978       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
4979                                       icon_view->priv->pixbuf_cell, 
4980                                       "pixbuf", icon_view->priv->pixbuf_column, 
4981                                       NULL);
4982
4983       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
4984         g_object_set (icon_view->priv->pixbuf_cell,
4985                       "xalign", 0.5,
4986                       "yalign", 1.0,
4987                       NULL);
4988       else
4989         g_object_set (icon_view->priv->pixbuf_cell,
4990                       "xalign", 0.0,
4991                       "yalign", 0.0,
4992                       NULL);
4993     }
4994 }
4995
4996 /**
4997  * gtk_icon_view_set_text_column:
4998  * @icon_view: A #GtkIconView.
4999  * @column: A column in the currently used model, or -1 to display no text
5000  * 
5001  * Sets the column with text for @icon_view to be @column. The text
5002  * column must be of type #G_TYPE_STRING.
5003  *
5004  * Since: 2.6 
5005  **/
5006 void
5007 gtk_icon_view_set_text_column (GtkIconView *icon_view,
5008                                gint          column)
5009 {
5010   if (column == icon_view->priv->text_column)
5011     return;
5012   
5013   if (column == -1)
5014     icon_view->priv->text_column = -1;
5015   else
5016     {
5017       if (icon_view->priv->model != NULL)
5018         {
5019           GType column_type;
5020           
5021           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5022
5023           g_return_if_fail (column_type == G_TYPE_STRING);
5024         }
5025       
5026       icon_view->priv->text_column = column;
5027     }
5028
5029   if (icon_view->priv->cell_area)
5030     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5031
5032   update_text_cell (icon_view);
5033
5034   gtk_icon_view_invalidate_sizes (icon_view);
5035   
5036   g_object_notify (G_OBJECT (icon_view), "text-column");
5037 }
5038
5039 /**
5040  * gtk_icon_view_get_text_column:
5041  * @icon_view: A #GtkIconView.
5042  *
5043  * Returns the column with text for @icon_view.
5044  *
5045  * Returns: the text column, or -1 if it's unset.
5046  *
5047  * Since: 2.6
5048  */
5049 gint
5050 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
5051 {
5052   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5053
5054   return icon_view->priv->text_column;
5055 }
5056
5057 /**
5058  * gtk_icon_view_set_markup_column:
5059  * @icon_view: A #GtkIconView.
5060  * @column: A column in the currently used model, or -1 to display no text
5061  * 
5062  * Sets the column with markup information for @icon_view to be
5063  * @column. The markup column must be of type #G_TYPE_STRING.
5064  * If the markup column is set to something, it overrides
5065  * the text column set by gtk_icon_view_set_text_column().
5066  *
5067  * Since: 2.6
5068  **/
5069 void
5070 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5071                                  gint         column)
5072 {
5073   if (column == icon_view->priv->markup_column)
5074     return;
5075   
5076   if (column == -1)
5077     icon_view->priv->markup_column = -1;
5078   else
5079     {
5080       if (icon_view->priv->model != NULL)
5081         {
5082           GType column_type;
5083           
5084           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5085
5086           g_return_if_fail (column_type == G_TYPE_STRING);
5087         }
5088       
5089       icon_view->priv->markup_column = column;
5090     }
5091
5092   if (icon_view->priv->cell_area)
5093     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5094
5095   update_text_cell (icon_view);
5096
5097   gtk_icon_view_invalidate_sizes (icon_view);
5098   
5099   g_object_notify (G_OBJECT (icon_view), "markup-column");
5100 }
5101
5102 /**
5103  * gtk_icon_view_get_markup_column:
5104  * @icon_view: A #GtkIconView.
5105  *
5106  * Returns the column with markup text for @icon_view.
5107  *
5108  * Returns: the markup column, or -1 if it's unset.
5109  *
5110  * Since: 2.6
5111  */
5112 gint
5113 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
5114 {
5115   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5116
5117   return icon_view->priv->markup_column;
5118 }
5119
5120 /**
5121  * gtk_icon_view_set_pixbuf_column:
5122  * @icon_view: A #GtkIconView.
5123  * @column: A column in the currently used model, or -1 to disable
5124  * 
5125  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5126  * column must be of type #GDK_TYPE_PIXBUF
5127  *
5128  * Since: 2.6 
5129  **/
5130 void
5131 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5132                                  gint         column)
5133 {
5134   if (column == icon_view->priv->pixbuf_column)
5135     return;
5136   
5137   if (column == -1)
5138     icon_view->priv->pixbuf_column = -1;
5139   else
5140     {
5141       if (icon_view->priv->model != NULL)
5142         {
5143           GType column_type;
5144           
5145           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5146
5147           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5148         }
5149       
5150       icon_view->priv->pixbuf_column = column;
5151     }
5152
5153   if (icon_view->priv->cell_area)
5154     gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5155
5156   update_pixbuf_cell (icon_view);
5157
5158   gtk_icon_view_invalidate_sizes (icon_view);
5159   
5160   g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5161   
5162 }
5163
5164 /**
5165  * gtk_icon_view_get_pixbuf_column:
5166  * @icon_view: A #GtkIconView.
5167  *
5168  * Returns the column with pixbufs for @icon_view.
5169  *
5170  * Returns: the pixbuf column, or -1 if it's unset.
5171  *
5172  * Since: 2.6
5173  */
5174 gint
5175 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
5176 {
5177   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5178
5179   return icon_view->priv->pixbuf_column;
5180 }
5181
5182 /**
5183  * gtk_icon_view_select_path:
5184  * @icon_view: A #GtkIconView.
5185  * @path: The #GtkTreePath to be selected.
5186  * 
5187  * Selects the row at @path.
5188  *
5189  * Since: 2.6
5190  **/
5191 void
5192 gtk_icon_view_select_path (GtkIconView *icon_view,
5193                            GtkTreePath *path)
5194 {
5195   GtkIconViewItem *item = NULL;
5196
5197   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5198   g_return_if_fail (icon_view->priv->model != NULL);
5199   g_return_if_fail (path != NULL);
5200
5201   if (gtk_tree_path_get_depth (path) > 0)
5202     item = g_list_nth_data (icon_view->priv->items,
5203                             gtk_tree_path_get_indices(path)[0]);
5204
5205   if (item)
5206     gtk_icon_view_select_item (icon_view, item);
5207 }
5208
5209 /**
5210  * gtk_icon_view_unselect_path:
5211  * @icon_view: A #GtkIconView.
5212  * @path: The #GtkTreePath to be unselected.
5213  * 
5214  * Unselects the row at @path.
5215  *
5216  * Since: 2.6
5217  **/
5218 void
5219 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5220                              GtkTreePath *path)
5221 {
5222   GtkIconViewItem *item;
5223   
5224   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5225   g_return_if_fail (icon_view->priv->model != NULL);
5226   g_return_if_fail (path != NULL);
5227
5228   item = g_list_nth_data (icon_view->priv->items,
5229                           gtk_tree_path_get_indices(path)[0]);
5230
5231   if (!item)
5232     return;
5233   
5234   gtk_icon_view_unselect_item (icon_view, item);
5235 }
5236
5237 /**
5238  * gtk_icon_view_get_selected_items:
5239  * @icon_view: A #GtkIconView.
5240  *
5241  * Creates a list of paths of all selected items. Additionally, if you are
5242  * planning on modifying the model after calling this function, you may
5243  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5244  * To do this, you can use gtk_tree_row_reference_new().
5245  *
5246  * To free the return value, use:
5247  * |[
5248  * g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
5249  * g_list_free (list);
5250  * ]|
5251  *
5252  * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
5253  *
5254  * Since: 2.6
5255  **/
5256 GList *
5257 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5258 {
5259   GList *list;
5260   GList *selected = NULL;
5261   
5262   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5263   
5264   for (list = icon_view->priv->items; list != NULL; list = list->next)
5265     {
5266       GtkIconViewItem *item = list->data;
5267
5268       if (item->selected)
5269         {
5270           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5271
5272           selected = g_list_prepend (selected, path);
5273         }
5274     }
5275
5276   return selected;
5277 }
5278
5279 /**
5280  * gtk_icon_view_select_all:
5281  * @icon_view: A #GtkIconView.
5282  * 
5283  * Selects all the icons. @icon_view must has its selection mode set
5284  * to #GTK_SELECTION_MULTIPLE.
5285  *
5286  * Since: 2.6
5287  **/
5288 void
5289 gtk_icon_view_select_all (GtkIconView *icon_view)
5290 {
5291   GList *items;
5292   gboolean dirty = FALSE;
5293   
5294   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5295
5296   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5297     return;
5298
5299   for (items = icon_view->priv->items; items; items = items->next)
5300     {
5301       GtkIconViewItem *item = items->data;
5302       
5303       if (!item->selected)
5304         {
5305           dirty = TRUE;
5306           item->selected = TRUE;
5307           gtk_icon_view_queue_draw_item (icon_view, item);
5308         }
5309     }
5310
5311   if (dirty)
5312     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5313 }
5314
5315 /**
5316  * gtk_icon_view_unselect_all:
5317  * @icon_view: A #GtkIconView.
5318  * 
5319  * Unselects all the icons.
5320  *
5321  * Since: 2.6
5322  **/
5323 void
5324 gtk_icon_view_unselect_all (GtkIconView *icon_view)
5325 {
5326   gboolean dirty = FALSE;
5327   
5328   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5329
5330   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
5331     return;
5332
5333   dirty = gtk_icon_view_unselect_all_internal (icon_view);
5334
5335   if (dirty)
5336     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
5337 }
5338
5339 /**
5340  * gtk_icon_view_path_is_selected:
5341  * @icon_view: A #GtkIconView.
5342  * @path: A #GtkTreePath to check selection on.
5343  * 
5344  * Returns %TRUE if the icon pointed to by @path is currently
5345  * selected. If @path does not point to a valid location, %FALSE is returned.
5346  * 
5347  * Return value: %TRUE if @path is selected.
5348  *
5349  * Since: 2.6
5350  **/
5351 gboolean
5352 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
5353                                 GtkTreePath *path)
5354 {
5355   GtkIconViewItem *item;
5356   
5357   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5358   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
5359   g_return_val_if_fail (path != NULL, FALSE);
5360   
5361   item = g_list_nth_data (icon_view->priv->items,
5362                           gtk_tree_path_get_indices(path)[0]);
5363
5364   if (!item)
5365     return FALSE;
5366   
5367   return item->selected;
5368 }
5369
5370 /**
5371  * gtk_icon_view_get_item_row:
5372  * @icon_view: a #GtkIconView
5373  * @path: the #GtkTreePath of the item
5374  *
5375  * Gets the row in which the item @path is currently
5376  * displayed. Row numbers start at 0.
5377  *
5378  * Returns: The row in which the item is displayed
5379  *
5380  * Since: 2.22
5381  */
5382 gint
5383 gtk_icon_view_get_item_row (GtkIconView *icon_view,
5384                             GtkTreePath *path)
5385 {
5386   GtkIconViewItem *item;
5387
5388   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5389   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5390   g_return_val_if_fail (path != NULL, -1);
5391
5392   item = g_list_nth_data (icon_view->priv->items,
5393                           gtk_tree_path_get_indices(path)[0]);
5394
5395   if (!item)
5396     return -1;
5397
5398   return item->row;
5399 }
5400
5401 /**
5402  * gtk_icon_view_get_item_column:
5403  * @icon_view: a #GtkIconView
5404  * @path: the #GtkTreePath of the item
5405  *
5406  * Gets the column in which the item @path is currently
5407  * displayed. Column numbers start at 0.
5408  *
5409  * Returns: The column in which the item is displayed
5410  *
5411  * Since: 2.22
5412  */
5413 gint
5414 gtk_icon_view_get_item_column (GtkIconView *icon_view,
5415                                GtkTreePath *path)
5416 {
5417   GtkIconViewItem *item;
5418
5419   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5420   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
5421   g_return_val_if_fail (path != NULL, -1);
5422
5423   item = g_list_nth_data (icon_view->priv->items,
5424                           gtk_tree_path_get_indices(path)[0]);
5425
5426   if (!item)
5427     return -1;
5428
5429   return item->col;
5430 }
5431
5432 /**
5433  * gtk_icon_view_item_activated:
5434  * @icon_view: A #GtkIconView
5435  * @path: The #GtkTreePath to be activated
5436  * 
5437  * Activates the item determined by @path.
5438  *
5439  * Since: 2.6
5440  **/
5441 void
5442 gtk_icon_view_item_activated (GtkIconView      *icon_view,
5443                               GtkTreePath      *path)
5444 {
5445   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5446   g_return_if_fail (path != NULL);
5447   
5448   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
5449 }
5450
5451 /**
5452  * gtk_icon_view_set_item_orientation:
5453  * @icon_view: a #GtkIconView
5454  * @orientation: the relative position of texts and icons 
5455  * 
5456  * Sets the ::item-orientation property which determines whether the labels 
5457  * are drawn beside the icons instead of below.
5458  *
5459  * Since: 2.6
5460  **/
5461 void 
5462 gtk_icon_view_set_item_orientation (GtkIconView    *icon_view,
5463                                     GtkOrientation  orientation)
5464 {
5465   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5466
5467   if (icon_view->priv->item_orientation != orientation)
5468     {
5469       icon_view->priv->item_orientation = orientation;
5470
5471       if (icon_view->priv->cell_area)
5472         {
5473           if (GTK_IS_ORIENTABLE (icon_view->priv->cell_area))
5474             gtk_orientable_set_orientation (GTK_ORIENTABLE (icon_view->priv->cell_area), 
5475                                             icon_view->priv->item_orientation);
5476
5477           gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5478         }
5479
5480       gtk_icon_view_invalidate_sizes (icon_view);
5481
5482       update_text_cell (icon_view);
5483       update_pixbuf_cell (icon_view);
5484       
5485       g_object_notify (G_OBJECT (icon_view), "item-orientation");
5486     }
5487 }
5488
5489 /**
5490  * gtk_icon_view_get_item_orientation:
5491  * @icon_view: a #GtkIconView
5492  * 
5493  * Returns the value of the ::item-orientation property which determines 
5494  * whether the labels are drawn beside the icons instead of below. 
5495  * 
5496  * Return value: the relative position of texts and icons 
5497  *
5498  * Since: 2.6
5499  **/
5500 GtkOrientation
5501 gtk_icon_view_get_item_orientation (GtkIconView *icon_view)
5502 {
5503   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
5504                         GTK_ORIENTATION_VERTICAL);
5505
5506   return icon_view->priv->item_orientation;
5507 }
5508
5509 /**
5510  * gtk_icon_view_set_columns:
5511  * @icon_view: a #GtkIconView
5512  * @columns: the number of columns
5513  * 
5514  * Sets the ::columns property which determines in how
5515  * many columns the icons are arranged. If @columns is
5516  * -1, the number of columns will be chosen automatically 
5517  * to fill the available area. 
5518  *
5519  * Since: 2.6
5520  */
5521 void 
5522 gtk_icon_view_set_columns (GtkIconView *icon_view,
5523                            gint         columns)
5524 {
5525   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5526   
5527   if (icon_view->priv->columns != columns)
5528     {
5529       icon_view->priv->columns = columns;
5530
5531       if (icon_view->priv->cell_area)
5532         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5533
5534       gtk_icon_view_queue_layout (icon_view);
5535       
5536       g_object_notify (G_OBJECT (icon_view), "columns");
5537     }  
5538 }
5539
5540 /**
5541  * gtk_icon_view_get_columns:
5542  * @icon_view: a #GtkIconView
5543  * 
5544  * Returns the value of the ::columns property.
5545  * 
5546  * Return value: the number of columns, or -1
5547  *
5548  * Since: 2.6
5549  */
5550 gint
5551 gtk_icon_view_get_columns (GtkIconView *icon_view)
5552 {
5553   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5554
5555   return icon_view->priv->columns;
5556 }
5557
5558 /**
5559  * gtk_icon_view_set_item_width:
5560  * @icon_view: a #GtkIconView
5561  * @item_width: the width for each item
5562  * 
5563  * Sets the ::item-width property which specifies the width 
5564  * to use for each item. If it is set to -1, the icon view will 
5565  * automatically determine a suitable item size.
5566  *
5567  * Since: 2.6
5568  */
5569 void 
5570 gtk_icon_view_set_item_width (GtkIconView *icon_view,
5571                               gint         item_width)
5572 {
5573   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5574   
5575   if (icon_view->priv->item_width != item_width)
5576     {
5577       icon_view->priv->item_width = item_width;
5578       
5579       if (icon_view->priv->cell_area)
5580         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5581
5582       gtk_icon_view_invalidate_sizes (icon_view);
5583       
5584       update_text_cell (icon_view);
5585
5586       g_object_notify (G_OBJECT (icon_view), "item-width");
5587     }  
5588 }
5589
5590 /**
5591  * gtk_icon_view_get_item_width:
5592  * @icon_view: a #GtkIconView
5593  * 
5594  * Returns the value of the ::item-width property.
5595  * 
5596  * Return value: the width of a single item, or -1
5597  *
5598  * Since: 2.6
5599  */
5600 gint
5601 gtk_icon_view_get_item_width (GtkIconView *icon_view)
5602 {
5603   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5604
5605   return icon_view->priv->item_width;
5606 }
5607
5608
5609 /**
5610  * gtk_icon_view_set_spacing:
5611  * @icon_view: a #GtkIconView
5612  * @spacing: the spacing
5613  * 
5614  * Sets the ::spacing property which specifies the space 
5615  * which is inserted between the cells (i.e. the icon and 
5616  * the text) of an item.
5617  *
5618  * Since: 2.6
5619  */
5620 void 
5621 gtk_icon_view_set_spacing (GtkIconView *icon_view,
5622                            gint         spacing)
5623 {
5624   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5625   
5626   if (icon_view->priv->spacing != spacing)
5627     {
5628       icon_view->priv->spacing = spacing;
5629
5630       if (icon_view->priv->cell_area)
5631         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5632
5633       gtk_icon_view_invalidate_sizes (icon_view);
5634
5635       g_object_notify (G_OBJECT (icon_view), "spacing");
5636     }  
5637 }
5638
5639 /**
5640  * gtk_icon_view_get_spacing:
5641  * @icon_view: a #GtkIconView
5642  * 
5643  * Returns the value of the ::spacing property.
5644  * 
5645  * Return value: the space between cells 
5646  *
5647  * Since: 2.6
5648  */
5649 gint
5650 gtk_icon_view_get_spacing (GtkIconView *icon_view)
5651 {
5652   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5653
5654   return icon_view->priv->spacing;
5655 }
5656
5657 /**
5658  * gtk_icon_view_set_row_spacing:
5659  * @icon_view: a #GtkIconView
5660  * @row_spacing: the row spacing
5661  * 
5662  * Sets the ::row-spacing property which specifies the space 
5663  * which is inserted between the rows of the icon view.
5664  *
5665  * Since: 2.6
5666  */
5667 void 
5668 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
5669                                gint         row_spacing)
5670 {
5671   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5672   
5673   if (icon_view->priv->row_spacing != row_spacing)
5674     {
5675       icon_view->priv->row_spacing = row_spacing;
5676
5677       if (icon_view->priv->cell_area)
5678         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5679
5680       gtk_icon_view_invalidate_sizes (icon_view);
5681
5682       g_object_notify (G_OBJECT (icon_view), "row-spacing");
5683     }  
5684 }
5685
5686 /**
5687  * gtk_icon_view_get_row_spacing:
5688  * @icon_view: a #GtkIconView
5689  * 
5690  * Returns the value of the ::row-spacing property.
5691  * 
5692  * Return value: the space between rows
5693  *
5694  * Since: 2.6
5695  */
5696 gint
5697 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
5698 {
5699   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5700
5701   return icon_view->priv->row_spacing;
5702 }
5703
5704 /**
5705  * gtk_icon_view_set_column_spacing:
5706  * @icon_view: a #GtkIconView
5707  * @column_spacing: the column spacing
5708  * 
5709  * Sets the ::column-spacing property which specifies the space 
5710  * which is inserted between the columns of the icon view.
5711  *
5712  * Since: 2.6
5713  */
5714 void 
5715 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
5716                                   gint         column_spacing)
5717 {
5718   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5719   
5720   if (icon_view->priv->column_spacing != column_spacing)
5721     {
5722       icon_view->priv->column_spacing = column_spacing;
5723
5724       if (icon_view->priv->cell_area)
5725         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5726
5727       gtk_icon_view_invalidate_sizes (icon_view);
5728
5729       g_object_notify (G_OBJECT (icon_view), "column-spacing");
5730     }  
5731 }
5732
5733 /**
5734  * gtk_icon_view_get_column_spacing:
5735  * @icon_view: a #GtkIconView
5736  * 
5737  * Returns the value of the ::column-spacing property.
5738  * 
5739  * Return value: the space between columns
5740  *
5741  * Since: 2.6
5742  */
5743 gint
5744 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
5745 {
5746   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5747
5748   return icon_view->priv->column_spacing;
5749 }
5750
5751 /**
5752  * gtk_icon_view_set_margin:
5753  * @icon_view: a #GtkIconView
5754  * @margin: the margin
5755  * 
5756  * Sets the ::margin property which specifies the space 
5757  * which is inserted at the top, bottom, left and right 
5758  * of the icon view.
5759  *
5760  * Since: 2.6
5761  */
5762 void 
5763 gtk_icon_view_set_margin (GtkIconView *icon_view,
5764                           gint         margin)
5765 {
5766   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5767   
5768   if (icon_view->priv->margin != margin)
5769     {
5770       icon_view->priv->margin = margin;
5771
5772       if (icon_view->priv->cell_area)
5773         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5774
5775       gtk_icon_view_invalidate_sizes (icon_view);
5776
5777       g_object_notify (G_OBJECT (icon_view), "margin");
5778     }  
5779 }
5780
5781 /**
5782  * gtk_icon_view_get_margin:
5783  * @icon_view: a #GtkIconView
5784  * 
5785  * Returns the value of the ::margin property.
5786  * 
5787  * Return value: the space at the borders 
5788  *
5789  * Since: 2.6
5790  */
5791 gint
5792 gtk_icon_view_get_margin (GtkIconView *icon_view)
5793 {
5794   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5795
5796   return icon_view->priv->margin;
5797 }
5798
5799 /**
5800  * gtk_icon_view_set_item_padding:
5801  * @icon_view: a #GtkIconView
5802  * @item_padding: the item padding
5803  *
5804  * Sets the #GtkIconView:item-padding property which specifies the padding
5805  * around each of the icon view's items.
5806  *
5807  * Since: 2.18
5808  */
5809 void
5810 gtk_icon_view_set_item_padding (GtkIconView *icon_view,
5811                                 gint         item_padding)
5812 {
5813   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5814   
5815   if (icon_view->priv->item_padding != item_padding)
5816     {
5817       icon_view->priv->item_padding = item_padding;
5818
5819       if (icon_view->priv->cell_area)
5820         gtk_cell_area_stop_editing (icon_view->priv->cell_area, TRUE);
5821
5822       gtk_icon_view_invalidate_sizes (icon_view);
5823
5824       g_object_notify (G_OBJECT (icon_view), "item-padding");
5825     }  
5826 }
5827
5828 /**
5829  * gtk_icon_view_get_item_padding:
5830  * @icon_view: a #GtkIconView
5831  * 
5832  * Returns the value of the ::item-padding property.
5833  * 
5834  * Return value: the padding around items
5835  *
5836  * Since: 2.18
5837  */
5838 gint
5839 gtk_icon_view_get_item_padding (GtkIconView *icon_view)
5840 {
5841   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5842
5843   return icon_view->priv->item_padding;
5844 }
5845
5846 /* Get/set whether drag_motion requested the drag data and
5847  * drag_data_received should thus not actually insert the data,
5848  * since the data doesn't result from a drop.
5849  */
5850 static void
5851 set_status_pending (GdkDragContext *context,
5852                     GdkDragAction   suggested_action)
5853 {
5854   g_object_set_data (G_OBJECT (context),
5855                      I_("gtk-icon-view-status-pending"),
5856                      GINT_TO_POINTER (suggested_action));
5857 }
5858
5859 static GdkDragAction
5860 get_status_pending (GdkDragContext *context)
5861 {
5862   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
5863                                              "gtk-icon-view-status-pending"));
5864 }
5865
5866 static void
5867 unset_reorderable (GtkIconView *icon_view)
5868 {
5869   if (icon_view->priv->reorderable)
5870     {
5871       icon_view->priv->reorderable = FALSE;
5872       g_object_notify (G_OBJECT (icon_view), "reorderable");
5873     }
5874 }
5875
5876 static void
5877 set_source_row (GdkDragContext *context,
5878                 GtkTreeModel   *model,
5879                 GtkTreePath    *source_row)
5880 {
5881   if (source_row)
5882     g_object_set_data_full (G_OBJECT (context),
5883                             I_("gtk-icon-view-source-row"),
5884                             gtk_tree_row_reference_new (model, source_row),
5885                             (GDestroyNotify) gtk_tree_row_reference_free);
5886   else
5887     g_object_set_data_full (G_OBJECT (context),
5888                             I_("gtk-icon-view-source-row"),
5889                             NULL, NULL);
5890 }
5891
5892 static GtkTreePath*
5893 get_source_row (GdkDragContext *context)
5894 {
5895   GtkTreeRowReference *ref;
5896
5897   ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
5898
5899   if (ref)
5900     return gtk_tree_row_reference_get_path (ref);
5901   else
5902     return NULL;
5903 }
5904
5905 typedef struct
5906 {
5907   GtkTreeRowReference *dest_row;
5908   gboolean             empty_view_drop;
5909   gboolean             drop_append_mode;
5910 } DestRow;
5911
5912 static void
5913 dest_row_free (gpointer data)
5914 {
5915   DestRow *dr = (DestRow *)data;
5916
5917   gtk_tree_row_reference_free (dr->dest_row);
5918   g_free (dr);
5919 }
5920
5921 static void
5922 set_dest_row (GdkDragContext *context,
5923               GtkTreeModel   *model,
5924               GtkTreePath    *dest_row,
5925               gboolean        empty_view_drop,
5926               gboolean        drop_append_mode)
5927 {
5928   DestRow *dr;
5929
5930   if (!dest_row)
5931     {
5932       g_object_set_data_full (G_OBJECT (context),
5933                               I_("gtk-icon-view-dest-row"),
5934                               NULL, NULL);
5935       return;
5936     }
5937   
5938   dr = g_new0 (DestRow, 1);
5939      
5940   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
5941   dr->empty_view_drop = empty_view_drop;
5942   dr->drop_append_mode = drop_append_mode;
5943   g_object_set_data_full (G_OBJECT (context),
5944                           I_("gtk-icon-view-dest-row"),
5945                           dr, (GDestroyNotify) dest_row_free);
5946 }
5947
5948 static GtkTreePath*
5949 get_dest_row (GdkDragContext *context)
5950 {
5951   DestRow *dr;
5952
5953   dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
5954
5955   if (dr)
5956     {
5957       GtkTreePath *path = NULL;
5958       
5959       if (dr->dest_row)
5960         path = gtk_tree_row_reference_get_path (dr->dest_row);
5961       else if (dr->empty_view_drop)
5962         path = gtk_tree_path_new_from_indices (0, -1);
5963       else
5964         path = NULL;
5965
5966       if (path && dr->drop_append_mode)
5967         gtk_tree_path_next (path);
5968
5969       return path;
5970     }
5971   else
5972     return NULL;
5973 }
5974
5975 static gboolean
5976 check_model_dnd (GtkTreeModel *model,
5977                  GType         required_iface,
5978                  const gchar  *signal)
5979 {
5980   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
5981     {
5982       g_warning ("You must override the default '%s' handler "
5983                  "on GtkIconView when using models that don't support "
5984                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
5985                  "is to connect to '%s' and call "
5986                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
5987                  "the default handler from running. Look at the source code "
5988                  "for the default handler in gtkiconview.c to get an idea what "
5989                  "your handler should do. (gtkiconview.c is in the GTK+ source "
5990                  "code.) If you're using GTK+ from a language other than C, "
5991                  "there may be a more natural way to override default handlers, e.g. via derivation.",
5992                  signal, g_type_name (required_iface), signal);
5993       return FALSE;
5994     }
5995   else
5996     return TRUE;
5997 }
5998
5999 static void
6000 remove_scroll_timeout (GtkIconView *icon_view)
6001 {
6002   if (icon_view->priv->scroll_timeout_id != 0)
6003     {
6004       g_source_remove (icon_view->priv->scroll_timeout_id);
6005
6006       icon_view->priv->scroll_timeout_id = 0;
6007     }
6008 }
6009
6010 static void
6011 gtk_icon_view_autoscroll (GtkIconView *icon_view)
6012 {
6013   GdkWindow *window;
6014   gint px, py, x, y, width, height;
6015   gint hoffset, voffset;
6016
6017   window = gtk_widget_get_window (GTK_WIDGET (icon_view));
6018
6019   gdk_window_get_pointer (window, &px, &py, NULL);
6020   gdk_window_get_geometry (window, &x, &y, &width, &height);
6021
6022   /* see if we are near the edge. */
6023   voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
6024   if (voffset > 0)
6025     voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
6026
6027   hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
6028   if (hoffset > 0)
6029     hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
6030
6031   if (voffset != 0)
6032     gtk_adjustment_set_value (icon_view->priv->vadjustment,
6033                               gtk_adjustment_get_value (icon_view->priv->vadjustment) + voffset);
6034
6035   if (hoffset != 0)
6036     gtk_adjustment_set_value (icon_view->priv->hadjustment,
6037                               gtk_adjustment_get_value (icon_view->priv->hadjustment) + hoffset);
6038 }
6039
6040
6041 static gboolean
6042 drag_scroll_timeout (gpointer data)
6043 {
6044   GtkIconView *icon_view = GTK_ICON_VIEW (data);
6045
6046   gtk_icon_view_autoscroll (icon_view);
6047
6048   return TRUE;
6049 }
6050
6051
6052 static gboolean
6053 set_destination (GtkIconView    *icon_view,
6054                  GdkDragContext *context,
6055                  gint            x,
6056                  gint            y,
6057                  GdkDragAction  *suggested_action,
6058                  GdkAtom        *target)
6059 {
6060   GtkWidget *widget;
6061   GtkTreePath *path = NULL;
6062   GtkIconViewDropPosition pos;
6063   GtkIconViewDropPosition old_pos;
6064   GtkTreePath *old_dest_path = NULL;
6065   gboolean can_drop = FALSE;
6066
6067   widget = GTK_WIDGET (icon_view);
6068
6069   *suggested_action = 0;
6070   *target = GDK_NONE;
6071
6072   if (!icon_view->priv->dest_set)
6073     {
6074       /* someone unset us as a drag dest, note that if
6075        * we return FALSE drag_leave isn't called
6076        */
6077
6078       gtk_icon_view_set_drag_dest_item (icon_view,
6079                                         NULL,
6080                                         GTK_ICON_VIEW_DROP_LEFT);
6081
6082       remove_scroll_timeout (GTK_ICON_VIEW (widget));
6083
6084       return FALSE; /* no longer a drop site */
6085     }
6086
6087   *target = gtk_drag_dest_find_target (widget, context,
6088                                        gtk_drag_dest_get_target_list (widget));
6089   if (*target == GDK_NONE)
6090     return FALSE;
6091
6092   if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos)) 
6093     {
6094       gint n_children;
6095       GtkTreeModel *model;
6096       
6097       /* the row got dropped on empty space, let's setup a special case
6098        */
6099
6100       if (path)
6101         gtk_tree_path_free (path);
6102
6103       model = gtk_icon_view_get_model (icon_view);
6104
6105       n_children = gtk_tree_model_iter_n_children (model, NULL);
6106       if (n_children)
6107         {
6108           pos = GTK_ICON_VIEW_DROP_BELOW;
6109           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6110         }
6111       else
6112         {
6113           pos = GTK_ICON_VIEW_DROP_ABOVE;
6114           path = gtk_tree_path_new_from_indices (0, -1);
6115         }
6116
6117       can_drop = TRUE;
6118
6119       goto out;
6120     }
6121
6122   g_assert (path);
6123
6124   gtk_icon_view_get_drag_dest_item (icon_view,
6125                                     &old_dest_path,
6126                                     &old_pos);
6127   
6128   if (old_dest_path)
6129     gtk_tree_path_free (old_dest_path);
6130   
6131   if (TRUE /* FIXME if the location droppable predicate */)
6132     {
6133       can_drop = TRUE;
6134     }
6135
6136 out:
6137   if (can_drop)
6138     {
6139       GtkWidget *source_widget;
6140
6141       *suggested_action = gdk_drag_context_get_suggested_action (context);
6142       source_widget = gtk_drag_get_source_widget (context);
6143
6144       if (source_widget == widget)
6145         {
6146           /* Default to MOVE, unless the user has
6147            * pressed ctrl or shift to affect available actions
6148            */
6149           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
6150             *suggested_action = GDK_ACTION_MOVE;
6151         }
6152
6153       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6154                                         path, pos);
6155     }
6156   else
6157     {
6158       /* can't drop here */
6159       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6160                                         NULL,
6161                                         GTK_ICON_VIEW_DROP_LEFT);
6162     }
6163   
6164   if (path)
6165     gtk_tree_path_free (path);
6166   
6167   return TRUE;
6168 }
6169
6170 static GtkTreePath*
6171 get_logical_destination (GtkIconView *icon_view,
6172                          gboolean    *drop_append_mode)
6173 {
6174   /* adjust path to point to the row the drop goes in front of */
6175   GtkTreePath *path = NULL;
6176   GtkIconViewDropPosition pos;
6177   
6178   *drop_append_mode = FALSE;
6179
6180   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6181
6182   if (path == NULL)
6183     return NULL;
6184
6185   if (pos == GTK_ICON_VIEW_DROP_RIGHT || 
6186       pos == GTK_ICON_VIEW_DROP_BELOW)
6187     {
6188       GtkTreeIter iter;
6189       GtkTreeModel *model = icon_view->priv->model;
6190
6191       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6192           !gtk_tree_model_iter_next (model, &iter))
6193         *drop_append_mode = TRUE;
6194       else
6195         {
6196           *drop_append_mode = FALSE;
6197           gtk_tree_path_next (path);
6198         }      
6199     }
6200
6201   return path;
6202 }
6203
6204 static gboolean
6205 gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
6206                                 GdkEventMotion *event)
6207 {
6208   GtkWidget *widget = GTK_WIDGET (icon_view);
6209   GdkDragContext *context;
6210   GtkTreePath *path = NULL;
6211   gint button;
6212   GtkTreeModel *model;
6213   gboolean retval = FALSE;
6214
6215   if (!icon_view->priv->source_set)
6216     goto out;
6217
6218   if (icon_view->priv->pressed_button < 0)
6219     goto out;
6220
6221   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6222                                  icon_view->priv->press_start_x,
6223                                  icon_view->priv->press_start_y,
6224                                  event->x, event->y))
6225     goto out;
6226
6227   model = gtk_icon_view_get_model (icon_view);
6228
6229   if (model == NULL)
6230     goto out;
6231
6232   button = icon_view->priv->pressed_button;
6233   icon_view->priv->pressed_button = -1;
6234
6235   path = gtk_icon_view_get_path_at_pos (icon_view,
6236                                         icon_view->priv->press_start_x,
6237                                         icon_view->priv->press_start_y);
6238
6239   if (path == NULL)
6240     goto out;
6241
6242   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6243       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6244                                            path))
6245     goto out;
6246
6247   /* FIXME Check whether we're a start button, if not return FALSE and
6248    * free path
6249    */
6250
6251   /* Now we can begin the drag */
6252   
6253   retval = TRUE;
6254
6255   context = gtk_drag_begin (widget,
6256                             gtk_drag_source_get_target_list (widget),
6257                             icon_view->priv->source_actions,
6258                             button,
6259                             (GdkEvent*)event);
6260
6261   set_source_row (context, model, path);
6262   
6263  out:
6264   if (path)
6265     gtk_tree_path_free (path);
6266
6267   return retval;
6268 }
6269
6270 /* Source side drag signals */
6271 static void 
6272 gtk_icon_view_drag_begin (GtkWidget      *widget,
6273                           GdkDragContext *context)
6274 {
6275   GtkIconView *icon_view;
6276   GtkIconViewItem *item;
6277   cairo_surface_t *icon;
6278   gint x, y;
6279   GtkTreePath *path;
6280
6281   icon_view = GTK_ICON_VIEW (widget);
6282
6283   /* if the user uses a custom DnD impl, we don't set the icon here */
6284   if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6285     return;
6286
6287   item = gtk_icon_view_get_item_at_coords (icon_view,
6288                                            icon_view->priv->press_start_x,
6289                                            icon_view->priv->press_start_y,
6290                                            TRUE,
6291                                            NULL);
6292
6293   g_return_if_fail (item != NULL);
6294
6295   x = icon_view->priv->press_start_x - item->cell_area.x + 1;
6296   y = icon_view->priv->press_start_y - item->cell_area.y + 1;
6297   
6298   path = gtk_tree_path_new_from_indices (item->index, -1);
6299   icon = gtk_icon_view_create_drag_icon (icon_view, path);
6300   gtk_tree_path_free (path);
6301
6302   cairo_surface_set_device_offset (icon, -x, -y);
6303
6304   gtk_drag_set_icon_surface (context, icon);
6305
6306   cairo_surface_destroy (icon);
6307 }
6308
6309 static void 
6310 gtk_icon_view_drag_end (GtkWidget      *widget,
6311                         GdkDragContext *context)
6312 {
6313   /* do nothing */
6314 }
6315
6316 static void 
6317 gtk_icon_view_drag_data_get (GtkWidget        *widget,
6318                              GdkDragContext   *context,
6319                              GtkSelectionData *selection_data,
6320                              guint             info,
6321                              guint             time)
6322 {
6323   GtkIconView *icon_view;
6324   GtkTreeModel *model;
6325   GtkTreePath *source_row;
6326
6327   icon_view = GTK_ICON_VIEW (widget);
6328   model = gtk_icon_view_get_model (icon_view);
6329
6330   if (model == NULL)
6331     return;
6332
6333   if (!icon_view->priv->source_set)
6334     return;
6335
6336   source_row = get_source_row (context);
6337
6338   if (source_row == NULL)
6339     return;
6340
6341   /* We can implement the GTK_TREE_MODEL_ROW target generically for
6342    * any model; for DragSource models there are some other targets
6343    * we also support.
6344    */
6345
6346   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
6347       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
6348                                           source_row,
6349                                           selection_data))
6350     goto done;
6351
6352   /* If drag_data_get does nothing, try providing row data. */
6353   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6354     gtk_tree_set_row_drag_data (selection_data,
6355                                 model,
6356                                 source_row);
6357
6358  done:
6359   gtk_tree_path_free (source_row);
6360 }
6361
6362 static void 
6363 gtk_icon_view_drag_data_delete (GtkWidget      *widget,
6364                                 GdkDragContext *context)
6365 {
6366   GtkTreeModel *model;
6367   GtkIconView *icon_view;
6368   GtkTreePath *source_row;
6369
6370   icon_view = GTK_ICON_VIEW (widget);
6371   model = gtk_icon_view_get_model (icon_view);
6372
6373   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag-data-delete"))
6374     return;
6375
6376   if (!icon_view->priv->source_set)
6377     return;
6378
6379   source_row = get_source_row (context);
6380
6381   if (source_row == NULL)
6382     return;
6383
6384   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
6385                                          source_row);
6386
6387   gtk_tree_path_free (source_row);
6388
6389   set_source_row (context, NULL, NULL);
6390 }
6391
6392 /* Target side drag signals */
6393 static void
6394 gtk_icon_view_drag_leave (GtkWidget      *widget,
6395                           GdkDragContext *context,
6396                           guint           time)
6397 {
6398   GtkIconView *icon_view;
6399
6400   icon_view = GTK_ICON_VIEW (widget);
6401
6402   /* unset any highlight row */
6403   gtk_icon_view_set_drag_dest_item (icon_view,
6404                                     NULL,
6405                                     GTK_ICON_VIEW_DROP_LEFT);
6406
6407   remove_scroll_timeout (icon_view);
6408 }
6409
6410 static gboolean 
6411 gtk_icon_view_drag_motion (GtkWidget      *widget,
6412                            GdkDragContext *context,
6413                            gint            x,
6414                            gint            y,
6415                            guint           time)
6416 {
6417   GtkTreePath *path = NULL;
6418   GtkIconViewDropPosition pos;
6419   GtkIconView *icon_view;
6420   GdkDragAction suggested_action = 0;
6421   GdkAtom target;
6422   gboolean empty;
6423
6424   icon_view = GTK_ICON_VIEW (widget);
6425
6426   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6427     return FALSE;
6428
6429   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6430
6431   /* we only know this *after* set_desination_row */
6432   empty = icon_view->priv->empty_view_drop;
6433
6434   if (path == NULL && !empty)
6435     {
6436       /* Can't drop here. */
6437       gdk_drag_status (context, 0, time);
6438     }
6439   else
6440     {
6441       if (icon_view->priv->scroll_timeout_id == 0)
6442         {
6443           icon_view->priv->scroll_timeout_id =
6444             gdk_threads_add_timeout (50, drag_scroll_timeout, icon_view);
6445         }
6446
6447       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
6448         {
6449           /* Request data so we can use the source row when
6450            * determining whether to accept the drop
6451            */
6452           set_status_pending (context, suggested_action);
6453           gtk_drag_get_data (widget, context, target, time);
6454         }
6455       else
6456         {
6457           set_status_pending (context, 0);
6458           gdk_drag_status (context, suggested_action, time);
6459         }
6460     }
6461
6462   if (path)
6463     gtk_tree_path_free (path);
6464
6465   return TRUE;
6466 }
6467
6468 static gboolean 
6469 gtk_icon_view_drag_drop (GtkWidget      *widget,
6470                          GdkDragContext *context,
6471                          gint            x,
6472                          gint            y,
6473                          guint           time)
6474 {
6475   GtkIconView *icon_view;
6476   GtkTreePath *path;
6477   GdkDragAction suggested_action = 0;
6478   GdkAtom target = GDK_NONE;
6479   GtkTreeModel *model;
6480   gboolean drop_append_mode;
6481
6482   icon_view = GTK_ICON_VIEW (widget);
6483   model = gtk_icon_view_get_model (icon_view);
6484
6485   remove_scroll_timeout (GTK_ICON_VIEW (widget));
6486
6487   if (!icon_view->priv->dest_set)
6488     return FALSE;
6489
6490   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
6491     return FALSE;
6492
6493   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
6494     return FALSE;
6495   
6496   path = get_logical_destination (icon_view, &drop_append_mode);
6497
6498   if (target != GDK_NONE && path != NULL)
6499     {
6500       /* in case a motion had requested drag data, change things so we
6501        * treat drag data receives as a drop.
6502        */
6503       set_status_pending (context, 0);
6504       set_dest_row (context, model, path, 
6505                     icon_view->priv->empty_view_drop, drop_append_mode);
6506     }
6507
6508   if (path)
6509     gtk_tree_path_free (path);
6510
6511   /* Unset this thing */
6512   gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
6513
6514   if (target != GDK_NONE)
6515     {
6516       gtk_drag_get_data (widget, context, target, time);
6517       return TRUE;
6518     }
6519   else
6520     return FALSE;
6521 }
6522
6523 static void
6524 gtk_icon_view_drag_data_received (GtkWidget        *widget,
6525                                   GdkDragContext   *context,
6526                                   gint              x,
6527                                   gint              y,
6528                                   GtkSelectionData *selection_data,
6529                                   guint             info,
6530                                   guint             time)
6531 {
6532   GtkTreePath *path;
6533   gboolean accepted = FALSE;
6534   GtkTreeModel *model;
6535   GtkIconView *icon_view;
6536   GtkTreePath *dest_row;
6537   GdkDragAction suggested_action;
6538   gboolean drop_append_mode;
6539   
6540   icon_view = GTK_ICON_VIEW (widget);  
6541   model = gtk_icon_view_get_model (icon_view);
6542
6543   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
6544     return;
6545
6546   if (!icon_view->priv->dest_set)
6547     return;
6548
6549   suggested_action = get_status_pending (context);
6550
6551   if (suggested_action)
6552     {
6553       /* We are getting this data due to a request in drag_motion,
6554        * rather than due to a request in drag_drop, so we are just
6555        * supposed to call drag_status, not actually paste in the
6556        * data.
6557        */
6558       path = get_logical_destination (icon_view, &drop_append_mode);
6559
6560       if (path == NULL)
6561         suggested_action = 0;
6562
6563       if (suggested_action)
6564         {
6565           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
6566                                                      path,
6567                                                      selection_data))
6568             suggested_action = 0;
6569         }
6570
6571       gdk_drag_status (context, suggested_action, time);
6572
6573       if (path)
6574         gtk_tree_path_free (path);
6575
6576       /* If you can't drop, remove user drop indicator until the next motion */
6577       if (suggested_action == 0)
6578         gtk_icon_view_set_drag_dest_item (icon_view,
6579                                           NULL,
6580                                           GTK_ICON_VIEW_DROP_LEFT);
6581       return;
6582     }
6583   
6584
6585   dest_row = get_dest_row (context);
6586
6587   if (dest_row == NULL)
6588     return;
6589
6590   if (gtk_selection_data_get_length (selection_data) >= 0)
6591     {
6592       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
6593                                                  dest_row,
6594                                                  selection_data))
6595         accepted = TRUE;
6596     }
6597
6598   gtk_drag_finish (context,
6599                    accepted,
6600                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
6601                    time);
6602
6603   gtk_tree_path_free (dest_row);
6604
6605   /* drop dest_row */
6606   set_dest_row (context, NULL, NULL, FALSE, FALSE);
6607 }
6608
6609 /* Drag-and-Drop support */
6610 /**
6611  * gtk_icon_view_enable_model_drag_source:
6612  * @icon_view: a #GtkIconTreeView
6613  * @start_button_mask: Mask of allowed buttons to start drag
6614  * @targets: (array length=n_targets): the table of targets that the drag will
6615  *           support
6616  * @n_targets: the number of items in @targets
6617  * @actions: the bitmask of possible actions for a drag from this
6618  *    widget
6619  *
6620  * Turns @icon_view into a drag source for automatic DND. Calling this
6621  * method sets #GtkIconView:reorderable to %FALSE.
6622  *
6623  * Since: 2.8
6624  **/
6625 void
6626 gtk_icon_view_enable_model_drag_source (GtkIconView              *icon_view,
6627                                         GdkModifierType           start_button_mask,
6628                                         const GtkTargetEntry     *targets,
6629                                         gint                      n_targets,
6630                                         GdkDragAction             actions)
6631 {
6632   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6633
6634   gtk_drag_source_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6635
6636   icon_view->priv->start_button_mask = start_button_mask;
6637   icon_view->priv->source_actions = actions;
6638
6639   icon_view->priv->source_set = TRUE;
6640
6641   unset_reorderable (icon_view);
6642 }
6643
6644 /**
6645  * gtk_icon_view_enable_model_drag_dest:
6646  * @icon_view: a #GtkIconView
6647  * @targets: (array length=n_targets): the table of targets that the drag will
6648  *           support
6649  * @n_targets: the number of items in @targets
6650  * @actions: the bitmask of possible actions for a drag to this
6651  *    widget
6652  *
6653  * Turns @icon_view into a drop destination for automatic DND. Calling this
6654  * method sets #GtkIconView:reorderable to %FALSE.
6655  *
6656  * Since: 2.8
6657  **/
6658 void 
6659 gtk_icon_view_enable_model_drag_dest (GtkIconView          *icon_view,
6660                                       const GtkTargetEntry *targets,
6661                                       gint                  n_targets,
6662                                       GdkDragAction         actions)
6663 {
6664   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6665
6666   gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
6667
6668   icon_view->priv->dest_actions = actions;
6669
6670   icon_view->priv->dest_set = TRUE;
6671
6672   unset_reorderable (icon_view);  
6673 }
6674
6675 /**
6676  * gtk_icon_view_unset_model_drag_source:
6677  * @icon_view: a #GtkIconView
6678  * 
6679  * Undoes the effect of gtk_icon_view_enable_model_drag_source(). Calling this
6680  * method sets #GtkIconView:reorderable to %FALSE.
6681  *
6682  * Since: 2.8
6683  **/
6684 void
6685 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
6686 {
6687   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6688
6689   if (icon_view->priv->source_set)
6690     {
6691       gtk_drag_source_unset (GTK_WIDGET (icon_view));
6692       icon_view->priv->source_set = FALSE;
6693     }
6694
6695   unset_reorderable (icon_view);
6696 }
6697
6698 /**
6699  * gtk_icon_view_unset_model_drag_dest:
6700  * @icon_view: a #GtkIconView
6701  * 
6702  * Undoes the effect of gtk_icon_view_enable_model_drag_dest(). Calling this
6703  * method sets #GtkIconView:reorderable to %FALSE.
6704  *
6705  * Since: 2.8
6706  **/
6707 void
6708 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
6709 {
6710   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6711
6712   if (icon_view->priv->dest_set)
6713     {
6714       gtk_drag_dest_unset (GTK_WIDGET (icon_view));
6715       icon_view->priv->dest_set = FALSE;
6716     }
6717
6718   unset_reorderable (icon_view);
6719 }
6720
6721 /* These are useful to implement your own custom stuff. */
6722 /**
6723  * gtk_icon_view_set_drag_dest_item:
6724  * @icon_view: a #GtkIconView
6725  * @path: (allow-none): The path of the item to highlight, or %NULL.
6726  * @pos: Specifies where to drop, relative to the item
6727  *
6728  * Sets the item that is highlighted for feedback.
6729  *
6730  * Since: 2.8
6731  */
6732 void
6733 gtk_icon_view_set_drag_dest_item (GtkIconView              *icon_view,
6734                                   GtkTreePath              *path,
6735                                   GtkIconViewDropPosition   pos)
6736 {
6737   /* Note; this function is exported to allow a custom DND
6738    * implementation, so it can't touch TreeViewDragInfo
6739    */
6740
6741   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6742
6743   if (icon_view->priv->dest_item)
6744     {
6745       GtkTreePath *current_path;
6746       current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6747       gtk_tree_row_reference_free (icon_view->priv->dest_item);
6748       icon_view->priv->dest_item = NULL;      
6749
6750       gtk_icon_view_queue_draw_path (icon_view, current_path);
6751       gtk_tree_path_free (current_path);
6752     }
6753   
6754   /* special case a drop on an empty model */
6755   icon_view->priv->empty_view_drop = FALSE;
6756   if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
6757       && gtk_tree_path_get_depth (path) == 1
6758       && gtk_tree_path_get_indices (path)[0] == 0)
6759     {
6760       gint n_children;
6761
6762       n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
6763                                                    NULL);
6764
6765       if (n_children == 0)
6766         icon_view->priv->empty_view_drop = TRUE;
6767     }
6768
6769   icon_view->priv->dest_pos = pos;
6770
6771   if (path)
6772     {
6773       icon_view->priv->dest_item =
6774         gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), 
6775                                           icon_view->priv->model, path);
6776       
6777       gtk_icon_view_queue_draw_path (icon_view, path);
6778     }
6779 }
6780
6781 /**
6782  * gtk_icon_view_get_drag_dest_item:
6783  * @icon_view: a #GtkIconView
6784  * @path: (out) (allow-none): Return location for the path of
6785  *        the highlighted item, or %NULL.
6786  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6787  * 
6788  * Gets information about the item that is highlighted for feedback.
6789  *
6790  * Since: 2.8
6791  **/
6792 void
6793 gtk_icon_view_get_drag_dest_item (GtkIconView              *icon_view,
6794                                   GtkTreePath             **path,
6795                                   GtkIconViewDropPosition  *pos)
6796 {
6797   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6798
6799   if (path)
6800     {
6801       if (icon_view->priv->dest_item)
6802         *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
6803       else
6804         *path = NULL;
6805     }
6806
6807   if (pos)
6808     *pos = icon_view->priv->dest_pos;
6809 }
6810
6811 /**
6812  * gtk_icon_view_get_dest_item_at_pos:
6813  * @icon_view: a #GtkIconView
6814  * @drag_x: the position to determine the destination item for
6815  * @drag_y: the position to determine the destination item for
6816  * @path: (out) (allow-none): Return location for the path of the item,
6817  *    or %NULL.
6818  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
6819  * 
6820  * Determines the destination item for a given position.
6821  * 
6822  * Return value: whether there is an item at the given position.
6823  *
6824  * Since: 2.8
6825  **/
6826 gboolean
6827 gtk_icon_view_get_dest_item_at_pos (GtkIconView              *icon_view,
6828                                     gint                      drag_x,
6829                                     gint                      drag_y,
6830                                     GtkTreePath             **path,
6831                                     GtkIconViewDropPosition  *pos)
6832 {
6833   GtkIconViewItem *item;
6834
6835   /* Note; this function is exported to allow a custom DND
6836    * implementation, so it can't touch TreeViewDragInfo
6837    */
6838
6839   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6840   g_return_val_if_fail (drag_x >= 0, FALSE);
6841   g_return_val_if_fail (drag_y >= 0, FALSE);
6842   g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
6843
6844
6845   if (path)
6846     *path = NULL;
6847
6848   item = gtk_icon_view_get_item_at_coords (icon_view, 
6849                                            drag_x + gtk_adjustment_get_value (icon_view->priv->hadjustment), 
6850                                            drag_y + gtk_adjustment_get_value (icon_view->priv->vadjustment),
6851                                            FALSE, NULL);
6852
6853   if (item == NULL)
6854     return FALSE;
6855
6856   if (path)
6857     *path = gtk_tree_path_new_from_indices (item->index, -1);
6858
6859   if (pos)
6860     {
6861       if (drag_x < item->cell_area.x + item->cell_area.width / 4)
6862         *pos = GTK_ICON_VIEW_DROP_LEFT;
6863       else if (drag_x > item->cell_area.x + item->cell_area.width * 3 / 4)
6864         *pos = GTK_ICON_VIEW_DROP_RIGHT;
6865       else if (drag_y < item->cell_area.y + item->cell_area.height / 4)
6866         *pos = GTK_ICON_VIEW_DROP_ABOVE;
6867       else if (drag_y > item->cell_area.y + item->cell_area.height * 3 / 4)
6868         *pos = GTK_ICON_VIEW_DROP_BELOW;
6869       else
6870         *pos = GTK_ICON_VIEW_DROP_INTO;
6871     }
6872
6873   return TRUE;
6874 }
6875
6876 /**
6877  * gtk_icon_view_create_drag_icon:
6878  * @icon_view: a #GtkIconView
6879  * @path: a #GtkTreePath in @icon_view
6880  *
6881  * Creates a #cairo_surface_t representation of the item at @path.  
6882  * This image is used for a drag icon.
6883  *
6884  * Return value: (transfer full): a newly-allocated surface of the drag icon.
6885  * 
6886  * Since: 2.8
6887  **/
6888 cairo_surface_t *
6889 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
6890                                 GtkTreePath *path)
6891 {
6892   GtkWidget *widget;
6893   GtkStyleContext *context;
6894   cairo_t *cr;
6895   cairo_surface_t *surface;
6896   GList *l;
6897   gint index;
6898
6899   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
6900   g_return_val_if_fail (path != NULL, NULL);
6901
6902   widget = GTK_WIDGET (icon_view);
6903   context = gtk_widget_get_style_context (widget);
6904
6905   if (!gtk_widget_get_realized (widget))
6906     return NULL;
6907
6908   index = gtk_tree_path_get_indices (path)[0];
6909
6910   for (l = icon_view->priv->items; l; l = l->next) 
6911     {
6912       GtkIconViewItem *item = l->data;
6913       
6914       if (index == item->index)
6915         {
6916           GdkRectangle rect = { 
6917             item->cell_area.x - icon_view->priv->item_padding, 
6918             item->cell_area.y - icon_view->priv->item_padding, 
6919             item->cell_area.width  + icon_view->priv->item_padding * 2, 
6920             item->cell_area.height + icon_view->priv->item_padding * 2 
6921           };
6922
6923           surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
6924                                                        CAIRO_CONTENT_COLOR,
6925                                                        rect.width + 2,
6926                                                        rect.height + 2);
6927
6928           cr = cairo_create (surface);
6929           cairo_set_line_width (cr, 1.);
6930
6931           gtk_render_background (context, cr, 0, 0,
6932                                  rect.width + 2, rect.height + 2);
6933
6934           cairo_save (cr);
6935
6936           cairo_rectangle (cr, 1, 1, rect.width, rect.height);
6937           cairo_clip (cr);
6938
6939           gtk_icon_view_paint_item (icon_view, cr, item, 
6940                                     icon_view->priv->item_padding + 1, 
6941                                     icon_view->priv->item_padding + 1, FALSE);
6942
6943           cairo_restore (cr);
6944
6945           cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
6946           cairo_rectangle (cr, 0.5, 0.5, rect.width + 1, rect.height + 1);
6947           cairo_stroke (cr);
6948
6949           cairo_destroy (cr);
6950
6951           return surface;
6952         }
6953     }
6954   
6955   return NULL;
6956 }
6957
6958 /**
6959  * gtk_icon_view_get_reorderable:
6960  * @icon_view: a #GtkIconView
6961  *
6962  * Retrieves whether the user can reorder the list via drag-and-drop. 
6963  * See gtk_icon_view_set_reorderable().
6964  *
6965  * Return value: %TRUE if the list can be reordered.
6966  *
6967  * Since: 2.8
6968  **/
6969 gboolean
6970 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
6971 {
6972   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6973
6974   return icon_view->priv->reorderable;
6975 }
6976
6977 static const GtkTargetEntry item_targets[] = {
6978   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
6979 };
6980
6981
6982 /**
6983  * gtk_icon_view_set_reorderable:
6984  * @icon_view: A #GtkIconView.
6985  * @reorderable: %TRUE, if the list of items can be reordered.
6986  *
6987  * This function is a convenience function to allow you to reorder models that
6988  * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface.  Both
6989  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
6990  * the user can reorder the model by dragging and dropping rows.  The
6991  * developer can listen to these changes by connecting to the model's
6992  * row_inserted and row_deleted signals. The reordering is implemented by setting up
6993  * the icon view as a drag source and destination. Therefore, drag and
6994  * drop can not be used in a reorderable view for any other purpose.
6995  *
6996  * This function does not give you any degree of control over the order -- any
6997  * reordering is allowed.  If more control is needed, you should probably
6998  * handle drag and drop manually.
6999  *
7000  * Since: 2.8
7001  **/
7002 void
7003 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
7004                                gboolean     reorderable)
7005 {
7006   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7007
7008   reorderable = reorderable != FALSE;
7009
7010   if (icon_view->priv->reorderable == reorderable)
7011     return;
7012
7013   if (reorderable)
7014     {
7015       gtk_icon_view_enable_model_drag_source (icon_view,
7016                                               GDK_BUTTON1_MASK,
7017                                               item_targets,
7018                                               G_N_ELEMENTS (item_targets),
7019                                               GDK_ACTION_MOVE);
7020       gtk_icon_view_enable_model_drag_dest (icon_view,
7021                                             item_targets,
7022                                             G_N_ELEMENTS (item_targets),
7023                                             GDK_ACTION_MOVE);
7024     }
7025   else
7026     {
7027       gtk_icon_view_unset_model_drag_source (icon_view);
7028       gtk_icon_view_unset_model_drag_dest (icon_view);
7029     }
7030
7031   icon_view->priv->reorderable = reorderable;
7032
7033   g_object_notify (G_OBJECT (icon_view), "reorderable");
7034 }
7035
7036
7037 /* Accessibility Support */
7038
7039 static gpointer accessible_parent_class;
7040 static gpointer accessible_item_parent_class;
7041 static GQuark accessible_private_data_quark = 0;
7042
7043 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (gtk_icon_view_item_accessible_get_type ())
7044 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
7045 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
7046
7047 static GType gtk_icon_view_item_accessible_get_type (void);
7048
7049 enum {
7050     ACTION_ACTIVATE,
7051     LAST_ACTION
7052 };
7053
7054 typedef struct
7055 {
7056   AtkObject parent;
7057
7058   GtkIconViewItem *item;
7059
7060   GtkWidget *widget;
7061
7062   AtkStateSet *state_set;
7063
7064   gchar *text;
7065
7066   GtkTextBuffer *text_buffer;
7067
7068   gchar *action_descriptions[LAST_ACTION];
7069   gchar *image_description;
7070   guint action_idle_handler;
7071 } GtkIconViewItemAccessible;
7072
7073 static const gchar *const gtk_icon_view_item_accessible_action_names[] = 
7074 {
7075   "activate",
7076   NULL
7077 };
7078
7079 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
7080 {
7081   "Activate item",
7082   NULL
7083 };
7084 typedef struct _GtkIconViewItemAccessibleClass
7085 {
7086   AtkObjectClass parent_class;
7087
7088 } GtkIconViewItemAccessibleClass;
7089
7090 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
7091
7092 static gboolean
7093 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
7094 {
7095   GtkIconViewItemAccessible *item;
7096   GtkIconView *icon_view;
7097   GtkTreePath *path;
7098
7099   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
7100   item->action_idle_handler = 0;
7101
7102   if (item->widget != NULL)
7103     {
7104       icon_view = GTK_ICON_VIEW (item->widget);
7105       path = gtk_tree_path_new_from_indices (item->item->index, -1);
7106       gtk_icon_view_item_activated (icon_view, path);
7107       gtk_tree_path_free (path);
7108     }
7109
7110   return FALSE;
7111 }
7112
7113 static gboolean
7114 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
7115                                                 gint       i)
7116 {
7117   GtkIconViewItemAccessible *item;
7118
7119   if (i < 0 || i >= LAST_ACTION) 
7120     return FALSE;
7121
7122   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7123
7124   if (!GTK_IS_ICON_VIEW (item->widget))
7125     return FALSE;
7126
7127   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7128     return FALSE;
7129
7130   switch (i)
7131     {
7132     case ACTION_ACTIVATE:
7133       if (!item->action_idle_handler)
7134         item->action_idle_handler = gdk_threads_add_idle (gtk_icon_view_item_accessible_idle_do_action, item);
7135       break;
7136     default:
7137       g_assert_not_reached ();
7138       return FALSE;
7139
7140     }        
7141   return TRUE;
7142 }
7143
7144 static gint
7145 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
7146 {
7147         return LAST_ACTION;
7148 }
7149
7150 static const gchar *
7151 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
7152                                                       gint       i)
7153 {
7154   GtkIconViewItemAccessible *item;
7155
7156   if (i < 0 || i >= LAST_ACTION) 
7157     return NULL;
7158
7159   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7160
7161   if (item->action_descriptions[i])
7162     return item->action_descriptions[i];
7163   else
7164     return gtk_icon_view_item_accessible_action_descriptions[i];
7165 }
7166
7167 static const gchar *
7168 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
7169                                                gint       i)
7170 {
7171   if (i < 0 || i >= LAST_ACTION) 
7172     return NULL;
7173
7174   return gtk_icon_view_item_accessible_action_names[i];
7175 }
7176
7177 static gboolean
7178 gtk_icon_view_item_accessible_action_set_description (AtkAction   *action,
7179                                                       gint         i,
7180                                                       const gchar *description)
7181 {
7182   GtkIconViewItemAccessible *item;
7183
7184   if (i < 0 || i >= LAST_ACTION) 
7185     return FALSE;
7186
7187   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7188
7189   g_free (item->action_descriptions[i]);
7190
7191   item->action_descriptions[i] = g_strdup (description);
7192
7193   return TRUE;
7194 }
7195
7196 static void
7197 atk_action_item_interface_init (AtkActionIface *iface)
7198 {
7199   iface->do_action = gtk_icon_view_item_accessible_action_do_action;
7200   iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
7201   iface->get_description = gtk_icon_view_item_accessible_action_get_description;
7202   iface->get_name = gtk_icon_view_item_accessible_action_get_name;
7203   iface->set_description = gtk_icon_view_item_accessible_action_set_description;
7204 }
7205
7206 static const gchar *
7207 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
7208 {
7209   GtkIconViewItemAccessible *item;
7210
7211   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7212
7213   return item->image_description;
7214 }
7215
7216 static gboolean
7217 gtk_icon_view_item_accessible_image_set_image_description (AtkImage    *image,
7218                                                            const gchar *description)
7219 {
7220   GtkIconViewItemAccessible *item;
7221
7222   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7223
7224   g_free (item->image_description);
7225   item->image_description = g_strdup (description);
7226
7227   return TRUE;
7228 }
7229
7230 typedef struct {
7231   GdkRectangle box;
7232   gboolean     pixbuf_found;
7233 } GetPixbufBoxData;
7234
7235 static gboolean 
7236 get_pixbuf_foreach (GtkCellRenderer    *renderer,
7237                     const GdkRectangle *cell_area,
7238                     const GdkRectangle *cell_background,
7239                     GetPixbufBoxData   *data)
7240 {
7241   if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
7242     {
7243       data->box = *cell_area;
7244       data->pixbuf_found = TRUE;
7245     }
7246   return (data->pixbuf_found != FALSE);
7247 }
7248
7249 static gboolean
7250 get_pixbuf_box (GtkIconView     *icon_view,
7251                 GtkIconViewItem *item,
7252                 GdkRectangle    *box)
7253 {
7254   GetPixbufBoxData data = { { 0, }, FALSE };
7255   GtkCellAreaContext *context;
7256
7257   context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
7258
7259   gtk_icon_view_set_cell_data (icon_view, item);
7260   gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
7261                                GTK_WIDGET (icon_view),
7262                                (GdkRectangle *)item, (GdkRectangle *)item,
7263                                (GtkCellAllocCallback)get_pixbuf_foreach, &data);
7264
7265   return data.pixbuf_found;
7266 }
7267
7268 static gboolean 
7269 get_text_foreach (GtkCellRenderer    *renderer,
7270                   gchar             **text)
7271 {
7272   if (GTK_IS_CELL_RENDERER_TEXT (renderer))
7273     {
7274       g_object_get (renderer, "text", text, NULL);
7275
7276       return TRUE;
7277     }
7278   return FALSE;
7279 }
7280
7281 static gchar *
7282 get_text (GtkIconView     *icon_view,
7283           GtkIconViewItem *item)
7284 {
7285   gchar *text = NULL;
7286
7287   gtk_icon_view_set_cell_data (icon_view, item);
7288   gtk_cell_area_foreach (icon_view->priv->cell_area,
7289                          (GtkCellCallback)get_text_foreach, &text);
7290
7291   return text;
7292 }
7293
7294 static void
7295 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
7296                                                     gint     *width,
7297                                                     gint     *height)
7298 {
7299   GtkIconViewItemAccessible *item;
7300   GdkRectangle box;
7301
7302   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7303
7304   if (!GTK_IS_ICON_VIEW (item->widget))
7305     return;
7306
7307   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7308     return;
7309
7310   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7311     {
7312       *width = box.width;
7313       *height = box.height;  
7314     }
7315 }
7316
7317 static void
7318 gtk_icon_view_item_accessible_image_get_image_position (AtkImage    *image,
7319                                                         gint        *x,
7320                                                         gint        *y,
7321                                                         AtkCoordType coord_type)
7322 {
7323   GtkIconViewItemAccessible *item;
7324   GdkRectangle box;
7325
7326   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7327
7328   if (!GTK_IS_ICON_VIEW (item->widget))
7329     return;
7330
7331   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7332     return;
7333
7334   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7335
7336   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7337     {
7338       *x+= box.x - item->item->cell_area.x;
7339       *y+= box.y - item->item->cell_area.y;
7340     }
7341
7342 }
7343
7344 static void
7345 atk_image_item_interface_init (AtkImageIface *iface)
7346 {
7347   iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
7348   iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
7349   iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
7350   iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
7351 }
7352
7353 static gchar *
7354 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
7355                                              gint     start_pos,
7356                                              gint     end_pos)
7357 {
7358   GtkIconViewItemAccessible *item;
7359   GtkTextIter start, end;
7360   GtkTextBuffer *buffer;
7361
7362   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7363
7364   if (!GTK_IS_ICON_VIEW (item->widget))
7365     return NULL;
7366
7367   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7368     return NULL;
7369
7370   buffer = item->text_buffer;
7371   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
7372   if (end_pos < 0)
7373     gtk_text_buffer_get_end_iter (buffer, &end);
7374   else
7375     gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
7376
7377   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7378 }
7379
7380 static gunichar
7381 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
7382                                                             gint     offset)
7383 {
7384   GtkIconViewItemAccessible *item;
7385   GtkTextIter start, end;
7386   GtkTextBuffer *buffer;
7387   gchar *string;
7388   gunichar unichar;
7389
7390   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7391
7392   if (!GTK_IS_ICON_VIEW (item->widget))
7393     return '\0';
7394
7395   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7396     return '\0';
7397
7398   buffer = item->text_buffer;
7399   if (offset >= gtk_text_buffer_get_char_count (buffer))
7400     return '\0';
7401
7402   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7403   end = start;
7404   gtk_text_iter_forward_char (&end);
7405   string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
7406   unichar = g_utf8_get_char (string);
7407   g_free(string);
7408
7409   return unichar;
7410 }
7411
7412 #if 0
7413 static void
7414 get_pango_text_offsets (PangoLayout     *layout,
7415                         GtkTextBuffer   *buffer,
7416                         gint             function,
7417                         AtkTextBoundary  boundary_type,
7418                         gint             offset,
7419                         gint            *start_offset,
7420                         gint            *end_offset,
7421                         GtkTextIter     *start_iter,
7422                         GtkTextIter     *end_iter)
7423 {
7424   PangoLayoutIter *iter;
7425   PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
7426   gint index, start_index, end_index;
7427   const gchar *text;
7428   gboolean found = FALSE;
7429
7430   text = pango_layout_get_text (layout);
7431   index = g_utf8_offset_to_pointer (text, offset) - text;
7432   iter = pango_layout_get_iter (layout);
7433   do
7434     {
7435       line = pango_layout_iter_get_line_readonly (iter);
7436       start_index = line->start_index;
7437       end_index = start_index + line->length;
7438
7439       if (index >= start_index && index <= end_index)
7440         {
7441           /*
7442            * Found line for offset
7443            */
7444           switch (function)
7445             {
7446             case 0:
7447                   /*
7448                    * We want the previous line
7449                    */
7450               if (prev_line)
7451                 {
7452                   switch (boundary_type)
7453                     {
7454                     case ATK_TEXT_BOUNDARY_LINE_START:
7455                       end_index = start_index;
7456                       start_index = prev_line->start_index;
7457                       break;
7458                     case ATK_TEXT_BOUNDARY_LINE_END:
7459                       if (prev_prev_line)
7460                         start_index = prev_prev_line->start_index + 
7461                                   prev_prev_line->length;
7462                       end_index = prev_line->start_index + prev_line->length;
7463                       break;
7464                     default:
7465                       g_assert_not_reached();
7466                     }
7467                 }
7468               else
7469                 start_index = end_index = 0;
7470               break;
7471             case 1:
7472               switch (boundary_type)
7473                 {
7474                 case ATK_TEXT_BOUNDARY_LINE_START:
7475                   if (pango_layout_iter_next_line (iter))
7476                     end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7477                   break;
7478                 case ATK_TEXT_BOUNDARY_LINE_END:
7479                   if (prev_line)
7480                     start_index = prev_line->start_index + 
7481                                   prev_line->length;
7482                   break;
7483                 default:
7484                   g_assert_not_reached();
7485                 }
7486               break;
7487             case 2:
7488                /*
7489                 * We want the next line
7490                 */
7491               if (pango_layout_iter_next_line (iter))
7492                 {
7493                   line = pango_layout_iter_get_line_readonly (iter);
7494                   switch (boundary_type)
7495                     {
7496                     case ATK_TEXT_BOUNDARY_LINE_START:
7497                       start_index = line->start_index;
7498                       if (pango_layout_iter_next_line (iter))
7499                         end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
7500                       else
7501                         end_index = start_index + line->length;
7502                       break;
7503                     case ATK_TEXT_BOUNDARY_LINE_END:
7504                       start_index = end_index;
7505                       end_index = line->start_index + line->length;
7506                       break;
7507                     default:
7508                       g_assert_not_reached();
7509                     }
7510                 }
7511               else
7512                 start_index = end_index;
7513               break;
7514             }
7515           found = TRUE;
7516           break;
7517         }
7518       prev_prev_line = prev_line; 
7519       prev_line = line; 
7520     }
7521   while (pango_layout_iter_next_line (iter));
7522
7523   if (!found)
7524     {
7525       start_index = prev_line->start_index + prev_line->length;
7526       end_index = start_index;
7527     }
7528   pango_layout_iter_free (iter);
7529   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
7530   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
7531  
7532   gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
7533   gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
7534 }
7535 #endif
7536
7537 static gchar*
7538 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText         *text,
7539                                                            gint            offset,
7540                                                            AtkTextBoundary boundary_type,
7541                                                            gint            *start_offset,
7542                                                            gint            *end_offset)
7543 {
7544   GtkIconViewItemAccessible *item;
7545   GtkTextIter start, end;
7546   GtkTextBuffer *buffer;
7547 #if 0
7548   GtkIconView *icon_view;
7549 #endif
7550
7551   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7552
7553   if (!GTK_IS_ICON_VIEW (item->widget))
7554     return NULL;
7555
7556   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7557     return NULL;
7558
7559   buffer = item->text_buffer;
7560
7561   if (!gtk_text_buffer_get_char_count (buffer))
7562     {
7563       *start_offset = 0;
7564       *end_offset = 0;
7565       return g_strdup ("");
7566     }
7567   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7568    
7569   end = start;
7570
7571   switch (boundary_type)
7572     {
7573     case ATK_TEXT_BOUNDARY_CHAR:
7574       gtk_text_iter_backward_char(&start);
7575       break;
7576     case ATK_TEXT_BOUNDARY_WORD_START:
7577       if (!gtk_text_iter_starts_word (&start))
7578         gtk_text_iter_backward_word_start (&start);
7579       end = start;
7580       gtk_text_iter_backward_word_start(&start);
7581       break;
7582     case ATK_TEXT_BOUNDARY_WORD_END:
7583       if (gtk_text_iter_inside_word (&start) &&
7584           !gtk_text_iter_starts_word (&start))
7585         gtk_text_iter_backward_word_start (&start);
7586       while (!gtk_text_iter_ends_word (&start))
7587         {
7588           if (!gtk_text_iter_backward_char (&start))
7589             break;
7590         }
7591       end = start;
7592       gtk_text_iter_backward_word_start(&start);
7593       while (!gtk_text_iter_ends_word (&start))
7594         {
7595           if (!gtk_text_iter_backward_char (&start))
7596             break;
7597         }
7598       break;
7599     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7600       if (!gtk_text_iter_starts_sentence (&start))
7601         gtk_text_iter_backward_sentence_start (&start);
7602       end = start;
7603       gtk_text_iter_backward_sentence_start (&start);
7604       break;
7605     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7606       if (gtk_text_iter_inside_sentence (&start) &&
7607           !gtk_text_iter_starts_sentence (&start))
7608         gtk_text_iter_backward_sentence_start (&start);
7609       while (!gtk_text_iter_ends_sentence (&start))
7610         {
7611           if (!gtk_text_iter_backward_char (&start))
7612             break;
7613         }
7614       end = start;
7615       gtk_text_iter_backward_sentence_start (&start);
7616       while (!gtk_text_iter_ends_sentence (&start))
7617         {
7618           if (!gtk_text_iter_backward_char (&start))
7619             break;
7620         }
7621       break;
7622    case ATK_TEXT_BOUNDARY_LINE_START:
7623    case ATK_TEXT_BOUNDARY_LINE_END:
7624 #if 0
7625       icon_view = GTK_ICON_VIEW (item->widget);
7626       /* FIXME we probably have to use GailTextCell to salvage this */
7627       gtk_icon_view_update_item_text (icon_view, item->item);
7628       get_pango_text_offsets (icon_view->priv->layout,
7629                               buffer,
7630                               0,
7631                               boundary_type,
7632                               offset,
7633                               start_offset,
7634                               end_offset,
7635                               &start,
7636                               &end);
7637 #endif
7638       break;
7639     }
7640
7641   *start_offset = gtk_text_iter_get_offset (&start);
7642   *end_offset = gtk_text_iter_get_offset (&end);
7643
7644   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7645 }
7646
7647 static gchar*
7648 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText         *text,
7649                                                        gint            offset,
7650                                                        AtkTextBoundary boundary_type,
7651                                                        gint            *start_offset,
7652                                                        gint            *end_offset)
7653 {
7654   GtkIconViewItemAccessible *item;
7655   GtkTextIter start, end;
7656   GtkTextBuffer *buffer;
7657 #if 0
7658   GtkIconView *icon_view;
7659 #endif
7660
7661   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7662
7663   if (!GTK_IS_ICON_VIEW (item->widget))
7664     return NULL;
7665
7666   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7667     return NULL;
7668
7669   buffer = item->text_buffer;
7670
7671   if (!gtk_text_buffer_get_char_count (buffer))
7672     {
7673       *start_offset = 0;
7674       *end_offset = 0;
7675       return g_strdup ("");
7676     }
7677   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7678    
7679   end = start;
7680
7681   switch (boundary_type)
7682     {
7683     case ATK_TEXT_BOUNDARY_CHAR:
7684       gtk_text_iter_forward_char (&end);
7685       break;
7686     case ATK_TEXT_BOUNDARY_WORD_START:
7687       if (!gtk_text_iter_starts_word (&start))
7688         gtk_text_iter_backward_word_start (&start);
7689       if (gtk_text_iter_inside_word (&end))
7690         gtk_text_iter_forward_word_end (&end);
7691       while (!gtk_text_iter_starts_word (&end))
7692         {
7693           if (!gtk_text_iter_forward_char (&end))
7694             break;
7695         }
7696       break;
7697     case ATK_TEXT_BOUNDARY_WORD_END:
7698       if (gtk_text_iter_inside_word (&start) &&
7699           !gtk_text_iter_starts_word (&start))
7700         gtk_text_iter_backward_word_start (&start);
7701       while (!gtk_text_iter_ends_word (&start))
7702         {
7703           if (!gtk_text_iter_backward_char (&start))
7704             break;
7705         }
7706       gtk_text_iter_forward_word_end (&end);
7707       break;
7708     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7709       if (!gtk_text_iter_starts_sentence (&start))
7710         gtk_text_iter_backward_sentence_start (&start);
7711       if (gtk_text_iter_inside_sentence (&end))
7712         gtk_text_iter_forward_sentence_end (&end);
7713       while (!gtk_text_iter_starts_sentence (&end))
7714         {
7715           if (!gtk_text_iter_forward_char (&end))
7716             break;
7717         }
7718       break;
7719     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7720       if (gtk_text_iter_inside_sentence (&start) &&
7721           !gtk_text_iter_starts_sentence (&start))
7722         gtk_text_iter_backward_sentence_start (&start);
7723       while (!gtk_text_iter_ends_sentence (&start))
7724         {
7725           if (!gtk_text_iter_backward_char (&start))
7726             break;
7727         }
7728       gtk_text_iter_forward_sentence_end (&end);
7729       break;
7730    case ATK_TEXT_BOUNDARY_LINE_START:
7731    case ATK_TEXT_BOUNDARY_LINE_END:
7732 #if 0
7733       icon_view = GTK_ICON_VIEW (item->widget);
7734       /* FIXME we probably have to use GailTextCell to salvage this */
7735       gtk_icon_view_update_item_text (icon_view, item->item);
7736       get_pango_text_offsets (icon_view->priv->layout,
7737                               buffer,
7738                               1,
7739                               boundary_type,
7740                               offset,
7741                               start_offset,
7742                               end_offset,
7743                               &start,
7744                               &end);
7745 #endif
7746       break;
7747     }
7748
7749
7750   *start_offset = gtk_text_iter_get_offset (&start);
7751   *end_offset = gtk_text_iter_get_offset (&end);
7752
7753   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7754 }
7755
7756 static gchar*
7757 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText         *text,
7758                                                           gint            offset,
7759                                                           AtkTextBoundary boundary_type,
7760                                                           gint            *start_offset,
7761                                                           gint            *end_offset)
7762 {
7763   GtkIconViewItemAccessible *item;
7764   GtkTextIter start, end;
7765   GtkTextBuffer *buffer;
7766 #if 0
7767   GtkIconView *icon_view;
7768 #endif
7769
7770   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7771
7772   if (!GTK_IS_ICON_VIEW (item->widget))
7773     return NULL;
7774
7775   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7776     return NULL;
7777
7778   buffer = item->text_buffer;
7779
7780   if (!gtk_text_buffer_get_char_count (buffer))
7781     {
7782       *start_offset = 0;
7783       *end_offset = 0;
7784       return g_strdup ("");
7785     }
7786   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
7787    
7788   end = start;
7789
7790   switch (boundary_type)
7791     {
7792     case ATK_TEXT_BOUNDARY_CHAR:
7793       gtk_text_iter_forward_char(&start);
7794       gtk_text_iter_forward_chars(&end, 2);
7795       break;
7796     case ATK_TEXT_BOUNDARY_WORD_START:
7797       if (gtk_text_iter_inside_word (&end))
7798         gtk_text_iter_forward_word_end (&end);
7799       while (!gtk_text_iter_starts_word (&end))
7800         {
7801           if (!gtk_text_iter_forward_char (&end))
7802             break;
7803         }
7804       start = end;
7805       if (!gtk_text_iter_is_end (&end))
7806         {
7807           gtk_text_iter_forward_word_end (&end);
7808           while (!gtk_text_iter_starts_word (&end))
7809             {
7810               if (!gtk_text_iter_forward_char (&end))
7811                 break;
7812             }
7813         }
7814       break;
7815     case ATK_TEXT_BOUNDARY_WORD_END:
7816       gtk_text_iter_forward_word_end (&end);
7817       start = end;
7818       if (!gtk_text_iter_is_end (&end))
7819         gtk_text_iter_forward_word_end (&end);
7820       break;
7821     case ATK_TEXT_BOUNDARY_SENTENCE_START:
7822       if (gtk_text_iter_inside_sentence (&end))
7823         gtk_text_iter_forward_sentence_end (&end);
7824       while (!gtk_text_iter_starts_sentence (&end))
7825         {
7826           if (!gtk_text_iter_forward_char (&end))
7827             break;
7828         }
7829       start = end;
7830       if (!gtk_text_iter_is_end (&end))
7831         {
7832           gtk_text_iter_forward_sentence_end (&end);
7833           while (!gtk_text_iter_starts_sentence (&end))
7834             {
7835               if (!gtk_text_iter_forward_char (&end))
7836                 break;
7837             }
7838         }
7839       break;
7840     case ATK_TEXT_BOUNDARY_SENTENCE_END:
7841       gtk_text_iter_forward_sentence_end (&end);
7842       start = end;
7843       if (!gtk_text_iter_is_end (&end))
7844         gtk_text_iter_forward_sentence_end (&end);
7845       break;
7846    case ATK_TEXT_BOUNDARY_LINE_START:
7847    case ATK_TEXT_BOUNDARY_LINE_END:
7848 #if 0
7849       icon_view = GTK_ICON_VIEW (item->widget);
7850       /* FIXME we probably have to use GailTextCell to salvage this */
7851       gtk_icon_view_update_item_text (icon_view, item->item);
7852       get_pango_text_offsets (icon_view->priv->layout,
7853                               buffer,
7854                               2,
7855                               boundary_type,
7856                               offset,
7857                               start_offset,
7858                               end_offset,
7859                               &start,
7860                               &end);
7861 #endif
7862       break;
7863     }
7864   *start_offset = gtk_text_iter_get_offset (&start);
7865   *end_offset = gtk_text_iter_get_offset (&end);
7866
7867   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
7868 }
7869
7870 static gint
7871 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
7872 {
7873   GtkIconViewItemAccessible *item;
7874
7875   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7876
7877   if (!GTK_IS_ICON_VIEW (item->widget))
7878     return 0;
7879
7880   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7881     return 0;
7882
7883   return gtk_text_buffer_get_char_count (item->text_buffer);
7884 }
7885
7886 static void
7887 gtk_icon_view_item_accessible_text_get_character_extents (AtkText      *text,
7888                                                           gint         offset,
7889                                                           gint         *x,
7890                                                           gint         *y,
7891                                                           gint         *width,
7892                                                           gint         *height,
7893                                                           AtkCoordType coord_type)
7894 {
7895   GtkIconViewItemAccessible *item;
7896 #if 0
7897   GtkIconView *icon_view;
7898   PangoRectangle char_rect;
7899   const gchar *item_text;
7900   gint index;
7901 #endif
7902
7903   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7904
7905   if (!GTK_IS_ICON_VIEW (item->widget))
7906     return;
7907
7908   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7909     return;
7910
7911 #if 0
7912   icon_view = GTK_ICON_VIEW (item->widget);
7913       /* FIXME we probably have to use GailTextCell to salvage this */
7914   gtk_icon_view_update_item_text (icon_view, item->item);
7915   item_text = pango_layout_get_text (icon_view->priv->layout);
7916   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
7917   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
7918
7919   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
7920   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
7921   /* Look at gtk_icon_view_paint_item() to see where the text is. */
7922   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7923   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
7924   *width = char_rect.width / PANGO_SCALE;
7925   *height = char_rect.height / PANGO_SCALE;
7926 #endif
7927 }
7928
7929 static gint
7930 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText      *text,
7931                                                         gint          x,
7932                                                         gint          y,
7933                                                         AtkCoordType coord_type)
7934 {
7935   GtkIconViewItemAccessible *item;
7936   gint offset = 0;
7937 #if 0
7938   GtkIconView *icon_view;
7939   const gchar *item_text;
7940   gint index;
7941   gint l_x, l_y;
7942 #endif
7943
7944   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
7945
7946   if (!GTK_IS_ICON_VIEW (item->widget))
7947     return -1;
7948
7949   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7950     return -1;
7951
7952 #if 0
7953   icon_view = GTK_ICON_VIEW (item->widget);
7954       /* FIXME we probably have to use GailTextCell to salvage this */
7955   gtk_icon_view_update_item_text (icon_view, item->item);
7956   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
7957   x -= l_x + item->item->layout_x - item->item->x;
7958   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
7959   y -= l_y + item->item->layout_y - item->item->y;
7960   item_text = pango_layout_get_text (icon_view->priv->layout);
7961   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
7962                                 x * PANGO_SCALE,
7963                                 y * PANGO_SCALE,
7964                                 &index, NULL))
7965     {
7966       if (x < 0 || y < 0)
7967         index = 0;
7968       else
7969         index = -1;
7970     } 
7971   if (index == -1)
7972     offset = g_utf8_strlen (item_text, -1);
7973   else
7974     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
7975 #endif
7976   return offset;
7977 }
7978
7979 static void
7980 atk_text_item_interface_init (AtkTextIface *iface)
7981 {
7982   iface->get_text = gtk_icon_view_item_accessible_text_get_text;
7983   iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
7984   iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
7985   iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
7986   iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
7987   iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
7988   iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
7989   iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
7990 }
7991
7992 static void
7993 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
7994                                            gint         *x,
7995                                            gint         *y,
7996                                            gint         *width,
7997                                            gint         *height,
7998                                            AtkCoordType  coord_type)
7999 {
8000   GtkIconViewItemAccessible *item;
8001   AtkObject *parent_obj;
8002   gint l_x, l_y;
8003
8004   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
8005
8006   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8007   if (!GTK_IS_WIDGET (item->widget))
8008     return;
8009
8010   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8011     return;
8012
8013   *width = item->item->cell_area.width;
8014   *height = item->item->cell_area.height;
8015   if (gtk_icon_view_item_accessible_is_showing (item))
8016     {
8017       parent_obj = gtk_widget_get_accessible (item->widget);
8018       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
8019       *x = l_x + item->item->cell_area.x;
8020       *y = l_y + item->item->cell_area.y;
8021     }
8022   else
8023     {
8024       *x = G_MININT;
8025       *y = G_MININT;
8026     }
8027 }
8028
8029 static gboolean
8030 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
8031 {
8032   GtkIconViewItemAccessible *item;
8033   GtkWidget *toplevel;
8034
8035   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
8036
8037   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8038   if (!GTK_IS_WIDGET (item->widget))
8039     return FALSE;
8040
8041   gtk_widget_grab_focus (item->widget);
8042   gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
8043   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
8044   if (gtk_widget_is_toplevel (toplevel))
8045     gtk_window_present (GTK_WINDOW (toplevel));
8046
8047   return TRUE;
8048 }
8049
8050 static void
8051 atk_component_item_interface_init (AtkComponentIface *iface)
8052 {
8053   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
8054   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
8055 }
8056
8057 static gboolean
8058 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
8059                                          AtkStateType               state_type,
8060                                          gboolean                   emit_signal)
8061 {
8062   gboolean rc;
8063
8064   rc = atk_state_set_add_state (item->state_set, state_type);
8065   /*
8066    * The signal should only be generated if the value changed,
8067    * not when the item is set up.  So states that are set
8068    * initially should pass FALSE as the emit_signal argument.
8069    */
8070
8071   if (emit_signal)
8072     {
8073       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
8074       /* If state_type is ATK_STATE_VISIBLE, additional notification */
8075       if (state_type == ATK_STATE_VISIBLE)
8076         g_signal_emit_by_name (item, "visible-data-changed");
8077     }
8078
8079   return rc;
8080 }
8081
8082 static gboolean
8083 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
8084                                             AtkStateType               state_type,
8085                                             gboolean                   emit_signal)
8086 {
8087   if (atk_state_set_contains_state (item->state_set, state_type))
8088     {
8089       gboolean rc;
8090
8091       rc = atk_state_set_remove_state (item->state_set, state_type);
8092       /*
8093        * The signal should only be generated if the value changed,
8094        * not when the item is set up.  So states that are set
8095        * initially should pass FALSE as the emit_signal argument.
8096        */
8097
8098       if (emit_signal)
8099         {
8100           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
8101           /* If state_type is ATK_STATE_VISIBLE, additional notification */
8102           if (state_type == ATK_STATE_VISIBLE)
8103             g_signal_emit_by_name (item, "visible-data-changed");
8104         }
8105
8106       return rc;
8107     }
8108   else
8109     return FALSE;
8110 }
8111
8112 static gboolean
8113 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
8114 {
8115   GtkAllocation allocation;
8116   GtkIconView *icon_view;
8117   GdkRectangle visible_rect;
8118   gboolean is_showing;
8119
8120   /*
8121    * An item is considered "SHOWING" if any part of the item is in the
8122    * visible rectangle.
8123    */
8124
8125   if (!GTK_IS_ICON_VIEW (item->widget))
8126     return FALSE;
8127
8128   if (item->item == NULL)
8129     return FALSE;
8130
8131   gtk_widget_get_allocation (item->widget, &allocation);
8132
8133   icon_view = GTK_ICON_VIEW (item->widget);
8134   visible_rect.x = 0;
8135   if (icon_view->priv->hadjustment)
8136     visible_rect.x += gtk_adjustment_get_value (icon_view->priv->hadjustment);
8137   visible_rect.y = 0;
8138   if (icon_view->priv->hadjustment)
8139     visible_rect.y += gtk_adjustment_get_value (icon_view->priv->vadjustment);
8140   visible_rect.width = allocation.width;
8141   visible_rect.height = allocation.height;
8142
8143   if (((item->item->cell_area.x + item->item->cell_area.width) < visible_rect.x) ||
8144      ((item->item->cell_area.y + item->item->cell_area.height) < (visible_rect.y)) ||
8145      (item->item->cell_area.x > (visible_rect.x + visible_rect.width)) ||
8146      (item->item->cell_area.y > (visible_rect.y + visible_rect.height)))
8147     is_showing =  FALSE;
8148   else
8149     is_showing = TRUE;
8150
8151   return is_showing;
8152 }
8153
8154 static gboolean
8155 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
8156                                               gboolean                   emit_signal)
8157 {
8158   if (gtk_icon_view_item_accessible_is_showing (item))
8159     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
8160                                                     emit_signal);
8161   else
8162     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
8163                                                        emit_signal);
8164 }
8165
8166 static void
8167 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
8168 {
8169   gint i;
8170
8171   item->state_set = atk_state_set_new ();
8172
8173   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
8174   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
8175   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
8176   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
8177   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
8178
8179   for (i = 0; i < LAST_ACTION; i++)
8180     item->action_descriptions[i] = NULL;
8181
8182   item->image_description = NULL;
8183
8184   item->action_idle_handler = 0;
8185 }
8186
8187 static void
8188 gtk_icon_view_item_accessible_finalize (GObject *object)
8189 {
8190   GtkIconViewItemAccessible *item;
8191   gint i;
8192
8193   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
8194
8195   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
8196
8197   if (item->widget)
8198     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
8199
8200   if (item->state_set)
8201     g_object_unref (item->state_set);
8202
8203   if (item->text_buffer)
8204      g_object_unref (item->text_buffer);
8205
8206   for (i = 0; i < LAST_ACTION; i++)
8207     g_free (item->action_descriptions[i]);
8208
8209   g_free (item->image_description);
8210
8211   if (item->action_idle_handler)
8212     {
8213       g_source_remove (item->action_idle_handler);
8214       item->action_idle_handler = 0;
8215     }
8216
8217   G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
8218 }
8219
8220 static AtkObject*
8221 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
8222 {
8223   GtkIconViewItemAccessible *item;
8224
8225   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
8226   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8227
8228   if (item->widget)
8229     return gtk_widget_get_accessible (item->widget);
8230   else
8231     return NULL;
8232 }
8233
8234 static gint
8235 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
8236 {
8237   GtkIconViewItemAccessible *item;
8238
8239   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
8240   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8241
8242   return item->item->index; 
8243 }
8244
8245 static AtkStateSet *
8246 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
8247 {
8248   GtkIconViewItemAccessible *item;
8249   GtkIconView *icon_view;
8250
8251   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8252   g_return_val_if_fail (item->state_set, NULL);
8253
8254   if (!item->widget)
8255     return NULL;
8256
8257   icon_view = GTK_ICON_VIEW (item->widget);
8258   if (icon_view->priv->cursor_item == item->item)
8259     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
8260   else
8261     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
8262   if (item->item->selected)
8263     atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
8264   else
8265     atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
8266
8267   return g_object_ref (item->state_set);
8268 }
8269
8270 static void
8271 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
8272 {
8273   GObjectClass *gobject_class;
8274
8275   accessible_item_parent_class = g_type_class_peek_parent (klass);
8276
8277   gobject_class = (GObjectClass *)klass;
8278
8279   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
8280
8281   klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent;
8282   klass->get_parent = gtk_icon_view_item_accessible_get_parent;
8283   klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set;
8284 }
8285
8286 static GType
8287 gtk_icon_view_item_accessible_get_type (void)
8288 {
8289   static GType type = 0;
8290
8291   if (!type)
8292     {
8293       const GTypeInfo tinfo =
8294       {
8295         sizeof (GtkIconViewItemAccessibleClass),
8296         (GBaseInitFunc) NULL, /* base init */
8297         (GBaseFinalizeFunc) NULL, /* base finalize */
8298         (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
8299         (GClassFinalizeFunc) NULL, /* class finalize */
8300         NULL, /* class data */
8301         sizeof (GtkIconViewItemAccessible), /* instance size */
8302         0, /* nb preallocs */
8303         (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
8304         NULL /* value table */
8305       };
8306
8307       const GInterfaceInfo atk_component_info =
8308       {
8309         (GInterfaceInitFunc) atk_component_item_interface_init,
8310         (GInterfaceFinalizeFunc) NULL,
8311         NULL
8312       };
8313       const GInterfaceInfo atk_action_info =
8314       {
8315         (GInterfaceInitFunc) atk_action_item_interface_init,
8316         (GInterfaceFinalizeFunc) NULL,
8317         NULL
8318       };
8319       const GInterfaceInfo atk_image_info =
8320       {
8321         (GInterfaceInitFunc) atk_image_item_interface_init,
8322         (GInterfaceFinalizeFunc) NULL,
8323         NULL
8324       };
8325       const GInterfaceInfo atk_text_info =
8326       {
8327         (GInterfaceInitFunc) atk_text_item_interface_init,
8328         (GInterfaceFinalizeFunc) NULL,
8329         NULL
8330       };
8331
8332       type = g_type_register_static (ATK_TYPE_OBJECT,
8333                                      I_("GtkIconViewItemAccessible"), &tinfo, 0);
8334       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
8335                                    &atk_component_info);
8336       g_type_add_interface_static (type, ATK_TYPE_ACTION,
8337                                    &atk_action_info);
8338       g_type_add_interface_static (type, ATK_TYPE_IMAGE,
8339                                    &atk_image_info);
8340       g_type_add_interface_static (type, ATK_TYPE_TEXT,
8341                                    &atk_text_info);
8342     }
8343
8344   return type;
8345 }
8346
8347 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE      (gtk_icon_view_accessible_get_type ())
8348 #define GTK_ICON_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
8349 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
8350
8351 static GType gtk_icon_view_accessible_get_type (void);
8352
8353 typedef struct
8354 {
8355    AtkObject parent;
8356 } GtkIconViewAccessible;
8357
8358 typedef struct
8359 {
8360   AtkObject *item;
8361   gint       index;
8362 } GtkIconViewItemAccessibleInfo;
8363
8364 typedef struct
8365 {
8366   GList *items;
8367
8368   GtkAdjustment *old_hadj;
8369   GtkAdjustment *old_vadj;
8370
8371   GtkTreeModel *model;
8372
8373 } GtkIconViewAccessiblePrivate;
8374
8375 static GtkIconViewAccessiblePrivate *
8376 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
8377 {
8378   return g_object_get_qdata (G_OBJECT (accessible),
8379                              accessible_private_data_quark);
8380 }
8381
8382 static void
8383 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
8384                                         AtkObject *item,
8385                                         gint       index)
8386 {
8387   GtkIconViewItemAccessibleInfo *info;
8388   GtkIconViewItemAccessibleInfo *tmp_info;
8389   GtkIconViewAccessiblePrivate *priv;
8390   GList *items;
8391
8392   info = g_new (GtkIconViewItemAccessibleInfo, 1);
8393   info->item = item;
8394   info->index = index;
8395
8396   priv = gtk_icon_view_accessible_get_priv (accessible);
8397   items = priv->items;
8398   while (items)
8399     {
8400       tmp_info = items->data;
8401       if (tmp_info->index > index)
8402         break;
8403       items = items->next;
8404     }
8405   priv->items = g_list_insert_before (priv->items, items, info);
8406   priv->old_hadj = NULL;
8407   priv->old_vadj = NULL;
8408 }
8409
8410 static gint
8411 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
8412 {
8413   GtkIconView *icon_view;
8414   GtkWidget *widget;
8415
8416   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8417   if (!widget)
8418       return 0;
8419
8420   icon_view = GTK_ICON_VIEW (widget);
8421
8422   return g_list_length (icon_view->priv->items);
8423 }
8424
8425 static AtkObject *
8426 gtk_icon_view_accessible_find_child (AtkObject *accessible,
8427                                      gint       index)
8428 {
8429   GtkIconViewAccessiblePrivate *priv;
8430   GtkIconViewItemAccessibleInfo *info;
8431   GList *items;
8432
8433   priv = gtk_icon_view_accessible_get_priv (accessible);
8434   items = priv->items;
8435
8436   while (items)
8437     {
8438       info = items->data;
8439       if (info->index == index)
8440         return info->item;
8441       items = items->next; 
8442     }
8443   return NULL;
8444 }
8445
8446 static AtkObject *
8447 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
8448                                     gint       index)
8449 {
8450   GtkIconView *icon_view;
8451   GtkWidget *widget;
8452   GList *icons;
8453   AtkObject *obj;
8454   GtkIconViewItemAccessible *a11y_item;
8455
8456   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8457   if (!widget)
8458     return NULL;
8459
8460   icon_view = GTK_ICON_VIEW (widget);
8461   icons = g_list_nth (icon_view->priv->items, index);
8462   obj = NULL;
8463   if (icons)
8464     {
8465       GtkIconViewItem *item = icons->data;
8466    
8467       g_return_val_if_fail (item->index == index, NULL);
8468       obj = gtk_icon_view_accessible_find_child (accessible, index);
8469       if (!obj)
8470         {
8471           gchar *text;
8472
8473           obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
8474           gtk_icon_view_item_accessible_info_new (accessible,
8475                                                   obj,
8476                                                   index);
8477           obj->role = ATK_ROLE_ICON;
8478           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8479           a11y_item->item = item;
8480           a11y_item->widget = widget;
8481           a11y_item->text_buffer = gtk_text_buffer_new (NULL);
8482
8483           text = get_text (icon_view, item);
8484           if (text)
8485             {
8486               gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8487               g_free (text);
8488             } 
8489
8490           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
8491           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
8492        }
8493       g_object_ref (obj);
8494     }
8495   return obj;
8496 }
8497
8498 static void
8499 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
8500                                          GList                 *list)
8501 {
8502   GtkIconViewAccessiblePrivate *priv;
8503   GtkIconViewItemAccessibleInfo *info;
8504   GtkIconViewItemAccessible *item;
8505   GList *items;
8506   
8507   priv =  gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
8508   if (priv->items)
8509     {
8510       GtkWidget *widget;
8511       gboolean act_on_item;
8512
8513       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
8514       if (widget == NULL)
8515         return;
8516
8517       items = priv->items;
8518
8519       act_on_item = (list == NULL);
8520
8521       while (items)
8522         {
8523
8524           info = (GtkIconViewItemAccessibleInfo *)items->data;
8525           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8526
8527           if (act_on_item == FALSE && list == items)
8528             act_on_item = TRUE;
8529
8530           if (act_on_item)
8531             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
8532
8533           items = items->next;
8534        }
8535    }
8536 }
8537
8538 static void
8539 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment         *adjustment,
8540                                              GtkIconViewAccessible *view)
8541 {
8542   gtk_icon_view_accessible_traverse_items (view, NULL);
8543 }
8544
8545 static void
8546 gtk_icon_view_accessible_set_adjustment (AtkObject      *accessible,
8547                                          GtkOrientation  orientation,
8548                                          GtkAdjustment  *adjustment)
8549 {
8550   GtkIconViewAccessiblePrivate *priv;
8551   GtkAdjustment **old_adj_ptr;
8552
8553   priv = gtk_icon_view_accessible_get_priv (accessible);
8554
8555   /* Adjustments are set for the first time in constructor and priv is not
8556    * initialized at that time, so skip this first setting. */
8557   if (!priv)
8558     return;
8559
8560   if (orientation == GTK_ORIENTATION_HORIZONTAL)
8561     {
8562       if (priv->old_hadj == adjustment)
8563         return;
8564
8565       old_adj_ptr = &priv->old_hadj;
8566     }
8567   else
8568     {
8569       if (priv->old_vadj == adjustment)
8570         return;
8571
8572       old_adj_ptr = &priv->old_vadj;
8573     }
8574
8575   /* Disconnect signal handlers */
8576   if (*old_adj_ptr)
8577     {
8578       g_object_remove_weak_pointer (G_OBJECT (*old_adj_ptr),
8579                                     (gpointer *)&priv->old_hadj);
8580       g_signal_handlers_disconnect_by_func (*old_adj_ptr,
8581                                             gtk_icon_view_accessible_adjustment_changed,
8582                                             accessible);
8583     }
8584
8585   /* Connect signal */
8586   *old_adj_ptr = adjustment;
8587   g_object_add_weak_pointer (G_OBJECT (adjustment), (gpointer *)old_adj_ptr);
8588   g_signal_connect (adjustment, "value-changed",
8589                     G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
8590                     accessible);
8591 }
8592
8593 static void
8594 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
8595                                             GtkTreePath  *path,
8596                                             GtkTreeIter  *iter,
8597                                             gpointer      user_data)
8598 {
8599   AtkObject *atk_obj;
8600   gint index;
8601   GtkWidget *widget;
8602   GtkIconView *icon_view;
8603   GtkIconViewItem *item;
8604   GtkIconViewItemAccessible *a11y_item;
8605   const gchar *name;
8606   gchar *text;
8607
8608   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8609   index = gtk_tree_path_get_indices(path)[0];
8610   a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
8611       gtk_icon_view_accessible_find_child (atk_obj, index));
8612
8613   if (a11y_item)
8614     {
8615       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
8616       icon_view = GTK_ICON_VIEW (widget);
8617       item = a11y_item->item;
8618
8619       name = atk_object_get_name (ATK_OBJECT (a11y_item));
8620
8621       if (!name || strcmp (name, "") == 0)
8622         {
8623           text = get_text (icon_view, item);
8624           if (text)
8625             {
8626               gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
8627               g_free (text);
8628             }
8629         }
8630     }
8631
8632   g_signal_emit_by_name (atk_obj, "visible-data-changed");
8633
8634   return;
8635 }
8636
8637 static void
8638 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
8639                                              GtkTreePath  *path,
8640                                              GtkTreeIter  *iter,
8641                                              gpointer     user_data)
8642 {
8643   GtkIconViewAccessiblePrivate *priv;
8644   GtkIconViewItemAccessibleInfo *info;
8645   GtkIconViewAccessible *view;
8646   GtkIconViewItemAccessible *item;
8647   GList *items;
8648   GList *tmp_list;
8649   AtkObject *atk_obj;
8650   gint index;
8651
8652   index = gtk_tree_path_get_indices(path)[0];
8653   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8654   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8655   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8656
8657   items = priv->items;
8658   tmp_list = NULL;
8659   while (items)
8660     {
8661       info = items->data;
8662       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8663       if (info->index != item->item->index)
8664         {
8665           if (info->index < index)
8666             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
8667  
8668           if (tmp_list == NULL)
8669             tmp_list = items;
8670    
8671           info->index = item->item->index;
8672         }
8673
8674       items = items->next;
8675     }
8676   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8677   g_signal_emit_by_name (atk_obj, "children-changed::add",
8678                          index, NULL, NULL);
8679   return;
8680 }
8681
8682 static void
8683 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
8684                                             GtkTreePath  *path,
8685                                             gpointer     user_data)
8686 {
8687   GtkIconViewAccessiblePrivate *priv;
8688   GtkIconViewItemAccessibleInfo *info;
8689   GtkIconViewAccessible *view;
8690   GtkIconViewItemAccessible *item;
8691   GList *items;
8692   GList *tmp_list;
8693   GList *deleted_item;
8694   AtkObject *atk_obj;
8695   gint index;
8696
8697   index = gtk_tree_path_get_indices(path)[0];
8698   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8699   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
8700   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8701
8702   items = priv->items;
8703   tmp_list = NULL;
8704   deleted_item = NULL;
8705   info = NULL;
8706   while (items)
8707     {
8708       info = items->data;
8709       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8710       if (info->index == index)
8711         {
8712           deleted_item = items;
8713         }
8714       if (info->index != item->item->index)
8715         {
8716           if (tmp_list == NULL)
8717             tmp_list = items;
8718             
8719           info->index = item->item->index;
8720         }
8721
8722       items = items->next;
8723     }
8724   gtk_icon_view_accessible_traverse_items (view, tmp_list);
8725   if (deleted_item)
8726     {
8727       info = deleted_item->data;
8728       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
8729       g_signal_emit_by_name (atk_obj, "children-changed::remove",
8730                              index, NULL, NULL);
8731       priv->items = g_list_remove_link (priv->items, deleted_item);
8732       g_free (info);
8733     }
8734
8735   return;
8736 }
8737
8738 static gint
8739 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
8740                                        GtkIconViewItemAccessibleInfo *i2)
8741 {
8742   return i1->index - i2->index;
8743 }
8744
8745 static void
8746 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
8747                                                GtkTreePath  *path,
8748                                                GtkTreeIter  *iter,
8749                                                gint         *new_order,
8750                                                gpointer     user_data)
8751 {
8752   GtkIconViewAccessiblePrivate *priv;
8753   GtkIconViewItemAccessibleInfo *info;
8754   GtkIconView *icon_view;
8755   GtkIconViewItemAccessible *item;
8756   GList *items;
8757   AtkObject *atk_obj;
8758   gint *order;
8759   gint length, i;
8760
8761   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
8762   icon_view = GTK_ICON_VIEW (user_data);
8763   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8764
8765   length = gtk_tree_model_iter_n_children (tree_model, NULL);
8766
8767   order = g_new (gint, length);
8768   for (i = 0; i < length; i++)
8769     order [new_order[i]] = i;
8770
8771   items = priv->items;
8772   while (items)
8773     {
8774       info = items->data;
8775       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
8776       info->index = order[info->index];
8777       item->item = g_list_nth_data (icon_view->priv->items, info->index);
8778       items = items->next;
8779     }
8780   g_free (order);
8781   priv->items = g_list_sort (priv->items, 
8782                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
8783
8784   return;
8785 }
8786
8787 static void
8788 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
8789                                                    GtkWidget *widget)
8790 {
8791   GObject *obj;
8792
8793   obj = G_OBJECT (model);
8794   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
8795   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
8796   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
8797   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
8798 }
8799
8800 static void
8801 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
8802 {
8803   GObject *obj;
8804
8805   obj = G_OBJECT (icon_view->priv->model);
8806   g_signal_connect_data (obj, "row-changed",
8807                          (GCallback) gtk_icon_view_accessible_model_row_changed,
8808                          icon_view, NULL, 0);
8809   g_signal_connect_data (obj, "row-inserted",
8810                          (GCallback) gtk_icon_view_accessible_model_row_inserted, 
8811                          icon_view, NULL, G_CONNECT_AFTER);
8812   g_signal_connect_data (obj, "row-deleted",
8813                          (GCallback) gtk_icon_view_accessible_model_row_deleted, 
8814                          icon_view, NULL, G_CONNECT_AFTER);
8815   g_signal_connect_data (obj, "rows-reordered",
8816                          (GCallback) gtk_icon_view_accessible_model_rows_reordered, 
8817                          icon_view, NULL, G_CONNECT_AFTER);
8818 }
8819
8820 static void
8821 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
8822 {
8823   GtkIconViewItemAccessibleInfo *info;
8824   GList *items;
8825
8826   items = priv->items;
8827   while (items)
8828     {
8829       info = (GtkIconViewItemAccessibleInfo *) items->data;
8830       g_object_unref (info->item);
8831       g_free (items->data);
8832       items = items->next;
8833     }
8834   g_list_free (priv->items);
8835   priv->items = NULL;
8836 }
8837
8838 static void
8839 gtk_icon_view_accessible_notify_gtk (GObject *obj,
8840                                      GParamSpec *pspec)
8841 {
8842   GtkIconView *icon_view;
8843   GtkWidget *widget;
8844   AtkObject *atk_obj;
8845   GtkIconViewAccessiblePrivate *priv;
8846
8847   if (strcmp (pspec->name, "model") == 0)
8848     {
8849       widget = GTK_WIDGET (obj); 
8850       atk_obj = gtk_widget_get_accessible (widget);
8851       priv = gtk_icon_view_accessible_get_priv (atk_obj);
8852       if (priv->model)
8853         {
8854           g_object_remove_weak_pointer (G_OBJECT (priv->model),
8855                                         (gpointer *)&priv->model);
8856           gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
8857         }
8858       gtk_icon_view_accessible_clear_cache (priv);
8859
8860       icon_view = GTK_ICON_VIEW (obj);
8861       priv->model = icon_view->priv->model;
8862       /* If there is no model the GtkIconView is probably being destroyed */
8863       if (priv->model)
8864         {
8865           g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8866           gtk_icon_view_accessible_connect_model_signals (icon_view);
8867         }
8868     }
8869
8870   return;
8871 }
8872
8873 static void
8874 gtk_icon_view_accessible_initialize (AtkObject *accessible,
8875                                      gpointer   data)
8876 {
8877   GtkIconViewAccessiblePrivate *priv;
8878   GtkIconView *icon_view;
8879
8880   if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
8881     ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
8882
8883   priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
8884   g_object_set_qdata (G_OBJECT (accessible),
8885                       accessible_private_data_quark,
8886                       priv);
8887
8888   icon_view = GTK_ICON_VIEW (data);
8889   if (icon_view->priv->hadjustment)
8890     gtk_icon_view_accessible_set_adjustment (accessible,
8891                                              GTK_ORIENTATION_HORIZONTAL,
8892                                              icon_view->priv->hadjustment);
8893   if (icon_view->priv->vadjustment)
8894     gtk_icon_view_accessible_set_adjustment (accessible,
8895                                              GTK_ORIENTATION_VERTICAL,
8896                                              icon_view->priv->vadjustment);
8897   g_signal_connect (data,
8898                     "notify",
8899                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
8900                     NULL);
8901
8902   priv->model = icon_view->priv->model;
8903   if (priv->model)
8904     {
8905       g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
8906       gtk_icon_view_accessible_connect_model_signals (icon_view);
8907     }
8908                           
8909   accessible->role = ATK_ROLE_LAYERED_PANE;
8910 }
8911
8912 static void
8913 gtk_icon_view_accessible_finalize (GObject *object)
8914 {
8915   GtkIconViewAccessiblePrivate *priv;
8916
8917   priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
8918   gtk_icon_view_accessible_clear_cache (priv);
8919
8920   g_free (priv);
8921
8922   G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
8923 }
8924
8925 static void
8926 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
8927                                     GtkAccessible *accessible)
8928 {
8929   AtkObject *atk_obj;
8930   GtkIconViewAccessiblePrivate *priv;
8931
8932   atk_obj = ATK_OBJECT (accessible);
8933   priv = gtk_icon_view_accessible_get_priv (atk_obj);
8934   if (priv->old_hadj)
8935     {
8936       g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
8937                                     (gpointer *)&priv->old_hadj);
8938           
8939       g_signal_handlers_disconnect_by_func (priv->old_hadj,
8940                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
8941                                             accessible);
8942       priv->old_hadj = NULL;
8943     }
8944   if (priv->old_vadj)
8945     {
8946       g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
8947                                     (gpointer *)&priv->old_vadj);
8948           
8949       g_signal_handlers_disconnect_by_func (priv->old_vadj,
8950                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
8951                                             accessible);
8952       priv->old_vadj = NULL;
8953     }
8954 }
8955
8956 static void
8957 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
8958 {
8959   GtkWidget *widget;
8960
8961   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8962   if (widget)
8963     {
8964       g_signal_connect_after (widget,
8965                               "destroy",
8966                               G_CALLBACK (gtk_icon_view_accessible_destroyed),
8967                               accessible);
8968     }
8969   GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
8970 }
8971
8972 static void
8973 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
8974 {
8975   GObjectClass *gobject_class;
8976   GtkAccessibleClass *accessible_class;
8977
8978   accessible_parent_class = g_type_class_peek_parent (klass);
8979
8980   gobject_class = (GObjectClass *)klass;
8981   accessible_class = (GtkAccessibleClass *)klass;
8982
8983   gobject_class->finalize = gtk_icon_view_accessible_finalize;
8984
8985   klass->get_n_children = gtk_icon_view_accessible_get_n_children;
8986   klass->ref_child = gtk_icon_view_accessible_ref_child;
8987   klass->initialize = gtk_icon_view_accessible_initialize;
8988
8989   accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
8990
8991   accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
8992 }
8993
8994 static AtkObject*
8995 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
8996                                                   gint          x,
8997                                                   gint          y,
8998                                                   AtkCoordType  coord_type)
8999 {
9000   GtkWidget *widget;
9001   GtkIconView *icon_view;
9002   GtkIconViewItem *item;
9003   gint x_pos, y_pos;
9004
9005   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
9006   if (widget == NULL)
9007   /* State is defunct */
9008     return NULL;
9009
9010   icon_view = GTK_ICON_VIEW (widget);
9011   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
9012   item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
9013   if (item)
9014     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
9015
9016   return NULL;
9017 }
9018
9019 static void
9020 atk_component_interface_init (AtkComponentIface *iface)
9021 {
9022   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
9023 }
9024
9025 static gboolean
9026 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
9027                                         gint i)
9028 {
9029   GtkWidget *widget;
9030   GtkIconView *icon_view;
9031   GtkIconViewItem *item;
9032
9033   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9034   if (widget == NULL)
9035     return FALSE;
9036
9037   icon_view = GTK_ICON_VIEW (widget);
9038
9039   item = g_list_nth_data (icon_view->priv->items, i);
9040
9041   if (!item)
9042     return FALSE;
9043
9044   gtk_icon_view_select_item (icon_view, item);
9045
9046   return TRUE;
9047 }
9048
9049 static gboolean
9050 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
9051 {
9052   GtkWidget *widget;
9053   GtkIconView *icon_view;
9054
9055   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9056   if (widget == NULL)
9057     return FALSE;
9058
9059   icon_view = GTK_ICON_VIEW (widget);
9060   gtk_icon_view_unselect_all (icon_view);
9061
9062   return TRUE;
9063 }
9064
9065 static AtkObject*
9066 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
9067                                         gint          i)
9068 {
9069   GList *l;
9070   GtkWidget *widget;
9071   GtkIconView *icon_view;
9072   GtkIconViewItem *item;
9073
9074   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9075   if (widget == NULL)
9076     return NULL;
9077
9078   icon_view = GTK_ICON_VIEW (widget);
9079
9080   l = icon_view->priv->items;
9081   while (l)
9082     {
9083       item = l->data;
9084       if (item->selected)
9085         {
9086           if (i == 0)
9087             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
9088           else
9089             i--;
9090         }
9091       l = l->next;
9092     }
9093
9094   return NULL;
9095 }
9096
9097 static gint
9098 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
9099 {
9100   GtkWidget *widget;
9101   GtkIconView *icon_view;
9102   GtkIconViewItem *item;
9103   GList *l;
9104   gint count;
9105
9106   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9107   if (widget == NULL)
9108     return 0;
9109
9110   icon_view = GTK_ICON_VIEW (widget);
9111
9112   l = icon_view->priv->items;
9113   count = 0;
9114   while (l)
9115     {
9116       item = l->data;
9117
9118       if (item->selected)
9119         count++;
9120
9121       l = l->next;
9122     }
9123
9124   return count;
9125 }
9126
9127 static gboolean
9128 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
9129                                             gint          i)
9130 {
9131   GtkWidget *widget;
9132   GtkIconView *icon_view;
9133   GtkIconViewItem *item;
9134
9135   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9136   if (widget == NULL)
9137     return FALSE;
9138
9139   icon_view = GTK_ICON_VIEW (widget);
9140
9141   item = g_list_nth_data (icon_view->priv->items, i);
9142   if (!item)
9143     return FALSE;
9144
9145   return item->selected;
9146 }
9147
9148 static gboolean
9149 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
9150                                            gint          i)
9151 {
9152   GtkWidget *widget;
9153   GtkIconView *icon_view;
9154   GtkIconViewItem *item;
9155   GList *l;
9156   gint count;
9157
9158   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9159   if (widget == NULL)
9160     return FALSE;
9161
9162   icon_view = GTK_ICON_VIEW (widget);
9163   l = icon_view->priv->items;
9164   count = 0;
9165   while (l)
9166     {
9167       item = l->data;
9168       if (item->selected)
9169         {
9170           if (count == i)
9171             {
9172               gtk_icon_view_unselect_item (icon_view, item);
9173               return TRUE;
9174             }
9175           count++;
9176         }
9177       l = l->next;
9178     }
9179
9180   return FALSE;
9181 }
9182  
9183 static gboolean
9184 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
9185 {
9186   GtkWidget *widget;
9187   GtkIconView *icon_view;
9188
9189   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9190   if (widget == NULL)
9191     return FALSE;
9192
9193   icon_view = GTK_ICON_VIEW (widget);
9194   gtk_icon_view_select_all (icon_view);
9195   return TRUE;
9196 }
9197
9198 static void
9199 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
9200 {
9201   iface->add_selection = gtk_icon_view_accessible_add_selection;
9202   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
9203   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
9204   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
9205   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
9206   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
9207   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
9208 }
9209
9210 static GType
9211 gtk_icon_view_accessible_get_type (void)
9212 {
9213   static GType type = 0;
9214
9215   if (!type)
9216     {
9217       GTypeInfo tinfo =
9218       {
9219         0, /* class size */
9220         (GBaseInitFunc) NULL, /* base init */
9221         (GBaseFinalizeFunc) NULL, /* base finalize */
9222         (GClassInitFunc) gtk_icon_view_accessible_class_init,
9223         (GClassFinalizeFunc) NULL, /* class finalize */
9224         NULL, /* class data */
9225         0, /* instance size */
9226         0, /* nb preallocs */
9227         (GInstanceInitFunc) NULL, /* instance init */
9228         NULL /* value table */
9229       };
9230       const GInterfaceInfo atk_component_info =
9231       {
9232         (GInterfaceInitFunc) atk_component_interface_init,
9233         (GInterfaceFinalizeFunc) NULL,
9234         NULL
9235       };
9236       const GInterfaceInfo atk_selection_info =
9237       {
9238         (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
9239         (GInterfaceFinalizeFunc) NULL,
9240         NULL
9241       };
9242
9243       /*
9244        * Figure out the size of the class and instance
9245        * we are deriving from
9246        */
9247       AtkObjectFactory *factory;
9248       GType derived_type;
9249       GTypeQuery query;
9250       GType derived_atk_type;
9251
9252       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9253       factory = atk_registry_get_factory (atk_get_default_registry (), 
9254                                           derived_type);
9255       derived_atk_type = atk_object_factory_get_accessible_type (factory);
9256       g_type_query (derived_atk_type, &query);
9257       tinfo.class_size = query.class_size;
9258       tinfo.instance_size = query.instance_size;
9259  
9260       type = g_type_register_static (derived_atk_type, 
9261                                      I_("GtkIconViewAccessible"), 
9262                                      &tinfo, 0);
9263       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9264                                    &atk_component_info);
9265       g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9266                                    &atk_selection_info);
9267     }
9268   return type;
9269 }
9270
9271 static AtkObject *
9272 gtk_icon_view_accessible_new (GObject *obj)
9273 {
9274   AtkObject *accessible;
9275
9276   g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
9277
9278   accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
9279   atk_object_initialize (accessible, obj);
9280
9281   return accessible;
9282 }
9283
9284 static GType
9285 gtk_icon_view_accessible_factory_get_accessible_type (void)
9286 {
9287   return gtk_icon_view_accessible_get_type ();
9288 }
9289
9290 static AtkObject*
9291 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
9292 {
9293   return gtk_icon_view_accessible_new (obj);
9294 }
9295
9296 static void
9297 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
9298 {
9299   klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
9300   klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
9301 }
9302
9303 static GType
9304 gtk_icon_view_accessible_factory_get_type (void)
9305 {
9306   static GType type = 0;
9307
9308   if (!type)
9309     {
9310       const GTypeInfo tinfo =
9311       {
9312         sizeof (AtkObjectFactoryClass),
9313         NULL,           /* base_init */
9314         NULL,           /* base_finalize */
9315         (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
9316         NULL,           /* class_finalize */
9317         NULL,           /* class_data */
9318         sizeof (AtkObjectFactory),
9319         0,             /* n_preallocs */
9320         NULL, NULL
9321       };
9322
9323       type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
9324                                     I_("GtkIconViewAccessibleFactory"),
9325                                     &tinfo, 0);
9326     }
9327   return type;
9328 }
9329
9330
9331 static AtkObject *
9332 gtk_icon_view_get_accessible (GtkWidget *widget)
9333 {
9334   static gboolean first_time = TRUE;
9335
9336   if (first_time)
9337     {
9338       _gtk_accessible_set_factory_type (GTK_TYPE_ICON_VIEW,
9339                                         gtk_icon_view_accessible_factory_get_type ());
9340       first_time = FALSE;
9341     }
9342   return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible (widget);
9343 }
9344
9345 static gboolean
9346 gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
9347                                           GtkBuilder    *builder,
9348                                           GObject       *child,
9349                                           const gchar   *tagname,
9350                                           GMarkupParser *parser,
9351                                           gpointer      *data)
9352 {
9353   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
9354                                                 tagname, parser, data))
9355     return TRUE;
9356
9357   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
9358                                                       tagname, parser, data);
9359 }
9360
9361 static void
9362 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
9363                                         GtkBuilder   *builder,
9364                                         GObject      *child,
9365                                         const gchar  *tagname,
9366                                         gpointer     *data)
9367 {
9368   if (!_gtk_cell_layout_buildable_custom_tag_end (buildable, builder, 
9369                                                   child, tagname, data))
9370     parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
9371                                             data);
9372 }