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