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