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