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