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