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