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