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