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