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