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