]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
Fix make check
[~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      (GtkIconView            *icon_view,
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
2711   if (adjustment && priv->hadjustment == adjustment)
2712     return;
2713
2714   if (priv->hadjustment != NULL)
2715     {
2716       g_signal_handlers_disconnect_matched (priv->hadjustment,
2717                                             G_SIGNAL_MATCH_DATA,
2718                                             0, 0, NULL, NULL, icon_view);
2719       g_object_unref (priv->hadjustment);
2720     }
2721
2722   if (!adjustment)
2723     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2724                                      0.0, 0.0, 0.0);
2725
2726   g_signal_connect (adjustment, "value-changed",
2727                     G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2728   priv->hadjustment = g_object_ref_sink (adjustment);
2729   gtk_icon_view_set_hadjustment_values (icon_view);
2730
2731   gtk_icon_view_accessible_set_adjustment (icon_view,
2732                                            GTK_ORIENTATION_HORIZONTAL,
2733                                            priv->hadjustment);
2734
2735   g_object_notify (G_OBJECT (icon_view), "hadjustment");
2736 }
2737
2738 static void
2739 gtk_icon_view_set_vadjustment (GtkIconView   *icon_view,
2740                                GtkAdjustment *adjustment)
2741 {
2742   GtkIconViewPrivate *priv = icon_view->priv;
2743
2744   if (adjustment && priv->vadjustment == adjustment)
2745     return;
2746
2747   if (priv->vadjustment != NULL)
2748     {
2749       g_signal_handlers_disconnect_matched (priv->vadjustment,
2750                                             G_SIGNAL_MATCH_DATA,
2751                                             0, 0, NULL, NULL, icon_view);
2752       g_object_unref (priv->vadjustment);
2753     }
2754
2755   if (!adjustment)
2756     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
2757                                      0.0, 0.0, 0.0);
2758
2759   g_signal_connect (adjustment, "value-changed",
2760                     G_CALLBACK (gtk_icon_view_adjustment_changed), icon_view);
2761   priv->vadjustment = g_object_ref_sink (adjustment);
2762   gtk_icon_view_set_vadjustment_values (icon_view);
2763
2764   gtk_icon_view_accessible_set_adjustment (icon_view,
2765                                            GTK_ORIENTATION_VERTICAL,
2766                                            priv->vadjustment);
2767
2768   g_object_notify (G_OBJECT (icon_view), "vadjustment");
2769 }
2770
2771 static void
2772 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
2773                                   GtkIconView   *icon_view)
2774 {
2775   GtkIconViewPrivate *priv = icon_view->priv;
2776
2777   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2778     {
2779       gdk_window_move (priv->bin_window,
2780                        - priv->hadjustment->value,
2781                        - priv->vadjustment->value);
2782
2783       if (icon_view->priv->doing_rubberband)
2784         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
2785
2786       gtk_icon_view_process_updates (icon_view);
2787     }
2788 }
2789
2790 static GList *
2791 gtk_icon_view_layout_single_row (GtkIconView *icon_view, 
2792                                  GList       *first_item, 
2793                                  gint         item_width,
2794                                  gint         row,
2795                                  gint        *y, 
2796                                  gint        *maximum_width)
2797 {
2798   GtkAllocation allocation;
2799   GtkWidget *widget = GTK_WIDGET (icon_view);
2800   gint focus_width;
2801   gint x, current_width;
2802   GList *items, *last_item;
2803   gint col;
2804   gint colspan;
2805   gint *max_height;
2806   gint i;
2807   gboolean rtl;
2808
2809   rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2810   max_height = g_new0 (gint, icon_view->priv->n_cells);
2811
2812   x = 0;
2813   col = 0;
2814   items = first_item;
2815   current_width = 0;
2816
2817   gtk_widget_style_get (widget,
2818                         "focus-line-width", &focus_width,
2819                         NULL);
2820
2821   x += icon_view->priv->margin + focus_width;
2822   current_width += 2 * (icon_view->priv->margin + focus_width);
2823
2824   items = first_item;
2825   while (items)
2826     {
2827       GtkIconViewItem *item = items->data;
2828
2829       gtk_icon_view_calculate_item_size (icon_view, item);
2830       colspan = 1 + (item->width - 1) / (item_width + icon_view->priv->column_spacing);
2831
2832       item->width = colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing;
2833
2834       current_width += item->width;
2835
2836       if (items != first_item)
2837         {
2838           gtk_widget_get_allocation (widget, &allocation);
2839
2840           if ((icon_view->priv->columns <= 0 && current_width > allocation.width) ||
2841               (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
2842             break;
2843         }
2844
2845       current_width += icon_view->priv->column_spacing + 2 * focus_width;
2846
2847       item->y = *y + focus_width;
2848       item->x = x;
2849
2850       x = current_width - (icon_view->priv->margin + focus_width); 
2851
2852       for (i = 0; i < icon_view->priv->n_cells; i++)
2853         max_height[i] = MAX (max_height[i], item->box[i].height);
2854               
2855       if (current_width > *maximum_width)
2856         *maximum_width = current_width;
2857
2858       item->row = row;
2859       item->col = col;
2860
2861       col += colspan;
2862       items = items->next;
2863     }
2864
2865   last_item = items;
2866
2867   /* Now go through the row again and align the icons */
2868   for (items = first_item; items != last_item; items = items->next)
2869     {
2870       GtkIconViewItem *item = items->data;
2871
2872       if (rtl)
2873         {
2874           item->x = *maximum_width - item->width - item->x;
2875           item->col = col - 1 - item->col;
2876         }
2877
2878       gtk_icon_view_calculate_item_size2 (icon_view, item, max_height);
2879
2880       /* We may want to readjust the new y coordinate. */
2881       if (item->y + item->height + focus_width + icon_view->priv->row_spacing > *y)
2882         *y = item->y + item->height + focus_width + icon_view->priv->row_spacing;
2883     }
2884
2885   g_free (max_height);
2886   
2887   return last_item;
2888 }
2889
2890 static void
2891 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
2892                                     gdouble        upper)
2893 {
2894   if (upper != adj->upper)
2895     {
2896       gdouble min = MAX (0.0, upper - adj->page_size);
2897       gboolean value_changed = FALSE;
2898       
2899       adj->upper = upper;
2900
2901       if (adj->value > min)
2902         {
2903           adj->value = min;
2904           value_changed = TRUE;
2905         }
2906       
2907       gtk_adjustment_changed (adj);
2908       
2909       if (value_changed)
2910         gtk_adjustment_value_changed (adj);
2911     }
2912 }
2913
2914 static void
2915 gtk_icon_view_layout (GtkIconView *icon_view)
2916 {
2917   GtkAllocation allocation;
2918   GtkWidget *widget;
2919   GList *icons;
2920   gint y = 0, maximum_width = 0;
2921   gint row;
2922   gint item_width;
2923   gboolean size_changed = FALSE;
2924
2925   if (icon_view->priv->layout_idle_id != 0)
2926     {
2927       g_source_remove (icon_view->priv->layout_idle_id);
2928       icon_view->priv->layout_idle_id = 0;
2929     }
2930   
2931   if (icon_view->priv->model == NULL)
2932     return;
2933
2934   widget = GTK_WIDGET (icon_view);
2935
2936   item_width = icon_view->priv->item_width;
2937
2938   if (item_width < 0)
2939     {
2940       for (icons = icon_view->priv->items; icons; icons = icons->next)
2941         {
2942           GtkIconViewItem *item = icons->data;
2943           gtk_icon_view_calculate_item_size (icon_view, item);
2944           item_width = MAX (item_width, item->width);
2945         }
2946     }
2947
2948
2949   icons = icon_view->priv->items;
2950   y += icon_view->priv->margin;
2951   row = 0;
2952
2953   if (icons)
2954     {
2955       gtk_icon_view_set_cell_data (icon_view, icons->data);
2956       adjust_wrap_width (icon_view, icons->data);
2957     }
2958   
2959   do
2960     {
2961       icons = gtk_icon_view_layout_single_row (icon_view, icons, 
2962                                                item_width, row,
2963                                                &y, &maximum_width);
2964       row++;
2965     }
2966   while (icons != NULL);
2967
2968   if (maximum_width != icon_view->priv->width)
2969     {
2970       icon_view->priv->width = maximum_width;
2971       size_changed = TRUE;
2972     }
2973
2974   y += icon_view->priv->margin;
2975   
2976   if (y != icon_view->priv->height)
2977     {
2978       icon_view->priv->height = y;
2979       size_changed = TRUE;
2980     }
2981
2982   gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, 
2983                                       icon_view->priv->width);
2984   gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, 
2985                                       icon_view->priv->height);
2986
2987   if (size_changed)
2988     gtk_widget_queue_resize_no_redraw (widget);
2989
2990   gtk_widget_get_allocation (widget, &allocation);
2991   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
2992     gdk_window_resize (icon_view->priv->bin_window,
2993                        MAX (icon_view->priv->width, allocation.width),
2994                        MAX (icon_view->priv->height, allocation.height));
2995
2996   if (icon_view->priv->scroll_to_path)
2997     {
2998       GtkTreePath *path;
2999
3000       path = gtk_tree_row_reference_get_path (icon_view->priv->scroll_to_path);
3001       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
3002       icon_view->priv->scroll_to_path = NULL;
3003       
3004       gtk_icon_view_scroll_to_path (icon_view, path,
3005                                     icon_view->priv->scroll_to_use_align,
3006                                     icon_view->priv->scroll_to_row_align,
3007                                     icon_view->priv->scroll_to_col_align);
3008       gtk_tree_path_free (path);
3009     }
3010   
3011   gtk_widget_queue_draw (widget);
3012 }
3013
3014 static void 
3015 gtk_icon_view_get_cell_area (GtkIconView         *icon_view,
3016                              GtkIconViewItem     *item,
3017                              GtkIconViewCellInfo *info,
3018                              GdkRectangle        *cell_area)
3019 {
3020   g_return_if_fail (info->position < item->n_cells);
3021
3022   if (icon_view->priv->item_orientation == GTK_ORIENTATION_HORIZONTAL)
3023     {
3024       cell_area->x = item->box[info->position].x - item->before[info->position];
3025       cell_area->y = item->y + icon_view->priv->item_padding;
3026       cell_area->width = item->box[info->position].width + 
3027         item->before[info->position] + item->after[info->position];
3028       cell_area->height = item->height - icon_view->priv->item_padding * 2;
3029     }
3030   else
3031     {
3032       cell_area->x = item->x + icon_view->priv->item_padding;
3033       cell_area->y = item->box[info->position].y - item->before[info->position];
3034       cell_area->width = item->width - icon_view->priv->item_padding * 2;
3035       cell_area->height = item->box[info->position].height + 
3036         item->before[info->position] + item->after[info->position];
3037     }
3038 }
3039
3040 static void 
3041 gtk_icon_view_get_cell_box (GtkIconView         *icon_view,
3042                             GtkIconViewItem     *item,
3043                             GtkIconViewCellInfo *info,
3044                             GdkRectangle        *box)
3045 {
3046   g_return_if_fail (info->position < item->n_cells);
3047
3048   *box = item->box[info->position];
3049 }
3050
3051 /* try to guess a reasonable wrap width for an implicit text cell renderer
3052  */
3053 static void
3054 adjust_wrap_width (GtkIconView     *icon_view,
3055                    GtkIconViewItem *item)
3056 {
3057   GtkIconViewCellInfo *text_info;
3058   GtkIconViewCellInfo *pixbuf_info;
3059   gint wrap_width;
3060
3061   if (icon_view->priv->text_cell != -1 &&
3062       icon_view->priv->pixbuf_cell != -1)
3063     {
3064       GtkRequisition min_size;
3065       gint item_width;
3066
3067       text_info = g_list_nth_data (icon_view->priv->cell_list,
3068                                    icon_view->priv->text_cell);
3069       pixbuf_info = g_list_nth_data (icon_view->priv->cell_list,
3070                                      icon_view->priv->pixbuf_cell);
3071
3072       gtk_cell_renderer_get_preferred_size (pixbuf_info->cell,
3073                                             GTK_WIDGET (icon_view),
3074                                             &min_size, NULL);
3075
3076       if (icon_view->priv->item_width > 0)
3077         item_width = icon_view->priv->item_width;
3078       else
3079         item_width = item->width;
3080
3081       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
3082         wrap_width = item_width;
3083       else {
3084         if (item->width == -1 && item_width <= 0)
3085           wrap_width = MAX (2 * min_size.width, 50);
3086         else
3087           wrap_width = item_width - min_size.width - icon_view->priv->spacing;
3088         }
3089
3090       wrap_width -= icon_view->priv->item_padding * 2;
3091
3092       g_object_set (text_info->cell, "wrap-width", wrap_width, NULL);
3093       g_object_set (text_info->cell, "width", wrap_width, NULL);
3094     }
3095 }
3096
3097 static void
3098 gtk_icon_view_calculate_item_size (GtkIconView     *icon_view,
3099                                    GtkIconViewItem *item)
3100 {
3101   GtkRequisition min_size;
3102   gint spacing;
3103   GList *l;
3104
3105   if (item->width != -1 && item->height != -1) 
3106     return;
3107
3108   if (item->n_cells != icon_view->priv->n_cells)
3109     {
3110       g_free (item->before);
3111       g_free (item->after);
3112       g_free (item->box);
3113       
3114       item->before = g_new0 (gint, icon_view->priv->n_cells);
3115       item->after = g_new0 (gint, icon_view->priv->n_cells);
3116       item->box = g_new0 (GdkRectangle, icon_view->priv->n_cells);
3117
3118       item->n_cells = icon_view->priv->n_cells;
3119     }
3120
3121   gtk_icon_view_set_cell_data (icon_view, item);
3122
3123   spacing = icon_view->priv->spacing;
3124
3125   item->width = 0;
3126   item->height = 0;
3127   for (l = icon_view->priv->cell_list; l; l = l->next)
3128     {
3129       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3130       
3131       if (!gtk_cell_renderer_get_visible (info->cell))
3132         continue;
3133
3134       gtk_cell_renderer_get_preferred_size (info->cell,
3135                                             GTK_WIDGET (icon_view),
3136                                             &min_size, NULL);
3137       item->box[info->position].width = min_size.width;
3138       item->box[info->position].height = min_size.height;
3139
3140       if (icon_view->priv->item_orientation == GTK_ORIENTATION_HORIZONTAL)
3141         {
3142           item->width += item->box[info->position].width 
3143             + (info->position > 0 ? spacing : 0);
3144           item->height = MAX (item->height, item->box[info->position].height);
3145         }
3146       else
3147         {
3148           item->width = MAX (item->width, item->box[info->position].width);
3149           item->height += item->box[info->position].height + (info->position > 0 ? spacing : 0);
3150         }
3151     }
3152
3153   item->width += icon_view->priv->item_padding * 2;
3154   item->height += icon_view->priv->item_padding * 2;
3155 }
3156
3157 static void
3158 gtk_icon_view_calculate_item_size2 (GtkIconView     *icon_view,
3159                                     GtkIconViewItem *item,
3160                                     gint            *max_height)
3161 {
3162   GtkRequisition min_size;
3163   GdkRectangle cell_area;
3164   gint spacing;
3165   GList *l;
3166   gint i, k;
3167   gboolean rtl;
3168
3169   rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
3170
3171   gtk_icon_view_set_cell_data (icon_view, item);
3172
3173   spacing = icon_view->priv->spacing;
3174
3175   item->height = 0;
3176   for (i = 0; i < icon_view->priv->n_cells; i++)
3177     {
3178       if (icon_view->priv->item_orientation == GTK_ORIENTATION_HORIZONTAL)
3179         item->height = MAX (item->height, max_height[i]);
3180       else
3181         item->height += max_height[i] + (i > 0 ? spacing : 0);
3182     }
3183
3184   cell_area.x = item->x + icon_view->priv->item_padding;
3185   cell_area.y = item->y + icon_view->priv->item_padding;
3186       
3187   for (k = 0; k < 2; k++)
3188     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
3189       {
3190         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3191
3192         if (info->pack == (k ? GTK_PACK_START : GTK_PACK_END))
3193           continue;
3194
3195         if (!gtk_cell_renderer_get_visible (info->cell))
3196           continue;
3197
3198         if (icon_view->priv->item_orientation == GTK_ORIENTATION_HORIZONTAL)
3199           {
3200             /* We should not subtract icon_view->priv->item_padding from item->height,
3201              * because item->height is recalculated above using
3202              * max_height which does not contain item padding.
3203              */
3204             cell_area.width = item->box[info->position].width;
3205             cell_area.height = item->height;
3206           }
3207         else
3208           {
3209             /* item->width is not recalculated and thus needs to be
3210              * corrected for the padding.
3211              */
3212             cell_area.width = item->width - 2 * icon_view->priv->item_padding;
3213             cell_area.height = max_height[i];
3214           }
3215
3216         gtk_cell_renderer_get_preferred_size (info->cell,
3217                                               GTK_WIDGET (icon_view),
3218                                               &min_size, NULL);
3219         item->box[info->position].width  = min_size.width;
3220         item->box[info->position].height = min_size.height;
3221
3222         _gtk_cell_renderer_calc_offset (info->cell, &cell_area,
3223                                         gtk_widget_get_direction (GTK_WIDGET (icon_view)),
3224                                         item->box[info->position].width, item->box[info->position].height,
3225                                         &item->box[info->position].x, &item->box[info->position].y);
3226         item->box[info->position].x += cell_area.x;
3227         item->box[info->position].y += cell_area.y;
3228
3229         if (icon_view->priv->item_orientation == GTK_ORIENTATION_HORIZONTAL)
3230           {
3231             item->before[info->position] = item->box[info->position].x - cell_area.x;
3232             item->after[info->position] = cell_area.width - item->box[info->position].width - item->before[info->position];
3233             cell_area.x += cell_area.width + spacing;
3234           }
3235         else
3236           {
3237             if (item->box[info->position].width > item->width - icon_view->priv->item_padding * 2)
3238               {
3239                 item->width = item->box[info->position].width + icon_view->priv->item_padding * 2;
3240                 cell_area.width = item->width;
3241               }
3242             item->before[info->position] = item->box[info->position].y - cell_area.y;
3243             item->after[info->position] = cell_area.height - item->box[info->position].height - item->before[info->position];
3244             cell_area.y += cell_area.height + spacing;
3245           }
3246       }
3247   
3248   if (rtl && icon_view->priv->item_orientation == GTK_ORIENTATION_HORIZONTAL)
3249     {
3250       for (i = 0; i < icon_view->priv->n_cells; i++)
3251         {
3252           item->box[i].x = item->x + item->width - 
3253             (item->box[i].x + item->box[i].width - item->x);
3254         }      
3255     }
3256
3257   item->height += icon_view->priv->item_padding * 2;
3258 }
3259
3260 static void
3261 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
3262 {
3263   g_list_foreach (icon_view->priv->items,
3264                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
3265 }
3266
3267 static void
3268 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
3269 {
3270   item->width = -1;
3271   item->height = -1;
3272 }
3273
3274 static void
3275 gtk_icon_view_paint_item (GtkIconView     *icon_view,
3276                           cairo_t         *cr,
3277                           GtkIconViewItem *item,
3278                           gint             x,
3279                           gint             y,
3280                           gboolean         draw_focus)
3281 {
3282   gint focus_width;
3283   gint padding;
3284   GdkRectangle cell_area, box;
3285   GList *l;
3286   gint i;
3287   GtkStateType state;
3288   GtkCellRendererState flags;
3289   GtkStyle *style;
3290   GtkWidget *widget = GTK_WIDGET (icon_view);
3291
3292   if (icon_view->priv->model == NULL)
3293     return;
3294   
3295   gtk_icon_view_set_cell_data (icon_view, item);
3296
3297   style = gtk_widget_get_style (widget);
3298   gtk_widget_style_get (widget,
3299                         "focus-line-width", &focus_width,
3300                         NULL);
3301   
3302   padding = focus_width; 
3303   
3304   if (item->selected)
3305     {
3306       flags = GTK_CELL_RENDERER_SELECTED;
3307       if (gtk_widget_has_focus (widget))
3308         state = GTK_STATE_SELECTED;
3309       else
3310         state = GTK_STATE_ACTIVE;
3311     }
3312   else
3313     {
3314       flags = 0;
3315       state = GTK_STATE_NORMAL;
3316     }
3317
3318   if (item->selected)
3319     {
3320       gtk_paint_flat_box (style,
3321                           cr,
3322                           GTK_STATE_SELECTED,
3323                           GTK_SHADOW_NONE,
3324                           GTK_WIDGET (icon_view),
3325                           "icon_view_item",
3326                           x, y,
3327                           item->width, item->height);
3328     }
3329   
3330   for (l = icon_view->priv->cell_list; l; l = l->next)
3331     {
3332       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3333       
3334       if (!gtk_cell_renderer_get_visible (info->cell))
3335         continue;
3336       
3337       gtk_icon_view_get_cell_area (icon_view, item, info, &cell_area);
3338
3339       cell_area.x = x - item->x + cell_area.x;
3340       cell_area.y = y - item->y + cell_area.y;
3341
3342       gtk_cell_renderer_render (info->cell,
3343                                 cr,
3344                                 widget,
3345                                 &cell_area, &cell_area, flags);
3346     }
3347
3348   if (draw_focus &&
3349       gtk_widget_has_focus (widget) &&
3350       item == icon_view->priv->cursor_item)
3351     {
3352       for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
3353         {
3354           GtkCellRendererMode mode;
3355           GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3356
3357           if (!gtk_cell_renderer_get_visible (info->cell))
3358             continue;
3359
3360           /* If found a editable/activatable cell, draw focus on it. */
3361           g_object_get (info->cell, "mode", &mode, NULL);
3362           if (icon_view->priv->cursor_cell < 0 &&
3363               mode != GTK_CELL_RENDERER_MODE_INERT)
3364             icon_view->priv->cursor_cell = i;
3365
3366           gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3367
3368           if (i == icon_view->priv->cursor_cell)
3369             {
3370               gtk_paint_focus (style,
3371                                cr,
3372                                GTK_STATE_NORMAL,
3373                                widget,
3374                                "icon_view",
3375                                x - item->x + box.x - padding,
3376                                y - item->y + box.y - padding,
3377                                box.width + 2 * padding,
3378                                box.height + 2 * padding);
3379               break;
3380             }
3381         }
3382
3383       /* If there are no editable/activatable cells, draw focus 
3384        * around the whole item.
3385        */
3386       if (icon_view->priv->cursor_cell < 0)
3387         gtk_paint_focus (style,
3388                          cr,
3389                          GTK_STATE_NORMAL,
3390                          widget,
3391                          "icon_view",
3392                          x - padding,
3393                          y - padding,
3394                          item->width + 2 * padding,
3395                          item->height + 2 * padding);
3396     }
3397 }
3398
3399 static void
3400 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
3401                                 cairo_t         *cr)
3402 {
3403   GdkRectangle rect;
3404   GdkColor *fill_color_gdk;
3405   guchar fill_color_alpha;
3406
3407   cairo_save (cr);
3408
3409   rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
3410   rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
3411   rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
3412   rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
3413
3414   gtk_widget_style_get (GTK_WIDGET (icon_view),
3415                         "selection-box-color", &fill_color_gdk,
3416                         "selection-box-alpha", &fill_color_alpha,
3417                         NULL);
3418
3419   if (!fill_color_gdk)
3420     fill_color_gdk = gdk_color_copy (&gtk_widget_get_style (GTK_WIDGET (icon_view))->base[GTK_STATE_SELECTED]);
3421
3422   gdk_cairo_set_source_color (cr, fill_color_gdk);
3423
3424   gdk_cairo_rectangle (cr, &rect);
3425   cairo_clip (cr);
3426
3427   cairo_paint_with_alpha (cr, fill_color_alpha / 255.);
3428
3429   cairo_rectangle (cr, 
3430                    rect.x + 0.5, rect.y + 0.5,
3431                    rect.width - 1, rect.height - 1);
3432   cairo_stroke (cr);
3433
3434   gdk_color_free (fill_color_gdk);
3435
3436   cairo_restore (cr);
3437 }
3438
3439 static void
3440 gtk_icon_view_queue_draw_path (GtkIconView *icon_view,
3441                                GtkTreePath *path)
3442 {
3443   GList *l;
3444   gint index;
3445
3446   index = gtk_tree_path_get_indices (path)[0];
3447
3448   for (l = icon_view->priv->items; l; l = l->next) 
3449     {
3450       GtkIconViewItem *item = l->data;
3451
3452       if (item->index == index)
3453         {
3454           gtk_icon_view_queue_draw_item (icon_view, item);
3455           break;
3456         }
3457     }
3458 }
3459
3460 static void
3461 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
3462                                GtkIconViewItem *item)
3463 {
3464   gint focus_width;
3465   GdkRectangle rect;
3466
3467   gtk_widget_style_get (GTK_WIDGET (icon_view),
3468                         "focus-line-width", &focus_width,
3469                         NULL);
3470
3471   rect.x = item->x - focus_width;
3472   rect.y = item->y - focus_width;
3473   rect.width = item->width + 2 * focus_width;
3474   rect.height = item->height + 2 * focus_width;
3475
3476   if (icon_view->priv->bin_window)
3477     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
3478 }
3479
3480 static gboolean
3481 layout_callback (gpointer user_data)
3482 {
3483   GtkIconView *icon_view;
3484
3485   icon_view = GTK_ICON_VIEW (user_data);
3486   
3487   icon_view->priv->layout_idle_id = 0;
3488
3489   gtk_icon_view_layout (icon_view);
3490   
3491   return FALSE;
3492 }
3493
3494 static void
3495 gtk_icon_view_queue_layout (GtkIconView *icon_view)
3496 {
3497   if (icon_view->priv->layout_idle_id != 0)
3498     return;
3499
3500   icon_view->priv->layout_idle_id =
3501       gdk_threads_add_idle_full (GTK_ICON_VIEW_PRIORITY_LAYOUT,
3502                                  layout_callback, icon_view, NULL);
3503 }
3504
3505 static void
3506 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
3507                                GtkIconViewItem *item,
3508                                gint             cursor_cell)
3509 {
3510   AtkObject *obj;
3511   AtkObject *item_obj;
3512   AtkObject *cursor_item_obj;
3513
3514   if (icon_view->priv->cursor_item == item &&
3515       (cursor_cell < 0 || cursor_cell == icon_view->priv->cursor_cell))
3516     return;
3517
3518   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
3519   if (icon_view->priv->cursor_item != NULL)
3520     {
3521       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
3522       if (obj != NULL)
3523         {
3524           cursor_item_obj = atk_object_ref_accessible_child (obj, icon_view->priv->cursor_item->index);
3525           if (cursor_item_obj != NULL)
3526             atk_object_notify_state_change (cursor_item_obj, ATK_STATE_FOCUSED, FALSE);
3527         }
3528     }
3529   icon_view->priv->cursor_item = item;
3530   if (cursor_cell >= 0)
3531     icon_view->priv->cursor_cell = cursor_cell;
3532
3533   gtk_icon_view_queue_draw_item (icon_view, item);
3534   
3535   /* Notify that accessible focus object has changed */
3536   item_obj = atk_object_ref_accessible_child (obj, item->index);
3537
3538   if (item_obj != NULL)
3539     {
3540       atk_focus_tracker_notify (item_obj);
3541       atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
3542       g_object_unref (item_obj); 
3543     }
3544 }
3545
3546
3547 static GtkIconViewItem *
3548 gtk_icon_view_item_new (void)
3549 {
3550   GtkIconViewItem *item;
3551
3552   item = g_new0 (GtkIconViewItem, 1);
3553
3554   item->width = -1;
3555   item->height = -1;
3556   
3557   return item;
3558 }
3559
3560 static void
3561 gtk_icon_view_item_free (GtkIconViewItem *item)
3562 {
3563   g_return_if_fail (item != NULL);
3564
3565   g_free (item->before);
3566   g_free (item->after);
3567   g_free (item->box);
3568
3569   g_free (item);
3570 }
3571
3572
3573 static GtkIconViewItem *
3574 gtk_icon_view_get_item_at_coords (GtkIconView          *icon_view,
3575                                   gint                  x,
3576                                   gint                  y,
3577                                   gboolean              only_in_cell,
3578                                   GtkIconViewCellInfo **cell_at_pos)
3579 {
3580   GList *items, *l;
3581   GdkRectangle box;
3582
3583   if (cell_at_pos)
3584     *cell_at_pos = NULL;
3585
3586   for (items = icon_view->priv->items; items; items = items->next)
3587     {
3588       GtkIconViewItem *item = items->data;
3589
3590       if (x >= item->x - icon_view->priv->column_spacing/2 && x <= item->x + item->width + icon_view->priv->column_spacing/2 &&
3591           y >= item->y - icon_view->priv->row_spacing/2 && y <= item->y + item->height + icon_view->priv->row_spacing/2)
3592         {
3593           if (only_in_cell || cell_at_pos)
3594             {
3595               gtk_icon_view_set_cell_data (icon_view, item);
3596
3597               for (l = icon_view->priv->cell_list; l; l = l->next)
3598                 {
3599                   GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
3600
3601                   if (!gtk_cell_renderer_get_visible (info->cell))
3602                     continue;
3603
3604                   gtk_icon_view_get_cell_box (icon_view, item, info, &box);
3605
3606                   if ((x >= box.x && x <= box.x + box.width &&
3607                        y >= box.y && y <= box.y + box.height) ||
3608                       (x >= box.x  &&
3609                        x <= box.x + box.width &&
3610                        y >= box.y &&
3611                        y <= box.y + box.height))
3612                     {
3613                       if (cell_at_pos)
3614                         *cell_at_pos = info;
3615
3616                       return item;
3617                     }
3618                 }
3619
3620               if (only_in_cell)
3621                 return NULL;
3622             }
3623
3624           return item;
3625         }
3626     }
3627
3628   return NULL;
3629 }
3630
3631 static void
3632 gtk_icon_view_select_item (GtkIconView      *icon_view,
3633                            GtkIconViewItem  *item)
3634 {
3635   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3636   g_return_if_fail (item != NULL);
3637
3638   if (item->selected)
3639     return;
3640   
3641   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
3642     return;
3643   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3644     gtk_icon_view_unselect_all_internal (icon_view);
3645
3646   item->selected = TRUE;
3647
3648   gtk_icon_view_item_selected_changed (icon_view, item);
3649   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3650
3651   gtk_icon_view_queue_draw_item (icon_view, item);
3652 }
3653
3654
3655 static void
3656 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
3657                              GtkIconViewItem  *item)
3658 {
3659   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3660   g_return_if_fail (item != NULL);
3661
3662   if (!item->selected)
3663     return;
3664   
3665   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
3666       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3667     return;
3668   
3669   item->selected = FALSE;
3670
3671   gtk_icon_view_item_selected_changed (icon_view, item);
3672   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3673
3674   gtk_icon_view_queue_draw_item (icon_view, item);
3675 }
3676
3677 static void
3678 verify_items (GtkIconView *icon_view)
3679 {
3680   GList *items;
3681   int i = 0;
3682
3683   for (items = icon_view->priv->items; items; items = items->next)
3684     {
3685       GtkIconViewItem *item = items->data;
3686
3687       if (item->index != i)
3688         g_error ("List item does not match its index: "
3689                  "item index %d and list index %d\n", item->index, i);
3690
3691       i++;
3692     }
3693 }
3694
3695 static void
3696 gtk_icon_view_row_changed (GtkTreeModel *model,
3697                            GtkTreePath  *path,
3698                            GtkTreeIter  *iter,
3699                            gpointer      data)
3700 {
3701   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3702   GtkIconViewItem *item;
3703   gint index;
3704
3705   /* ignore changes in branches */
3706   if (gtk_tree_path_get_depth (path) > 1)
3707     return;
3708
3709   gtk_icon_view_stop_editing (icon_view, TRUE);
3710   
3711   index = gtk_tree_path_get_indices(path)[0];
3712   item = g_list_nth_data (icon_view->priv->items, index);
3713
3714   gtk_icon_view_item_invalidate_size (item);
3715   gtk_icon_view_queue_layout (icon_view);
3716
3717   verify_items (icon_view);
3718 }
3719
3720 static void
3721 gtk_icon_view_row_inserted (GtkTreeModel *model,
3722                             GtkTreePath  *path,
3723                             GtkTreeIter  *iter,
3724                             gpointer      data)
3725 {
3726   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3727   gint index;
3728   GtkIconViewItem *item;
3729   gboolean iters_persist;
3730   GList *list;
3731
3732   /* ignore changes in branches */
3733   if (gtk_tree_path_get_depth (path) > 1)
3734     return;
3735
3736   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3737   
3738   index = gtk_tree_path_get_indices(path)[0];
3739
3740   item = gtk_icon_view_item_new ();
3741
3742   if (iters_persist)
3743     item->iter = *iter;
3744
3745   item->index = index;
3746
3747   /* FIXME: We can be more efficient here,
3748      we can store a tail pointer and use that when
3749      appending (which is a rather common operation)
3750   */
3751   icon_view->priv->items = g_list_insert (icon_view->priv->items,
3752                                          item, index);
3753   
3754   list = g_list_nth (icon_view->priv->items, index + 1);
3755   for (; list; list = list->next)
3756     {
3757       item = list->data;
3758
3759       item->index++;
3760     }
3761     
3762   verify_items (icon_view);
3763
3764   gtk_icon_view_queue_layout (icon_view);
3765 }
3766
3767 static void
3768 gtk_icon_view_row_deleted (GtkTreeModel *model,
3769                            GtkTreePath  *path,
3770                            gpointer      data)
3771 {
3772   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3773   gint index;
3774   GtkIconViewItem *item;
3775   GList *list, *next;
3776   gboolean emit = FALSE;
3777
3778   /* ignore changes in branches */
3779   if (gtk_tree_path_get_depth (path) > 1)
3780     return;
3781
3782   index = gtk_tree_path_get_indices(path)[0];
3783
3784   list = g_list_nth (icon_view->priv->items, index);
3785   item = list->data;
3786
3787   gtk_icon_view_stop_editing (icon_view, TRUE);
3788
3789   if (item == icon_view->priv->anchor_item)
3790     icon_view->priv->anchor_item = NULL;
3791
3792   if (item == icon_view->priv->cursor_item)
3793     icon_view->priv->cursor_item = NULL;
3794
3795   if (item->selected)
3796     emit = TRUE;
3797   
3798   gtk_icon_view_item_free (item);
3799
3800   for (next = list->next; next; next = next->next)
3801     {
3802       item = next->data;
3803
3804       item->index--;
3805     }
3806   
3807   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
3808
3809   verify_items (icon_view);  
3810   
3811   gtk_icon_view_queue_layout (icon_view);
3812
3813   if (emit)
3814     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3815 }
3816
3817 static void
3818 gtk_icon_view_rows_reordered (GtkTreeModel *model,
3819                               GtkTreePath  *parent,
3820                               GtkTreeIter  *iter,
3821                               gint         *new_order,
3822                               gpointer      data)
3823 {
3824   GtkIconView *icon_view = GTK_ICON_VIEW (data);
3825   int i;
3826   int length;
3827   GList *items = NULL, *list;
3828   GtkIconViewItem **item_array;
3829   gint *order;
3830
3831   /* ignore changes in branches */
3832   if (iter != NULL)
3833     return;
3834
3835   gtk_icon_view_stop_editing (icon_view, TRUE);
3836
3837   length = gtk_tree_model_iter_n_children (model, NULL);
3838
3839   order = g_new (gint, length);
3840   for (i = 0; i < length; i++)
3841     order [new_order[i]] = i;
3842
3843   item_array = g_new (GtkIconViewItem *, length);
3844   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
3845     item_array[order[i]] = list->data;
3846   g_free (order);
3847
3848   for (i = length - 1; i >= 0; i--)
3849     {
3850       item_array[i]->index = i;
3851       items = g_list_prepend (items, item_array[i]);
3852     }
3853   
3854   g_free (item_array);
3855   g_list_free (icon_view->priv->items);
3856   icon_view->priv->items = items;
3857
3858   gtk_icon_view_queue_layout (icon_view);
3859
3860   verify_items (icon_view);  
3861 }
3862
3863 static void
3864 gtk_icon_view_build_items (GtkIconView *icon_view)
3865 {
3866   GtkTreeIter iter;
3867   int i;
3868   gboolean iters_persist;
3869   GList *items = NULL;
3870
3871   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
3872   
3873   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
3874                                       &iter))
3875     return;
3876
3877   i = 0;
3878   
3879   do
3880     {
3881       GtkIconViewItem *item = gtk_icon_view_item_new ();
3882
3883       if (iters_persist)
3884         item->iter = iter;
3885
3886       item->index = i;
3887       
3888       i++;
3889
3890       items = g_list_prepend (items, item);
3891       
3892     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
3893
3894   icon_view->priv->items = g_list_reverse (items);
3895 }
3896
3897 static void
3898 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
3899                                 guint           keyval,
3900                                 guint           modmask,
3901                                 GtkMovementStep step,
3902                                 gint            count)
3903 {
3904   
3905   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
3906                                 I_("move-cursor"), 2,
3907                                 G_TYPE_ENUM, step,
3908                                 G_TYPE_INT, count);
3909
3910   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
3911                                 "move-cursor", 2,
3912                                 G_TYPE_ENUM, step,
3913                                 G_TYPE_INT, count);
3914
3915   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3916    return;
3917
3918   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
3919                                 "move-cursor", 2,
3920                                 G_TYPE_ENUM, step,
3921                                 G_TYPE_INT, count);
3922
3923   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
3924                                 "move-cursor", 2,
3925                                 G_TYPE_ENUM, step,
3926                                 G_TYPE_INT, count);
3927 }
3928
3929 static gboolean
3930 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
3931                                 GtkMovementStep  step,
3932                                 gint             count)
3933 {
3934   GdkModifierType state;
3935
3936   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
3937   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
3938                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
3939                         step == GTK_MOVEMENT_DISPLAY_LINES ||
3940                         step == GTK_MOVEMENT_PAGES ||
3941                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
3942
3943   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
3944     return FALSE;
3945
3946   gtk_icon_view_stop_editing (icon_view, FALSE);
3947   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
3948
3949   if (gtk_get_current_event_state (&state))
3950     {
3951       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3952         icon_view->priv->ctrl_pressed = TRUE;
3953       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3954         icon_view->priv->shift_pressed = TRUE;
3955     }
3956   /* else we assume not pressed */
3957
3958   switch (step)
3959     {
3960     case GTK_MOVEMENT_LOGICAL_POSITIONS:
3961     case GTK_MOVEMENT_VISUAL_POSITIONS:
3962       gtk_icon_view_move_cursor_left_right (icon_view, count);
3963       break;
3964     case GTK_MOVEMENT_DISPLAY_LINES:
3965       gtk_icon_view_move_cursor_up_down (icon_view, count);
3966       break;
3967     case GTK_MOVEMENT_PAGES:
3968       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
3969       break;
3970     case GTK_MOVEMENT_BUFFER_ENDS:
3971       gtk_icon_view_move_cursor_start_end (icon_view, count);
3972       break;
3973     default:
3974       g_assert_not_reached ();
3975     }
3976
3977   icon_view->priv->ctrl_pressed = FALSE;
3978   icon_view->priv->shift_pressed = FALSE;
3979
3980   icon_view->priv->draw_focus = TRUE;
3981
3982   return TRUE;
3983 }
3984
3985 static GtkIconViewItem *
3986 find_item (GtkIconView     *icon_view,
3987            GtkIconViewItem *current,
3988            gint             row_ofs,
3989            gint             col_ofs)
3990 {
3991   gint row, col;
3992   GList *items;
3993   GtkIconViewItem *item;
3994
3995   /* FIXME: this could be more efficient 
3996    */
3997   row = current->row + row_ofs;
3998   col = current->col + col_ofs;
3999
4000   for (items = icon_view->priv->items; items; items = items->next)
4001     {
4002       item = items->data;
4003       if (item->row == row && item->col == col)
4004         return item;
4005     }
4006   
4007   return NULL;
4008 }
4009
4010 static gint
4011 find_cell (GtkIconView     *icon_view,
4012            GtkIconViewItem *item,
4013            gint             cell,
4014            GtkOrientation   orientation,
4015            gint             step,
4016            gint            *count)
4017 {
4018   gint n_focusable;
4019   gint *focusable;
4020   gint current;
4021   gint i, k;
4022   GList *l;
4023
4024   if (icon_view->priv->item_orientation != orientation)
4025     return cell;
4026
4027   gtk_icon_view_set_cell_data (icon_view, item);
4028
4029   focusable = g_new0 (gint, icon_view->priv->n_cells);
4030   n_focusable = 0;
4031
4032   current = 0;
4033   for (k = 0; k < 2; k++)
4034     for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
4035       {
4036         GtkCellRendererMode mode;
4037         GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
4038         
4039         if (info->pack == (k ? GTK_PACK_START : GTK_PACK_END))
4040           continue;
4041         
4042         if (!gtk_cell_renderer_get_visible (info->cell))
4043           continue;
4044
4045         g_object_get (info->cell, "mode", &mode, NULL);
4046         if (mode != GTK_CELL_RENDERER_MODE_INERT)
4047           {
4048             if (cell == i)
4049               current = n_focusable;
4050
4051             focusable[n_focusable] = i;
4052
4053             n_focusable++;
4054           }
4055       }
4056   
4057   if (n_focusable == 0)
4058     {
4059       g_free (focusable);
4060       return -1;
4061     }
4062
4063   if (cell < 0)
4064     {
4065       current = step > 0 ? 0 : n_focusable - 1;
4066       cell = focusable[current];
4067     }
4068
4069   if (current + *count < 0)
4070     {
4071       cell = -1;
4072       *count = current + *count;
4073     }
4074   else if (current + *count > n_focusable - 1)
4075     {
4076       cell = -1;
4077       *count = current + *count - (n_focusable - 1);
4078     }
4079   else
4080     {
4081       cell = focusable[current + *count];
4082       *count = 0;
4083     }
4084   
4085   g_free (focusable);
4086   
4087   return cell;
4088 }
4089
4090 static GtkIconViewItem *
4091 find_item_page_up_down (GtkIconView     *icon_view,
4092                         GtkIconViewItem *current,
4093                         gint             count)
4094 {
4095   GList *item, *next;
4096   gint y, col;
4097   
4098   col = current->col;
4099   y = current->y + count * icon_view->priv->vadjustment->page_size;
4100
4101   item = g_list_find (icon_view->priv->items, current);
4102   if (count > 0)
4103     {
4104       while (item)
4105         {
4106           for (next = item->next; next; next = next->next)
4107             {
4108               if (((GtkIconViewItem *)next->data)->col == col)
4109                 break;
4110             }
4111           if (!next || ((GtkIconViewItem *)next->data)->y > y)
4112             break;
4113
4114           item = next;
4115         }
4116     }
4117   else 
4118     {
4119       while (item)
4120         {
4121           for (next = item->prev; next; next = next->prev)
4122             {
4123               if (((GtkIconViewItem *)next->data)->col == col)
4124                 break;
4125             }
4126           if (!next || ((GtkIconViewItem *)next->data)->y < y)
4127             break;
4128
4129           item = next;
4130         }
4131     }
4132
4133   if (item)
4134     return item->data;
4135
4136   return NULL;
4137 }
4138
4139 static gboolean
4140 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
4141                                   GtkIconViewItem *anchor,
4142                                   GtkIconViewItem *cursor)
4143 {
4144   GList *items;
4145   GtkIconViewItem *item;
4146   gint row1, row2, col1, col2;
4147   gboolean dirty = FALSE;
4148   
4149   if (anchor->row < cursor->row)
4150     {
4151       row1 = anchor->row;
4152       row2 = cursor->row;
4153     }
4154   else
4155     {
4156       row1 = cursor->row;
4157       row2 = anchor->row;
4158     }
4159
4160   if (anchor->col < cursor->col)
4161     {
4162       col1 = anchor->col;
4163       col2 = cursor->col;
4164     }
4165   else
4166     {
4167       col1 = cursor->col;
4168       col2 = anchor->col;
4169     }
4170
4171   for (items = icon_view->priv->items; items; items = items->next)
4172     {
4173       item = items->data;
4174
4175       if (row1 <= item->row && item->row <= row2 &&
4176           col1 <= item->col && item->col <= col2)
4177         {
4178           if (!item->selected)
4179             {
4180               dirty = TRUE;
4181               item->selected = TRUE;
4182               gtk_icon_view_item_selected_changed (icon_view, item);
4183             }
4184           gtk_icon_view_queue_draw_item (icon_view, item);
4185         }
4186     }
4187
4188   return dirty;
4189 }
4190
4191 static void 
4192 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
4193                                    gint         count)
4194 {
4195   GtkIconViewItem *item;
4196   gint cell;
4197   gboolean dirty = FALSE;
4198   gint step;
4199   GtkDirectionType direction;
4200
4201   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
4202     return;
4203
4204   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
4205
4206   if (!icon_view->priv->cursor_item)
4207     {
4208       GList *list;
4209
4210       if (count > 0)
4211         list = icon_view->priv->items;
4212       else
4213         list = g_list_last (icon_view->priv->items);
4214
4215       item = list ? list->data : NULL;
4216       cell = -1;
4217     }
4218   else
4219     {
4220       item = icon_view->priv->cursor_item;
4221       cell = icon_view->priv->cursor_cell;
4222       step = count > 0 ? 1 : -1;      
4223       while (item)
4224         {
4225           cell = find_cell (icon_view, item, cell,
4226                             GTK_ORIENTATION_VERTICAL, 
4227                             step, &count);
4228           if (count == 0)
4229             break;
4230
4231           item = find_item (icon_view, item, step, 0);
4232           count = count - step;
4233         }
4234     }
4235
4236   if (!item)
4237     {
4238       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
4239         {
4240           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
4241           if (toplevel)
4242             gtk_widget_child_focus (toplevel,
4243                                     direction == GTK_DIR_UP ?
4244                                     GTK_DIR_TAB_BACKWARD :
4245                                     GTK_DIR_TAB_FORWARD);
4246         }
4247
4248       return;
4249     }
4250
4251   if (icon_view->priv->ctrl_pressed ||
4252       !icon_view->priv->shift_pressed ||
4253       !icon_view->priv->anchor_item ||
4254       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4255     icon_view->priv->anchor_item = item;
4256
4257   gtk_icon_view_set_cursor_item (icon_view, item, cell);
4258
4259   if (!icon_view->priv->ctrl_pressed &&
4260       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4261     {
4262       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4263       dirty = gtk_icon_view_select_all_between (icon_view, 
4264                                                 icon_view->priv->anchor_item,
4265                                                 item) || dirty;
4266     }
4267
4268   gtk_icon_view_scroll_to_item (icon_view, item);
4269
4270   if (dirty)
4271     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
4272 }
4273
4274 static void 
4275 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
4276                                         gint         count)
4277 {
4278   GtkIconViewItem *item;
4279   gboolean dirty = FALSE;
4280   
4281   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
4282     return;
4283   
4284   if (!icon_view->priv->cursor_item)
4285     {
4286       GList *list;
4287
4288       if (count > 0)
4289         list = icon_view->priv->items;
4290       else
4291         list = g_list_last (icon_view->priv->items);
4292
4293       item = list ? list->data : NULL;
4294     }
4295   else
4296     item = find_item_page_up_down (icon_view, 
4297                                    icon_view->priv->cursor_item,
4298                                    count);
4299
4300   if (item == icon_view->priv->cursor_item)
4301     gtk_widget_error_bell (GTK_WIDGET (icon_view));
4302
4303   if (!item)
4304     return;
4305
4306   if (icon_view->priv->ctrl_pressed ||
4307       !icon_view->priv->shift_pressed ||
4308       !icon_view->priv->anchor_item ||
4309       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4310     icon_view->priv->anchor_item = item;
4311
4312   gtk_icon_view_set_cursor_item (icon_view, item, -1);
4313
4314   if (!icon_view->priv->ctrl_pressed &&
4315       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4316     {
4317       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4318       dirty = gtk_icon_view_select_all_between (icon_view, 
4319                                                 icon_view->priv->anchor_item,
4320                                                 item) || dirty;
4321     }
4322
4323   gtk_icon_view_scroll_to_item (icon_view, item);
4324
4325   if (dirty)
4326     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
4327 }
4328
4329 static void 
4330 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
4331                                       gint         count)
4332 {
4333   GtkIconViewItem *item;
4334   gint cell = -1;
4335   gboolean dirty = FALSE;
4336   gint step;
4337   GtkDirectionType direction;
4338
4339   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
4340     return;
4341
4342   direction = count < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
4343
4344   if (!icon_view->priv->cursor_item)
4345     {
4346       GList *list;
4347
4348       if (count > 0)
4349         list = icon_view->priv->items;
4350       else
4351         list = g_list_last (icon_view->priv->items);
4352
4353       item = list ? list->data : NULL;
4354     }
4355   else
4356     {
4357       item = icon_view->priv->cursor_item;
4358       cell = icon_view->priv->cursor_cell;
4359       step = count > 0 ? 1 : -1;
4360       while (item)
4361         {
4362           cell = find_cell (icon_view, item, cell,
4363                             GTK_ORIENTATION_HORIZONTAL, 
4364                             step, &count);
4365           if (count == 0)
4366             break;
4367           
4368           item = find_item (icon_view, item, 0, step);
4369           count = count - step;
4370         }
4371     }
4372
4373   if (!item)
4374     {
4375       if (!gtk_widget_keynav_failed (GTK_WIDGET (icon_view), direction))
4376         {
4377           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (icon_view));
4378           if (toplevel)
4379             gtk_widget_child_focus (toplevel,
4380                                     direction == GTK_DIR_LEFT ?
4381                                     GTK_DIR_TAB_BACKWARD :
4382                                     GTK_DIR_TAB_FORWARD);
4383         }
4384
4385       return;
4386     }
4387
4388   if (icon_view->priv->ctrl_pressed ||
4389       !icon_view->priv->shift_pressed ||
4390       !icon_view->priv->anchor_item ||
4391       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4392     icon_view->priv->anchor_item = item;
4393
4394   gtk_icon_view_set_cursor_item (icon_view, item, cell);
4395
4396   if (!icon_view->priv->ctrl_pressed &&
4397       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4398     {
4399       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4400       dirty = gtk_icon_view_select_all_between (icon_view, 
4401                                                 icon_view->priv->anchor_item,
4402                                                 item) || dirty;
4403     }
4404
4405   gtk_icon_view_scroll_to_item (icon_view, item);
4406
4407   if (dirty)
4408     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
4409 }
4410
4411 static void 
4412 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
4413                                      gint         count)
4414 {
4415   GtkIconViewItem *item;
4416   GList *list;
4417   gboolean dirty = FALSE;
4418   
4419   if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
4420     return;
4421   
4422   if (count < 0)
4423     list = icon_view->priv->items;
4424   else
4425     list = g_list_last (icon_view->priv->items);
4426   
4427   item = list ? list->data : NULL;
4428
4429   if (item == icon_view->priv->cursor_item)
4430     gtk_widget_error_bell (GTK_WIDGET (icon_view));
4431
4432   if (!item)
4433     return;
4434
4435   if (icon_view->priv->ctrl_pressed ||
4436       !icon_view->priv->shift_pressed ||
4437       !icon_view->priv->anchor_item ||
4438       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
4439     icon_view->priv->anchor_item = item;
4440
4441   gtk_icon_view_set_cursor_item (icon_view, item, -1);
4442
4443   if (!icon_view->priv->ctrl_pressed &&
4444       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
4445     {
4446       dirty = gtk_icon_view_unselect_all_internal (icon_view);
4447       dirty = gtk_icon_view_select_all_between (icon_view, 
4448                                                 icon_view->priv->anchor_item,
4449                                                 item) || dirty;
4450     }
4451
4452   gtk_icon_view_scroll_to_item (icon_view, item);
4453
4454   if (dirty)
4455     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
4456 }
4457
4458 /**
4459  * gtk_icon_view_scroll_to_path:
4460  * @icon_view: A #GtkIconView.
4461  * @path: The path of the item to move to.
4462  * @use_align: whether to use alignment arguments, or %FALSE.
4463  * @row_align: The vertical alignment of the item specified by @path.
4464  * @col_align: The horizontal alignment of the item specified by @path.
4465  *
4466  * Moves the alignments of @icon_view to the position specified by @path.  
4467  * @row_align determines where the row is placed, and @col_align determines 
4468  * where @column is placed.  Both are expected to be between 0.0 and 1.0. 
4469  * 0.0 means left/top alignment, 1.0 means right/bottom alignment, 0.5 means 
4470  * center.
4471  *
4472  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
4473  * tree does the minimum amount of work to scroll the item onto the screen.
4474  * This means that the item will be scrolled to the edge closest to its current
4475  * position.  If the item is currently visible on the screen, nothing is done.
4476  *
4477  * This function only works if the model is set, and @path is a valid row on 
4478  * the model. If the model changes before the @icon_view is realized, the 
4479  * centered path will be modified to reflect this change.
4480  *
4481  * Since: 2.8
4482  **/
4483 void
4484 gtk_icon_view_scroll_to_path (GtkIconView *icon_view,
4485                               GtkTreePath *path,
4486                               gboolean     use_align,
4487                               gfloat       row_align,
4488                               gfloat       col_align)
4489 {
4490   GtkIconViewItem *item = NULL;
4491   GtkWidget *widget;
4492
4493   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4494   g_return_if_fail (path != NULL);
4495   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
4496   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
4497
4498   widget = GTK_WIDGET (icon_view);
4499
4500   if (gtk_tree_path_get_depth (path) > 0)
4501     item = g_list_nth_data (icon_view->priv->items,
4502                             gtk_tree_path_get_indices(path)[0]);
4503   
4504   if (!item || item->width < 0 ||
4505       !gtk_widget_get_realized (widget))
4506     {
4507       if (icon_view->priv->scroll_to_path)
4508         gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
4509
4510       icon_view->priv->scroll_to_path = NULL;
4511
4512       if (path)
4513         icon_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), icon_view->priv->model, path);
4514
4515       icon_view->priv->scroll_to_use_align = use_align;
4516       icon_view->priv->scroll_to_row_align = row_align;
4517       icon_view->priv->scroll_to_col_align = col_align;
4518
4519       return;
4520     }
4521
4522   if (use_align)
4523     {
4524       GtkAllocation allocation;
4525       gint x, y;
4526       gint focus_width;
4527       gfloat offset;
4528
4529       gtk_widget_style_get (widget,
4530                             "focus-line-width", &focus_width,
4531                             NULL);
4532       
4533       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4534
4535       gtk_widget_get_allocation (widget, &allocation);
4536
4537       offset = y + item->y - focus_width - row_align * (allocation.height - item->height);
4538
4539       gtk_adjustment_set_value (icon_view->priv->vadjustment,
4540                                 icon_view->priv->vadjustment->value + offset);
4541
4542       offset = x + item->x - focus_width - col_align * (allocation.width - item->width);
4543
4544       gtk_adjustment_set_value (icon_view->priv->hadjustment,
4545                                 icon_view->priv->hadjustment->value + offset);
4546
4547       gtk_adjustment_changed (icon_view->priv->hadjustment);
4548       gtk_adjustment_changed (icon_view->priv->vadjustment);
4549     }
4550   else
4551     gtk_icon_view_scroll_to_item (icon_view, item);
4552 }
4553
4554
4555 static void     
4556 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view, 
4557                               GtkIconViewItem *item)
4558 {
4559   GtkAllocation allocation;
4560   GtkWidget *widget = GTK_WIDGET (icon_view);
4561   gint x, y, width, height;
4562   gint focus_width;
4563
4564   gtk_widget_style_get (widget,
4565                         "focus-line-width", &focus_width,
4566                         NULL);
4567
4568   width = gdk_window_get_width (icon_view->priv->bin_window);
4569   height = gdk_window_get_height (icon_view->priv->bin_window);
4570   gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4571
4572   gtk_widget_get_allocation (widget, &allocation);
4573
4574   if (y + item->y - focus_width < 0)
4575     gtk_adjustment_set_value (icon_view->priv->vadjustment, 
4576                               icon_view->priv->vadjustment->value + y + item->y - focus_width);
4577   else if (y + item->y + item->height + focus_width > allocation.height)
4578     gtk_adjustment_set_value (icon_view->priv->vadjustment, 
4579                               icon_view->priv->vadjustment->value + y + item->y + item->height 
4580                               + focus_width - allocation.height);
4581
4582   if (x + item->x - focus_width < 0)
4583     gtk_adjustment_set_value (icon_view->priv->hadjustment, 
4584                               icon_view->priv->hadjustment->value + x + item->x - focus_width);
4585   else if (x + item->x + item->width + focus_width > allocation.width)
4586     gtk_adjustment_set_value (icon_view->priv->hadjustment, 
4587                               icon_view->priv->hadjustment->value + x + item->x + item->width 
4588                               + focus_width - allocation.width);
4589
4590   gtk_adjustment_changed (icon_view->priv->hadjustment);
4591   gtk_adjustment_changed (icon_view->priv->vadjustment);
4592 }
4593
4594 /* GtkCellLayout implementation */
4595 static GtkIconViewCellInfo *
4596 gtk_icon_view_get_cell_info (GtkIconView     *icon_view,
4597                              GtkCellRenderer *renderer)
4598 {
4599   GList *i;
4600
4601   for (i = icon_view->priv->cell_list; i; i = i->next)
4602     {
4603       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)i->data;
4604
4605       if (info->cell == renderer)
4606         return info;
4607     }
4608
4609   return NULL;
4610 }
4611
4612 static void
4613 gtk_icon_view_set_cell_data (GtkIconView     *icon_view, 
4614                              GtkIconViewItem *item)
4615 {
4616   GList *i;
4617   gboolean iters_persist;
4618   GtkTreeIter iter;
4619   
4620   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
4621   
4622   if (!iters_persist)
4623     {
4624       GtkTreePath *path;
4625
4626       path = gtk_tree_path_new_from_indices (item->index, -1);
4627       if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
4628         return;
4629       gtk_tree_path_free (path);
4630     }
4631   else
4632     iter = item->iter;
4633   
4634   for (i = icon_view->priv->cell_list; i; i = i->next)
4635     {
4636       GSList *j;
4637       GtkIconViewCellInfo *info = i->data;
4638
4639       g_object_freeze_notify (G_OBJECT (info->cell));
4640
4641       for (j = info->attributes; j && j->next; j = j->next->next)
4642         {
4643           gchar *property = j->data;
4644           gint column = GPOINTER_TO_INT (j->next->data);
4645           GValue value = {0, };
4646
4647           gtk_tree_model_get_value (icon_view->priv->model, &iter,
4648                                     column, &value);
4649           g_object_set_property (G_OBJECT (info->cell),
4650                                  property, &value);
4651           g_value_unset (&value);
4652         }
4653
4654       if (info->func)
4655         (* info->func) (GTK_CELL_LAYOUT (icon_view),
4656                         info->cell,
4657                         icon_view->priv->model,
4658                         &iter,
4659                         info->func_data);
4660       
4661       g_object_thaw_notify (G_OBJECT (info->cell));
4662     }  
4663 }
4664
4665 static void 
4666 free_cell_attributes (GtkIconViewCellInfo *info)
4667
4668   GSList *list;
4669
4670   list = info->attributes;
4671   while (list && list->next)
4672     {
4673       g_free (list->data);
4674       list = list->next->next;
4675     }
4676   
4677   g_slist_free (info->attributes);
4678   info->attributes = NULL;
4679 }
4680
4681 static void
4682 free_cell_info (GtkIconViewCellInfo *info)
4683 {
4684   free_cell_attributes (info);
4685
4686   g_object_unref (info->cell);
4687   
4688   if (info->destroy)
4689     (* info->destroy) (info->func_data);
4690
4691   g_free (info);
4692 }
4693
4694 static void
4695 gtk_icon_view_cell_layout_pack_start (GtkCellLayout   *layout,
4696                                       GtkCellRenderer *renderer,
4697                                       gboolean         expand)
4698 {
4699   GtkIconViewCellInfo *info;
4700   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4701
4702   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
4703   g_return_if_fail (!gtk_icon_view_get_cell_info (icon_view, renderer));
4704
4705   g_object_ref_sink (renderer);
4706
4707   info = g_new0 (GtkIconViewCellInfo, 1);
4708   info->cell = renderer;
4709   info->expand = expand ? TRUE : FALSE;
4710   info->pack = GTK_PACK_START;
4711   info->position = icon_view->priv->n_cells;
4712   
4713   icon_view->priv->cell_list = g_list_append (icon_view->priv->cell_list, info);
4714   icon_view->priv->n_cells++;
4715 }
4716
4717 static void
4718 gtk_icon_view_cell_layout_pack_end (GtkCellLayout   *layout,
4719                                     GtkCellRenderer *renderer,
4720                                     gboolean         expand)
4721 {
4722   GtkIconViewCellInfo *info;
4723   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4724
4725   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
4726   g_return_if_fail (!gtk_icon_view_get_cell_info (icon_view, renderer));
4727
4728   g_object_ref_sink (renderer);
4729
4730   info = g_new0 (GtkIconViewCellInfo, 1);
4731   info->cell = renderer;
4732   info->expand = expand ? TRUE : FALSE;
4733   info->pack = GTK_PACK_END;
4734   info->position = icon_view->priv->n_cells;
4735
4736   icon_view->priv->cell_list = g_list_append (icon_view->priv->cell_list, info);
4737   icon_view->priv->n_cells++;
4738 }
4739
4740 static void
4741 gtk_icon_view_cell_layout_add_attribute (GtkCellLayout   *layout,
4742                                          GtkCellRenderer *renderer,
4743                                          const gchar     *attribute,
4744                                          gint             column)
4745 {
4746   GtkIconViewCellInfo *info;
4747   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4748
4749   info = gtk_icon_view_get_cell_info (icon_view, renderer);
4750   g_return_if_fail (info != NULL);
4751
4752   info->attributes = g_slist_prepend (info->attributes,
4753                                       GINT_TO_POINTER (column));
4754   info->attributes = g_slist_prepend (info->attributes,
4755                                       g_strdup (attribute));
4756 }
4757
4758 static void
4759 gtk_icon_view_cell_layout_clear (GtkCellLayout *layout)
4760 {
4761   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4762
4763   while (icon_view->priv->cell_list)
4764     {
4765       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)icon_view->priv->cell_list->data;
4766       free_cell_info (info);
4767       icon_view->priv->cell_list = g_list_delete_link (icon_view->priv->cell_list, 
4768                                                        icon_view->priv->cell_list);
4769     }
4770
4771   icon_view->priv->n_cells = 0;
4772 }
4773
4774 static void
4775 gtk_icon_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
4776                                               GtkCellRenderer       *cell,
4777                                               GtkCellLayoutDataFunc  func,
4778                                               gpointer               func_data,
4779                                               GDestroyNotify         destroy)
4780 {
4781   GtkIconViewCellInfo *info;
4782   GtkIconView *icon_view = GTK_ICON_VIEW (layout);
4783
4784   info = gtk_icon_view_get_cell_info (icon_view, cell);
4785   g_return_if_fail (info != NULL);
4786
4787   if (info->destroy)
4788     {
4789       GDestroyNotify d = info->destroy;
4790
4791       info->destroy = NULL;
4792       d (info->func_data);
4793     }
4794
4795   info->func = func;
4796   info->func_data = func_data;
4797   info->destroy = destroy;
4798 }
4799
4800 static void
4801 gtk_icon_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
4802                                             GtkCellRenderer *renderer)
4803 {
4804   GtkIconViewCellInfo *info;
4805
4806   info = gtk_icon_view_get_cell_info (GTK_ICON_VIEW (layout), renderer);
4807   if (info != NULL)
4808     free_cell_attributes (info);
4809 }
4810
4811 static void
4812 gtk_icon_view_cell_layout_reorder (GtkCellLayout   *layout,
4813                                    GtkCellRenderer *cell,
4814                                    gint             position)
4815 {
4816   GtkIconView *icon_view;
4817   GList *link, *l;
4818   GtkIconViewCellInfo *info;
4819   gint i;
4820
4821   icon_view = GTK_ICON_VIEW (layout);
4822
4823   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
4824
4825   info = gtk_icon_view_get_cell_info (icon_view, cell);
4826
4827   g_return_if_fail (info != NULL);
4828   g_return_if_fail (position >= 0);
4829
4830   link = g_list_find (icon_view->priv->cell_list, info);
4831
4832   g_return_if_fail (link != NULL);
4833
4834   icon_view->priv->cell_list = g_list_delete_link (icon_view->priv->cell_list,
4835                                                    link);
4836   icon_view->priv->cell_list = g_list_insert (icon_view->priv->cell_list,
4837                                              info, position);
4838
4839   for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
4840     {
4841       info = l->data;
4842
4843       info->position = i;
4844     }
4845
4846   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
4847 }
4848
4849 static GList *
4850 gtk_icon_view_cell_layout_get_cells (GtkCellLayout *layout)
4851 {
4852   GtkIconView *icon_view = (GtkIconView *)layout;
4853   GList *retval = NULL, *l;
4854
4855   for (l = icon_view->priv->cell_list; l; l = l->next)
4856     {
4857       GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
4858
4859       retval = g_list_prepend (retval, info->cell);
4860     }
4861
4862   return g_list_reverse (retval);
4863 }
4864
4865 /* Public API */
4866
4867
4868 /**
4869  * gtk_icon_view_new:
4870  * 
4871  * Creates a new #GtkIconView widget
4872  * 
4873  * Return value: A newly created #GtkIconView widget
4874  *
4875  * Since: 2.6
4876  **/
4877 GtkWidget *
4878 gtk_icon_view_new (void)
4879 {
4880   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
4881 }
4882
4883 /**
4884  * gtk_icon_view_new_with_model:
4885  * @model: The model.
4886  * 
4887  * Creates a new #GtkIconView widget with the model @model.
4888  * 
4889  * Return value: A newly created #GtkIconView widget.
4890  *
4891  * Since: 2.6 
4892  **/
4893 GtkWidget *
4894 gtk_icon_view_new_with_model (GtkTreeModel *model)
4895 {
4896   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
4897 }
4898
4899 /**
4900  * gtk_icon_view_convert_widget_to_bin_window_coords:
4901  * @icon_view: a #GtkIconView 
4902  * @wx: X coordinate relative to the widget
4903  * @wy: Y coordinate relative to the widget
4904  * @bx: return location for bin_window X coordinate
4905  * @by: return location for bin_window Y coordinate
4906  * 
4907  * Converts widget coordinates to coordinates for the bin_window,
4908  * as expected by e.g. gtk_icon_view_get_path_at_pos(). 
4909  *
4910  * Since: 2.12
4911  */
4912 void
4913 gtk_icon_view_convert_widget_to_bin_window_coords (GtkIconView *icon_view,
4914                                                    gint         wx,
4915                                                    gint         wy, 
4916                                                    gint        *bx,
4917                                                    gint        *by)
4918 {
4919   gint x, y;
4920
4921   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
4922
4923   if (icon_view->priv->bin_window) 
4924     gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
4925   else
4926     x = y = 0;
4927  
4928   if (bx)
4929     *bx = wx - x;
4930   if (by)
4931     *by = wy - y;
4932 }
4933
4934 /**
4935  * gtk_icon_view_get_path_at_pos:
4936  * @icon_view: A #GtkIconView.
4937  * @x: The x position to be identified
4938  * @y: The y position to be identified
4939  * 
4940  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4941  * See gtk_icon_view_get_item_at_pos(), if you are also interested in
4942  * the cell at the specified position. 
4943  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4944  * widget coordinates to bin_window coordinates.
4945  * 
4946  * Return value: The #GtkTreePath corresponding to the icon or %NULL
4947  * if no icon exists at that position.
4948  *
4949  * Since: 2.6 
4950  **/
4951 GtkTreePath *
4952 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
4953                                gint         x,
4954                                gint         y)
4955 {
4956   GtkIconViewItem *item;
4957   GtkTreePath *path;
4958   
4959   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
4960
4961   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
4962
4963   if (!item)
4964     return NULL;
4965
4966   path = gtk_tree_path_new_from_indices (item->index, -1);
4967
4968   return path;
4969 }
4970
4971 /**
4972  * gtk_icon_view_get_item_at_pos:
4973  * @icon_view: A #GtkIconView.
4974  * @x: The x position to be identified
4975  * @y: The y position to be identified
4976  * @path: (allow-none): Return location for the path, or %NULL
4977  * @cell: Return location for the renderer responsible for the cell
4978  *   at (@x, @y), or %NULL
4979  * 
4980  * Finds the path at the point (@x, @y), relative to bin_window coordinates.
4981  * In contrast to gtk_icon_view_get_path_at_pos(), this function also 
4982  * obtains the cell at the specified position. The returned path should
4983  * be freed with gtk_tree_path_free().
4984  * See gtk_icon_view_convert_widget_to_bin_window_coords() for converting
4985  * widget coordinates to bin_window coordinates.
4986  * 
4987  * Return value: %TRUE if an item exists at the specified position
4988  *
4989  * Since: 2.8
4990  **/
4991 gboolean 
4992 gtk_icon_view_get_item_at_pos (GtkIconView      *icon_view,
4993                                gint              x,
4994                                gint              y,
4995                                GtkTreePath     **path,
4996                                GtkCellRenderer **cell)
4997 {
4998   GtkIconViewItem *item;
4999   GtkIconViewCellInfo *info;
5000   
5001   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5002
5003   item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, &info);
5004
5005   if (path != NULL)
5006     {
5007       if (item != NULL)
5008         *path = gtk_tree_path_new_from_indices (item->index, -1);
5009       else
5010         *path = NULL;
5011     }
5012
5013   if (cell != NULL)
5014     {
5015       if (info != NULL)
5016         *cell = info->cell;
5017       else 
5018         *cell = NULL;
5019     }
5020
5021   return (item != NULL);
5022 }
5023
5024 /**
5025  * gtk_icon_view_set_tooltip_item:
5026  * @icon_view: a #GtkIconView
5027  * @tooltip: a #GtkTooltip
5028  * @path: a #GtkTreePath
5029  * 
5030  * Sets the tip area of @tooltip to be the area covered by the item at @path.
5031  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
5032  * See also gtk_tooltip_set_tip_area().
5033  * 
5034  * Since: 2.12
5035  */
5036 void 
5037 gtk_icon_view_set_tooltip_item (GtkIconView     *icon_view,
5038                                 GtkTooltip      *tooltip,
5039                                 GtkTreePath     *path)
5040 {
5041   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5042   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
5043
5044   gtk_icon_view_set_tooltip_cell (icon_view, tooltip, path, NULL);
5045 }
5046
5047 /**
5048  * gtk_icon_view_set_tooltip_cell:
5049  * @icon_view: a #GtkIconView
5050  * @tooltip: a #GtkTooltip
5051  * @path: a #GtkTreePath
5052  * @cell: (allow-none): a #GtkCellRenderer or %NULL
5053  *
5054  * Sets the tip area of @tooltip to the area which @cell occupies in
5055  * the item pointed to by @path. See also gtk_tooltip_set_tip_area().
5056  *
5057  * See also gtk_icon_view_set_tooltip_column() for a simpler alternative.
5058  *
5059  * Since: 2.12
5060  */
5061 void
5062 gtk_icon_view_set_tooltip_cell (GtkIconView     *icon_view,
5063                                 GtkTooltip      *tooltip,
5064                                 GtkTreePath     *path,
5065                                 GtkCellRenderer *cell)
5066 {
5067   GdkRectangle rect;
5068   GtkIconViewItem *item = NULL;
5069   GtkIconViewCellInfo *info = NULL;
5070   gint x, y;
5071  
5072   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5073   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
5074   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
5075
5076   if (gtk_tree_path_get_depth (path) > 0)
5077     item = g_list_nth_data (icon_view->priv->items,
5078                             gtk_tree_path_get_indices(path)[0]);
5079  
5080   if (!item)
5081     return;
5082
5083   if (cell)
5084     {
5085       info = gtk_icon_view_get_cell_info (icon_view, cell);
5086       gtk_icon_view_get_cell_area (icon_view, item, info, &rect);
5087     }
5088   else
5089     {
5090       rect.x = item->x;
5091       rect.y = item->y;
5092       rect.width = item->width;
5093       rect.height = item->height;
5094     }
5095   
5096   if (icon_view->priv->bin_window)
5097     {
5098       gdk_window_get_position (icon_view->priv->bin_window, &x, &y);
5099       rect.x += x;
5100       rect.y += y; 
5101     }
5102
5103   gtk_tooltip_set_tip_area (tooltip, &rect); 
5104 }
5105
5106
5107 /**
5108  * gtk_icon_view_get_tooltip_context:
5109  * @icon_view: an #GtkIconView
5110  * @x: the x coordinate (relative to widget coordinates)
5111  * @y: the y coordinate (relative to widget coordinates)
5112  * @keyboard_tip: whether this is a keyboard tooltip or not
5113  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
5114  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
5115  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
5116  *
5117  * This function is supposed to be used in a #GtkWidget::query-tooltip
5118  * signal handler for #GtkIconView.  The @x, @y and @keyboard_tip values
5119  * which are received in the signal handler, should be passed to this
5120  * function without modification.
5121  *
5122  * The return value indicates whether there is an icon view item at the given
5123  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
5124  * tooltips the item returned will be the cursor item. When %TRUE, then any of
5125  * @model, @path and @iter which have been provided will be set to point to
5126  * that row and the corresponding model. @x and @y will always be converted
5127  * to be relative to @icon_view's bin_window if @keyboard_tooltip is %FALSE.
5128  *
5129  * Return value: whether or not the given tooltip context points to a item
5130  *
5131  * Since: 2.12
5132  */
5133 gboolean
5134 gtk_icon_view_get_tooltip_context (GtkIconView   *icon_view,
5135                                    gint          *x,
5136                                    gint          *y,
5137                                    gboolean       keyboard_tip,
5138                                    GtkTreeModel **model,
5139                                    GtkTreePath  **path,
5140                                    GtkTreeIter   *iter)
5141 {
5142   GtkTreePath *tmppath = NULL;
5143
5144   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5145   g_return_val_if_fail (x != NULL, FALSE);
5146   g_return_val_if_fail (y != NULL, FALSE);
5147
5148   if (keyboard_tip)
5149     {
5150       gtk_icon_view_get_cursor (icon_view, &tmppath, NULL);
5151
5152       if (!tmppath)
5153         return FALSE;
5154     }
5155   else
5156     {
5157       gtk_icon_view_convert_widget_to_bin_window_coords (icon_view, *x, *y,
5158                                                          x, y);
5159
5160       if (!gtk_icon_view_get_item_at_pos (icon_view, *x, *y, &tmppath, NULL))
5161         return FALSE;
5162     }
5163
5164   if (model)
5165     *model = gtk_icon_view_get_model (icon_view);
5166
5167   if (iter)
5168     gtk_tree_model_get_iter (gtk_icon_view_get_model (icon_view),
5169                              iter, tmppath);
5170
5171   if (path)
5172     *path = tmppath;
5173   else
5174     gtk_tree_path_free (tmppath);
5175
5176   return TRUE;
5177 }
5178
5179 static gboolean
5180 gtk_icon_view_set_tooltip_query_cb (GtkWidget  *widget,
5181                                     gint        x,
5182                                     gint        y,
5183                                     gboolean    keyboard_tip,
5184                                     GtkTooltip *tooltip,
5185                                     gpointer    data)
5186 {
5187   gchar *str;
5188   GtkTreeIter iter;
5189   GtkTreePath *path;
5190   GtkTreeModel *model;
5191   GtkIconView *icon_view = GTK_ICON_VIEW (widget);
5192
5193   if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (widget),
5194                                           &x, &y,
5195                                           keyboard_tip,
5196                                           &model, &path, &iter))
5197     return FALSE;
5198
5199   gtk_tree_model_get (model, &iter, icon_view->priv->tooltip_column, &str, -1);
5200
5201   if (!str)
5202     {
5203       gtk_tree_path_free (path);
5204       return FALSE;
5205     }
5206
5207   gtk_tooltip_set_markup (tooltip, str);
5208   gtk_icon_view_set_tooltip_item (icon_view, tooltip, path);
5209
5210   gtk_tree_path_free (path);
5211   g_free (str);
5212
5213   return TRUE;
5214 }
5215
5216
5217 /**
5218  * gtk_icon_view_set_tooltip_column:
5219  * @icon_view: a #GtkIconView
5220  * @column: an integer, which is a valid column number for @icon_view's model
5221  *
5222  * If you only plan to have simple (text-only) tooltips on full items, you
5223  * can use this function to have #GtkIconView handle these automatically
5224  * for you. @column should be set to the column in @icon_view's model
5225  * containing the tooltip texts, or -1 to disable this feature.
5226  *
5227  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
5228  * @icon_view will connect a #GtkWidget::query-tooltip signal handler.
5229  *
5230  * Since: 2.12
5231  */
5232 void
5233 gtk_icon_view_set_tooltip_column (GtkIconView *icon_view,
5234                                   gint         column)
5235 {
5236   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5237
5238   if (column == icon_view->priv->tooltip_column)
5239     return;
5240
5241   if (column == -1)
5242     {
5243       g_signal_handlers_disconnect_by_func (icon_view,
5244                                             gtk_icon_view_set_tooltip_query_cb,
5245                                             NULL);
5246       gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), FALSE);
5247     }
5248   else
5249     {
5250       if (icon_view->priv->tooltip_column == -1)
5251         {
5252           g_signal_connect (icon_view, "query-tooltip",
5253                             G_CALLBACK (gtk_icon_view_set_tooltip_query_cb), NULL);
5254           gtk_widget_set_has_tooltip (GTK_WIDGET (icon_view), TRUE);
5255         }
5256     }
5257
5258   icon_view->priv->tooltip_column = column;
5259   g_object_notify (G_OBJECT (icon_view), "tooltip-column");
5260 }
5261
5262 /** 
5263  * gtk_icon_view_get_tooltip_column:
5264  * @icon_view: a #GtkIconView
5265  *
5266  * Returns the column of @icon_view's model which is being used for
5267  * displaying tooltips on @icon_view's rows.
5268  *
5269  * Return value: the index of the tooltip column that is currently being
5270  * used, or -1 if this is disabled.
5271  *
5272  * Since: 2.12
5273  */
5274 gint
5275 gtk_icon_view_get_tooltip_column (GtkIconView *icon_view)
5276 {
5277   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
5278
5279   return icon_view->priv->tooltip_column;
5280 }
5281
5282 /**
5283  * gtk_icon_view_get_visible_range:
5284  * @icon_view: A #GtkIconView
5285  * @start_path: (allow-none): Return location for start of region, or %NULL
5286  * @end_path: (allow-none): Return location for end of region, or %NULL
5287  * 
5288  * Sets @start_path and @end_path to be the first and last visible path. 
5289  * Note that there may be invisible paths in between.
5290  * 
5291  * Both paths should be freed with gtk_tree_path_free() after use.
5292  * 
5293  * Return value: %TRUE, if valid paths were placed in @start_path and @end_path
5294  *
5295  * Since: 2.8
5296  **/
5297 gboolean
5298 gtk_icon_view_get_visible_range (GtkIconView  *icon_view,
5299                                  GtkTreePath **start_path,
5300                                  GtkTreePath **end_path)
5301 {
5302   gint start_index = -1;
5303   gint end_index = -1;
5304   GList *icons;
5305
5306   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
5307
5308   if (icon_view->priv->hadjustment == NULL ||
5309       icon_view->priv->vadjustment == NULL)
5310     return FALSE;
5311
5312   if (start_path == NULL && end_path == NULL)
5313     return FALSE;
5314   
5315   for (icons = icon_view->priv->items; icons; icons = icons->next) 
5316     {
5317       GtkIconViewItem *item = icons->data;
5318
5319       if ((item->x + item->width >= (int)icon_view->priv->hadjustment->value) &&
5320           (item->y + item->height >= (int)icon_view->priv->vadjustment->value) &&
5321           (item->x <= (int) (icon_view->priv->hadjustment->value + icon_view->priv->hadjustment->page_size)) &&
5322           (item->y <= (int) (icon_view->priv->vadjustment->value + icon_view->priv->vadjustment->page_size)))
5323         {
5324           if (start_index == -1)
5325             start_index = item->index;
5326           end_index = item->index;
5327         }
5328     }
5329
5330   if (start_path && start_index != -1)
5331     *start_path = gtk_tree_path_new_from_indices (start_index, -1);
5332   if (end_path && end_index != -1)
5333     *end_path = gtk_tree_path_new_from_indices (end_index, -1);
5334   
5335   return start_index != -1;
5336 }
5337
5338 /**
5339  * gtk_icon_view_selected_foreach:
5340  * @icon_view: A #GtkIconView.
5341  * @func: (scope call): The function to call for each selected icon.
5342  * @data: User data to pass to the function.
5343  * 
5344  * Calls a function for each selected icon. Note that the model or
5345  * selection cannot be modified from within this function.
5346  *
5347  * Since: 2.6 
5348  **/
5349 void
5350 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
5351                                 GtkIconViewForeachFunc func,
5352                                 gpointer               data)
5353 {
5354   GList *list;
5355   
5356   for (list = icon_view->priv->items; list; list = list->next)
5357     {
5358       GtkIconViewItem *item = list->data;
5359       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5360
5361       if (item->selected)
5362         (* func) (icon_view, path, data);
5363
5364       gtk_tree_path_free (path);
5365     }
5366 }
5367
5368 /**
5369  * gtk_icon_view_set_selection_mode:
5370  * @icon_view: A #GtkIconView.
5371  * @mode: The selection mode
5372  * 
5373  * Sets the selection mode of the @icon_view.
5374  *
5375  * Since: 2.6 
5376  **/
5377 void
5378 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
5379                                   GtkSelectionMode  mode)
5380 {
5381   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5382
5383   if (mode == icon_view->priv->selection_mode)
5384     return;
5385   
5386   if (mode == GTK_SELECTION_NONE ||
5387       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
5388     gtk_icon_view_unselect_all (icon_view);
5389   
5390   icon_view->priv->selection_mode = mode;
5391
5392   g_object_notify (G_OBJECT (icon_view), "selection-mode");
5393 }
5394
5395 /**
5396  * gtk_icon_view_get_selection_mode:
5397  * @icon_view: A #GtkIconView.
5398  * 
5399  * Gets the selection mode of the @icon_view.
5400  *
5401  * Return value: the current selection mode
5402  *
5403  * Since: 2.6 
5404  **/
5405 GtkSelectionMode
5406 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
5407 {
5408   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
5409
5410   return icon_view->priv->selection_mode;
5411 }
5412
5413 /**
5414  * gtk_icon_view_set_model:
5415  * @icon_view: A #GtkIconView.
5416  * @model: (allow-none): The model.
5417  *
5418  * Sets the model for a #GtkIconView.
5419  * If the @icon_view already has a model set, it will remove
5420  * it before setting the new model.  If @model is %NULL, then
5421  * it will unset the old model.
5422  *
5423  * Since: 2.6 
5424  **/
5425 void
5426 gtk_icon_view_set_model (GtkIconView *icon_view,
5427                          GtkTreeModel *model)
5428 {
5429   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5430   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
5431   
5432   if (icon_view->priv->model == model)
5433     return;
5434
5435   if (icon_view->priv->scroll_to_path)
5436     {
5437       gtk_tree_row_reference_free (icon_view->priv->scroll_to_path);
5438       icon_view->priv->scroll_to_path = NULL;
5439     }
5440
5441   gtk_icon_view_stop_editing (icon_view, TRUE);
5442
5443   if (model)
5444     {
5445       GType column_type;
5446
5447       if (icon_view->priv->pixbuf_column != -1)
5448         {
5449           column_type = gtk_tree_model_get_column_type (model,
5450                                                         icon_view->priv->pixbuf_column);          
5451
5452           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5453         }
5454
5455       if (icon_view->priv->text_column != -1)
5456         {
5457           column_type = gtk_tree_model_get_column_type (model,
5458                                                         icon_view->priv->text_column);    
5459
5460           g_return_if_fail (column_type == G_TYPE_STRING);
5461         }
5462
5463       if (icon_view->priv->markup_column != -1)
5464         {
5465           column_type = gtk_tree_model_get_column_type (model,
5466                                                         icon_view->priv->markup_column);          
5467
5468           g_return_if_fail (column_type == G_TYPE_STRING);
5469         }
5470       
5471     }
5472   
5473   if (icon_view->priv->model)
5474     {
5475       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5476                                             gtk_icon_view_row_changed,
5477                                             icon_view);
5478       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5479                                             gtk_icon_view_row_inserted,
5480                                             icon_view);
5481       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5482                                             gtk_icon_view_row_deleted,
5483                                             icon_view);
5484       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
5485                                             gtk_icon_view_rows_reordered,
5486                                             icon_view);
5487
5488       g_object_unref (icon_view->priv->model);
5489       
5490       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
5491       g_list_free (icon_view->priv->items);
5492       icon_view->priv->items = NULL;
5493       icon_view->priv->anchor_item = NULL;
5494       icon_view->priv->cursor_item = NULL;
5495       icon_view->priv->last_single_clicked = NULL;
5496       icon_view->priv->width = 0;
5497       icon_view->priv->height = 0;
5498     }
5499
5500   icon_view->priv->model = model;
5501
5502   if (icon_view->priv->model)
5503     {
5504       g_object_ref (icon_view->priv->model);
5505       g_signal_connect (icon_view->priv->model,
5506                         "row-changed",
5507                         G_CALLBACK (gtk_icon_view_row_changed),
5508                         icon_view);
5509       g_signal_connect (icon_view->priv->model,
5510                         "row-inserted",
5511                         G_CALLBACK (gtk_icon_view_row_inserted),
5512                         icon_view);
5513       g_signal_connect (icon_view->priv->model,
5514                         "row-deleted",
5515                         G_CALLBACK (gtk_icon_view_row_deleted),
5516                         icon_view);
5517       g_signal_connect (icon_view->priv->model,
5518                         "rows-reordered",
5519                         G_CALLBACK (gtk_icon_view_rows_reordered),
5520                         icon_view);
5521
5522       gtk_icon_view_build_items (icon_view);
5523
5524       gtk_icon_view_queue_layout (icon_view);
5525     }
5526
5527   g_object_notify (G_OBJECT (icon_view), "model");  
5528
5529   if (gtk_widget_get_realized (GTK_WIDGET (icon_view)))
5530     gtk_widget_queue_resize (GTK_WIDGET (icon_view));
5531 }
5532
5533 /**
5534  * gtk_icon_view_get_model:
5535  * @icon_view: a #GtkIconView
5536  *
5537  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
5538  * model is unset.
5539  *
5540  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is
5541  *     currently being used.
5542  *
5543  * Since: 2.6 
5544  **/
5545 GtkTreeModel *
5546 gtk_icon_view_get_model (GtkIconView *icon_view)
5547 {
5548   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5549
5550   return icon_view->priv->model;
5551 }
5552
5553 static void
5554 update_text_cell (GtkIconView *icon_view)
5555 {
5556   GtkIconViewCellInfo *info;
5557   GList *l;
5558   gint i;
5559           
5560   if (icon_view->priv->text_column == -1 &&
5561       icon_view->priv->markup_column == -1)
5562     {
5563       if (icon_view->priv->text_cell != -1)
5564         {
5565           if (icon_view->priv->pixbuf_cell > icon_view->priv->text_cell)
5566             icon_view->priv->pixbuf_cell--;
5567
5568           info = g_list_nth_data (icon_view->priv->cell_list, 
5569                                   icon_view->priv->text_cell);
5570           
5571           icon_view->priv->cell_list = g_list_remove (icon_view->priv->cell_list, info);
5572           
5573           free_cell_info (info);
5574           
5575           icon_view->priv->n_cells--;
5576           icon_view->priv->text_cell = -1;
5577         }
5578     }
5579   else 
5580     {
5581       if (icon_view->priv->text_cell == -1)
5582         {
5583           GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
5584           gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), cell, FALSE);
5585           for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
5586             {
5587               info = l->data;
5588               if (info->cell == cell)
5589                 {
5590                   icon_view->priv->text_cell = i;
5591                   break;
5592                 }
5593             }
5594         }
5595       
5596       info = g_list_nth_data (icon_view->priv->cell_list,
5597                               icon_view->priv->text_cell);
5598
5599       if (icon_view->priv->markup_column != -1)
5600         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5601                                         info->cell, 
5602                                         "markup", icon_view->priv->markup_column, 
5603                                         NULL);
5604       else
5605         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5606                                         info->cell, 
5607                                         "text", icon_view->priv->text_column, 
5608                                         NULL);
5609
5610       if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
5611         g_object_set (info->cell,
5612                       "alignment", PANGO_ALIGN_CENTER,
5613                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
5614                       "xalign", 0.0,
5615                       "yalign", 0.0,
5616                       NULL);
5617       else
5618         g_object_set (info->cell,
5619                       "alignment", PANGO_ALIGN_LEFT,
5620                       "wrap-mode", PANGO_WRAP_WORD_CHAR,
5621                       "xalign", 0.0,
5622                       "yalign", 0.0,
5623                       NULL);
5624     }
5625 }
5626
5627 static void
5628 update_pixbuf_cell (GtkIconView *icon_view)
5629 {
5630   GtkIconViewCellInfo *info;
5631   GList *l;
5632   gint i;
5633
5634   if (icon_view->priv->pixbuf_column == -1)
5635     {
5636       if (icon_view->priv->pixbuf_cell != -1)
5637         {
5638           if (icon_view->priv->text_cell > icon_view->priv->pixbuf_cell)
5639             icon_view->priv->text_cell--;
5640
5641           info = g_list_nth_data (icon_view->priv->cell_list, 
5642                                   icon_view->priv->pixbuf_cell);
5643           
5644           icon_view->priv->cell_list = g_list_remove (icon_view->priv->cell_list, info);
5645           
5646           free_cell_info (info);
5647           
5648           icon_view->priv->n_cells--;
5649           icon_view->priv->pixbuf_cell = -1;
5650         }
5651     }
5652   else 
5653     {
5654       if (icon_view->priv->pixbuf_cell == -1)
5655         {
5656           GtkCellRenderer *cell = gtk_cell_renderer_pixbuf_new ();
5657           
5658           gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), cell, FALSE);
5659           for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
5660             {
5661               info = l->data;
5662               if (info->cell == cell)
5663                 {
5664                   icon_view->priv->pixbuf_cell = i;
5665                   break;
5666                 }
5667             }
5668         }
5669       
5670         info = g_list_nth_data (icon_view->priv->cell_list, 
5671                                 icon_view->priv->pixbuf_cell);
5672         
5673         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
5674                                         info->cell, 
5675                                         "pixbuf", icon_view->priv->pixbuf_column, 
5676                                         NULL);
5677
5678         if (icon_view->priv->item_orientation == GTK_ORIENTATION_VERTICAL)
5679           g_object_set (info->cell,
5680                         "xalign", 0.5,
5681                         "yalign", 1.0,
5682                         NULL);
5683         else
5684           g_object_set (info->cell,
5685                         "xalign", 0.0,
5686                         "yalign", 0.0,
5687                         NULL);
5688     }
5689 }
5690
5691 /**
5692  * gtk_icon_view_set_text_column:
5693  * @icon_view: A #GtkIconView.
5694  * @column: A column in the currently used model, or -1 to display no text
5695  * 
5696  * Sets the column with text for @icon_view to be @column. The text
5697  * column must be of type #G_TYPE_STRING.
5698  *
5699  * Since: 2.6 
5700  **/
5701 void
5702 gtk_icon_view_set_text_column (GtkIconView *icon_view,
5703                                gint          column)
5704 {
5705   if (column == icon_view->priv->text_column)
5706     return;
5707   
5708   if (column == -1)
5709     icon_view->priv->text_column = -1;
5710   else
5711     {
5712       if (icon_view->priv->model != NULL)
5713         {
5714           GType column_type;
5715           
5716           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5717
5718           g_return_if_fail (column_type == G_TYPE_STRING);
5719         }
5720       
5721       icon_view->priv->text_column = column;
5722     }
5723
5724   gtk_icon_view_stop_editing (icon_view, TRUE);
5725
5726   update_text_cell (icon_view);
5727
5728   gtk_icon_view_invalidate_sizes (icon_view);
5729   gtk_icon_view_queue_layout (icon_view);
5730   
5731   g_object_notify (G_OBJECT (icon_view), "text-column");
5732 }
5733
5734 /**
5735  * gtk_icon_view_get_text_column:
5736  * @icon_view: A #GtkIconView.
5737  *
5738  * Returns the column with text for @icon_view.
5739  *
5740  * Returns: the text column, or -1 if it's unset.
5741  *
5742  * Since: 2.6
5743  */
5744 gint
5745 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
5746 {
5747   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5748
5749   return icon_view->priv->text_column;
5750 }
5751
5752 /**
5753  * gtk_icon_view_set_markup_column:
5754  * @icon_view: A #GtkIconView.
5755  * @column: A column in the currently used model, or -1 to display no text
5756  * 
5757  * Sets the column with markup information for @icon_view to be
5758  * @column. The markup column must be of type #G_TYPE_STRING.
5759  * If the markup column is set to something, it overrides
5760  * the text column set by gtk_icon_view_set_text_column().
5761  *
5762  * Since: 2.6
5763  **/
5764 void
5765 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
5766                                  gint         column)
5767 {
5768   if (column == icon_view->priv->markup_column)
5769     return;
5770   
5771   if (column == -1)
5772     icon_view->priv->markup_column = -1;
5773   else
5774     {
5775       if (icon_view->priv->model != NULL)
5776         {
5777           GType column_type;
5778           
5779           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5780
5781           g_return_if_fail (column_type == G_TYPE_STRING);
5782         }
5783       
5784       icon_view->priv->markup_column = column;
5785     }
5786
5787   gtk_icon_view_stop_editing (icon_view, TRUE);
5788
5789   update_text_cell (icon_view);
5790
5791   gtk_icon_view_invalidate_sizes (icon_view);
5792   gtk_icon_view_queue_layout (icon_view);
5793   
5794   g_object_notify (G_OBJECT (icon_view), "markup-column");
5795 }
5796
5797 /**
5798  * gtk_icon_view_get_markup_column:
5799  * @icon_view: A #GtkIconView.
5800  *
5801  * Returns the column with markup text for @icon_view.
5802  *
5803  * Returns: the markup column, or -1 if it's unset.
5804  *
5805  * Since: 2.6
5806  */
5807 gint
5808 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
5809 {
5810   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5811
5812   return icon_view->priv->markup_column;
5813 }
5814
5815 /**
5816  * gtk_icon_view_set_pixbuf_column:
5817  * @icon_view: A #GtkIconView.
5818  * @column: A column in the currently used model, or -1 to disable
5819  * 
5820  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
5821  * column must be of type #GDK_TYPE_PIXBUF
5822  *
5823  * Since: 2.6 
5824  **/
5825 void
5826 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
5827                                  gint         column)
5828 {
5829   if (column == icon_view->priv->pixbuf_column)
5830     return;
5831   
5832   if (column == -1)
5833     icon_view->priv->pixbuf_column = -1;
5834   else
5835     {
5836       if (icon_view->priv->model != NULL)
5837         {
5838           GType column_type;
5839           
5840           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
5841
5842           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
5843         }
5844       
5845       icon_view->priv->pixbuf_column = column;
5846     }
5847
5848   gtk_icon_view_stop_editing (icon_view, TRUE);
5849
5850   update_pixbuf_cell (icon_view);
5851
5852   gtk_icon_view_invalidate_sizes (icon_view);
5853   gtk_icon_view_queue_layout (icon_view);
5854   
5855   g_object_notify (G_OBJECT (icon_view), "pixbuf-column");
5856   
5857 }
5858
5859 /**
5860  * gtk_icon_view_get_pixbuf_column:
5861  * @icon_view: A #GtkIconView.
5862  *
5863  * Returns the column with pixbufs for @icon_view.
5864  *
5865  * Returns: the pixbuf column, or -1 if it's unset.
5866  *
5867  * Since: 2.6
5868  */
5869 gint
5870 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
5871 {
5872   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
5873
5874   return icon_view->priv->pixbuf_column;
5875 }
5876
5877 /**
5878  * gtk_icon_view_select_path:
5879  * @icon_view: A #GtkIconView.
5880  * @path: The #GtkTreePath to be selected.
5881  * 
5882  * Selects the row at @path.
5883  *
5884  * Since: 2.6
5885  **/
5886 void
5887 gtk_icon_view_select_path (GtkIconView *icon_view,
5888                            GtkTreePath *path)
5889 {
5890   GtkIconViewItem *item = NULL;
5891
5892   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5893   g_return_if_fail (icon_view->priv->model != NULL);
5894   g_return_if_fail (path != NULL);
5895
5896   if (gtk_tree_path_get_depth (path) > 0)
5897     item = g_list_nth_data (icon_view->priv->items,
5898                             gtk_tree_path_get_indices(path)[0]);
5899
5900   if (item)
5901     gtk_icon_view_select_item (icon_view, item);
5902 }
5903
5904 /**
5905  * gtk_icon_view_unselect_path:
5906  * @icon_view: A #GtkIconView.
5907  * @path: The #GtkTreePath to be unselected.
5908  * 
5909  * Unselects the row at @path.
5910  *
5911  * Since: 2.6
5912  **/
5913 void
5914 gtk_icon_view_unselect_path (GtkIconView *icon_view,
5915                              GtkTreePath *path)
5916 {
5917   GtkIconViewItem *item;
5918   
5919   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5920   g_return_if_fail (icon_view->priv->model != NULL);
5921   g_return_if_fail (path != NULL);
5922
5923   item = g_list_nth_data (icon_view->priv->items,
5924                           gtk_tree_path_get_indices(path)[0]);
5925
5926   if (!item)
5927     return;
5928   
5929   gtk_icon_view_unselect_item (icon_view, item);
5930 }
5931
5932 /**
5933  * gtk_icon_view_get_selected_items:
5934  * @icon_view: A #GtkIconView.
5935  *
5936  * Creates a list of paths of all selected items. Additionally, if you are
5937  * planning on modifying the model after calling this function, you may
5938  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
5939  * To do this, you can use gtk_tree_row_reference_new().
5940  *
5941  * To free the return value, use:
5942  * |[
5943  * g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
5944  * g_list_free (list);
5945  * ]|
5946  *
5947  * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
5948  *
5949  * Since: 2.6
5950  **/
5951 GList *
5952 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
5953 {
5954   GList *list;
5955   GList *selected = NULL;
5956   
5957   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
5958   
5959   for (list = icon_view->priv->items; list != NULL; list = list->next)
5960     {
5961       GtkIconViewItem *item = list->data;
5962
5963       if (item->selected)
5964         {
5965           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
5966
5967           selected = g_list_prepend (selected, path);
5968         }
5969     }
5970
5971   return selected;
5972 }
5973
5974 /**
5975  * gtk_icon_view_select_all:
5976  * @icon_view: A #GtkIconView.
5977  * 
5978  * Selects all the icons. @icon_view must has its selection mode set
5979  * to #GTK_SELECTION_MULTIPLE.
5980  *
5981  * Since: 2.6
5982  **/
5983 void
5984 gtk_icon_view_select_all (GtkIconView *icon_view)
5985 {
5986   GList *items;
5987   gboolean dirty = FALSE;
5988   
5989   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
5990
5991   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
5992     return;
5993
5994   for (items = icon_view->priv->items; items; items = items->next)
5995     {
5996       GtkIconViewItem *item = items->data;
5997       
5998       if (!item->selected)
5999         {
6000           dirty = TRUE;
6001           item->selected = TRUE;
6002           gtk_icon_view_queue_draw_item (icon_view, item);
6003         }
6004     }
6005
6006   if (dirty)
6007     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
6008 }
6009
6010 /**
6011  * gtk_icon_view_unselect_all:
6012  * @icon_view: A #GtkIconView.
6013  * 
6014  * Unselects all the icons.
6015  *
6016  * Since: 2.6
6017  **/
6018 void
6019 gtk_icon_view_unselect_all (GtkIconView *icon_view)
6020 {
6021   gboolean dirty = FALSE;
6022   
6023   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6024
6025   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
6026     return;
6027
6028   dirty = gtk_icon_view_unselect_all_internal (icon_view);
6029
6030   if (dirty)
6031     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
6032 }
6033
6034 /**
6035  * gtk_icon_view_path_is_selected:
6036  * @icon_view: A #GtkIconView.
6037  * @path: A #GtkTreePath to check selection on.
6038  * 
6039  * Returns %TRUE if the icon pointed to by @path is currently
6040  * selected. If @path does not point to a valid location, %FALSE is returned.
6041  * 
6042  * Return value: %TRUE if @path is selected.
6043  *
6044  * Since: 2.6
6045  **/
6046 gboolean
6047 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
6048                                 GtkTreePath *path)
6049 {
6050   GtkIconViewItem *item;
6051   
6052   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
6053   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
6054   g_return_val_if_fail (path != NULL, FALSE);
6055   
6056   item = g_list_nth_data (icon_view->priv->items,
6057                           gtk_tree_path_get_indices(path)[0]);
6058
6059   if (!item)
6060     return FALSE;
6061   
6062   return item->selected;
6063 }
6064
6065 /**
6066  * gtk_icon_view_get_item_row:
6067  * @icon_view: a #GtkIconView
6068  * @path: the #GtkTreePath of the item
6069  *
6070  * Gets the row in which the item @path is currently
6071  * displayed. Row numbers start at 0.
6072  *
6073  * Returns: The row in which the item is displayed
6074  *
6075  * Since: 2.22
6076  */
6077 gint
6078 gtk_icon_view_get_item_row (GtkIconView *icon_view,
6079                             GtkTreePath *path)
6080 {
6081   GtkIconViewItem *item;
6082
6083   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6084   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
6085   g_return_val_if_fail (path != NULL, -1);
6086
6087   item = g_list_nth_data (icon_view->priv->items,
6088                           gtk_tree_path_get_indices(path)[0]);
6089
6090   if (!item)
6091     return -1;
6092
6093   return item->row;
6094 }
6095
6096 /**
6097  * gtk_icon_view_get_item_column:
6098  * @icon_view: a #GtkIconView
6099  * @path: the #GtkTreePath of the item
6100  *
6101  * Gets the column in which the item @path is currently
6102  * displayed. Column numbers start at 0.
6103  *
6104  * Returns: The column in which the item is displayed
6105  *
6106  * Since: 2.22
6107  */
6108 gint
6109 gtk_icon_view_get_item_column (GtkIconView *icon_view,
6110                                GtkTreePath *path)
6111 {
6112   GtkIconViewItem *item;
6113
6114   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6115   g_return_val_if_fail (icon_view->priv->model != NULL, -1);
6116   g_return_val_if_fail (path != NULL, -1);
6117
6118   item = g_list_nth_data (icon_view->priv->items,
6119                           gtk_tree_path_get_indices(path)[0]);
6120
6121   if (!item)
6122     return -1;
6123
6124   return item->col;
6125 }
6126
6127 /**
6128  * gtk_icon_view_item_activated:
6129  * @icon_view: A #GtkIconView
6130  * @path: The #GtkTreePath to be activated
6131  * 
6132  * Activates the item determined by @path.
6133  *
6134  * Since: 2.6
6135  **/
6136 void
6137 gtk_icon_view_item_activated (GtkIconView      *icon_view,
6138                               GtkTreePath      *path)
6139 {
6140   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6141   g_return_if_fail (path != NULL);
6142   
6143   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
6144 }
6145
6146 /**
6147  * gtk_icon_view_set_item_orientation:
6148  * @icon_view: a #GtkIconView
6149  * @orientation: the relative position of texts and icons 
6150  * 
6151  * Sets the ::item-orientation property which determines whether the labels 
6152  * are drawn beside the icons instead of below.
6153  *
6154  * Since: 2.6
6155  **/
6156 void 
6157 gtk_icon_view_set_item_orientation (GtkIconView    *icon_view,
6158                                     GtkOrientation  orientation)
6159 {
6160   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6161
6162   if (icon_view->priv->item_orientation != orientation)
6163     {
6164       icon_view->priv->item_orientation = orientation;
6165
6166       gtk_icon_view_stop_editing (icon_view, TRUE);
6167       gtk_icon_view_invalidate_sizes (icon_view);
6168       gtk_icon_view_queue_layout (icon_view);
6169
6170       update_text_cell (icon_view);
6171       update_pixbuf_cell (icon_view);
6172       
6173       g_object_notify (G_OBJECT (icon_view), "item-orientation");
6174     }
6175 }
6176
6177 /**
6178  * gtk_icon_view_get_item_orientation:
6179  * @icon_view: a #GtkIconView
6180  * 
6181  * Returns the value of the ::item-orientation property which determines 
6182  * whether the labels are drawn beside the icons instead of below. 
6183  * 
6184  * Return value: the relative position of texts and icons 
6185  *
6186  * Since: 2.6
6187  **/
6188 GtkOrientation
6189 gtk_icon_view_get_item_orientation (GtkIconView *icon_view)
6190 {
6191   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
6192                         GTK_ORIENTATION_VERTICAL);
6193
6194   return icon_view->priv->item_orientation;
6195 }
6196
6197 /**
6198  * gtk_icon_view_set_columns:
6199  * @icon_view: a #GtkIconView
6200  * @columns: the number of columns
6201  * 
6202  * Sets the ::columns property which determines in how
6203  * many columns the icons are arranged. If @columns is
6204  * -1, the number of columns will be chosen automatically 
6205  * to fill the available area. 
6206  *
6207  * Since: 2.6
6208  */
6209 void 
6210 gtk_icon_view_set_columns (GtkIconView *icon_view,
6211                            gint         columns)
6212 {
6213   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6214   
6215   if (icon_view->priv->columns != columns)
6216     {
6217       icon_view->priv->columns = columns;
6218
6219       gtk_icon_view_stop_editing (icon_view, TRUE);
6220       gtk_icon_view_queue_layout (icon_view);
6221       
6222       g_object_notify (G_OBJECT (icon_view), "columns");
6223     }  
6224 }
6225
6226 /**
6227  * gtk_icon_view_get_columns:
6228  * @icon_view: a #GtkIconView
6229  * 
6230  * Returns the value of the ::columns property.
6231  * 
6232  * Return value: the number of columns, or -1
6233  *
6234  * Since: 2.6
6235  */
6236 gint
6237 gtk_icon_view_get_columns (GtkIconView *icon_view)
6238 {
6239   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6240
6241   return icon_view->priv->columns;
6242 }
6243
6244 /**
6245  * gtk_icon_view_set_item_width:
6246  * @icon_view: a #GtkIconView
6247  * @item_width: the width for each item
6248  * 
6249  * Sets the ::item-width property which specifies the width 
6250  * to use for each item. If it is set to -1, the icon view will 
6251  * automatically determine a suitable item size.
6252  *
6253  * Since: 2.6
6254  */
6255 void 
6256 gtk_icon_view_set_item_width (GtkIconView *icon_view,
6257                               gint         item_width)
6258 {
6259   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6260   
6261   if (icon_view->priv->item_width != item_width)
6262     {
6263       icon_view->priv->item_width = item_width;
6264       
6265       gtk_icon_view_stop_editing (icon_view, TRUE);
6266       gtk_icon_view_invalidate_sizes (icon_view);
6267       gtk_icon_view_queue_layout (icon_view);
6268       
6269       update_text_cell (icon_view);
6270
6271       g_object_notify (G_OBJECT (icon_view), "item-width");
6272     }  
6273 }
6274
6275 /**
6276  * gtk_icon_view_get_item_width:
6277  * @icon_view: a #GtkIconView
6278  * 
6279  * Returns the value of the ::item-width property.
6280  * 
6281  * Return value: the width of a single item, or -1
6282  *
6283  * Since: 2.6
6284  */
6285 gint
6286 gtk_icon_view_get_item_width (GtkIconView *icon_view)
6287 {
6288   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6289
6290   return icon_view->priv->item_width;
6291 }
6292
6293
6294 /**
6295  * gtk_icon_view_set_spacing:
6296  * @icon_view: a #GtkIconView
6297  * @spacing: the spacing
6298  * 
6299  * Sets the ::spacing property which specifies the space 
6300  * which is inserted between the cells (i.e. the icon and 
6301  * the text) of an item.
6302  *
6303  * Since: 2.6
6304  */
6305 void 
6306 gtk_icon_view_set_spacing (GtkIconView *icon_view,
6307                            gint         spacing)
6308 {
6309   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6310   
6311   if (icon_view->priv->spacing != spacing)
6312     {
6313       icon_view->priv->spacing = spacing;
6314
6315       gtk_icon_view_stop_editing (icon_view, TRUE);
6316       gtk_icon_view_invalidate_sizes (icon_view);
6317       gtk_icon_view_queue_layout (icon_view);
6318       
6319       g_object_notify (G_OBJECT (icon_view), "spacing");
6320     }  
6321 }
6322
6323 /**
6324  * gtk_icon_view_get_spacing:
6325  * @icon_view: a #GtkIconView
6326  * 
6327  * Returns the value of the ::spacing property.
6328  * 
6329  * Return value: the space between cells 
6330  *
6331  * Since: 2.6
6332  */
6333 gint
6334 gtk_icon_view_get_spacing (GtkIconView *icon_view)
6335 {
6336   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6337
6338   return icon_view->priv->spacing;
6339 }
6340
6341 /**
6342  * gtk_icon_view_set_row_spacing:
6343  * @icon_view: a #GtkIconView
6344  * @row_spacing: the row spacing
6345  * 
6346  * Sets the ::row-spacing property which specifies the space 
6347  * which is inserted between the rows of the icon view.
6348  *
6349  * Since: 2.6
6350  */
6351 void 
6352 gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
6353                                gint         row_spacing)
6354 {
6355   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6356   
6357   if (icon_view->priv->row_spacing != row_spacing)
6358     {
6359       icon_view->priv->row_spacing = row_spacing;
6360
6361       gtk_icon_view_stop_editing (icon_view, TRUE);
6362       gtk_icon_view_invalidate_sizes (icon_view);
6363       gtk_icon_view_queue_layout (icon_view);
6364       
6365       g_object_notify (G_OBJECT (icon_view), "row-spacing");
6366     }  
6367 }
6368
6369 /**
6370  * gtk_icon_view_get_row_spacing:
6371  * @icon_view: a #GtkIconView
6372  * 
6373  * Returns the value of the ::row-spacing property.
6374  * 
6375  * Return value: the space between rows
6376  *
6377  * Since: 2.6
6378  */
6379 gint
6380 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
6381 {
6382   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6383
6384   return icon_view->priv->row_spacing;
6385 }
6386
6387 /**
6388  * gtk_icon_view_set_column_spacing:
6389  * @icon_view: a #GtkIconView
6390  * @column_spacing: the column spacing
6391  * 
6392  * Sets the ::column-spacing property which specifies the space 
6393  * which is inserted between the columns of the icon view.
6394  *
6395  * Since: 2.6
6396  */
6397 void 
6398 gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
6399                                   gint         column_spacing)
6400 {
6401   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6402   
6403   if (icon_view->priv->column_spacing != column_spacing)
6404     {
6405       icon_view->priv->column_spacing = column_spacing;
6406
6407       gtk_icon_view_stop_editing (icon_view, TRUE);
6408       gtk_icon_view_invalidate_sizes (icon_view);
6409       gtk_icon_view_queue_layout (icon_view);
6410       
6411       g_object_notify (G_OBJECT (icon_view), "column-spacing");
6412     }  
6413 }
6414
6415 /**
6416  * gtk_icon_view_get_column_spacing:
6417  * @icon_view: a #GtkIconView
6418  * 
6419  * Returns the value of the ::column-spacing property.
6420  * 
6421  * Return value: the space between columns
6422  *
6423  * Since: 2.6
6424  */
6425 gint
6426 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
6427 {
6428   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6429
6430   return icon_view->priv->column_spacing;
6431 }
6432
6433 /**
6434  * gtk_icon_view_set_margin:
6435  * @icon_view: a #GtkIconView
6436  * @margin: the margin
6437  * 
6438  * Sets the ::margin property which specifies the space 
6439  * which is inserted at the top, bottom, left and right 
6440  * of the icon view.
6441  *
6442  * Since: 2.6
6443  */
6444 void 
6445 gtk_icon_view_set_margin (GtkIconView *icon_view,
6446                           gint         margin)
6447 {
6448   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6449   
6450   if (icon_view->priv->margin != margin)
6451     {
6452       icon_view->priv->margin = margin;
6453
6454       gtk_icon_view_stop_editing (icon_view, TRUE);
6455       gtk_icon_view_invalidate_sizes (icon_view);
6456       gtk_icon_view_queue_layout (icon_view);
6457       
6458       g_object_notify (G_OBJECT (icon_view), "margin");
6459     }  
6460 }
6461
6462 /**
6463  * gtk_icon_view_get_margin:
6464  * @icon_view: a #GtkIconView
6465  * 
6466  * Returns the value of the ::margin property.
6467  * 
6468  * Return value: the space at the borders 
6469  *
6470  * Since: 2.6
6471  */
6472 gint
6473 gtk_icon_view_get_margin (GtkIconView *icon_view)
6474 {
6475   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6476
6477   return icon_view->priv->margin;
6478 }
6479
6480 /**
6481  * gtk_icon_view_set_item_padding:
6482  * @icon_view: a #GtkIconView
6483  * @item_padding: the item padding
6484  *
6485  * Sets the #GtkIconView:item-padding property which specifies the padding
6486  * around each of the icon view's items.
6487  *
6488  * Since: 2.18
6489  */
6490 void
6491 gtk_icon_view_set_item_padding (GtkIconView *icon_view,
6492                                 gint         item_padding)
6493 {
6494   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
6495   
6496   if (icon_view->priv->item_padding != item_padding)
6497     {
6498       icon_view->priv->item_padding = item_padding;
6499
6500       gtk_icon_view_stop_editing (icon_view, TRUE);
6501       gtk_icon_view_invalidate_sizes (icon_view);
6502       gtk_icon_view_queue_layout (icon_view);
6503       
6504       g_object_notify (G_OBJECT (icon_view), "item-padding");
6505     }  
6506 }
6507
6508 /**
6509  * gtk_icon_view_get_item_padding:
6510  * @icon_view: a #GtkIconView
6511  * 
6512  * Returns the value of the ::item-padding property.
6513  * 
6514  * Return value: the padding around items
6515  *
6516  * Since: 2.18
6517  */
6518 gint
6519 gtk_icon_view_get_item_padding (GtkIconView *icon_view)
6520 {
6521   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
6522
6523   return icon_view->priv->item_padding;
6524 }
6525
6526 /* Get/set whether drag_motion requested the drag data and
6527  * drag_data_received should thus not actually insert the data,
6528  * since the data doesn't result from a drop.
6529  */
6530 static void
6531 set_status_pending (GdkDragContext *context,
6532                     GdkDragAction   suggested_action)
6533 {
6534   g_object_set_data (G_OBJECT (context),
6535                      I_("gtk-icon-view-status-pending"),
6536                      GINT_TO_POINTER (suggested_action));
6537 }
6538
6539 static GdkDragAction
6540 get_status_pending (GdkDragContext *context)
6541 {
6542   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6543                                              "gtk-icon-view-status-pending"));
6544 }
6545
6546 static void
6547 unset_reorderable (GtkIconView *icon_view)
6548 {
6549   if (icon_view->priv->reorderable)
6550     {
6551       icon_view->priv->reorderable = FALSE;
6552       g_object_notify (G_OBJECT (icon_view), "reorderable");
6553     }
6554 }
6555
6556 static void
6557 set_source_row (GdkDragContext *context,
6558                 GtkTreeModel   *model,
6559                 GtkTreePath    *source_row)
6560 {
6561   if (source_row)
6562     g_object_set_data_full (G_OBJECT (context),
6563                             I_("gtk-icon-view-source-row"),
6564                             gtk_tree_row_reference_new (model, source_row),
6565                             (GDestroyNotify) gtk_tree_row_reference_free);
6566   else
6567     g_object_set_data_full (G_OBJECT (context),
6568                             I_("gtk-icon-view-source-row"),
6569                             NULL, NULL);
6570 }
6571
6572 static GtkTreePath*
6573 get_source_row (GdkDragContext *context)
6574 {
6575   GtkTreeRowReference *ref;
6576
6577   ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
6578
6579   if (ref)
6580     return gtk_tree_row_reference_get_path (ref);
6581   else
6582     return NULL;
6583 }
6584
6585 typedef struct
6586 {
6587   GtkTreeRowReference *dest_row;
6588   gboolean             empty_view_drop;
6589   gboolean             drop_append_mode;
6590 } DestRow;
6591
6592 static void
6593 dest_row_free (gpointer data)
6594 {
6595   DestRow *dr = (DestRow *)data;
6596
6597   gtk_tree_row_reference_free (dr->dest_row);
6598   g_free (dr);
6599 }
6600
6601 static void
6602 set_dest_row (GdkDragContext *context,
6603               GtkTreeModel   *model,
6604               GtkTreePath    *dest_row,
6605               gboolean        empty_view_drop,
6606               gboolean        drop_append_mode)
6607 {
6608   DestRow *dr;
6609
6610   if (!dest_row)
6611     {
6612       g_object_set_data_full (G_OBJECT (context),
6613                               I_("gtk-icon-view-dest-row"),
6614                               NULL, NULL);
6615       return;
6616     }
6617   
6618   dr = g_new0 (DestRow, 1);
6619      
6620   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6621   dr->empty_view_drop = empty_view_drop;
6622   dr->drop_append_mode = drop_append_mode;
6623   g_object_set_data_full (G_OBJECT (context),
6624                           I_("gtk-icon-view-dest-row"),
6625                           dr, (GDestroyNotify) dest_row_free);
6626 }
6627
6628 static GtkTreePath*
6629 get_dest_row (GdkDragContext *context)
6630 {
6631   DestRow *dr;
6632
6633   dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
6634
6635   if (dr)
6636     {
6637       GtkTreePath *path = NULL;
6638       
6639       if (dr->dest_row)
6640         path = gtk_tree_row_reference_get_path (dr->dest_row);
6641       else if (dr->empty_view_drop)
6642         path = gtk_tree_path_new_from_indices (0, -1);
6643       else
6644         path = NULL;
6645
6646       if (path && dr->drop_append_mode)
6647         gtk_tree_path_next (path);
6648
6649       return path;
6650     }
6651   else
6652     return NULL;
6653 }
6654
6655 static gboolean
6656 check_model_dnd (GtkTreeModel *model,
6657                  GType         required_iface,
6658                  const gchar  *signal)
6659 {
6660   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6661     {
6662       g_warning ("You must override the default '%s' handler "
6663                  "on GtkIconView when using models that don't support "
6664                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6665                  "is to connect to '%s' and call "
6666                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6667                  "the default handler from running. Look at the source code "
6668                  "for the default handler in gtkiconview.c to get an idea what "
6669                  "your handler should do. (gtkiconview.c is in the GTK+ source "
6670                  "code.) If you're using GTK+ from a language other than C, "
6671                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6672                  signal, g_type_name (required_iface), signal);
6673       return FALSE;
6674     }
6675   else
6676     return TRUE;
6677 }
6678
6679 static void
6680 remove_scroll_timeout (GtkIconView *icon_view)
6681 {
6682   if (icon_view->priv->scroll_timeout_id != 0)
6683     {
6684       g_source_remove (icon_view->priv->scroll_timeout_id);
6685
6686       icon_view->priv->scroll_timeout_id = 0;
6687     }
6688 }
6689
6690 static void
6691 gtk_icon_view_autoscroll (GtkIconView *icon_view)
6692 {
6693   GdkWindow *window;
6694   gint px, py, x, y, width, height;
6695   gint hoffset, voffset;
6696
6697   window = gtk_widget_get_window (GTK_WIDGET (icon_view));
6698
6699   gdk_window_get_pointer (window, &px, &py, NULL);
6700   gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
6701
6702   /* see if we are near the edge. */
6703   voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
6704   if (voffset > 0)
6705     voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
6706
6707   hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
6708   if (hoffset > 0)
6709     hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
6710
6711   if (voffset != 0)
6712     gtk_adjustment_set_value (icon_view->priv->vadjustment,
6713                               icon_view->priv->vadjustment->value + voffset);
6714
6715   if (hoffset != 0)
6716     gtk_adjustment_set_value (icon_view->priv->hadjustment,
6717                               icon_view->priv->hadjustment->value + hoffset);
6718 }
6719
6720
6721 static gboolean
6722 drag_scroll_timeout (gpointer data)
6723 {
6724   GtkIconView *icon_view = GTK_ICON_VIEW (data);
6725
6726   gtk_icon_view_autoscroll (icon_view);
6727
6728   return TRUE;
6729 }
6730
6731
6732 static gboolean
6733 set_destination (GtkIconView    *icon_view,
6734                  GdkDragContext *context,
6735                  gint            x,
6736                  gint            y,
6737                  GdkDragAction  *suggested_action,
6738                  GdkAtom        *target)
6739 {
6740   GtkWidget *widget;
6741   GtkTreePath *path = NULL;
6742   GtkIconViewDropPosition pos;
6743   GtkIconViewDropPosition old_pos;
6744   GtkTreePath *old_dest_path = NULL;
6745   gboolean can_drop = FALSE;
6746
6747   widget = GTK_WIDGET (icon_view);
6748
6749   *suggested_action = 0;
6750   *target = GDK_NONE;
6751
6752   if (!icon_view->priv->dest_set)
6753     {
6754       /* someone unset us as a drag dest, note that if
6755        * we return FALSE drag_leave isn't called
6756        */
6757
6758       gtk_icon_view_set_drag_dest_item (icon_view,
6759                                         NULL,
6760                                         GTK_ICON_VIEW_DROP_LEFT);
6761
6762       remove_scroll_timeout (GTK_ICON_VIEW (widget));
6763
6764       return FALSE; /* no longer a drop site */
6765     }
6766
6767   *target = gtk_drag_dest_find_target (widget, context,
6768                                        gtk_drag_dest_get_target_list (widget));
6769   if (*target == GDK_NONE)
6770     return FALSE;
6771
6772   if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos)) 
6773     {
6774       gint n_children;
6775       GtkTreeModel *model;
6776       
6777       /* the row got dropped on empty space, let's setup a special case
6778        */
6779
6780       if (path)
6781         gtk_tree_path_free (path);
6782
6783       model = gtk_icon_view_get_model (icon_view);
6784
6785       n_children = gtk_tree_model_iter_n_children (model, NULL);
6786       if (n_children)
6787         {
6788           pos = GTK_ICON_VIEW_DROP_BELOW;
6789           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6790         }
6791       else
6792         {
6793           pos = GTK_ICON_VIEW_DROP_ABOVE;
6794           path = gtk_tree_path_new_from_indices (0, -1);
6795         }
6796
6797       can_drop = TRUE;
6798
6799       goto out;
6800     }
6801
6802   g_assert (path);
6803
6804   gtk_icon_view_get_drag_dest_item (icon_view,
6805                                     &old_dest_path,
6806                                     &old_pos);
6807   
6808   if (old_dest_path)
6809     gtk_tree_path_free (old_dest_path);
6810   
6811   if (TRUE /* FIXME if the location droppable predicate */)
6812     {
6813       can_drop = TRUE;
6814     }
6815
6816 out:
6817   if (can_drop)
6818     {
6819       GtkWidget *source_widget;
6820
6821       *suggested_action = context->suggested_action;
6822       source_widget = gtk_drag_get_source_widget (context);
6823
6824       if (source_widget == widget)
6825         {
6826           /* Default to MOVE, unless the user has
6827            * pressed ctrl or shift to affect available actions
6828            */
6829           if ((context->actions & GDK_ACTION_MOVE) != 0)
6830             *suggested_action = GDK_ACTION_MOVE;
6831         }
6832
6833       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6834                                         path, pos);
6835     }
6836   else
6837     {
6838       /* can't drop here */
6839       gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
6840                                         NULL,
6841                                         GTK_ICON_VIEW_DROP_LEFT);
6842     }
6843   
6844   if (path)
6845     gtk_tree_path_free (path);
6846   
6847   return TRUE;
6848 }
6849
6850 static GtkTreePath*
6851 get_logical_destination (GtkIconView *icon_view,
6852                          gboolean    *drop_append_mode)
6853 {
6854   /* adjust path to point to the row the drop goes in front of */
6855   GtkTreePath *path = NULL;
6856   GtkIconViewDropPosition pos;
6857   
6858   *drop_append_mode = FALSE;
6859
6860   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
6861
6862   if (path == NULL)
6863     return NULL;
6864
6865   if (pos == GTK_ICON_VIEW_DROP_RIGHT || 
6866       pos == GTK_ICON_VIEW_DROP_BELOW)
6867     {
6868       GtkTreeIter iter;
6869       GtkTreeModel *model = icon_view->priv->model;
6870
6871       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6872           !gtk_tree_model_iter_next (model, &iter))
6873         *drop_append_mode = TRUE;
6874       else
6875         {
6876           *drop_append_mode = FALSE;
6877           gtk_tree_path_next (path);
6878         }      
6879     }
6880
6881   return path;
6882 }
6883
6884 static gboolean
6885 gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
6886                                 GdkEventMotion *event)
6887 {
6888   GtkWidget *widget = GTK_WIDGET (icon_view);
6889   GdkDragContext *context;
6890   GtkTreePath *path = NULL;
6891   gint button;
6892   GtkTreeModel *model;
6893   gboolean retval = FALSE;
6894
6895   if (!icon_view->priv->source_set)
6896     goto out;
6897
6898   if (icon_view->priv->pressed_button < 0)
6899     goto out;
6900
6901   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
6902                                  icon_view->priv->press_start_x,
6903                                  icon_view->priv->press_start_y,
6904                                  event->x, event->y))
6905     goto out;
6906
6907   model = gtk_icon_view_get_model (icon_view);
6908
6909   if (model == NULL)
6910     goto out;
6911
6912   button = icon_view->priv->pressed_button;
6913   icon_view->priv->pressed_button = -1;
6914
6915   path = gtk_icon_view_get_path_at_pos (icon_view,
6916                                         icon_view->priv->press_start_x,
6917                                         icon_view->priv->press_start_y);
6918
6919   if (path == NULL)
6920     goto out;
6921
6922   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
6923       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
6924                                            path))
6925     goto out;
6926
6927   /* FIXME Check whether we're a start button, if not return FALSE and
6928    * free path
6929    */
6930
6931   /* Now we can begin the drag */
6932   
6933   retval = TRUE;
6934
6935   context = gtk_drag_begin (widget,
6936                             gtk_drag_source_get_target_list (widget),
6937                             icon_view->priv->source_actions,
6938                             button,
6939                             (GdkEvent*)event);
6940
6941   set_source_row (context, model, path);
6942   
6943  out:
6944   if (path)
6945     gtk_tree_path_free (path);
6946
6947   return retval;
6948 }
6949
6950 /* Source side drag signals */
6951 static void 
6952 gtk_icon_view_drag_begin (GtkWidget      *widget,
6953                           GdkDragContext *context)
6954 {
6955   GtkIconView *icon_view;
6956   GtkIconViewItem *item;
6957   cairo_surface_t *icon;
6958   gint x, y;
6959   GtkTreePath *path;
6960
6961   icon_view = GTK_ICON_VIEW (widget);
6962
6963   /* if the user uses a custom DnD impl, we don't set the icon here */
6964   if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
6965     return;
6966
6967   item = gtk_icon_view_get_item_at_coords (icon_view,
6968                                            icon_view->priv->press_start_x,
6969                                            icon_view->priv->press_start_y,
6970                                            TRUE,
6971                                            NULL);
6972
6973   g_return_if_fail (item != NULL);
6974
6975   x = icon_view->priv->press_start_x - item->x + 1;
6976   y = icon_view->priv->press_start_y - item->y + 1;
6977   
6978   path = gtk_tree_path_new_from_indices (item->index, -1);
6979   icon = gtk_icon_view_create_drag_icon (icon_view, path);
6980   gtk_tree_path_free (path);
6981
6982   cairo_surface_set_device_offset (icon, -x, -y);
6983
6984   gtk_drag_set_icon_surface (context, icon);
6985
6986   cairo_surface_destroy (icon);
6987 }
6988
6989 static void 
6990 gtk_icon_view_drag_end (GtkWidget      *widget,
6991                         GdkDragContext *context)
6992 {
6993   /* do nothing */
6994 }
6995
6996 static void 
6997 gtk_icon_view_drag_data_get (GtkWidget        *widget,
6998                              GdkDragContext   *context,
6999                              GtkSelectionData *selection_data,
7000                              guint             info,
7001                              guint             time)
7002 {
7003   GtkIconView *icon_view;
7004   GtkTreeModel *model;
7005   GtkTreePath *source_row;
7006
7007   icon_view = GTK_ICON_VIEW (widget);
7008   model = gtk_icon_view_get_model (icon_view);
7009
7010   if (model == NULL)
7011     return;
7012
7013   if (!icon_view->priv->source_set)
7014     return;
7015
7016   source_row = get_source_row (context);
7017
7018   if (source_row == NULL)
7019     return;
7020
7021   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7022    * any model; for DragSource models there are some other targets
7023    * we also support.
7024    */
7025
7026   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7027       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7028                                           source_row,
7029                                           selection_data))
7030     goto done;
7031
7032   /* If drag_data_get does nothing, try providing row data. */
7033   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7034     gtk_tree_set_row_drag_data (selection_data,
7035                                 model,
7036                                 source_row);
7037
7038  done:
7039   gtk_tree_path_free (source_row);
7040 }
7041
7042 static void 
7043 gtk_icon_view_drag_data_delete (GtkWidget      *widget,
7044                                 GdkDragContext *context)
7045 {
7046   GtkTreeModel *model;
7047   GtkIconView *icon_view;
7048   GtkTreePath *source_row;
7049
7050   icon_view = GTK_ICON_VIEW (widget);
7051   model = gtk_icon_view_get_model (icon_view);
7052
7053   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag-data-delete"))
7054     return;
7055
7056   if (!icon_view->priv->source_set)
7057     return;
7058
7059   source_row = get_source_row (context);
7060
7061   if (source_row == NULL)
7062     return;
7063
7064   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7065                                          source_row);
7066
7067   gtk_tree_path_free (source_row);
7068
7069   set_source_row (context, NULL, NULL);
7070 }
7071
7072 /* Target side drag signals */
7073 static void
7074 gtk_icon_view_drag_leave (GtkWidget      *widget,
7075                           GdkDragContext *context,
7076                           guint           time)
7077 {
7078   GtkIconView *icon_view;
7079
7080   icon_view = GTK_ICON_VIEW (widget);
7081
7082   /* unset any highlight row */
7083   gtk_icon_view_set_drag_dest_item (icon_view,
7084                                     NULL,
7085                                     GTK_ICON_VIEW_DROP_LEFT);
7086
7087   remove_scroll_timeout (icon_view);
7088 }
7089
7090 static gboolean 
7091 gtk_icon_view_drag_motion (GtkWidget      *widget,
7092                            GdkDragContext *context,
7093                            gint            x,
7094                            gint            y,
7095                            guint           time)
7096 {
7097   GtkTreePath *path = NULL;
7098   GtkIconViewDropPosition pos;
7099   GtkIconView *icon_view;
7100   GdkDragAction suggested_action = 0;
7101   GdkAtom target;
7102   gboolean empty;
7103
7104   icon_view = GTK_ICON_VIEW (widget);
7105
7106   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
7107     return FALSE;
7108
7109   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
7110
7111   /* we only know this *after* set_desination_row */
7112   empty = icon_view->priv->empty_view_drop;
7113
7114   if (path == NULL && !empty)
7115     {
7116       /* Can't drop here. */
7117       gdk_drag_status (context, 0, time);
7118     }
7119   else
7120     {
7121       if (icon_view->priv->scroll_timeout_id == 0)
7122         {
7123           icon_view->priv->scroll_timeout_id =
7124             gdk_threads_add_timeout (50, drag_scroll_timeout, icon_view);
7125         }
7126
7127       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7128         {
7129           /* Request data so we can use the source row when
7130            * determining whether to accept the drop
7131            */
7132           set_status_pending (context, suggested_action);
7133           gtk_drag_get_data (widget, context, target, time);
7134         }
7135       else
7136         {
7137           set_status_pending (context, 0);
7138           gdk_drag_status (context, suggested_action, time);
7139         }
7140     }
7141
7142   if (path)
7143     gtk_tree_path_free (path);
7144
7145   return TRUE;
7146 }
7147
7148 static gboolean 
7149 gtk_icon_view_drag_drop (GtkWidget      *widget,
7150                          GdkDragContext *context,
7151                          gint            x,
7152                          gint            y,
7153                          guint           time)
7154 {
7155   GtkIconView *icon_view;
7156   GtkTreePath *path;
7157   GdkDragAction suggested_action = 0;
7158   GdkAtom target = GDK_NONE;
7159   GtkTreeModel *model;
7160   gboolean drop_append_mode;
7161
7162   icon_view = GTK_ICON_VIEW (widget);
7163   model = gtk_icon_view_get_model (icon_view);
7164
7165   remove_scroll_timeout (GTK_ICON_VIEW (widget));
7166
7167   if (!icon_view->priv->dest_set)
7168     return FALSE;
7169
7170   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
7171     return FALSE;
7172
7173   if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
7174     return FALSE;
7175   
7176   path = get_logical_destination (icon_view, &drop_append_mode);
7177
7178   if (target != GDK_NONE && path != NULL)
7179     {
7180       /* in case a motion had requested drag data, change things so we
7181        * treat drag data receives as a drop.
7182        */
7183       set_status_pending (context, 0);
7184       set_dest_row (context, model, path, 
7185                     icon_view->priv->empty_view_drop, drop_append_mode);
7186     }
7187
7188   if (path)
7189     gtk_tree_path_free (path);
7190
7191   /* Unset this thing */
7192   gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
7193
7194   if (target != GDK_NONE)
7195     {
7196       gtk_drag_get_data (widget, context, target, time);
7197       return TRUE;
7198     }
7199   else
7200     return FALSE;
7201 }
7202
7203 static void
7204 gtk_icon_view_drag_data_received (GtkWidget        *widget,
7205                                   GdkDragContext   *context,
7206                                   gint              x,
7207                                   gint              y,
7208                                   GtkSelectionData *selection_data,
7209                                   guint             info,
7210                                   guint             time)
7211 {
7212   GtkTreePath *path;
7213   gboolean accepted = FALSE;
7214   GtkTreeModel *model;
7215   GtkIconView *icon_view;
7216   GtkTreePath *dest_row;
7217   GdkDragAction suggested_action;
7218   gboolean drop_append_mode;
7219   
7220   icon_view = GTK_ICON_VIEW (widget);  
7221   model = gtk_icon_view_get_model (icon_view);
7222
7223   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
7224     return;
7225
7226   if (!icon_view->priv->dest_set)
7227     return;
7228
7229   suggested_action = get_status_pending (context);
7230
7231   if (suggested_action)
7232     {
7233       /* We are getting this data due to a request in drag_motion,
7234        * rather than due to a request in drag_drop, so we are just
7235        * supposed to call drag_status, not actually paste in the
7236        * data.
7237        */
7238       path = get_logical_destination (icon_view, &drop_append_mode);
7239
7240       if (path == NULL)
7241         suggested_action = 0;
7242
7243       if (suggested_action)
7244         {
7245           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7246                                                      path,
7247                                                      selection_data))
7248             suggested_action = 0;
7249         }
7250
7251       gdk_drag_status (context, suggested_action, time);
7252
7253       if (path)
7254         gtk_tree_path_free (path);
7255
7256       /* If you can't drop, remove user drop indicator until the next motion */
7257       if (suggested_action == 0)
7258         gtk_icon_view_set_drag_dest_item (icon_view,
7259                                           NULL,
7260                                           GTK_ICON_VIEW_DROP_LEFT);
7261       return;
7262     }
7263   
7264
7265   dest_row = get_dest_row (context);
7266
7267   if (dest_row == NULL)
7268     return;
7269
7270   if (selection_data->length >= 0)
7271     {
7272       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7273                                                  dest_row,
7274                                                  selection_data))
7275         accepted = TRUE;
7276     }
7277
7278   gtk_drag_finish (context,
7279                    accepted,
7280                    (context->action == GDK_ACTION_MOVE),
7281                    time);
7282
7283   gtk_tree_path_free (dest_row);
7284
7285   /* drop dest_row */
7286   set_dest_row (context, NULL, NULL, FALSE, FALSE);
7287 }
7288
7289 /* Drag-and-Drop support */
7290 /**
7291  * gtk_icon_view_enable_model_drag_source:
7292  * @icon_view: a #GtkIconTreeView
7293  * @start_button_mask: Mask of allowed buttons to start drag
7294  * @targets: the table of targets that the drag will support
7295  * @n_targets: the number of items in @targets
7296  * @actions: the bitmask of possible actions for a drag from this
7297  *    widget
7298  *
7299  * Turns @icon_view into a drag source for automatic DND. Calling this
7300  * method sets #GtkIconView:reorderable to %FALSE.
7301  *
7302  * Since: 2.8
7303  **/
7304 void
7305 gtk_icon_view_enable_model_drag_source (GtkIconView              *icon_view,
7306                                         GdkModifierType           start_button_mask,
7307                                         const GtkTargetEntry     *targets,
7308                                         gint                      n_targets,
7309                                         GdkDragAction             actions)
7310 {
7311   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7312
7313   gtk_drag_source_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
7314
7315   icon_view->priv->start_button_mask = start_button_mask;
7316   icon_view->priv->source_actions = actions;
7317
7318   icon_view->priv->source_set = TRUE;
7319
7320   unset_reorderable (icon_view);
7321 }
7322
7323 /**
7324  * gtk_icon_view_enable_model_drag_dest:
7325  * @icon_view: a #GtkIconView
7326  * @targets: the table of targets that the drag will support
7327  * @n_targets: the number of items in @targets
7328  * @actions: the bitmask of possible actions for a drag to this
7329  *    widget
7330  *
7331  * Turns @icon_view into a drop destination for automatic DND. Calling this
7332  * method sets #GtkIconView:reorderable to %FALSE.
7333  *
7334  * Since: 2.8
7335  **/
7336 void 
7337 gtk_icon_view_enable_model_drag_dest (GtkIconView          *icon_view,
7338                                       const GtkTargetEntry *targets,
7339                                       gint                  n_targets,
7340                                       GdkDragAction         actions)
7341 {
7342   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7343
7344   gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, targets, n_targets, actions);
7345
7346   icon_view->priv->dest_actions = actions;
7347
7348   icon_view->priv->dest_set = TRUE;
7349
7350   unset_reorderable (icon_view);  
7351 }
7352
7353 /**
7354  * gtk_icon_view_unset_model_drag_source:
7355  * @icon_view: a #GtkIconView
7356  * 
7357  * Undoes the effect of gtk_icon_view_enable_model_drag_source(). Calling this
7358  * method sets #GtkIconView:reorderable to %FALSE.
7359  *
7360  * Since: 2.8
7361  **/
7362 void
7363 gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
7364 {
7365   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7366
7367   if (icon_view->priv->source_set)
7368     {
7369       gtk_drag_source_unset (GTK_WIDGET (icon_view));
7370       icon_view->priv->source_set = FALSE;
7371     }
7372
7373   unset_reorderable (icon_view);
7374 }
7375
7376 /**
7377  * gtk_icon_view_unset_model_drag_dest:
7378  * @icon_view: a #GtkIconView
7379  * 
7380  * Undoes the effect of gtk_icon_view_enable_model_drag_dest(). Calling this
7381  * method sets #GtkIconView:reorderable to %FALSE.
7382  *
7383  * Since: 2.8
7384  **/
7385 void
7386 gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
7387 {
7388   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7389
7390   if (icon_view->priv->dest_set)
7391     {
7392       gtk_drag_dest_unset (GTK_WIDGET (icon_view));
7393       icon_view->priv->dest_set = FALSE;
7394     }
7395
7396   unset_reorderable (icon_view);
7397 }
7398
7399 /* These are useful to implement your own custom stuff. */
7400 /**
7401  * gtk_icon_view_set_drag_dest_item:
7402  * @icon_view: a #GtkIconView
7403  * @path: (allow-none): The path of the item to highlight, or %NULL.
7404  * @pos: Specifies where to drop, relative to the item
7405  *
7406  * Sets the item that is highlighted for feedback.
7407  *
7408  * Since: 2.8
7409  */
7410 void
7411 gtk_icon_view_set_drag_dest_item (GtkIconView              *icon_view,
7412                                   GtkTreePath              *path,
7413                                   GtkIconViewDropPosition   pos)
7414 {
7415   /* Note; this function is exported to allow a custom DND
7416    * implementation, so it can't touch TreeViewDragInfo
7417    */
7418
7419   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7420
7421   if (icon_view->priv->dest_item)
7422     {
7423       GtkTreePath *current_path;
7424       current_path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
7425       gtk_tree_row_reference_free (icon_view->priv->dest_item);
7426       icon_view->priv->dest_item = NULL;      
7427
7428       gtk_icon_view_queue_draw_path (icon_view, current_path);
7429       gtk_tree_path_free (current_path);
7430     }
7431   
7432   /* special case a drop on an empty model */
7433   icon_view->priv->empty_view_drop = FALSE;
7434   if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
7435       && gtk_tree_path_get_depth (path) == 1
7436       && gtk_tree_path_get_indices (path)[0] == 0)
7437     {
7438       gint n_children;
7439
7440       n_children = gtk_tree_model_iter_n_children (icon_view->priv->model,
7441                                                    NULL);
7442
7443       if (n_children == 0)
7444         icon_view->priv->empty_view_drop = TRUE;
7445     }
7446
7447   icon_view->priv->dest_pos = pos;
7448
7449   if (path)
7450     {
7451       icon_view->priv->dest_item =
7452         gtk_tree_row_reference_new_proxy (G_OBJECT (icon_view), 
7453                                           icon_view->priv->model, path);
7454       
7455       gtk_icon_view_queue_draw_path (icon_view, path);
7456     }
7457 }
7458
7459 /**
7460  * gtk_icon_view_get_drag_dest_item:
7461  * @icon_view: a #GtkIconView
7462  * @path: (allow-none): Return location for the path of the highlighted item, or %NULL.
7463  * @pos: (allow-none): Return location for the drop position, or %NULL
7464  * 
7465  * Gets information about the item that is highlighted for feedback.
7466  *
7467  * Since: 2.8
7468  **/
7469 void
7470 gtk_icon_view_get_drag_dest_item (GtkIconView              *icon_view,
7471                                   GtkTreePath             **path,
7472                                   GtkIconViewDropPosition  *pos)
7473 {
7474   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7475
7476   if (path)
7477     {
7478       if (icon_view->priv->dest_item)
7479         *path = gtk_tree_row_reference_get_path (icon_view->priv->dest_item);
7480       else
7481         *path = NULL;
7482     }
7483
7484   if (pos)
7485     *pos = icon_view->priv->dest_pos;
7486 }
7487
7488 /**
7489  * gtk_icon_view_get_dest_item_at_pos:
7490  * @icon_view: a #GtkIconView
7491  * @drag_x: the position to determine the destination item for
7492  * @drag_y: the position to determine the destination item for
7493  * @path: (allow-none): Return location for the path of the item, or %NULL.
7494  * @pos: (allow-none): Return location for the drop position, or %NULL
7495  * 
7496  * Determines the destination item for a given position.
7497  * 
7498  * Return value: whether there is an item at the given position.
7499  *
7500  * Since: 2.8
7501  **/
7502 gboolean
7503 gtk_icon_view_get_dest_item_at_pos (GtkIconView              *icon_view,
7504                                     gint                      drag_x,
7505                                     gint                      drag_y,
7506                                     GtkTreePath             **path,
7507                                     GtkIconViewDropPosition  *pos)
7508 {
7509   GtkIconViewItem *item;
7510
7511   /* Note; this function is exported to allow a custom DND
7512    * implementation, so it can't touch TreeViewDragInfo
7513    */
7514
7515   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
7516   g_return_val_if_fail (drag_x >= 0, FALSE);
7517   g_return_val_if_fail (drag_y >= 0, FALSE);
7518   g_return_val_if_fail (icon_view->priv->bin_window != NULL, FALSE);
7519
7520
7521   if (path)
7522     *path = NULL;
7523
7524   item = gtk_icon_view_get_item_at_coords (icon_view, 
7525                                            drag_x + icon_view->priv->hadjustment->value, 
7526                                            drag_y + icon_view->priv->vadjustment->value,
7527                                            FALSE, NULL);
7528
7529   if (item == NULL)
7530     return FALSE;
7531
7532   if (path)
7533     *path = gtk_tree_path_new_from_indices (item->index, -1);
7534
7535   if (pos)
7536     {
7537       if (drag_x < item->x + item->width / 4)
7538         *pos = GTK_ICON_VIEW_DROP_LEFT;
7539       else if (drag_x > item->x + item->width * 3 / 4)
7540         *pos = GTK_ICON_VIEW_DROP_RIGHT;
7541       else if (drag_y < item->y + item->height / 4)
7542         *pos = GTK_ICON_VIEW_DROP_ABOVE;
7543       else if (drag_y > item->y + item->height * 3 / 4)
7544         *pos = GTK_ICON_VIEW_DROP_BELOW;
7545       else
7546         *pos = GTK_ICON_VIEW_DROP_INTO;
7547     }
7548
7549   return TRUE;
7550 }
7551
7552 /**
7553  * gtk_icon_view_create_drag_icon:
7554  * @icon_view: a #GtkIconView
7555  * @path: a #GtkTreePath in @icon_view
7556  *
7557  * Creates a #cairo_surface_t representation of the item at @path.  
7558  * This image is used for a drag icon.
7559  *
7560  * Return value: (transfer full) a newly-allocated surface of the drag icon.
7561  * 
7562  * Since: 2.8
7563  **/
7564 cairo_surface_t *
7565 gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
7566                                 GtkTreePath *path)
7567 {
7568   GtkWidget *widget;
7569   cairo_t *cr;
7570   cairo_surface_t *surface;
7571   GList *l;
7572   gint index;
7573
7574   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
7575   g_return_val_if_fail (path != NULL, NULL);
7576
7577   widget = GTK_WIDGET (icon_view);
7578
7579   if (!gtk_widget_get_realized (widget))
7580     return NULL;
7581
7582   index = gtk_tree_path_get_indices (path)[0];
7583
7584   for (l = icon_view->priv->items; l; l = l->next) 
7585     {
7586       GtkIconViewItem *item = l->data;
7587       
7588       if (index == item->index)
7589         {
7590           surface = gdk_window_create_similar_surface (icon_view->priv->bin_window,
7591                                                        CAIRO_CONTENT_COLOR,
7592                                                        item->width + 2,
7593                                                        item->height + 2);
7594
7595           cr = cairo_create (surface);
7596           cairo_set_line_width (cr, 1.);
7597
7598           gdk_cairo_set_source_color (cr, &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
7599           cairo_rectangle (cr, 0, 0, item->width + 2, item->height + 2);
7600           cairo_fill (cr);
7601
7602           cairo_save (cr);
7603
7604           cairo_rectangle (cr, 0, 0, item->width, item->height);
7605           cairo_clip (cr);
7606
7607           gtk_icon_view_paint_item (icon_view, cr, item, 1, 1, FALSE);
7608
7609           cairo_restore (cr);
7610
7611           cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
7612           cairo_rectangle (cr, 0.5, 0.5, item->width + 1, item->height + 1);
7613           cairo_stroke (cr);
7614
7615           cairo_destroy (cr);
7616
7617           return surface;
7618         }
7619     }
7620   
7621   return NULL;
7622 }
7623
7624 /**
7625  * gtk_icon_view_get_reorderable:
7626  * @icon_view: a #GtkIconView
7627  *
7628  * Retrieves whether the user can reorder the list via drag-and-drop. 
7629  * See gtk_icon_view_set_reorderable().
7630  *
7631  * Return value: %TRUE if the list can be reordered.
7632  *
7633  * Since: 2.8
7634  **/
7635 gboolean
7636 gtk_icon_view_get_reorderable (GtkIconView *icon_view)
7637 {
7638   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
7639
7640   return icon_view->priv->reorderable;
7641 }
7642
7643 static const GtkTargetEntry item_targets[] = {
7644   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
7645 };
7646
7647
7648 /**
7649  * gtk_icon_view_set_reorderable:
7650  * @icon_view: A #GtkIconView.
7651  * @reorderable: %TRUE, if the list of items can be reordered.
7652  *
7653  * This function is a convenience function to allow you to reorder models that
7654  * support the #GtkTreeDragSourceIface and the #GtkTreeDragDestIface.  Both
7655  * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
7656  * the user can reorder the model by dragging and dropping rows.  The
7657  * developer can listen to these changes by connecting to the model's
7658  * row_inserted and row_deleted signals. The reordering is implemented by setting up
7659  * the icon view as a drag source and destination. Therefore, drag and
7660  * drop can not be used in a reorderable view for any other purpose.
7661  *
7662  * This function does not give you any degree of control over the order -- any
7663  * reordering is allowed.  If more control is needed, you should probably
7664  * handle drag and drop manually.
7665  *
7666  * Since: 2.8
7667  **/
7668 void
7669 gtk_icon_view_set_reorderable (GtkIconView *icon_view,
7670                                gboolean     reorderable)
7671 {
7672   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
7673
7674   reorderable = reorderable != FALSE;
7675
7676   if (icon_view->priv->reorderable == reorderable)
7677     return;
7678
7679   if (reorderable)
7680     {
7681       gtk_icon_view_enable_model_drag_source (icon_view,
7682                                               GDK_BUTTON1_MASK,
7683                                               item_targets,
7684                                               G_N_ELEMENTS (item_targets),
7685                                               GDK_ACTION_MOVE);
7686       gtk_icon_view_enable_model_drag_dest (icon_view,
7687                                             item_targets,
7688                                             G_N_ELEMENTS (item_targets),
7689                                             GDK_ACTION_MOVE);
7690     }
7691   else
7692     {
7693       gtk_icon_view_unset_model_drag_source (icon_view);
7694       gtk_icon_view_unset_model_drag_dest (icon_view);
7695     }
7696
7697   icon_view->priv->reorderable = reorderable;
7698
7699   g_object_notify (G_OBJECT (icon_view), "reorderable");
7700 }
7701
7702
7703 /* Accessibility Support */
7704
7705 static gpointer accessible_parent_class;
7706 static gpointer accessible_item_parent_class;
7707 static GQuark accessible_private_data_quark = 0;
7708
7709 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (gtk_icon_view_item_accessible_get_type ())
7710 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
7711 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
7712
7713 static GType gtk_icon_view_item_accessible_get_type (void);
7714
7715 enum {
7716     ACTION_ACTIVATE,
7717     LAST_ACTION
7718 };
7719
7720 typedef struct
7721 {
7722   AtkObject parent;
7723
7724   GtkIconViewItem *item;
7725
7726   GtkWidget *widget;
7727
7728   AtkStateSet *state_set;
7729
7730   gchar *text;
7731
7732   GtkTextBuffer *text_buffer;
7733
7734   gchar *action_descriptions[LAST_ACTION];
7735   gchar *image_description;
7736   guint action_idle_handler;
7737 } GtkIconViewItemAccessible;
7738
7739 static const gchar *const gtk_icon_view_item_accessible_action_names[] = 
7740 {
7741   "activate",
7742   NULL
7743 };
7744
7745 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
7746 {
7747   "Activate item",
7748   NULL
7749 };
7750 typedef struct _GtkIconViewItemAccessibleClass
7751 {
7752   AtkObjectClass parent_class;
7753
7754 } GtkIconViewItemAccessibleClass;
7755
7756 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
7757
7758 static gboolean
7759 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
7760 {
7761   GtkIconViewItemAccessible *item;
7762   GtkIconView *icon_view;
7763   GtkTreePath *path;
7764
7765   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
7766   item->action_idle_handler = 0;
7767
7768   if (item->widget != NULL)
7769     {
7770       icon_view = GTK_ICON_VIEW (item->widget);
7771       path = gtk_tree_path_new_from_indices (item->item->index, -1);
7772       gtk_icon_view_item_activated (icon_view, path);
7773       gtk_tree_path_free (path);
7774     }
7775
7776   return FALSE;
7777 }
7778
7779 static gboolean
7780 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
7781                                                 gint       i)
7782 {
7783   GtkIconViewItemAccessible *item;
7784
7785   if (i < 0 || i >= LAST_ACTION) 
7786     return FALSE;
7787
7788   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7789
7790   if (!GTK_IS_ICON_VIEW (item->widget))
7791     return FALSE;
7792
7793   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7794     return FALSE;
7795
7796   switch (i)
7797     {
7798     case ACTION_ACTIVATE:
7799       if (!item->action_idle_handler)
7800         item->action_idle_handler = gdk_threads_add_idle (gtk_icon_view_item_accessible_idle_do_action, item);
7801       break;
7802     default:
7803       g_assert_not_reached ();
7804       return FALSE;
7805
7806     }        
7807   return TRUE;
7808 }
7809
7810 static gint
7811 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
7812 {
7813         return LAST_ACTION;
7814 }
7815
7816 static const gchar *
7817 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
7818                                                       gint       i)
7819 {
7820   GtkIconViewItemAccessible *item;
7821
7822   if (i < 0 || i >= LAST_ACTION) 
7823     return NULL;
7824
7825   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7826
7827   if (item->action_descriptions[i])
7828     return item->action_descriptions[i];
7829   else
7830     return gtk_icon_view_item_accessible_action_descriptions[i];
7831 }
7832
7833 static const gchar *
7834 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
7835                                                gint       i)
7836 {
7837   if (i < 0 || i >= LAST_ACTION) 
7838     return NULL;
7839
7840   return gtk_icon_view_item_accessible_action_names[i];
7841 }
7842
7843 static gboolean
7844 gtk_icon_view_item_accessible_action_set_description (AtkAction   *action,
7845                                                       gint         i,
7846                                                       const gchar *description)
7847 {
7848   GtkIconViewItemAccessible *item;
7849
7850   if (i < 0 || i >= LAST_ACTION) 
7851     return FALSE;
7852
7853   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
7854
7855   g_free (item->action_descriptions[i]);
7856
7857   item->action_descriptions[i] = g_strdup (description);
7858
7859   return TRUE;
7860 }
7861
7862 static void
7863 atk_action_item_interface_init (AtkActionIface *iface)
7864 {
7865   iface->do_action = gtk_icon_view_item_accessible_action_do_action;
7866   iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
7867   iface->get_description = gtk_icon_view_item_accessible_action_get_description;
7868   iface->get_name = gtk_icon_view_item_accessible_action_get_name;
7869   iface->set_description = gtk_icon_view_item_accessible_action_set_description;
7870 }
7871
7872 static const gchar *
7873 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
7874 {
7875   GtkIconViewItemAccessible *item;
7876
7877   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7878
7879   return item->image_description;
7880 }
7881
7882 static gboolean
7883 gtk_icon_view_item_accessible_image_set_image_description (AtkImage    *image,
7884                                                            const gchar *description)
7885 {
7886   GtkIconViewItemAccessible *item;
7887
7888   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7889
7890   g_free (item->image_description);
7891   item->image_description = g_strdup (description);
7892
7893   return TRUE;
7894 }
7895
7896 static gboolean
7897 get_pixbuf_box (GtkIconView     *icon_view,
7898                 GtkIconViewItem *item,
7899                 GdkRectangle    *box)
7900 {
7901   GList *l;
7902
7903   for (l = icon_view->priv->cell_list; l; l = l->next)
7904     {
7905       GtkIconViewCellInfo *info = l->data;
7906       
7907       if (GTK_IS_CELL_RENDERER_PIXBUF (info->cell))
7908         {
7909           gtk_icon_view_get_cell_box (icon_view, item, info, box);
7910
7911           return TRUE;
7912         }
7913     }
7914
7915   return FALSE;
7916 }
7917
7918 static gchar *
7919 get_text (GtkIconView     *icon_view,
7920           GtkIconViewItem *item)
7921 {
7922   GList *l;
7923   gchar *text;
7924
7925   for (l = icon_view->priv->cell_list; l; l = l->next)
7926     {
7927       GtkIconViewCellInfo *info = l->data;
7928       
7929       if (GTK_IS_CELL_RENDERER_TEXT (info->cell))
7930         {
7931           g_object_get (info->cell, "text", &text, NULL);
7932           
7933           return text;
7934         }
7935     }
7936
7937   return NULL;
7938 }
7939
7940 static void
7941 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
7942                                                     gint     *width,
7943                                                     gint     *height)
7944 {
7945   GtkIconViewItemAccessible *item;
7946   GdkRectangle box;
7947
7948   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7949
7950   if (!GTK_IS_ICON_VIEW (item->widget))
7951     return;
7952
7953   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7954     return;
7955
7956   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7957     {
7958       *width = box.width;
7959       *height = box.height;  
7960     }
7961 }
7962
7963 static void
7964 gtk_icon_view_item_accessible_image_get_image_position (AtkImage    *image,
7965                                                         gint        *x,
7966                                                         gint        *y,
7967                                                         AtkCoordType coord_type)
7968 {
7969   GtkIconViewItemAccessible *item;
7970   GdkRectangle box;
7971
7972   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
7973
7974   if (!GTK_IS_ICON_VIEW (item->widget))
7975     return;
7976
7977   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
7978     return;
7979
7980   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
7981
7982   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
7983     {
7984       *x+= box.x - item->item->x;
7985       *y+= box.y - item->item->y;
7986     }
7987
7988 }
7989
7990 static void
7991 atk_image_item_interface_init (AtkImageIface *iface)
7992 {
7993   iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
7994   iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
7995   iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
7996   iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
7997 }
7998
7999 static gchar *
8000 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
8001                                              gint     start_pos,
8002                                              gint     end_pos)
8003 {
8004   GtkIconViewItemAccessible *item;
8005   GtkTextIter start, end;
8006   GtkTextBuffer *buffer;
8007
8008   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8009
8010   if (!GTK_IS_ICON_VIEW (item->widget))
8011     return NULL;
8012
8013   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8014     return NULL;
8015
8016   buffer = item->text_buffer;
8017   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
8018   if (end_pos < 0)
8019     gtk_text_buffer_get_end_iter (buffer, &end);
8020   else
8021     gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
8022
8023   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
8024 }
8025
8026 static gunichar
8027 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
8028                                                             gint     offset)
8029 {
8030   GtkIconViewItemAccessible *item;
8031   GtkTextIter start, end;
8032   GtkTextBuffer *buffer;
8033   gchar *string;
8034   gunichar unichar;
8035
8036   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8037
8038   if (!GTK_IS_ICON_VIEW (item->widget))
8039     return '\0';
8040
8041   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8042     return '\0';
8043
8044   buffer = item->text_buffer;
8045   if (offset >= gtk_text_buffer_get_char_count (buffer))
8046     return '\0';
8047
8048   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
8049   end = start;
8050   gtk_text_iter_forward_char (&end);
8051   string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
8052   unichar = g_utf8_get_char (string);
8053   g_free(string);
8054
8055   return unichar;
8056 }
8057
8058 #if 0
8059 static void
8060 get_pango_text_offsets (PangoLayout     *layout,
8061                         GtkTextBuffer   *buffer,
8062                         gint             function,
8063                         AtkTextBoundary  boundary_type,
8064                         gint             offset,
8065                         gint            *start_offset,
8066                         gint            *end_offset,
8067                         GtkTextIter     *start_iter,
8068                         GtkTextIter     *end_iter)
8069 {
8070   PangoLayoutIter *iter;
8071   PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
8072   gint index, start_index, end_index;
8073   const gchar *text;
8074   gboolean found = FALSE;
8075
8076   text = pango_layout_get_text (layout);
8077   index = g_utf8_offset_to_pointer (text, offset) - text;
8078   iter = pango_layout_get_iter (layout);
8079   do
8080     {
8081       line = pango_layout_iter_get_line_readonly (iter);
8082       start_index = line->start_index;
8083       end_index = start_index + line->length;
8084
8085       if (index >= start_index && index <= end_index)
8086         {
8087           /*
8088            * Found line for offset
8089            */
8090           switch (function)
8091             {
8092             case 0:
8093                   /*
8094                    * We want the previous line
8095                    */
8096               if (prev_line)
8097                 {
8098                   switch (boundary_type)
8099                     {
8100                     case ATK_TEXT_BOUNDARY_LINE_START:
8101                       end_index = start_index;
8102                       start_index = prev_line->start_index;
8103                       break;
8104                     case ATK_TEXT_BOUNDARY_LINE_END:
8105                       if (prev_prev_line)
8106                         start_index = prev_prev_line->start_index + 
8107                                   prev_prev_line->length;
8108                       end_index = prev_line->start_index + prev_line->length;
8109                       break;
8110                     default:
8111                       g_assert_not_reached();
8112                     }
8113                 }
8114               else
8115                 start_index = end_index = 0;
8116               break;
8117             case 1:
8118               switch (boundary_type)
8119                 {
8120                 case ATK_TEXT_BOUNDARY_LINE_START:
8121                   if (pango_layout_iter_next_line (iter))
8122                     end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
8123                   break;
8124                 case ATK_TEXT_BOUNDARY_LINE_END:
8125                   if (prev_line)
8126                     start_index = prev_line->start_index + 
8127                                   prev_line->length;
8128                   break;
8129                 default:
8130                   g_assert_not_reached();
8131                 }
8132               break;
8133             case 2:
8134                /*
8135                 * We want the next line
8136                 */
8137               if (pango_layout_iter_next_line (iter))
8138                 {
8139                   line = pango_layout_iter_get_line_readonly (iter);
8140                   switch (boundary_type)
8141                     {
8142                     case ATK_TEXT_BOUNDARY_LINE_START:
8143                       start_index = line->start_index;
8144                       if (pango_layout_iter_next_line (iter))
8145                         end_index = pango_layout_iter_get_line_readonly (iter)->start_index;
8146                       else
8147                         end_index = start_index + line->length;
8148                       break;
8149                     case ATK_TEXT_BOUNDARY_LINE_END:
8150                       start_index = end_index;
8151                       end_index = line->start_index + line->length;
8152                       break;
8153                     default:
8154                       g_assert_not_reached();
8155                     }
8156                 }
8157               else
8158                 start_index = end_index;
8159               break;
8160             }
8161           found = TRUE;
8162           break;
8163         }
8164       prev_prev_line = prev_line; 
8165       prev_line = line; 
8166     }
8167   while (pango_layout_iter_next_line (iter));
8168
8169   if (!found)
8170     {
8171       start_index = prev_line->start_index + prev_line->length;
8172       end_index = start_index;
8173     }
8174   pango_layout_iter_free (iter);
8175   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
8176   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
8177  
8178   gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
8179   gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
8180 }
8181 #endif
8182
8183 static gchar*
8184 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText         *text,
8185                                                            gint            offset,
8186                                                            AtkTextBoundary boundary_type,
8187                                                            gint            *start_offset,
8188                                                            gint            *end_offset)
8189 {
8190   GtkIconViewItemAccessible *item;
8191   GtkTextIter start, end;
8192   GtkTextBuffer *buffer;
8193 #if 0
8194   GtkIconView *icon_view;
8195 #endif
8196
8197   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8198
8199   if (!GTK_IS_ICON_VIEW (item->widget))
8200     return NULL;
8201
8202   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8203     return NULL;
8204
8205   buffer = item->text_buffer;
8206
8207   if (!gtk_text_buffer_get_char_count (buffer))
8208     {
8209       *start_offset = 0;
8210       *end_offset = 0;
8211       return g_strdup ("");
8212     }
8213   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
8214    
8215   end = start;
8216
8217   switch (boundary_type)
8218     {
8219     case ATK_TEXT_BOUNDARY_CHAR:
8220       gtk_text_iter_backward_char(&start);
8221       break;
8222     case ATK_TEXT_BOUNDARY_WORD_START:
8223       if (!gtk_text_iter_starts_word (&start))
8224         gtk_text_iter_backward_word_start (&start);
8225       end = start;
8226       gtk_text_iter_backward_word_start(&start);
8227       break;
8228     case ATK_TEXT_BOUNDARY_WORD_END:
8229       if (gtk_text_iter_inside_word (&start) &&
8230           !gtk_text_iter_starts_word (&start))
8231         gtk_text_iter_backward_word_start (&start);
8232       while (!gtk_text_iter_ends_word (&start))
8233         {
8234           if (!gtk_text_iter_backward_char (&start))
8235             break;
8236         }
8237       end = 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       break;
8245     case ATK_TEXT_BOUNDARY_SENTENCE_START:
8246       if (!gtk_text_iter_starts_sentence (&start))
8247         gtk_text_iter_backward_sentence_start (&start);
8248       end = start;
8249       gtk_text_iter_backward_sentence_start (&start);
8250       break;
8251     case ATK_TEXT_BOUNDARY_SENTENCE_END:
8252       if (gtk_text_iter_inside_sentence (&start) &&
8253           !gtk_text_iter_starts_sentence (&start))
8254         gtk_text_iter_backward_sentence_start (&start);
8255       while (!gtk_text_iter_ends_sentence (&start))
8256         {
8257           if (!gtk_text_iter_backward_char (&start))
8258             break;
8259         }
8260       end = 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       break;
8268    case ATK_TEXT_BOUNDARY_LINE_START:
8269    case ATK_TEXT_BOUNDARY_LINE_END:
8270 #if 0
8271       icon_view = GTK_ICON_VIEW (item->widget);
8272       /* FIXME we probably have to use GailTextCell to salvage this */
8273       gtk_icon_view_update_item_text (icon_view, item->item);
8274       get_pango_text_offsets (icon_view->priv->layout,
8275                               buffer,
8276                               0,
8277                               boundary_type,
8278                               offset,
8279                               start_offset,
8280                               end_offset,
8281                               &start,
8282                               &end);
8283 #endif
8284       break;
8285     }
8286
8287   *start_offset = gtk_text_iter_get_offset (&start);
8288   *end_offset = gtk_text_iter_get_offset (&end);
8289
8290   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
8291 }
8292
8293 static gchar*
8294 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText         *text,
8295                                                        gint            offset,
8296                                                        AtkTextBoundary boundary_type,
8297                                                        gint            *start_offset,
8298                                                        gint            *end_offset)
8299 {
8300   GtkIconViewItemAccessible *item;
8301   GtkTextIter start, end;
8302   GtkTextBuffer *buffer;
8303 #if 0
8304   GtkIconView *icon_view;
8305 #endif
8306
8307   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8308
8309   if (!GTK_IS_ICON_VIEW (item->widget))
8310     return NULL;
8311
8312   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8313     return NULL;
8314
8315   buffer = item->text_buffer;
8316
8317   if (!gtk_text_buffer_get_char_count (buffer))
8318     {
8319       *start_offset = 0;
8320       *end_offset = 0;
8321       return g_strdup ("");
8322     }
8323   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
8324    
8325   end = start;
8326
8327   switch (boundary_type)
8328     {
8329     case ATK_TEXT_BOUNDARY_CHAR:
8330       gtk_text_iter_forward_char (&end);
8331       break;
8332     case ATK_TEXT_BOUNDARY_WORD_START:
8333       if (!gtk_text_iter_starts_word (&start))
8334         gtk_text_iter_backward_word_start (&start);
8335       if (gtk_text_iter_inside_word (&end))
8336         gtk_text_iter_forward_word_end (&end);
8337       while (!gtk_text_iter_starts_word (&end))
8338         {
8339           if (!gtk_text_iter_forward_char (&end))
8340             break;
8341         }
8342       break;
8343     case ATK_TEXT_BOUNDARY_WORD_END:
8344       if (gtk_text_iter_inside_word (&start) &&
8345           !gtk_text_iter_starts_word (&start))
8346         gtk_text_iter_backward_word_start (&start);
8347       while (!gtk_text_iter_ends_word (&start))
8348         {
8349           if (!gtk_text_iter_backward_char (&start))
8350             break;
8351         }
8352       gtk_text_iter_forward_word_end (&end);
8353       break;
8354     case ATK_TEXT_BOUNDARY_SENTENCE_START:
8355       if (!gtk_text_iter_starts_sentence (&start))
8356         gtk_text_iter_backward_sentence_start (&start);
8357       if (gtk_text_iter_inside_sentence (&end))
8358         gtk_text_iter_forward_sentence_end (&end);
8359       while (!gtk_text_iter_starts_sentence (&end))
8360         {
8361           if (!gtk_text_iter_forward_char (&end))
8362             break;
8363         }
8364       break;
8365     case ATK_TEXT_BOUNDARY_SENTENCE_END:
8366       if (gtk_text_iter_inside_sentence (&start) &&
8367           !gtk_text_iter_starts_sentence (&start))
8368         gtk_text_iter_backward_sentence_start (&start);
8369       while (!gtk_text_iter_ends_sentence (&start))
8370         {
8371           if (!gtk_text_iter_backward_char (&start))
8372             break;
8373         }
8374       gtk_text_iter_forward_sentence_end (&end);
8375       break;
8376    case ATK_TEXT_BOUNDARY_LINE_START:
8377    case ATK_TEXT_BOUNDARY_LINE_END:
8378 #if 0
8379       icon_view = GTK_ICON_VIEW (item->widget);
8380       /* FIXME we probably have to use GailTextCell to salvage this */
8381       gtk_icon_view_update_item_text (icon_view, item->item);
8382       get_pango_text_offsets (icon_view->priv->layout,
8383                               buffer,
8384                               1,
8385                               boundary_type,
8386                               offset,
8387                               start_offset,
8388                               end_offset,
8389                               &start,
8390                               &end);
8391 #endif
8392       break;
8393     }
8394
8395
8396   *start_offset = gtk_text_iter_get_offset (&start);
8397   *end_offset = gtk_text_iter_get_offset (&end);
8398
8399   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
8400 }
8401
8402 static gchar*
8403 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText         *text,
8404                                                           gint            offset,
8405                                                           AtkTextBoundary boundary_type,
8406                                                           gint            *start_offset,
8407                                                           gint            *end_offset)
8408 {
8409   GtkIconViewItemAccessible *item;
8410   GtkTextIter start, end;
8411   GtkTextBuffer *buffer;
8412 #if 0
8413   GtkIconView *icon_view;
8414 #endif
8415
8416   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8417
8418   if (!GTK_IS_ICON_VIEW (item->widget))
8419     return NULL;
8420
8421   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8422     return NULL;
8423
8424   buffer = item->text_buffer;
8425
8426   if (!gtk_text_buffer_get_char_count (buffer))
8427     {
8428       *start_offset = 0;
8429       *end_offset = 0;
8430       return g_strdup ("");
8431     }
8432   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
8433    
8434   end = start;
8435
8436   switch (boundary_type)
8437     {
8438     case ATK_TEXT_BOUNDARY_CHAR:
8439       gtk_text_iter_forward_char(&start);
8440       gtk_text_iter_forward_chars(&end, 2);
8441       break;
8442     case ATK_TEXT_BOUNDARY_WORD_START:
8443       if (gtk_text_iter_inside_word (&end))
8444         gtk_text_iter_forward_word_end (&end);
8445       while (!gtk_text_iter_starts_word (&end))
8446         {
8447           if (!gtk_text_iter_forward_char (&end))
8448             break;
8449         }
8450       start = end;
8451       if (!gtk_text_iter_is_end (&end))
8452         {
8453           gtk_text_iter_forward_word_end (&end);
8454           while (!gtk_text_iter_starts_word (&end))
8455             {
8456               if (!gtk_text_iter_forward_char (&end))
8457                 break;
8458             }
8459         }
8460       break;
8461     case ATK_TEXT_BOUNDARY_WORD_END:
8462       gtk_text_iter_forward_word_end (&end);
8463       start = end;
8464       if (!gtk_text_iter_is_end (&end))
8465         gtk_text_iter_forward_word_end (&end);
8466       break;
8467     case ATK_TEXT_BOUNDARY_SENTENCE_START:
8468       if (gtk_text_iter_inside_sentence (&end))
8469         gtk_text_iter_forward_sentence_end (&end);
8470       while (!gtk_text_iter_starts_sentence (&end))
8471         {
8472           if (!gtk_text_iter_forward_char (&end))
8473             break;
8474         }
8475       start = end;
8476       if (!gtk_text_iter_is_end (&end))
8477         {
8478           gtk_text_iter_forward_sentence_end (&end);
8479           while (!gtk_text_iter_starts_sentence (&end))
8480             {
8481               if (!gtk_text_iter_forward_char (&end))
8482                 break;
8483             }
8484         }
8485       break;
8486     case ATK_TEXT_BOUNDARY_SENTENCE_END:
8487       gtk_text_iter_forward_sentence_end (&end);
8488       start = end;
8489       if (!gtk_text_iter_is_end (&end))
8490         gtk_text_iter_forward_sentence_end (&end);
8491       break;
8492    case ATK_TEXT_BOUNDARY_LINE_START:
8493    case ATK_TEXT_BOUNDARY_LINE_END:
8494 #if 0
8495       icon_view = GTK_ICON_VIEW (item->widget);
8496       /* FIXME we probably have to use GailTextCell to salvage this */
8497       gtk_icon_view_update_item_text (icon_view, item->item);
8498       get_pango_text_offsets (icon_view->priv->layout,
8499                               buffer,
8500                               2,
8501                               boundary_type,
8502                               offset,
8503                               start_offset,
8504                               end_offset,
8505                               &start,
8506                               &end);
8507 #endif
8508       break;
8509     }
8510   *start_offset = gtk_text_iter_get_offset (&start);
8511   *end_offset = gtk_text_iter_get_offset (&end);
8512
8513   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
8514 }
8515
8516 static gint
8517 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
8518 {
8519   GtkIconViewItemAccessible *item;
8520
8521   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8522
8523   if (!GTK_IS_ICON_VIEW (item->widget))
8524     return 0;
8525
8526   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8527     return 0;
8528
8529   return gtk_text_buffer_get_char_count (item->text_buffer);
8530 }
8531
8532 static void
8533 gtk_icon_view_item_accessible_text_get_character_extents (AtkText      *text,
8534                                                           gint         offset,
8535                                                           gint         *x,
8536                                                           gint         *y,
8537                                                           gint         *width,
8538                                                           gint         *height,
8539                                                           AtkCoordType coord_type)
8540 {
8541   GtkIconViewItemAccessible *item;
8542 #if 0
8543   GtkIconView *icon_view;
8544   PangoRectangle char_rect;
8545   const gchar *item_text;
8546   gint index;
8547 #endif
8548
8549   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8550
8551   if (!GTK_IS_ICON_VIEW (item->widget))
8552     return;
8553
8554   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8555     return;
8556
8557 #if 0
8558   icon_view = GTK_ICON_VIEW (item->widget);
8559       /* FIXME we probably have to use GailTextCell to salvage this */
8560   gtk_icon_view_update_item_text (icon_view, item->item);
8561   item_text = pango_layout_get_text (icon_view->priv->layout);
8562   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
8563   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
8564
8565   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
8566   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
8567   /* Look at gtk_icon_view_paint_item() to see where the text is. */
8568   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
8569   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
8570   *width = char_rect.width / PANGO_SCALE;
8571   *height = char_rect.height / PANGO_SCALE;
8572 #endif
8573 }
8574
8575 static gint
8576 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText      *text,
8577                                                         gint          x,
8578                                                         gint          y,
8579                                                         AtkCoordType coord_type)
8580 {
8581   GtkIconViewItemAccessible *item;
8582   gint offset = 0;
8583 #if 0
8584   GtkIconView *icon_view;
8585   const gchar *item_text;
8586   gint index;
8587   gint l_x, l_y;
8588 #endif
8589
8590   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
8591
8592   if (!GTK_IS_ICON_VIEW (item->widget))
8593     return -1;
8594
8595   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8596     return -1;
8597
8598 #if 0
8599   icon_view = GTK_ICON_VIEW (item->widget);
8600       /* FIXME we probably have to use GailTextCell to salvage this */
8601   gtk_icon_view_update_item_text (icon_view, item->item);
8602   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
8603   x -= l_x + item->item->layout_x - item->item->x;
8604   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
8605   y -= l_y + item->item->layout_y - item->item->y;
8606   item_text = pango_layout_get_text (icon_view->priv->layout);
8607   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
8608                                 x * PANGO_SCALE,
8609                                 y * PANGO_SCALE,
8610                                 &index, NULL))
8611     {
8612       if (x < 0 || y < 0)
8613         index = 0;
8614       else
8615         index = -1;
8616     } 
8617   if (index == -1)
8618     offset = g_utf8_strlen (item_text, -1);
8619   else
8620     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
8621 #endif
8622   return offset;
8623 }
8624
8625 static void
8626 atk_text_item_interface_init (AtkTextIface *iface)
8627 {
8628   iface->get_text = gtk_icon_view_item_accessible_text_get_text;
8629   iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
8630   iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
8631   iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
8632   iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
8633   iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
8634   iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
8635   iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
8636 }
8637
8638 static void
8639 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
8640                                            gint         *x,
8641                                            gint         *y,
8642                                            gint         *width,
8643                                            gint         *height,
8644                                            AtkCoordType  coord_type)
8645 {
8646   GtkIconViewItemAccessible *item;
8647   AtkObject *parent_obj;
8648   gint l_x, l_y;
8649
8650   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
8651
8652   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8653   if (!GTK_IS_WIDGET (item->widget))
8654     return;
8655
8656   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
8657     return;
8658
8659   *width = item->item->width;
8660   *height = item->item->height;
8661   if (gtk_icon_view_item_accessible_is_showing (item))
8662     {
8663       parent_obj = gtk_widget_get_accessible (item->widget);
8664       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
8665       *x = l_x + item->item->x;
8666       *y = l_y + item->item->y;
8667     }
8668   else
8669     {
8670       *x = G_MININT;
8671       *y = G_MININT;
8672     }
8673 }
8674
8675 static gboolean
8676 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
8677 {
8678   GtkIconViewItemAccessible *item;
8679   GtkWidget *toplevel;
8680
8681   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
8682
8683   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
8684   if (!GTK_IS_WIDGET (item->widget))
8685     return FALSE;
8686
8687   gtk_widget_grab_focus (item->widget);
8688   gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, -1);
8689   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
8690   if (gtk_widget_is_toplevel (toplevel))
8691     gtk_window_present (GTK_WINDOW (toplevel));
8692
8693   return TRUE;
8694 }
8695
8696 static void
8697 atk_component_item_interface_init (AtkComponentIface *iface)
8698 {
8699   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
8700   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
8701 }
8702
8703 static gboolean
8704 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
8705                                          AtkStateType               state_type,
8706                                          gboolean                   emit_signal)
8707 {
8708   gboolean rc;
8709
8710   rc = atk_state_set_add_state (item->state_set, state_type);
8711   /*
8712    * The signal should only be generated if the value changed,
8713    * not when the item is set up.  So states that are set
8714    * initially should pass FALSE as the emit_signal argument.
8715    */
8716
8717   if (emit_signal)
8718     {
8719       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
8720       /* If state_type is ATK_STATE_VISIBLE, additional notification */
8721       if (state_type == ATK_STATE_VISIBLE)
8722         g_signal_emit_by_name (item, "visible-data-changed");
8723     }
8724
8725   return rc;
8726 }
8727
8728 static gboolean
8729 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
8730                                             AtkStateType               state_type,
8731                                             gboolean                   emit_signal)
8732 {
8733   if (atk_state_set_contains_state (item->state_set, state_type))
8734     {
8735       gboolean rc;
8736
8737       rc = atk_state_set_remove_state (item->state_set, state_type);
8738       /*
8739        * The signal should only be generated if the value changed,
8740        * not when the item is set up.  So states that are set
8741        * initially should pass FALSE as the emit_signal argument.
8742        */
8743
8744       if (emit_signal)
8745         {
8746           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
8747           /* If state_type is ATK_STATE_VISIBLE, additional notification */
8748           if (state_type == ATK_STATE_VISIBLE)
8749             g_signal_emit_by_name (item, "visible-data-changed");
8750         }
8751
8752       return rc;
8753     }
8754   else
8755     return FALSE;
8756 }
8757
8758 static gboolean
8759 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
8760 {
8761   GtkAllocation allocation;
8762   GtkIconView *icon_view;
8763   GdkRectangle visible_rect;
8764   gboolean is_showing;
8765
8766   /*
8767    * An item is considered "SHOWING" if any part of the item is in the
8768    * visible rectangle.
8769    */
8770
8771   if (!GTK_IS_ICON_VIEW (item->widget))
8772     return FALSE;
8773
8774   if (item->item == NULL)
8775     return FALSE;
8776
8777   gtk_widget_get_allocation (item->widget, &allocation);
8778
8779   icon_view = GTK_ICON_VIEW (item->widget);
8780   visible_rect.x = 0;
8781   if (icon_view->priv->hadjustment)
8782     visible_rect.x += icon_view->priv->hadjustment->value;
8783   visible_rect.y = 0;
8784   if (icon_view->priv->hadjustment)
8785     visible_rect.y += icon_view->priv->vadjustment->value;
8786   visible_rect.width = allocation.width;
8787   visible_rect.height = allocation.height;
8788
8789   if (((item->item->x + item->item->width) < visible_rect.x) ||
8790      ((item->item->y + item->item->height) < (visible_rect.y)) ||
8791      (item->item->x > (visible_rect.x + visible_rect.width)) ||
8792      (item->item->y > (visible_rect.y + visible_rect.height)))
8793     is_showing =  FALSE;
8794   else
8795     is_showing = TRUE;
8796
8797   return is_showing;
8798 }
8799
8800 static gboolean
8801 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
8802                                               gboolean                   emit_signal)
8803 {
8804   if (gtk_icon_view_item_accessible_is_showing (item))
8805     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
8806                                                     emit_signal);
8807   else
8808     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
8809                                                        emit_signal);
8810 }
8811
8812 static void
8813 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
8814 {
8815   gint i;
8816
8817   item->state_set = atk_state_set_new ();
8818
8819   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
8820   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
8821   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
8822   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
8823   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
8824
8825   for (i = 0; i < LAST_ACTION; i++)
8826     item->action_descriptions[i] = NULL;
8827
8828   item->image_description = NULL;
8829
8830   item->action_idle_handler = 0;
8831 }
8832
8833 static void
8834 gtk_icon_view_item_accessible_finalize (GObject *object)
8835 {
8836   GtkIconViewItemAccessible *item;
8837   gint i;
8838
8839   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
8840
8841   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
8842
8843   if (item->widget)
8844     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
8845
8846   if (item->state_set)
8847     g_object_unref (item->state_set);
8848
8849   if (item->text_buffer)
8850      g_object_unref (item->text_buffer);
8851
8852   for (i = 0; i < LAST_ACTION; i++)
8853     g_free (item->action_descriptions[i]);
8854
8855   g_free (item->image_description);
8856
8857   if (item->action_idle_handler)
8858     {
8859       g_source_remove (item->action_idle_handler);
8860       item->action_idle_handler = 0;
8861     }
8862
8863   G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
8864 }
8865
8866 static G_CONST_RETURN gchar*
8867 gtk_icon_view_item_accessible_get_name (AtkObject *obj)
8868 {
8869   if (obj->name)
8870     return obj->name;
8871   else
8872     {
8873       GtkIconViewItemAccessible *item;
8874       GtkTextIter start_iter;
8875       GtkTextIter end_iter;
8876
8877       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8878  
8879       gtk_text_buffer_get_start_iter (item->text_buffer, &start_iter); 
8880       gtk_text_buffer_get_end_iter (item->text_buffer, &end_iter); 
8881
8882       return gtk_text_buffer_get_text (item->text_buffer, &start_iter, &end_iter, FALSE);
8883     }
8884 }
8885
8886 static AtkObject*
8887 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
8888 {
8889   GtkIconViewItemAccessible *item;
8890
8891   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
8892   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8893
8894   if (item->widget)
8895     return gtk_widget_get_accessible (item->widget);
8896   else
8897     return NULL;
8898 }
8899
8900 static gint
8901 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
8902 {
8903   GtkIconViewItemAccessible *item;
8904
8905   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
8906   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8907
8908   return item->item->index; 
8909 }
8910
8911 static AtkStateSet *
8912 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
8913 {
8914   GtkIconViewItemAccessible *item;
8915   GtkIconView *icon_view;
8916
8917   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
8918   g_return_val_if_fail (item->state_set, NULL);
8919
8920   if (!item->widget)
8921     return NULL;
8922
8923   icon_view = GTK_ICON_VIEW (item->widget);
8924   if (icon_view->priv->cursor_item == item->item)
8925     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
8926   else
8927     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
8928   if (item->item->selected)
8929     atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
8930   else
8931     atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
8932
8933   return g_object_ref (item->state_set);
8934 }
8935
8936 static void
8937 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
8938 {
8939   GObjectClass *gobject_class;
8940
8941   accessible_item_parent_class = g_type_class_peek_parent (klass);
8942
8943   gobject_class = (GObjectClass *)klass;
8944
8945   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
8946
8947   klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent; 
8948   klass->get_name = gtk_icon_view_item_accessible_get_name; 
8949   klass->get_parent = gtk_icon_view_item_accessible_get_parent; 
8950   klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set; 
8951 }
8952
8953 static GType
8954 gtk_icon_view_item_accessible_get_type (void)
8955 {
8956   static GType type = 0;
8957
8958   if (!type)
8959     {
8960       const GTypeInfo tinfo =
8961       {
8962         sizeof (GtkIconViewItemAccessibleClass),
8963         (GBaseInitFunc) NULL, /* base init */
8964         (GBaseFinalizeFunc) NULL, /* base finalize */
8965         (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
8966         (GClassFinalizeFunc) NULL, /* class finalize */
8967         NULL, /* class data */
8968         sizeof (GtkIconViewItemAccessible), /* instance size */
8969         0, /* nb preallocs */
8970         (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
8971         NULL /* value table */
8972       };
8973
8974       const GInterfaceInfo atk_component_info =
8975       {
8976         (GInterfaceInitFunc) atk_component_item_interface_init,
8977         (GInterfaceFinalizeFunc) NULL,
8978         NULL
8979       };
8980       const GInterfaceInfo atk_action_info =
8981       {
8982         (GInterfaceInitFunc) atk_action_item_interface_init,
8983         (GInterfaceFinalizeFunc) NULL,
8984         NULL
8985       };
8986       const GInterfaceInfo atk_image_info =
8987       {
8988         (GInterfaceInitFunc) atk_image_item_interface_init,
8989         (GInterfaceFinalizeFunc) NULL,
8990         NULL
8991       };
8992       const GInterfaceInfo atk_text_info =
8993       {
8994         (GInterfaceInitFunc) atk_text_item_interface_init,
8995         (GInterfaceFinalizeFunc) NULL,
8996         NULL
8997       };
8998
8999       type = g_type_register_static (ATK_TYPE_OBJECT,
9000                                      I_("GtkIconViewItemAccessible"), &tinfo, 0);
9001       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9002                                    &atk_component_info);
9003       g_type_add_interface_static (type, ATK_TYPE_ACTION,
9004                                    &atk_action_info);
9005       g_type_add_interface_static (type, ATK_TYPE_IMAGE,
9006                                    &atk_image_info);
9007       g_type_add_interface_static (type, ATK_TYPE_TEXT,
9008                                    &atk_text_info);
9009     }
9010
9011   return type;
9012 }
9013
9014 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE      (gtk_icon_view_accessible_get_type ())
9015 #define GTK_ICON_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
9016 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
9017
9018 static GType gtk_icon_view_accessible_get_type (void);
9019
9020 typedef struct
9021 {
9022    AtkObject parent;
9023 } GtkIconViewAccessible;
9024
9025 typedef struct
9026 {
9027   AtkObject *item;
9028   gint       index;
9029 } GtkIconViewItemAccessibleInfo;
9030
9031 typedef struct
9032 {
9033   GList *items;
9034
9035   GtkAdjustment *old_hadj;
9036   GtkAdjustment *old_vadj;
9037
9038   GtkTreeModel *model;
9039
9040 } GtkIconViewAccessiblePrivate;
9041
9042 static GtkIconViewAccessiblePrivate *
9043 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
9044 {
9045   return g_object_get_qdata (G_OBJECT (accessible),
9046                              accessible_private_data_quark);
9047 }
9048
9049 static void
9050 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
9051                                         AtkObject *item,
9052                                         gint       index)
9053 {
9054   GtkIconViewItemAccessibleInfo *info;
9055   GtkIconViewItemAccessibleInfo *tmp_info;
9056   GtkIconViewAccessiblePrivate *priv;
9057   GList *items;
9058
9059   info = g_new (GtkIconViewItemAccessibleInfo, 1);
9060   info->item = item;
9061   info->index = index;
9062
9063   priv = gtk_icon_view_accessible_get_priv (accessible);
9064   items = priv->items;
9065   while (items)
9066     {
9067       tmp_info = items->data;
9068       if (tmp_info->index > index)
9069         break;
9070       items = items->next;
9071     }
9072   priv->items = g_list_insert_before (priv->items, items, info);
9073   priv->old_hadj = NULL;
9074   priv->old_vadj = NULL;
9075 }
9076
9077 static gint
9078 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
9079 {
9080   GtkIconView *icon_view;
9081   GtkWidget *widget;
9082
9083   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
9084   if (!widget)
9085       return 0;
9086
9087   icon_view = GTK_ICON_VIEW (widget);
9088
9089   return g_list_length (icon_view->priv->items);
9090 }
9091
9092 static AtkObject *
9093 gtk_icon_view_accessible_find_child (AtkObject *accessible,
9094                                      gint       index)
9095 {
9096   GtkIconViewAccessiblePrivate *priv;
9097   GtkIconViewItemAccessibleInfo *info;
9098   GList *items;
9099
9100   priv = gtk_icon_view_accessible_get_priv (accessible);
9101   items = priv->items;
9102
9103   while (items)
9104     {
9105       info = items->data;
9106       if (info->index == index)
9107         return info->item;
9108       items = items->next; 
9109     }
9110   return NULL;
9111 }
9112
9113 static AtkObject *
9114 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
9115                                     gint       index)
9116 {
9117   GtkIconView *icon_view;
9118   GtkWidget *widget;
9119   GList *icons;
9120   AtkObject *obj;
9121   GtkIconViewItemAccessible *a11y_item;
9122
9123   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
9124   if (!widget)
9125     return NULL;
9126
9127   icon_view = GTK_ICON_VIEW (widget);
9128   icons = g_list_nth (icon_view->priv->items, index);
9129   obj = NULL;
9130   if (icons)
9131     {
9132       GtkIconViewItem *item = icons->data;
9133    
9134       g_return_val_if_fail (item->index == index, NULL);
9135       obj = gtk_icon_view_accessible_find_child (accessible, index);
9136       if (!obj)
9137         {
9138           gchar *text;
9139
9140           obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
9141           gtk_icon_view_item_accessible_info_new (accessible,
9142                                                   obj,
9143                                                   index);
9144           obj->role = ATK_ROLE_ICON;
9145           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
9146           a11y_item->item = item;
9147           a11y_item->widget = widget;
9148           a11y_item->text_buffer = gtk_text_buffer_new (NULL);
9149
9150           gtk_icon_view_set_cell_data (icon_view, item);
9151           text = get_text (icon_view, item);
9152           if (text)
9153             {
9154               gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
9155               g_free (text);
9156             } 
9157
9158           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
9159           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
9160        }
9161       g_object_ref (obj);
9162     }
9163   return obj;
9164 }
9165
9166 static void
9167 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
9168                                          GList                 *list)
9169 {
9170   GtkIconViewAccessiblePrivate *priv;
9171   GtkIconViewItemAccessibleInfo *info;
9172   GtkIconViewItemAccessible *item;
9173   GList *items;
9174   
9175   priv =  gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
9176   if (priv->items)
9177     {
9178       GtkWidget *widget;
9179       gboolean act_on_item;
9180
9181       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
9182       if (widget == NULL)
9183         return;
9184
9185       items = priv->items;
9186
9187       act_on_item = (list == NULL);
9188
9189       while (items)
9190         {
9191
9192           info = (GtkIconViewItemAccessibleInfo *)items->data;
9193           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
9194
9195           if (act_on_item == FALSE && list == items)
9196             act_on_item = TRUE;
9197
9198           if (act_on_item)
9199             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
9200
9201           items = items->next;
9202        }
9203    }
9204 }
9205
9206 static void
9207 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
9208                                              GtkIconView   *icon_view)
9209 {
9210   AtkObject *obj;
9211   GtkIconViewAccessible *view;
9212
9213   /*
9214    * The scrollbars have changed
9215    */
9216   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
9217   view = GTK_ICON_VIEW_ACCESSIBLE (obj);
9218
9219   gtk_icon_view_accessible_traverse_items (view, NULL);
9220 }
9221
9222 static void
9223 gtk_icon_view_accessible_set_adjustment (GtkIconView    *icon_view,
9224                                          GtkOrientation  orientation,
9225                                          GtkAdjustment  *adjustment)
9226 {
9227   AtkObject *atk_obj;
9228   GtkIconViewAccessiblePrivate *priv;
9229   GtkAdjustment **old_adj_ptr;
9230
9231   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
9232   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9233
9234   /* Adjustments are set for the first time in constructor and priv is not
9235    * initialized at that time, so skip this first setting. */
9236   if (!priv)
9237     return;
9238
9239   if (orientation == GTK_ORIENTATION_HORIZONTAL)
9240     {
9241       if (priv->old_hadj == adjustment)
9242         return;
9243
9244       old_adj_ptr = &priv->old_hadj;
9245     }
9246   else
9247     {
9248       if (priv->old_vadj == adjustment)
9249         return;
9250
9251       old_adj_ptr = &priv->old_vadj;
9252     }
9253
9254   /* Disconnect signal handlers */
9255   if (*old_adj_ptr)
9256     {
9257       g_object_remove_weak_pointer (G_OBJECT (*old_adj_ptr),
9258                                     (gpointer *)&priv->old_hadj);
9259       g_signal_handlers_disconnect_by_func (*old_adj_ptr,
9260                                             gtk_icon_view_accessible_adjustment_changed,
9261                                             icon_view);
9262     }
9263
9264   /* Connect signal */
9265   *old_adj_ptr = adjustment;
9266   g_object_add_weak_pointer (G_OBJECT (adjustment), (gpointer *)old_adj_ptr);
9267   g_signal_connect (adjustment, "value-changed",
9268                     G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
9269                     icon_view);
9270 }
9271
9272 static void
9273 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
9274                                             GtkTreePath  *path,
9275                                             GtkTreeIter  *iter,
9276                                             gpointer      user_data)
9277 {
9278   AtkObject *atk_obj;
9279   gint index;
9280   GtkWidget *widget;
9281   GtkIconView *icon_view;
9282   GtkIconViewItem *item;
9283   GtkIconViewAccessible *a11y_view;
9284   GtkIconViewItemAccessible *a11y_item;
9285   const gchar *name;
9286   gchar *text;
9287
9288   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
9289   a11y_view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
9290   index = gtk_tree_path_get_indices(path)[0];
9291   a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
9292       gtk_icon_view_accessible_find_child (atk_obj, index));
9293
9294   if (a11y_item)
9295     {
9296       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
9297       icon_view = GTK_ICON_VIEW (widget);
9298       item = a11y_item->item;
9299
9300       name = gtk_icon_view_item_accessible_get_name (ATK_OBJECT (a11y_item));
9301
9302       if (!name || strcmp (name, "") == 0)
9303         {
9304           gtk_icon_view_set_cell_data (icon_view, item);
9305           text = get_text (icon_view, item);
9306           if (text)
9307             {
9308               gtk_text_buffer_set_text (a11y_item->text_buffer, text, -1);
9309               g_free (text);
9310             }
9311         }
9312     }
9313
9314   g_signal_emit_by_name (atk_obj, "visible-data-changed");
9315
9316   return;
9317 }
9318
9319 static void
9320 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
9321                                              GtkTreePath  *path,
9322                                              GtkTreeIter  *iter,
9323                                              gpointer     user_data)
9324 {
9325   GtkIconViewAccessiblePrivate *priv;
9326   GtkIconViewItemAccessibleInfo *info;
9327   GtkIconViewAccessible *view;
9328   GtkIconViewItemAccessible *item;
9329   GList *items;
9330   GList *tmp_list;
9331   AtkObject *atk_obj;
9332   gint index;
9333
9334   index = gtk_tree_path_get_indices(path)[0];
9335   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
9336   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
9337   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9338
9339   items = priv->items;
9340   tmp_list = NULL;
9341   while (items)
9342     {
9343       info = items->data;
9344       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
9345       if (info->index != item->item->index)
9346         {
9347           if (info->index < index)
9348             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
9349  
9350           if (tmp_list == NULL)
9351             tmp_list = items;
9352    
9353           info->index = item->item->index;
9354         }
9355
9356       items = items->next;
9357     }
9358   gtk_icon_view_accessible_traverse_items (view, tmp_list);
9359   g_signal_emit_by_name (atk_obj, "children-changed::add",
9360                          index, NULL, NULL);
9361   return;
9362 }
9363
9364 static void
9365 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
9366                                             GtkTreePath  *path,
9367                                             gpointer     user_data)
9368 {
9369   GtkIconViewAccessiblePrivate *priv;
9370   GtkIconViewItemAccessibleInfo *info;
9371   GtkIconViewAccessible *view;
9372   GtkIconViewItemAccessible *item;
9373   GList *items;
9374   GList *tmp_list;
9375   GList *deleted_item;
9376   AtkObject *atk_obj;
9377   gint index;
9378
9379   index = gtk_tree_path_get_indices(path)[0];
9380   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
9381   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
9382   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9383
9384   items = priv->items;
9385   tmp_list = NULL;
9386   deleted_item = NULL;
9387   info = NULL;
9388   while (items)
9389     {
9390       info = items->data;
9391       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
9392       if (info->index == index)
9393         {
9394           deleted_item = items;
9395         }
9396       if (info->index != item->item->index)
9397         {
9398           if (tmp_list == NULL)
9399             tmp_list = items;
9400             
9401           info->index = item->item->index;
9402         }
9403
9404       items = items->next;
9405     }
9406   gtk_icon_view_accessible_traverse_items (view, tmp_list);
9407   if (deleted_item)
9408     {
9409       info = deleted_item->data;
9410       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
9411       g_signal_emit_by_name (atk_obj, "children-changed::remove",
9412                              index, NULL, NULL);
9413       priv->items = g_list_remove_link (priv->items, deleted_item);
9414       g_free (info);
9415     }
9416
9417   return;
9418 }
9419
9420 static gint
9421 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
9422                                        GtkIconViewItemAccessibleInfo *i2)
9423 {
9424   return i1->index - i2->index;
9425 }
9426
9427 static void
9428 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
9429                                                GtkTreePath  *path,
9430                                                GtkTreeIter  *iter,
9431                                                gint         *new_order,
9432                                                gpointer     user_data)
9433 {
9434   GtkIconViewAccessiblePrivate *priv;
9435   GtkIconViewItemAccessibleInfo *info;
9436   GtkIconView *icon_view;
9437   GtkIconViewItemAccessible *item;
9438   GList *items;
9439   AtkObject *atk_obj;
9440   gint *order;
9441   gint length, i;
9442
9443   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
9444   icon_view = GTK_ICON_VIEW (user_data);
9445   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9446
9447   length = gtk_tree_model_iter_n_children (tree_model, NULL);
9448
9449   order = g_new (gint, length);
9450   for (i = 0; i < length; i++)
9451     order [new_order[i]] = i;
9452
9453   items = priv->items;
9454   while (items)
9455     {
9456       info = items->data;
9457       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
9458       info->index = order[info->index];
9459       item->item = g_list_nth_data (icon_view->priv->items, info->index);
9460       items = items->next;
9461     }
9462   g_free (order);
9463   priv->items = g_list_sort (priv->items, 
9464                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
9465
9466   return;
9467 }
9468
9469 static void
9470 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
9471                                                    GtkWidget *widget)
9472 {
9473   GObject *obj;
9474
9475   obj = G_OBJECT (model);
9476   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
9477   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
9478   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
9479   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
9480 }
9481
9482 static void
9483 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
9484 {
9485   GObject *obj;
9486
9487   obj = G_OBJECT (icon_view->priv->model);
9488   g_signal_connect_data (obj, "row-changed",
9489                          (GCallback) gtk_icon_view_accessible_model_row_changed,
9490                          icon_view, NULL, 0);
9491   g_signal_connect_data (obj, "row-inserted",
9492                          (GCallback) gtk_icon_view_accessible_model_row_inserted, 
9493                          icon_view, NULL, G_CONNECT_AFTER);
9494   g_signal_connect_data (obj, "row-deleted",
9495                          (GCallback) gtk_icon_view_accessible_model_row_deleted, 
9496                          icon_view, NULL, G_CONNECT_AFTER);
9497   g_signal_connect_data (obj, "rows-reordered",
9498                          (GCallback) gtk_icon_view_accessible_model_rows_reordered, 
9499                          icon_view, NULL, G_CONNECT_AFTER);
9500 }
9501
9502 static void
9503 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
9504 {
9505   GtkIconViewItemAccessibleInfo *info;
9506   GList *items;
9507
9508   items = priv->items;
9509   while (items)
9510     {
9511       info = (GtkIconViewItemAccessibleInfo *) items->data;
9512       g_object_unref (info->item);
9513       g_free (items->data);
9514       items = items->next;
9515     }
9516   g_list_free (priv->items);
9517   priv->items = NULL;
9518 }
9519
9520 static void
9521 gtk_icon_view_accessible_notify_gtk (GObject *obj,
9522                                      GParamSpec *pspec)
9523 {
9524   GtkIconView *icon_view;
9525   GtkWidget *widget;
9526   AtkObject *atk_obj;
9527   GtkIconViewAccessiblePrivate *priv;
9528
9529   if (strcmp (pspec->name, "model") == 0)
9530     {
9531       widget = GTK_WIDGET (obj); 
9532       atk_obj = gtk_widget_get_accessible (widget);
9533       priv = gtk_icon_view_accessible_get_priv (atk_obj);
9534       if (priv->model)
9535         {
9536           g_object_remove_weak_pointer (G_OBJECT (priv->model),
9537                                         (gpointer *)&priv->model);
9538           gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
9539         }
9540       gtk_icon_view_accessible_clear_cache (priv);
9541
9542       icon_view = GTK_ICON_VIEW (obj);
9543       priv->model = icon_view->priv->model;
9544       /* If there is no model the GtkIconView is probably being destroyed */
9545       if (priv->model)
9546         {
9547           g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
9548           gtk_icon_view_accessible_connect_model_signals (icon_view);
9549         }
9550     }
9551
9552   return;
9553 }
9554
9555 static void
9556 gtk_icon_view_accessible_initialize (AtkObject *accessible,
9557                                      gpointer   data)
9558 {
9559   GtkIconViewAccessiblePrivate *priv;
9560   GtkIconView *icon_view;
9561
9562   if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
9563     ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
9564
9565   priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
9566   g_object_set_qdata (G_OBJECT (accessible),
9567                       accessible_private_data_quark,
9568                       priv);
9569
9570   icon_view = GTK_ICON_VIEW (data);
9571   if (icon_view->priv->hadjustment)
9572     gtk_icon_view_accessible_set_adjustment (icon_view,
9573                                              GTK_ORIENTATION_HORIZONTAL,
9574                                              icon_view->priv->hadjustment);
9575   if (icon_view->priv->vadjustment)
9576     gtk_icon_view_accessible_set_adjustment (icon_view,
9577                                              GTK_ORIENTATION_VERTICAL,
9578                                              icon_view->priv->vadjustment);
9579   g_signal_connect (data,
9580                     "notify",
9581                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
9582                     NULL);
9583
9584   priv->model = icon_view->priv->model;
9585   if (priv->model)
9586     {
9587       g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
9588       gtk_icon_view_accessible_connect_model_signals (icon_view);
9589     }
9590                           
9591   accessible->role = ATK_ROLE_LAYERED_PANE;
9592 }
9593
9594 static void
9595 gtk_icon_view_accessible_finalize (GObject *object)
9596 {
9597   GtkIconViewAccessiblePrivate *priv;
9598
9599   priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
9600   gtk_icon_view_accessible_clear_cache (priv);
9601
9602   g_free (priv);
9603
9604   G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
9605 }
9606
9607 static void
9608 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
9609                                     GtkAccessible *accessible)
9610 {
9611   AtkObject *atk_obj;
9612   GtkIconViewAccessiblePrivate *priv;
9613
9614   atk_obj = ATK_OBJECT (accessible);
9615   priv = gtk_icon_view_accessible_get_priv (atk_obj);
9616   if (priv->old_hadj)
9617     {
9618       g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
9619                                     (gpointer *)&priv->old_hadj);
9620           
9621       g_signal_handlers_disconnect_by_func (priv->old_hadj,
9622                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
9623                                             widget);
9624       priv->old_hadj = NULL;
9625     }
9626   if (priv->old_vadj)
9627     {
9628       g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
9629                                     (gpointer *)&priv->old_vadj);
9630           
9631       g_signal_handlers_disconnect_by_func (priv->old_vadj,
9632                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
9633                                             widget);
9634       priv->old_vadj = NULL;
9635     }
9636 }
9637
9638 static void
9639 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
9640 {
9641   GtkWidget *widget;
9642
9643   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
9644   if (widget)
9645     {
9646       g_signal_connect_after (widget,
9647                               "destroy",
9648                               G_CALLBACK (gtk_icon_view_accessible_destroyed),
9649                               accessible);
9650     }
9651   GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
9652 }
9653
9654 static void
9655 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
9656 {
9657   GObjectClass *gobject_class;
9658   GtkAccessibleClass *accessible_class;
9659
9660   accessible_parent_class = g_type_class_peek_parent (klass);
9661
9662   gobject_class = (GObjectClass *)klass;
9663   accessible_class = (GtkAccessibleClass *)klass;
9664
9665   gobject_class->finalize = gtk_icon_view_accessible_finalize;
9666
9667   klass->get_n_children = gtk_icon_view_accessible_get_n_children;
9668   klass->ref_child = gtk_icon_view_accessible_ref_child;
9669   klass->initialize = gtk_icon_view_accessible_initialize;
9670
9671   accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
9672
9673   accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
9674 }
9675
9676 static AtkObject*
9677 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
9678                                                   gint          x,
9679                                                   gint          y,
9680                                                   AtkCoordType  coord_type)
9681 {
9682   GtkWidget *widget;
9683   GtkIconView *icon_view;
9684   GtkIconViewItem *item;
9685   gint x_pos, y_pos;
9686
9687   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
9688   if (widget == NULL)
9689   /* State is defunct */
9690     return NULL;
9691
9692   icon_view = GTK_ICON_VIEW (widget);
9693   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
9694   item = gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
9695   if (item)
9696     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
9697
9698   return NULL;
9699 }
9700
9701 static void
9702 atk_component_interface_init (AtkComponentIface *iface)
9703 {
9704   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
9705 }
9706
9707 static gboolean
9708 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
9709                                         gint i)
9710 {
9711   GtkWidget *widget;
9712   GtkIconView *icon_view;
9713   GtkIconViewItem *item;
9714
9715   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9716   if (widget == NULL)
9717     return FALSE;
9718
9719   icon_view = GTK_ICON_VIEW (widget);
9720
9721   item = g_list_nth_data (icon_view->priv->items, i);
9722
9723   if (!item)
9724     return FALSE;
9725
9726   gtk_icon_view_select_item (icon_view, item);
9727
9728   return TRUE;
9729 }
9730
9731 static gboolean
9732 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
9733 {
9734   GtkWidget *widget;
9735   GtkIconView *icon_view;
9736
9737   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9738   if (widget == NULL)
9739     return FALSE;
9740
9741   icon_view = GTK_ICON_VIEW (widget);
9742   gtk_icon_view_unselect_all (icon_view);
9743
9744   return TRUE;
9745 }
9746
9747 static AtkObject*
9748 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
9749                                         gint          i)
9750 {
9751   GList *l;
9752   GtkWidget *widget;
9753   GtkIconView *icon_view;
9754   GtkIconViewItem *item;
9755
9756   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9757   if (widget == NULL)
9758     return NULL;
9759
9760   icon_view = GTK_ICON_VIEW (widget);
9761
9762   l = icon_view->priv->items;
9763   while (l)
9764     {
9765       item = l->data;
9766       if (item->selected)
9767         {
9768           if (i == 0)
9769             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
9770           else
9771             i--;
9772         }
9773       l = l->next;
9774     }
9775
9776   return NULL;
9777 }
9778
9779 static gint
9780 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
9781 {
9782   GtkWidget *widget;
9783   GtkIconView *icon_view;
9784   GtkIconViewItem *item;
9785   GList *l;
9786   gint count;
9787
9788   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9789   if (widget == NULL)
9790     return 0;
9791
9792   icon_view = GTK_ICON_VIEW (widget);
9793
9794   l = icon_view->priv->items;
9795   count = 0;
9796   while (l)
9797     {
9798       item = l->data;
9799
9800       if (item->selected)
9801         count++;
9802
9803       l = l->next;
9804     }
9805
9806   return count;
9807 }
9808
9809 static gboolean
9810 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
9811                                             gint          i)
9812 {
9813   GtkWidget *widget;
9814   GtkIconView *icon_view;
9815   GtkIconViewItem *item;
9816
9817   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9818   if (widget == NULL)
9819     return FALSE;
9820
9821   icon_view = GTK_ICON_VIEW (widget);
9822
9823   item = g_list_nth_data (icon_view->priv->items, i);
9824   if (!item)
9825     return FALSE;
9826
9827   return item->selected;
9828 }
9829
9830 static gboolean
9831 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
9832                                            gint          i)
9833 {
9834   GtkWidget *widget;
9835   GtkIconView *icon_view;
9836   GtkIconViewItem *item;
9837   GList *l;
9838   gint count;
9839
9840   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9841   if (widget == NULL)
9842     return FALSE;
9843
9844   icon_view = GTK_ICON_VIEW (widget);
9845   l = icon_view->priv->items;
9846   count = 0;
9847   while (l)
9848     {
9849       item = l->data;
9850       if (item->selected)
9851         {
9852           if (count == i)
9853             {
9854               gtk_icon_view_unselect_item (icon_view, item);
9855               return TRUE;
9856             }
9857           count++;
9858         }
9859       l = l->next;
9860     }
9861
9862   return FALSE;
9863 }
9864  
9865 static gboolean
9866 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
9867 {
9868   GtkWidget *widget;
9869   GtkIconView *icon_view;
9870
9871   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
9872   if (widget == NULL)
9873     return FALSE;
9874
9875   icon_view = GTK_ICON_VIEW (widget);
9876   gtk_icon_view_select_all (icon_view);
9877   return TRUE;
9878 }
9879
9880 static void
9881 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
9882 {
9883   iface->add_selection = gtk_icon_view_accessible_add_selection;
9884   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
9885   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
9886   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
9887   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
9888   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
9889   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
9890 }
9891
9892 static GType
9893 gtk_icon_view_accessible_get_type (void)
9894 {
9895   static GType type = 0;
9896
9897   if (!type)
9898     {
9899       GTypeInfo tinfo =
9900       {
9901         0, /* class size */
9902         (GBaseInitFunc) NULL, /* base init */
9903         (GBaseFinalizeFunc) NULL, /* base finalize */
9904         (GClassInitFunc) gtk_icon_view_accessible_class_init,
9905         (GClassFinalizeFunc) NULL, /* class finalize */
9906         NULL, /* class data */
9907         0, /* instance size */
9908         0, /* nb preallocs */
9909         (GInstanceInitFunc) NULL, /* instance init */
9910         NULL /* value table */
9911       };
9912       const GInterfaceInfo atk_component_info =
9913       {
9914         (GInterfaceInitFunc) atk_component_interface_init,
9915         (GInterfaceFinalizeFunc) NULL,
9916         NULL
9917       };
9918       const GInterfaceInfo atk_selection_info =
9919       {
9920         (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
9921         (GInterfaceFinalizeFunc) NULL,
9922         NULL
9923       };
9924
9925       /*
9926        * Figure out the size of the class and instance
9927        * we are deriving from
9928        */
9929       AtkObjectFactory *factory;
9930       GType derived_type;
9931       GTypeQuery query;
9932       GType derived_atk_type;
9933
9934       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
9935       factory = atk_registry_get_factory (atk_get_default_registry (), 
9936                                           derived_type);
9937       derived_atk_type = atk_object_factory_get_accessible_type (factory);
9938       g_type_query (derived_atk_type, &query);
9939       tinfo.class_size = query.class_size;
9940       tinfo.instance_size = query.instance_size;
9941  
9942       type = g_type_register_static (derived_atk_type, 
9943                                      I_("GtkIconViewAccessible"), 
9944                                      &tinfo, 0);
9945       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
9946                                    &atk_component_info);
9947       g_type_add_interface_static (type, ATK_TYPE_SELECTION,
9948                                    &atk_selection_info);
9949     }
9950   return type;
9951 }
9952
9953 static AtkObject *
9954 gtk_icon_view_accessible_new (GObject *obj)
9955 {
9956   AtkObject *accessible;
9957
9958   g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
9959
9960   accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
9961   atk_object_initialize (accessible, obj);
9962
9963   return accessible;
9964 }
9965
9966 static GType
9967 gtk_icon_view_accessible_factory_get_accessible_type (void)
9968 {
9969   return gtk_icon_view_accessible_get_type ();
9970 }
9971
9972 static AtkObject*
9973 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
9974 {
9975   return gtk_icon_view_accessible_new (obj);
9976 }
9977
9978 static void
9979 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
9980 {
9981   klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
9982   klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
9983 }
9984
9985 static GType
9986 gtk_icon_view_accessible_factory_get_type (void)
9987 {
9988   static GType type = 0;
9989
9990   if (!type)
9991     {
9992       const GTypeInfo tinfo =
9993       {
9994         sizeof (AtkObjectFactoryClass),
9995         NULL,           /* base_init */
9996         NULL,           /* base_finalize */
9997         (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
9998         NULL,           /* class_finalize */
9999         NULL,           /* class_data */
10000         sizeof (AtkObjectFactory),
10001         0,             /* n_preallocs */
10002         NULL, NULL
10003       };
10004
10005       type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
10006                                     I_("GtkIconViewAccessibleFactory"),
10007                                     &tinfo, 0);
10008     }
10009   return type;
10010 }
10011
10012
10013 static AtkObject *
10014 gtk_icon_view_get_accessible (GtkWidget *widget)
10015 {
10016   static gboolean first_time = TRUE;
10017
10018   if (first_time)
10019     {
10020       AtkObjectFactory *factory;
10021       AtkRegistry *registry;
10022       GType derived_type; 
10023       GType derived_atk_type; 
10024
10025       /*
10026        * Figure out whether accessibility is enabled by looking at the
10027        * type of the accessible object which would be created for
10028        * the parent type of GtkIconView.
10029        */
10030       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
10031
10032       registry = atk_get_default_registry ();
10033       factory = atk_registry_get_factory (registry,
10034                                           derived_type);
10035       derived_atk_type = atk_object_factory_get_accessible_type (factory);
10036       if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
10037         atk_registry_set_factory_type (registry, 
10038                                        GTK_TYPE_ICON_VIEW,
10039                                        gtk_icon_view_accessible_factory_get_type ());
10040       first_time = FALSE;
10041     } 
10042   return GTK_WIDGET_CLASS (gtk_icon_view_parent_class)->get_accessible (widget);
10043 }
10044
10045 static gboolean
10046 gtk_icon_view_buildable_custom_tag_start (GtkBuildable  *buildable,
10047                                           GtkBuilder    *builder,
10048                                           GObject       *child,
10049                                           const gchar   *tagname,
10050                                           GMarkupParser *parser,
10051                                           gpointer      *data)
10052 {
10053   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
10054                                                 tagname, parser, data))
10055     return TRUE;
10056
10057   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
10058                                                       tagname, parser, data);
10059 }
10060
10061 static void
10062 gtk_icon_view_buildable_custom_tag_end (GtkBuildable *buildable,
10063                                         GtkBuilder   *builder,
10064                                         GObject      *child,
10065                                         const gchar  *tagname,
10066                                         gpointer     *data)
10067 {
10068   if (strcmp (tagname, "attributes") == 0)
10069     _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
10070                                                data);
10071   else
10072     parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
10073                                             data);
10074 }