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