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