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