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