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