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