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