]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconview.c
gdk/gdkkeyuni.c gdk/gdkpixbuf-drawable.c gdk/gdkrgb.c gdk/x11/gdkdnd-x11.c
[~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 "gtkalias.h"
28 #include "gtkiconview.h"
29 #include "gtkmarshalers.h"
30 #include "gtkbindings.h"
31 #include "gtkdnd.h"
32 #include "gtkmain.h"
33 #include "gtksignal.h"
34 #include "gtkintl.h"
35 #include "gtkaccessible.h"
36 #include "gtkwindow.h"
37 #include "gtktextbuffer.h"
38
39 #undef DEBUG_ICON_VIEW
40
41 #define ICON_TEXT_PADDING 3
42
43 #define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
44 #define VALID_MODEL_AND_COLUMNS(obj) ((obj)->priv->model != NULL && \
45                                       ((obj)->priv->pixbuf_column != -1 || \
46                                        (obj)->priv->text_column != -1 || \
47                                        (obj)->priv->markup_column != -1))
48
49 typedef struct 
50 {
51   GtkTreeIter iter;
52   int index;
53   
54   gint row, col;
55
56   /* Bounding boxes */
57   gint x, y;
58   gint width, height;
59
60   gint pixbuf_x, pixbuf_y;
61   gint pixbuf_height, pixbuf_width;
62
63   gint layout_x, layout_y;
64   gint layout_width, layout_height;
65
66   guint selected : 1;
67   guint selected_before_rubberbanding : 1;
68 } GtkIconViewItem;
69
70 struct _GtkIconViewPrivate
71 {
72   gint width, height;
73
74   gint text_column;
75   gint markup_column;
76   gint pixbuf_column;
77   
78   GtkSelectionMode selection_mode;
79
80   GdkWindow *bin_window;
81
82   GtkTreeModel *model;
83   
84   GList *items;
85   
86   GtkAdjustment *hadjustment;
87   GtkAdjustment *vadjustment;
88
89   guint layout_idle_id;
90   
91   gboolean doing_rubberband;
92   gint rubberband_x1, rubberband_y1;
93   gint rubberband_x2, rubberband_y2;
94
95   guint scroll_timeout_id;
96   gint scroll_value_diff;
97   gint event_last_x, event_last_y;
98
99   GtkIconViewItem *anchor_item;
100   GtkIconViewItem *cursor_item;
101
102   guint ctrl_pressed : 1;
103   guint shift_pressed : 1;
104   
105   GtkIconViewItem *last_single_clicked;
106
107 #ifdef DND_WORKS
108   /* Drag-and-drop. */
109   gint pressed_button;
110   gint press_start_x;
111   gint press_start_y;
112 #endif
113
114   /* Layout used to draw icon text */
115   PangoLayout *layout;
116   
117   GtkOrientation orientation;
118
119   gint columns;
120   gint item_width;
121   gint spacing;
122   gint row_spacing;
123   gint column_spacing;
124   gint margin;
125 };
126
127 /* Signals */
128 enum
129 {
130   ITEM_ACTIVATED,
131   SELECTION_CHANGED,
132   SELECT_ALL,
133   UNSELECT_ALL,
134   SELECT_CURSOR_ITEM,
135   TOGGLE_CURSOR_ITEM,
136   MOVE_CURSOR,
137   ACTIVATE_CURSOR_ITEM,
138   LAST_SIGNAL
139 };
140
141 /* Properties */
142 enum
143 {
144   PROP_0,
145   PROP_PIXBUF_COLUMN,
146   PROP_TEXT_COLUMN,
147   PROP_MARKUP_COLUMN,  
148   PROP_SELECTION_MODE,
149   PROP_ORIENTATION,
150   PROP_MODEL,
151   PROP_COLUMNS,
152   PROP_ITEM_WIDTH,
153   PROP_SPACING,
154   PROP_ROW_SPACING,
155   PROP_COLUMN_SPACING,
156   PROP_MARGIN
157 };
158
159 /* GObject signals */
160 static void gtk_icon_view_finalize     (GObject      *object);
161 static void gtk_icon_view_set_property (GObject      *object,
162                                         guint         prop_id,
163                                         const GValue *value,
164                                         GParamSpec   *pspec);
165 static void gtk_icon_view_get_property (GObject      *object,
166                                         guint         prop_id,
167                                         GValue       *value,
168                                         GParamSpec   *pspec);
169
170
171 /* GtkObject signals */
172 static void gtk_icon_view_destroy (GtkObject *object);
173
174 /* GtkWidget signals */
175 static void     gtk_icon_view_realize        (GtkWidget      *widget);
176 static void     gtk_icon_view_unrealize      (GtkWidget      *widget);
177 static void     gtk_icon_view_map            (GtkWidget      *widget);
178 static void     gtk_icon_view_size_request   (GtkWidget      *widget,
179                                               GtkRequisition *requisition);
180 static void     gtk_icon_view_size_allocate  (GtkWidget      *widget,
181                                               GtkAllocation  *allocation);
182 static gboolean gtk_icon_view_expose         (GtkWidget      *widget,
183                                               GdkEventExpose *expose);
184 static gboolean gtk_icon_view_motion         (GtkWidget      *widget,
185                                               GdkEventMotion *event);
186 static gboolean gtk_icon_view_button_press   (GtkWidget      *widget,
187                                               GdkEventButton *event);
188 static gboolean gtk_icon_view_button_release (GtkWidget      *widget,
189                                               GdkEventButton *event);
190 /* GtkIconView signals */
191 static void     gtk_icon_view_set_adjustments           (GtkIconView   *icon_view,
192                                                          GtkAdjustment *hadj,
193                                                          GtkAdjustment *vadj);
194 static void     gtk_icon_view_real_select_all           (GtkIconView   *icon_view);
195 static void     gtk_icon_view_real_unselect_all         (GtkIconView   *icon_view);
196 static void     gtk_icon_view_real_select_cursor_item   (GtkIconView   *icon_view);
197 static void     gtk_icon_view_real_toggle_cursor_item   (GtkIconView   *icon_view);
198 static gboolean gtk_icon_view_real_activate_cursor_item (GtkIconView   *icon_view);
199
200 /* Internal functions */
201 static void       gtk_icon_view_adjustment_changed          (GtkAdjustment   *adjustment,
202                                                              GtkIconView     *icon_view);
203 static void       gtk_icon_view_layout                      (GtkIconView     *icon_view);
204 static void       gtk_icon_view_paint_item                  (GtkIconView     *icon_view,
205                                                              GtkIconViewItem *item,
206                                                              GdkRectangle    *area);
207 static void       gtk_icon_view_paint_rubberband            (GtkIconView     *icon_view,
208                                                              GdkRectangle    *area);
209 static void       gtk_icon_view_queue_draw_item             (GtkIconView     *icon_view,
210                                                              GtkIconViewItem *item);
211 static void       gtk_icon_view_queue_layout                (GtkIconView     *icon_view);
212 static void       gtk_icon_view_set_cursor_item             (GtkIconView     *icon_view,
213                                                              GtkIconViewItem *item);
214 static void       gtk_icon_view_start_rubberbanding         (GtkIconView     *icon_view,
215                                                              gint             x,
216                                                              gint             y);
217 static void       gtk_icon_view_stop_rubberbanding          (GtkIconView     *icon_view);
218 static void       gtk_icon_view_update_rubberband_selection (GtkIconView     *icon_view);
219 static gboolean   gtk_icon_view_item_hit_test               (GtkIconViewItem *item,
220                                                              gint             x,
221                                                              gint             y,
222                                                              gint             width,
223                                                              gint             height);
224 #ifdef DND_WORKS
225 static gboolean   gtk_icon_view_maybe_begin_dragging_items  (GtkIconView     *icon_view,
226                                                              GdkEventMotion  *event);
227 #endif
228 static gboolean   gtk_icon_view_unselect_all_internal       (GtkIconView     *icon_view);
229 static void       gtk_icon_view_calculate_item_size         (GtkIconView     *icon_view,
230                                                              GtkIconViewItem *item,
231                                                              gint             item_width);
232 static void       gtk_icon_view_update_rubberband           (gpointer         data);
233 static void       gtk_icon_view_item_invalidate_size        (GtkIconViewItem *item);
234 static void       gtk_icon_view_invalidate_sizes            (GtkIconView     *icon_view);
235 static void       gtk_icon_view_add_move_binding            (GtkBindingSet   *binding_set,
236                                                              guint            keyval,
237                                                              guint            modmask,
238                                                              GtkMovementStep  step,
239                                                              gint             count);
240 static gboolean   gtk_icon_view_real_move_cursor            (GtkIconView     *icon_view,
241                                                              GtkMovementStep  step,
242                                                              gint             count);
243 static void       gtk_icon_view_move_cursor_up_down         (GtkIconView     *icon_view,
244                                                              gint             count);
245 static void       gtk_icon_view_move_cursor_page_up_down    (GtkIconView     *icon_view,
246                                                              gint             count);
247 static void       gtk_icon_view_move_cursor_left_right      (GtkIconView     *icon_view,
248                                                              gint             count);
249 static void       gtk_icon_view_move_cursor_start_end       (GtkIconView     *icon_view,
250                                                              gint             count);
251 static void       gtk_icon_view_scroll_to_item              (GtkIconView     *icon_view,
252                                                              GtkIconViewItem *item);
253 static GdkPixbuf *gtk_icon_view_get_item_icon               (GtkIconView     *icon_view,
254                                                              GtkIconViewItem *item);
255 static void       gtk_icon_view_update_item_text            (GtkIconView     *icon_view,
256                                                              GtkIconViewItem *item);
257 static void       gtk_icon_view_select_item                 (GtkIconView     *icon_view,
258                                                              GtkIconViewItem *item);
259 static void       gtk_icon_view_unselect_item               (GtkIconView     *icon_view,
260                                                              GtkIconViewItem *item);
261 static gboolean gtk_icon_view_select_all_between            (GtkIconView     *icon_view,
262                                                              GtkIconViewItem *anchor,
263                                                              GtkIconViewItem *cursor);
264
265 static GtkIconViewItem *gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
266                                                        gint         x,
267                                                        gint         y);
268
269
270 /* Accessibility Support */
271 static AtkObject       *gtk_icon_view_get_accessible  (GtkWidget   *widget);
272
273 static GtkContainerClass *parent_class = NULL;
274 static guint icon_view_signals[LAST_SIGNAL] = { 0 };
275
276 G_DEFINE_TYPE (GtkIconView, gtk_icon_view, GTK_TYPE_CONTAINER);
277
278 static void
279 gtk_icon_view_class_init (GtkIconViewClass *klass)
280 {
281   GObjectClass *gobject_class;
282   GtkObjectClass *object_class;
283   GtkWidgetClass *widget_class;
284   GtkBindingSet *binding_set;
285   
286   parent_class = g_type_class_peek_parent (klass);
287   binding_set = gtk_binding_set_by_class (klass);
288
289   g_type_class_add_private (klass, sizeof (GtkIconViewPrivate));
290
291   gobject_class = (GObjectClass *) klass;
292   object_class = (GtkObjectClass *) klass;
293   widget_class = (GtkWidgetClass *) klass;
294
295   gobject_class->finalize = gtk_icon_view_finalize;
296   gobject_class->set_property = gtk_icon_view_set_property;
297   gobject_class->get_property = gtk_icon_view_get_property;
298
299   object_class->destroy = gtk_icon_view_destroy;
300   
301   widget_class->realize = gtk_icon_view_realize;
302   widget_class->unrealize = gtk_icon_view_unrealize;
303   widget_class->map = gtk_icon_view_map;
304   widget_class->size_request = gtk_icon_view_size_request;
305   widget_class->size_allocate = gtk_icon_view_size_allocate;
306   widget_class->expose_event = gtk_icon_view_expose;
307   widget_class->motion_notify_event = gtk_icon_view_motion;
308   widget_class->button_press_event = gtk_icon_view_button_press;
309   widget_class->button_release_event = gtk_icon_view_button_release;
310   widget_class->get_accessible = gtk_icon_view_get_accessible;
311
312   klass->set_scroll_adjustments = gtk_icon_view_set_adjustments;
313   klass->select_all = gtk_icon_view_real_select_all;
314   klass->unselect_all = gtk_icon_view_real_unselect_all;
315   klass->select_cursor_item = gtk_icon_view_real_select_cursor_item;
316   klass->toggle_cursor_item = gtk_icon_view_real_toggle_cursor_item;
317   klass->activate_cursor_item = gtk_icon_view_real_activate_cursor_item;  
318   klass->move_cursor = gtk_icon_view_real_move_cursor;
319   
320   /* Properties */
321   /**
322    * GtkIconView:selection-mode:
323    * 
324    * The ::selection-mode property specifies the selection mode of
325    * icon view. If the mode is #GTK_SELECTION_MULTIPLE, rubberband selection
326    * is enabled, for the other modes, only keyboard selection is possible.
327    *
328    * Since: 2.6
329    */
330   g_object_class_install_property (gobject_class,
331                                    PROP_SELECTION_MODE,
332                                    g_param_spec_enum ("selection_mode",
333                                                       P_("Selection mode"),
334                                                       P_("The selection mode"),
335                                                       GTK_TYPE_SELECTION_MODE,
336                                                       GTK_SELECTION_SINGLE,
337                                                       G_PARAM_READWRITE));
338
339   /**
340    * GtkIconView:pixbuf-column:
341    *
342    * The ::pixbuf-column property contains the number of the model column
343    * containing the pixbufs which are displayed. The pixbuf column must be 
344    * of type #GDK_TYPE_PIXBUF. Setting this property to -1 turns off the
345    * display of pixbufs.
346    *
347    * Since: 2.6
348    */
349   g_object_class_install_property (gobject_class,
350                                    PROP_PIXBUF_COLUMN,
351                                    g_param_spec_int ("pixbuf_column",
352                                                      P_("Pixbuf column"),
353                                                      P_("Model column used to retrieve the icon pixbuf from"),
354                                                      -1, G_MAXINT, -1,
355                                                      G_PARAM_READWRITE));
356
357   /**
358    * GtkIconView:text-column:
359    *
360    * The ::text-column property contains the number of the model column
361    * containing the texts which are displayed. The text column must be 
362    * of type #G_TYPE_STRING. If this property and the :markup-column 
363    * property are both set to -1, no texts are displayed.   
364    *
365    * Since: 2.6
366    */
367   g_object_class_install_property (gobject_class,
368                                    PROP_TEXT_COLUMN,
369                                    g_param_spec_int ("text_column",
370                                                      P_("Text column"),
371                                                      P_("Model column used to retrieve the text from"),
372                                                      -1, G_MAXINT, -1,
373                                                      G_PARAM_READWRITE));
374
375   
376   /**
377    * GtkIconView:markup-column:
378    *
379    * The ::markup-column property contains the number of the model column
380    * containing markup information to be displayed. The markup column must be 
381    * of type #G_TYPE_STRING. If this property and the :text-column property 
382    * are both set to column numbers, it overrides the text column.
383    * If both are set to -1, no texts are displayed.   
384    *
385    * Since: 2.6
386    */
387   g_object_class_install_property (gobject_class,
388                                    PROP_MARKUP_COLUMN,
389                                    g_param_spec_int ("markup_column",
390                                                      P_("Markup column"),
391                                                      P_("Model column used to retrieve the text if using Pango markup"),
392                                                      -1, G_MAXINT, -1,
393                                                      G_PARAM_READWRITE));
394   
395   g_object_class_install_property (gobject_class,
396                                    PROP_MODEL,
397                                    g_param_spec_object ("model",
398                                                         P_("Icon View Model"),
399                                                         P_("The model for the icon view"),
400                                                         GTK_TYPE_TREE_MODEL,
401                                                         G_PARAM_READWRITE));
402   
403   /**
404    * GtkIconView:columns:
405    *
406    * The columns property contains the number of the columns in which the
407    * items should be displayed. If it is -1, the number of columns will
408    * be chosen automatically to fill the available area.
409    *
410    * Since: 2.6
411    */
412   g_object_class_install_property (gobject_class,
413                                    PROP_COLUMNS,
414                                    g_param_spec_int ("columns",
415                                                      P_("Number of columns"),
416                                                      P_("Number of columns to display"),
417                                                      -1, G_MAXINT, -1,
418                                                      G_PARAM_READWRITE));
419   
420
421   /**
422    * GtkIconView::item-width:
423    *
424    * The item-width property specifies the width to use for each item. 
425    * If it is set to -1, the icon view will automatically determine a 
426    * suitable item size.
427    *
428    * Since: 2.6
429    */
430   g_object_class_install_property (gobject_class,
431                                    PROP_ITEM_WIDTH,
432                                    g_param_spec_int ("item_width",
433                                                      P_("Width for each item"),
434                                                      P_("The width used for each item"),
435                                                      -1, G_MAXINT, -1,
436                                                      G_PARAM_READWRITE));  
437
438   /**
439    * GtkIconView::spacing:
440    *
441    * The spacing property specifies the space which is inserted between
442    * the cells (i.e. the icon and the text) of an item.
443    *
444    * Since: 2.6
445    */
446   g_object_class_install_property (gobject_class,
447                                    PROP_SPACING,
448                                    g_param_spec_int ("spacing",
449                                                      P_("Spacing"),
450                                                      P_("Space which is inserted between cells of an item"),
451                                                      0, G_MAXINT, 0,
452                                                      G_PARAM_READWRITE));
453
454   /**
455    * GtkIconView::row-spacing:
456    *
457    * The row-spacing property specifies the space which is inserted between
458    * the rows of the icon view.
459    *
460    * Since: 2.6
461    */
462   g_object_class_install_property (gobject_class,
463                                    PROP_ROW_SPACING,
464                                    g_param_spec_int ("row_spacing",
465                                                      P_("Row Spacing"),
466                                                      P_("Space which is inserted between grid rows"),
467                                                      0, G_MAXINT, 6,
468                                                      G_PARAM_READWRITE));
469
470   /**
471    * GtkIconView::column-spacing:
472    *
473    * The column-spacing property specifies the space which is inserted between
474    * the columns of the icon view.
475    *
476    * Since: 2.6
477    */
478   g_object_class_install_property (gobject_class,
479                                    PROP_COLUMN_SPACING,
480                                    g_param_spec_int ("column_spacing",
481                                                      P_("Column Spacing"),
482                                                      P_("Space which is inserted between grid column"),
483                                                      0, G_MAXINT, 6,
484                                                      G_PARAM_READWRITE));
485
486   /**
487    * GtkIconView::margin:
488    *
489    * The margin property specifies the space which is inserted 
490    * at the edges of the icon view.
491    *
492    * Since: 2.6
493    */
494   g_object_class_install_property (gobject_class,
495                                    PROP_MARGIN,
496                                    g_param_spec_int ("margin",
497                                                      P_("Margin"),
498                                                      P_("Space which is inserted at the edges of the icon view"),
499                                                      0, G_MAXINT, 6,
500                                                      G_PARAM_READWRITE));
501
502
503   /**
504    * GtkIconView::orientation:
505    *
506    * The orientation property specifies how the cells (i.e. the icon and 
507    * the text) of the item are positioned relative to each other.
508    *
509    * Since: 2.6
510    */
511   g_object_class_install_property (gobject_class,
512                                    PROP_ORIENTATION,
513                                    g_param_spec_enum ("orientation",
514                                                       P_("Orientation"),
515                                                       P_("How the text and icon of each item are positioned relative to each other"),
516                                                       GTK_TYPE_ORIENTATION,
517                                                       GTK_ORIENTATION_VERTICAL,
518                                                       G_PARAM_READWRITE));
519
520   /* Style properties */
521   gtk_widget_class_install_style_property (widget_class,
522                                            g_param_spec_boxed ("selection_box_color",
523                                                                P_("Selection Box Color"),
524                                                                P_("Color of the selection box"),
525                                                                GDK_TYPE_COLOR,
526                                                                G_PARAM_READABLE));
527
528   gtk_widget_class_install_style_property (widget_class,
529                                            g_param_spec_uchar ("selection_box_alpha",
530                                                                P_("Selection Box Alpha"),
531                                                                P_("Opacity of the selection box"),
532                                                                0, 0xff,
533                                                                0x40,
534                                                                G_PARAM_READABLE));
535
536   /* Signals */
537   widget_class->set_scroll_adjustments_signal =
538     g_signal_new ("set_scroll_adjustments",
539                   G_TYPE_FROM_CLASS (gobject_class),
540                   G_SIGNAL_RUN_LAST,
541                   G_STRUCT_OFFSET (GtkIconViewClass, set_scroll_adjustments),
542                   NULL, NULL, 
543                   _gtk_marshal_VOID__OBJECT_OBJECT,
544                   G_TYPE_NONE, 2,
545                   GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
546
547   icon_view_signals[ITEM_ACTIVATED] =
548     g_signal_new ("item_activated",
549                   G_TYPE_FROM_CLASS (gobject_class),
550                   G_SIGNAL_RUN_LAST,
551                   G_STRUCT_OFFSET (GtkIconViewClass, item_activated),
552                   NULL, NULL,
553                   g_cclosure_marshal_VOID__BOXED,
554                   G_TYPE_NONE, 1,
555                   GTK_TYPE_TREE_PATH);
556
557   icon_view_signals[SELECTION_CHANGED] =
558     g_signal_new ("selection_changed",
559                   G_TYPE_FROM_CLASS (gobject_class),
560                   G_SIGNAL_RUN_FIRST,
561                   G_STRUCT_OFFSET (GtkIconViewClass, selection_changed),
562                   NULL, NULL,
563                   g_cclosure_marshal_VOID__VOID,
564                   G_TYPE_NONE, 0);
565   
566   icon_view_signals[SELECT_ALL] =
567     g_signal_new ("select_all",
568                   G_TYPE_FROM_CLASS (gobject_class),
569                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
570                   G_STRUCT_OFFSET (GtkIconViewClass, select_all),
571                   NULL, NULL,
572                   g_cclosure_marshal_VOID__VOID,
573                   G_TYPE_NONE, 0);
574   
575   icon_view_signals[UNSELECT_ALL] =
576     g_signal_new ("unselect_all",
577                   G_TYPE_FROM_CLASS (gobject_class),
578                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
579                   G_STRUCT_OFFSET (GtkIconViewClass, unselect_all),
580                   NULL, NULL,
581                   g_cclosure_marshal_VOID__VOID,
582                   G_TYPE_NONE, 0);
583
584   icon_view_signals[SELECT_CURSOR_ITEM] =
585     g_signal_new ("select_cursor_item",
586                   G_TYPE_FROM_CLASS (gobject_class),
587                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
588                   G_STRUCT_OFFSET (GtkIconViewClass, select_cursor_item),
589                   NULL, NULL,
590                   g_cclosure_marshal_VOID__VOID,
591                   G_TYPE_NONE, 0);
592
593   icon_view_signals[TOGGLE_CURSOR_ITEM] =
594     g_signal_new ("toggle_cursor_item",
595                   G_TYPE_FROM_CLASS (gobject_class),
596                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
597                   G_STRUCT_OFFSET (GtkIconViewClass, toggle_cursor_item),
598                   NULL, NULL,
599                   g_cclosure_marshal_VOID__VOID,
600                   G_TYPE_NONE, 0);
601
602   icon_view_signals[ACTIVATE_CURSOR_ITEM] =
603     g_signal_new ("activate_cursor_item",
604                   G_TYPE_FROM_CLASS (gobject_class),
605                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
606                   G_STRUCT_OFFSET (GtkIconViewClass, activate_cursor_item),
607                   NULL, NULL,
608                   _gtk_marshal_BOOLEAN__VOID,
609                   G_TYPE_BOOLEAN, 0);
610   
611   icon_view_signals[MOVE_CURSOR] =
612     g_signal_new ("move_cursor",
613                   G_TYPE_FROM_CLASS (gobject_class),
614                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
615                   G_STRUCT_OFFSET (GtkIconViewClass, move_cursor),
616                   NULL, NULL,
617                   _gtk_marshal_BOOLEAN__ENUM_INT,
618                   G_TYPE_BOOLEAN, 2,
619                   GTK_TYPE_MOVEMENT_STEP,
620                   G_TYPE_INT);
621
622   /* Key bindings */
623   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
624   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
625   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_item", 0);
626   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_item", 0);
627
628   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "activate_cursor_item", 0);
629   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "activate_cursor_item", 0);
630   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "activate_cursor_item", 0);
631
632   gtk_icon_view_add_move_binding (binding_set, GDK_Up, 0,
633                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
634   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Up, 0,
635                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
636
637   gtk_icon_view_add_move_binding (binding_set, GDK_Down, 0,
638                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
639   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Down, 0,
640                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
641
642   gtk_icon_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
643                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
644
645   gtk_icon_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
646                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
647
648   gtk_icon_view_add_move_binding (binding_set, GDK_Home, 0,
649                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
650   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Home, 0,
651                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
652
653   gtk_icon_view_add_move_binding (binding_set, GDK_End, 0,
654                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
655   gtk_icon_view_add_move_binding (binding_set, GDK_KP_End, 0,
656                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
657
658   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Up, 0,
659                                   GTK_MOVEMENT_PAGES, -1);
660   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
661                                   GTK_MOVEMENT_PAGES, -1);
662
663   gtk_icon_view_add_move_binding (binding_set, GDK_Page_Down, 0,
664                                   GTK_MOVEMENT_PAGES, 1);
665   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
666                                   GTK_MOVEMENT_PAGES, 1);
667
668   gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0, 
669                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
670   gtk_icon_view_add_move_binding (binding_set, GDK_Left, 0, 
671                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
672
673   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Right, 0, 
674                                   GTK_MOVEMENT_VISUAL_POSITIONS, 1);
675   gtk_icon_view_add_move_binding (binding_set, GDK_KP_Left, 0, 
676                                   GTK_MOVEMENT_VISUAL_POSITIONS, -1);
677 }
678
679 static void
680 gtk_icon_view_init (GtkIconView *icon_view)
681 {
682   icon_view->priv = GTK_ICON_VIEW_GET_PRIVATE (icon_view);
683   
684   icon_view->priv->width = 0;
685   icon_view->priv->height = 0;
686   icon_view->priv->selection_mode = GTK_SELECTION_SINGLE;
687 #ifdef DND_WORKS
688   icon_view->priv->pressed_button = -1;
689   icon_view->priv->press_start_x = -1;
690   icon_view->priv->press_start_y = -1;
691 #endif
692   icon_view->priv->text_column = -1;
693   icon_view->priv->markup_column = -1;  
694   icon_view->priv->pixbuf_column = -1;
695   
696   icon_view->priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (icon_view), NULL);
697
698   pango_layout_set_wrap (icon_view->priv->layout, PANGO_WRAP_WORD_CHAR);
699
700   GTK_WIDGET_SET_FLAGS (icon_view, GTK_CAN_FOCUS);
701   
702   gtk_icon_view_set_adjustments (icon_view, NULL, NULL);
703
704   icon_view->priv->orientation = GTK_ORIENTATION_VERTICAL;
705
706   icon_view->priv->columns = -1;
707   icon_view->priv->item_width = -1;
708   icon_view->priv->spacing = 0;
709   icon_view->priv->row_spacing = 6;
710   icon_view->priv->column_spacing = 6;
711   icon_view->priv->margin = 6;
712 }
713
714 static void
715 gtk_icon_view_destroy (GtkObject *object)
716 {
717   GtkIconView *icon_view;
718
719   icon_view = GTK_ICON_VIEW (object);
720   
721   gtk_icon_view_set_model (icon_view, NULL);
722   
723   if (icon_view->priv->layout_idle_id != 0)
724     g_source_remove (icon_view->priv->layout_idle_id);
725
726   if (icon_view->priv->scroll_timeout_id != 0)
727     g_source_remove (icon_view->priv->scroll_timeout_id);
728   
729   (GTK_OBJECT_CLASS (parent_class)->destroy) (object);
730 }
731
732 /* GObject methods */
733 static void
734 gtk_icon_view_finalize (GObject *object)
735 {
736   GtkIconView *icon_view;
737
738   icon_view = GTK_ICON_VIEW (object);
739
740   g_object_unref (icon_view->priv->layout);
741   
742   (G_OBJECT_CLASS (parent_class)->finalize) (object);
743 }
744
745
746 static void
747 gtk_icon_view_set_property (GObject      *object,
748                             guint         prop_id,
749                             const GValue *value,
750                             GParamSpec   *pspec)
751 {
752   GtkIconView *icon_view;
753
754   icon_view = GTK_ICON_VIEW (object);
755
756   switch (prop_id)
757     {
758     case PROP_SELECTION_MODE:
759       gtk_icon_view_set_selection_mode (icon_view, g_value_get_enum (value));
760       break;
761     case PROP_PIXBUF_COLUMN:
762       gtk_icon_view_set_pixbuf_column (icon_view, g_value_get_int (value));
763       break;
764     case PROP_TEXT_COLUMN:
765       gtk_icon_view_set_text_column (icon_view, g_value_get_int (value));
766       break;
767     case PROP_MARKUP_COLUMN:
768       gtk_icon_view_set_markup_column (icon_view, g_value_get_int (value));
769       break;
770     case PROP_MODEL:
771       gtk_icon_view_set_model (icon_view, g_value_get_object (value));
772       break;
773     case PROP_ORIENTATION:
774       gtk_icon_view_set_orientation (icon_view, g_value_get_enum (value));
775       break;
776     case PROP_COLUMNS:
777       gtk_icon_view_set_columns (icon_view, g_value_get_int (value));
778       break;
779     case PROP_ITEM_WIDTH:
780       gtk_icon_view_set_item_width (icon_view, g_value_get_int (value));
781       break;
782     case PROP_SPACING:
783       gtk_icon_view_set_spacing (icon_view, g_value_get_int (value));
784       break;
785     case PROP_ROW_SPACING:
786       gtk_icon_view_set_row_spacing (icon_view, g_value_get_int (value));
787       break;
788     case PROP_COLUMN_SPACING:
789       gtk_icon_view_set_column_spacing (icon_view, g_value_get_int (value));
790       break;
791     case PROP_MARGIN:
792       gtk_icon_view_set_margin (icon_view, g_value_get_int (value));
793       break;
794       
795     default:
796       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
797       break;
798     }
799 }
800
801 static void
802 gtk_icon_view_get_property (GObject      *object,
803                             guint         prop_id,
804                             GValue       *value,
805                             GParamSpec   *pspec)
806 {
807   GtkIconView *icon_view;
808
809   icon_view = GTK_ICON_VIEW (object);
810
811   switch (prop_id)
812     {
813     case PROP_SELECTION_MODE:
814       g_value_set_enum (value, icon_view->priv->selection_mode);
815       break;
816     case PROP_PIXBUF_COLUMN:
817       g_value_set_int (value, icon_view->priv->pixbuf_column);
818       break;
819     case PROP_TEXT_COLUMN:
820       g_value_set_int (value, icon_view->priv->text_column);
821       break;
822     case PROP_MARKUP_COLUMN:
823       g_value_set_int (value, icon_view->priv->markup_column);
824       break;
825     case PROP_MODEL:
826       g_value_set_object (value, icon_view->priv->model);
827       break;
828     case PROP_ORIENTATION:
829       g_value_set_enum (value, icon_view->priv->orientation);
830       break;
831     case PROP_COLUMNS:
832       g_value_set_int (value, icon_view->priv->columns);
833       break;
834     case PROP_ITEM_WIDTH:
835       g_value_set_int (value, icon_view->priv->item_width);
836       break;
837     case PROP_SPACING:
838       g_value_set_int (value, icon_view->priv->spacing);
839       break;
840     case PROP_ROW_SPACING:
841       g_value_set_int (value, icon_view->priv->row_spacing);
842       break;
843     case PROP_COLUMN_SPACING:
844       g_value_set_int (value, icon_view->priv->column_spacing);
845       break;
846     case PROP_MARGIN:
847       g_value_set_int (value, icon_view->priv->margin);
848       break;
849
850     default:
851       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
852       break;
853     }
854 }
855
856 /* GtkWidget signals */
857 static void
858 gtk_icon_view_realize (GtkWidget *widget)
859 {
860   GtkIconView *icon_view;
861   GdkWindowAttr attributes;
862   gint attributes_mask;
863   
864   icon_view = GTK_ICON_VIEW (widget);
865
866   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
867
868   /* Make the main, clipping window */
869   attributes.window_type = GDK_WINDOW_CHILD;
870   attributes.x = widget->allocation.x;
871   attributes.y = widget->allocation.y;
872   attributes.width = widget->allocation.width;
873   attributes.height = widget->allocation.height;
874   attributes.wclass = GDK_INPUT_OUTPUT;
875   attributes.visual = gtk_widget_get_visual (widget);
876   attributes.colormap = gtk_widget_get_colormap (widget);
877   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
878
879   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
880
881   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
882                                    &attributes, attributes_mask);
883   gdk_window_set_user_data (widget->window, widget);
884
885   /* Make the window for the icon view */
886   attributes.x = 0;
887   attributes.y = 0;
888   attributes.width = MAX (icon_view->priv->width, widget->allocation.width);
889   attributes.height = MAX (icon_view->priv->height, widget->allocation.height);
890   attributes.event_mask = (GDK_EXPOSURE_MASK |
891                            GDK_SCROLL_MASK |
892                            GDK_POINTER_MOTION_MASK |
893                            GDK_BUTTON_PRESS_MASK |
894                            GDK_BUTTON_RELEASE_MASK |
895                            GDK_KEY_PRESS_MASK |
896                            GDK_KEY_RELEASE_MASK) |
897     gtk_widget_get_events (widget);
898   
899   icon_view->priv->bin_window = gdk_window_new (widget->window,
900                                                 &attributes, attributes_mask);
901   gdk_window_set_user_data (icon_view->priv->bin_window, widget);
902
903   widget->style = gtk_style_attach (widget->style, widget->window);
904   gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
905   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
906 }
907
908 static void
909 gtk_icon_view_unrealize (GtkWidget *widget)
910 {
911   GtkIconView *icon_view;
912
913   icon_view = GTK_ICON_VIEW (widget);
914
915   gdk_window_set_user_data (icon_view->priv->bin_window, NULL);
916   gdk_window_destroy (icon_view->priv->bin_window);
917   icon_view->priv->bin_window = NULL;
918
919   /* GtkWidget::unrealize destroys children and widget->window */
920   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
921     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
922 }
923
924 static void
925 gtk_icon_view_map (GtkWidget *widget)
926 {
927   GtkIconView *icon_view;
928
929   icon_view = GTK_ICON_VIEW (widget);
930
931   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
932
933   gdk_window_show (icon_view->priv->bin_window);
934   gdk_window_show (widget->window);
935 }
936
937 static void
938 gtk_icon_view_size_request (GtkWidget      *widget,
939                             GtkRequisition *requisition)
940 {
941   GtkIconView *icon_view;
942
943   icon_view = GTK_ICON_VIEW (widget);
944
945   requisition->width = icon_view->priv->width;
946   requisition->height = icon_view->priv->height;
947 }
948
949 static void
950 gtk_icon_view_size_allocate (GtkWidget      *widget,
951                              GtkAllocation  *allocation)
952 {
953   GtkIconView *icon_view;
954
955   widget->allocation = *allocation;
956   
957   icon_view = GTK_ICON_VIEW (widget);
958   
959   if (GTK_WIDGET_REALIZED (widget))
960     {
961       gdk_window_move_resize (widget->window,
962                               allocation->x, allocation->y,
963                               allocation->width, allocation->height);
964       gdk_window_resize (icon_view->priv->bin_window,
965                          MAX (icon_view->priv->width, allocation->width),
966                          MAX (icon_view->priv->height, allocation->height));
967     }
968
969   icon_view->priv->hadjustment->page_size = allocation->width;
970   icon_view->priv->hadjustment->page_increment = allocation->width * 0.9;
971   icon_view->priv->hadjustment->step_increment = allocation->width * 0.1;
972   icon_view->priv->hadjustment->lower = 0;
973   icon_view->priv->hadjustment->upper = MAX (allocation->width, icon_view->priv->width);
974   gtk_adjustment_changed (icon_view->priv->hadjustment);
975
976   icon_view->priv->vadjustment->page_size = allocation->height;
977   icon_view->priv->vadjustment->page_increment = allocation->height * 0.9;
978   icon_view->priv->vadjustment->step_increment = allocation->width * 0.1;
979   icon_view->priv->vadjustment->lower = 0;
980   icon_view->priv->vadjustment->upper = MAX (allocation->height, icon_view->priv->height);
981   gtk_adjustment_changed (icon_view->priv->vadjustment);
982
983   gtk_icon_view_layout (icon_view);
984 }
985
986 static gboolean
987 gtk_icon_view_expose (GtkWidget *widget,
988                       GdkEventExpose *expose)
989 {
990   GtkIconView *icon_view;
991   GList *icons;
992
993   icon_view = GTK_ICON_VIEW (widget);
994
995   if (expose->window != icon_view->priv->bin_window)
996     return FALSE;
997
998   for (icons = icon_view->priv->items; icons; icons = icons->next) {
999     GtkIconViewItem *item = icons->data;
1000     GdkRectangle item_rectangle;
1001
1002     item_rectangle.x = item->x;
1003     item_rectangle.y = item->y;
1004     item_rectangle.width = item->width;
1005     item_rectangle.height = item->height;
1006
1007     if (gdk_region_rect_in (expose->region, &item_rectangle) == GDK_OVERLAP_RECTANGLE_OUT)
1008       continue;
1009
1010 #ifdef DEBUG_ICON_VIEW
1011     gdk_draw_rectangle (icon_view->priv->bin_window,
1012                         GTK_WIDGET (icon_view)->style->black_gc,
1013                         FALSE,
1014                         item->x, item->y, 
1015                         item->width, item->height);
1016     gdk_draw_rectangle (icon_view->priv->bin_window,
1017                         GTK_WIDGET (icon_view)->style->black_gc,
1018                         FALSE,
1019                         item->pixbuf_x, item->pixbuf_y, 
1020                         item->pixbuf_width, item->pixbuf_height);
1021     gdk_draw_rectangle (icon_view->priv->bin_window,
1022                         GTK_WIDGET (icon_view)->style->black_gc,
1023                         FALSE,
1024                         item->layout_x, item->layout_y, 
1025                         item->layout_width, item->layout_height);
1026 #endif
1027     gtk_icon_view_paint_item (icon_view, item, &expose->area);
1028
1029   }
1030
1031   if (icon_view->priv->doing_rubberband)
1032     {
1033       GdkRectangle *rectangles;
1034       gint n_rectangles;
1035       
1036       gdk_region_get_rectangles (expose->region,
1037                                  &rectangles,
1038                                  &n_rectangles);
1039       
1040       while (n_rectangles--)
1041         gtk_icon_view_paint_rubberband (icon_view, &rectangles[n_rectangles]);
1042
1043       g_free (rectangles);
1044     }
1045
1046   return TRUE;
1047 }
1048
1049 static gboolean
1050 scroll_timeout (gpointer data)
1051 {
1052   GtkIconView *icon_view;
1053   gdouble value;
1054
1055   GDK_THREADS_ENTER ();
1056   
1057   icon_view = data;
1058
1059   value = MIN (icon_view->priv->vadjustment->value +
1060                icon_view->priv->scroll_value_diff,
1061                icon_view->priv->vadjustment->upper -
1062                icon_view->priv->vadjustment->page_size);
1063
1064   gtk_adjustment_set_value (icon_view->priv->vadjustment,
1065                             value);
1066
1067   gtk_icon_view_update_rubberband (icon_view);
1068   
1069   GDK_THREADS_LEAVE ();
1070
1071   return TRUE;
1072 }
1073
1074 static gboolean
1075 gtk_icon_view_motion (GtkWidget      *widget,
1076                       GdkEventMotion *event)
1077 {
1078   GtkIconView *icon_view;
1079   gint abs_y;
1080   
1081   icon_view = GTK_ICON_VIEW (widget);
1082 #ifdef DND_WORKS
1083   gtk_icon_view_maybe_begin_dragging_items (icon_view, event);
1084 #endif
1085   if (icon_view->priv->doing_rubberband)
1086     {
1087       gtk_icon_view_update_rubberband (widget);
1088       
1089       abs_y = event->y - icon_view->priv->height *
1090         (icon_view->priv->vadjustment->value /
1091          (icon_view->priv->vadjustment->upper -
1092           icon_view->priv->vadjustment->lower));
1093
1094       if (abs_y < 0 || abs_y > widget->allocation.height)
1095         {
1096           if (icon_view->priv->scroll_timeout_id == 0)
1097             icon_view->priv->scroll_timeout_id = g_timeout_add (30, scroll_timeout, icon_view);
1098
1099           if (abs_y < 0)
1100             icon_view->priv->scroll_value_diff = abs_y;
1101           else
1102             icon_view->priv->scroll_value_diff = abs_y - widget->allocation.height;
1103
1104           icon_view->priv->event_last_x = event->x;
1105           icon_view->priv->event_last_y = event->y;
1106         }
1107       else if (icon_view->priv->scroll_timeout_id != 0)
1108         {
1109           g_source_remove (icon_view->priv->scroll_timeout_id);
1110
1111           icon_view->priv->scroll_timeout_id = 0;
1112         }
1113     }
1114   
1115   return TRUE;
1116 }
1117
1118 static gboolean
1119 gtk_icon_view_button_press (GtkWidget      *widget,
1120                             GdkEventButton *event)
1121 {
1122   GtkIconView *icon_view;
1123   GtkIconViewItem *item;
1124   gboolean dirty = FALSE;
1125
1126   icon_view = GTK_ICON_VIEW (widget);
1127
1128   if (event->window != icon_view->priv->bin_window)
1129     return FALSE;
1130
1131   if (!GTK_WIDGET_HAS_FOCUS (widget))
1132     gtk_widget_grab_focus (widget);
1133
1134   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1135     {
1136
1137       item = gtk_icon_view_get_item_at_pos (icon_view,
1138                                             event->x, event->y);
1139       
1140       if (item != NULL)
1141         {
1142           gtk_icon_view_scroll_to_item (icon_view, item);
1143           
1144           if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
1145             {
1146               gtk_icon_view_set_cursor_item (icon_view, item);
1147             }
1148           else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
1149                    (event->state & GDK_SHIFT_MASK))
1150             {
1151               gtk_icon_view_unselect_all_internal (icon_view);
1152
1153               gtk_icon_view_set_cursor_item (icon_view, item);
1154               if (!icon_view->priv->anchor_item)
1155                 icon_view->priv->anchor_item = item;
1156               else 
1157                 gtk_icon_view_select_all_between (icon_view,
1158                                                   icon_view->priv->anchor_item,
1159                                                   item);
1160               dirty = TRUE;
1161             }
1162           else 
1163             {
1164               if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
1165                   ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
1166                   (event->state & GDK_CONTROL_MASK))
1167                 {
1168                   item->selected = !item->selected;
1169                   gtk_icon_view_queue_draw_item (icon_view, item);
1170                   dirty = TRUE;
1171                 }
1172               else
1173                 {
1174                   if (!item->selected)
1175                     {
1176                       gtk_icon_view_unselect_all_internal (icon_view);
1177                       
1178                       item->selected = TRUE;
1179                       gtk_icon_view_queue_draw_item (icon_view, item);
1180                       dirty = TRUE;
1181                     }
1182                 }
1183               gtk_icon_view_set_cursor_item (icon_view, item);
1184               icon_view->priv->anchor_item = item;
1185             }
1186 #ifdef DND_WORKS
1187           /* Save press to possibly begin a drag */
1188           if (icon_view->priv->pressed_button < 0)
1189             {
1190               icon_view->priv->pressed_button = event->button;
1191               icon_view->priv->press_start_x = event->x;
1192               icon_view->priv->press_start_y = event->y;
1193             }
1194 #endif
1195           if (!icon_view->priv->last_single_clicked)
1196             icon_view->priv->last_single_clicked = item;
1197         }
1198       else
1199         {
1200           if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
1201               !(event->state & GDK_CONTROL_MASK))
1202             {
1203               dirty = gtk_icon_view_unselect_all_internal (icon_view);
1204             }
1205           
1206           if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
1207             gtk_icon_view_start_rubberbanding (icon_view, event->x, event->y);
1208         }
1209
1210     }
1211
1212   if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1213     {
1214       item = gtk_icon_view_get_item_at_pos (icon_view,
1215                                             event->x, event->y);
1216
1217       if (item && item == icon_view->priv->last_single_clicked)
1218         {
1219           GtkTreePath *path;
1220
1221           path = gtk_tree_path_new_from_indices (item->index, -1);
1222           gtk_icon_view_item_activated (icon_view, path);
1223           gtk_tree_path_free (path);
1224         }
1225
1226       icon_view->priv->last_single_clicked = NULL;
1227     }
1228   
1229   if (dirty)
1230     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1231
1232   return event->button == 1;
1233 }
1234
1235 static gboolean
1236 gtk_icon_view_button_release (GtkWidget      *widget,
1237                               GdkEventButton *event)
1238 {
1239   GtkIconView *icon_view;
1240
1241   icon_view = GTK_ICON_VIEW (widget);
1242   
1243 #ifdef DND_WORKS
1244   if (icon_view->priv->pressed_button == event->button)
1245     icon_view->priv->pressed_button = -1;
1246 #endif
1247   gtk_icon_view_stop_rubberbanding (icon_view);
1248
1249   if (icon_view->priv->scroll_timeout_id != 0)
1250     {
1251       g_source_remove (icon_view->priv->scroll_timeout_id);
1252       icon_view->priv->scroll_timeout_id = 0;
1253     }
1254
1255   return TRUE;
1256 }
1257
1258 static void
1259 gtk_icon_view_update_rubberband (gpointer data)
1260 {
1261   GtkIconView *icon_view;
1262   gint x, y;
1263   GdkRectangle old_area;
1264   GdkRectangle new_area;
1265   GdkRectangle common;
1266   GdkRegion *invalid_region;
1267   
1268   icon_view = GTK_ICON_VIEW (data);
1269
1270   gdk_window_get_pointer (icon_view->priv->bin_window, &x, &y, NULL);
1271
1272   x = MAX (x, 0);
1273   y = MAX (y, 0);
1274
1275   old_area.x = MIN (icon_view->priv->rubberband_x1,
1276                     icon_view->priv->rubberband_x2);
1277   old_area.y = MIN (icon_view->priv->rubberband_y1,
1278                     icon_view->priv->rubberband_y2);
1279   old_area.width = ABS (icon_view->priv->rubberband_x2 -
1280                         icon_view->priv->rubberband_x1) + 1;
1281   old_area.height = ABS (icon_view->priv->rubberband_y2 -
1282                          icon_view->priv->rubberband_y1) + 1;
1283   
1284   new_area.x = MIN (icon_view->priv->rubberband_x1, x);
1285   new_area.y = MIN (icon_view->priv->rubberband_y1, y);
1286   new_area.width = ABS (x - icon_view->priv->rubberband_x1) + 1;
1287   new_area.height = ABS (y - icon_view->priv->rubberband_y1) + 1;
1288
1289   invalid_region = gdk_region_rectangle (&old_area);
1290   gdk_region_union_with_rect (invalid_region, &new_area);
1291
1292   gdk_rectangle_intersect (&old_area, &new_area, &common);
1293   if (common.width > 2 && common.height > 2)
1294     {
1295       GdkRegion *common_region;
1296
1297       /* make sure the border is invalidated */
1298       common.x += 1;
1299       common.y += 1;
1300       common.width -= 2;
1301       common.height -= 2;
1302       
1303       common_region = gdk_region_rectangle (&common);
1304
1305       gdk_region_subtract (invalid_region, common_region);
1306       gdk_region_destroy (common_region);
1307     }
1308   
1309   gdk_window_invalidate_region (icon_view->priv->bin_window, invalid_region, TRUE);
1310     
1311   gdk_region_destroy (invalid_region);
1312
1313   icon_view->priv->rubberband_x2 = x;
1314   icon_view->priv->rubberband_y2 = y;  
1315
1316   gtk_icon_view_update_rubberband_selection (icon_view);
1317 }
1318
1319 static void
1320 gtk_icon_view_start_rubberbanding (GtkIconView  *icon_view,
1321                                    gint          x,
1322                                    gint          y)
1323 {
1324   GList *items;
1325
1326   g_assert (!icon_view->priv->doing_rubberband);
1327
1328   for (items = icon_view->priv->items; items; items = items->next)
1329     {
1330       GtkIconViewItem *item = items->data;
1331
1332       item->selected_before_rubberbanding = item->selected;
1333     }
1334   
1335   icon_view->priv->rubberband_x1 = x;
1336   icon_view->priv->rubberband_y1 = y;
1337   icon_view->priv->rubberband_x2 = x;
1338   icon_view->priv->rubberband_y2 = y;
1339
1340   icon_view->priv->doing_rubberband = TRUE;
1341
1342   gtk_grab_add (GTK_WIDGET (icon_view));
1343 }
1344
1345 static void
1346 gtk_icon_view_stop_rubberbanding (GtkIconView *icon_view)
1347 {
1348   if (!icon_view->priv->doing_rubberband)
1349     return;
1350
1351   icon_view->priv->doing_rubberband = FALSE;
1352
1353   gtk_grab_remove (GTK_WIDGET (icon_view));
1354   
1355   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1356 }
1357
1358 static void
1359 gtk_icon_view_update_rubberband_selection (GtkIconView *icon_view)
1360 {
1361   GList *items;
1362   gint x, y, width, height;
1363   gboolean dirty = FALSE;
1364   
1365   x = MIN (icon_view->priv->rubberband_x1,
1366            icon_view->priv->rubberband_x2);
1367   y = MIN (icon_view->priv->rubberband_y1,
1368            icon_view->priv->rubberband_y2);
1369   width = ABS (icon_view->priv->rubberband_x1 - 
1370                icon_view->priv->rubberband_x2);
1371   height = ABS (icon_view->priv->rubberband_y1 - 
1372                 icon_view->priv->rubberband_y2);
1373   
1374   for (items = icon_view->priv->items; items; items = items->next)
1375     {
1376       GtkIconViewItem *item = items->data;
1377       gboolean is_in;
1378       gboolean selected;
1379       
1380       is_in = gtk_icon_view_item_hit_test (item, x, y, width, height);
1381
1382       selected = is_in ^ item->selected_before_rubberbanding;
1383
1384       if (item->selected != selected)
1385         {
1386           item->selected = selected;
1387           dirty = TRUE;
1388           gtk_icon_view_queue_draw_item (icon_view, item);
1389         }
1390     }
1391
1392   if (dirty)
1393     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
1394 }
1395
1396 static gboolean
1397 gtk_icon_view_item_hit_test (GtkIconViewItem  *item,
1398                              gint              x,
1399                              gint              y,
1400                              gint              width,
1401                              gint              height)
1402 {
1403   /* First try the pixbuf */
1404   if (MIN (x + width, item->pixbuf_x + item->pixbuf_width) - MAX (x, item->pixbuf_x) > 0 &&
1405       MIN (y + height, item->pixbuf_y + item->pixbuf_height) - MAX (y, item->pixbuf_y) > 0)
1406     return TRUE;
1407
1408   /* Then try the text */
1409   if (MIN (x + width, item->layout_x + item->layout_width) - MAX (x, item->layout_x) > 0 &&
1410       MIN (y + height, item->layout_y + item->layout_height) - MAX (y, item->layout_y) > 0)
1411     return TRUE;
1412   
1413   return FALSE;
1414 }
1415
1416 #ifdef DND_WORKS
1417 static gboolean
1418 gtk_icon_view_maybe_begin_dragging_items (GtkIconView     *icon_view,
1419                                           GdkEventMotion  *event)
1420 {
1421   gboolean retval = FALSE;
1422   gint button;
1423   if (icon_view->priv->pressed_button < 0)
1424     return retval;
1425
1426   if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
1427                                  icon_view->priv->press_start_x,
1428                                  icon_view->priv->press_start_y,
1429                                  event->x, event->y))
1430     return retval;
1431
1432   button = icon_view->priv->pressed_button;
1433   icon_view->priv->pressed_button = -1;
1434   
1435   {
1436     static GtkTargetEntry row_targets[] = {
1437       { "GTK_ICON_VIEW_ITEMS", GTK_TARGET_SAME_APP, 0 }
1438     };
1439     GtkTargetList *target_list;
1440     GdkDragContext *context;
1441     GtkIconViewItem *item;
1442     
1443     retval = TRUE;
1444     
1445     target_list = gtk_target_list_new (row_targets, G_N_ELEMENTS (row_targets));
1446
1447     context = gtk_drag_begin (GTK_WIDGET (icon_view),
1448                               target_list, GDK_ACTION_MOVE,
1449                               button,
1450                               (GdkEvent *)event);
1451
1452     item = gtk_icon_view_get_item_at_pos (icon_view,
1453                                           icon_view->priv->press_start_x,
1454                                           icon_view->priv->press_start_y);
1455     g_assert (item != NULL);
1456     gtk_drag_set_icon_pixbuf (context, gtk_icon_view_get_item_icon (icon_view, item),
1457                               event->x - item->x,
1458                               event->y - item->y);
1459   }
1460   
1461   return retval;
1462 }
1463 #endif
1464
1465 static gboolean
1466 gtk_icon_view_unselect_all_internal (GtkIconView  *icon_view)
1467 {
1468   gboolean dirty = FALSE;
1469   GList *items;
1470
1471   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
1472     return FALSE;
1473
1474   for (items = icon_view->priv->items; items; items = items->next)
1475     {
1476       GtkIconViewItem *item = items->data;
1477
1478       if (item->selected)
1479         {
1480           item->selected = FALSE;
1481           dirty = TRUE;
1482           gtk_icon_view_queue_draw_item (icon_view, item);
1483         }
1484     }
1485
1486   return dirty;
1487 }
1488
1489
1490 /* GtkIconView signals */
1491 static void
1492 gtk_icon_view_set_adjustments (GtkIconView   *icon_view,
1493                                GtkAdjustment *hadj,
1494                                GtkAdjustment *vadj)
1495 {
1496   gboolean need_adjust = FALSE;
1497
1498   if (hadj)
1499     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
1500   else
1501     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1502   if (vadj)
1503     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
1504   else
1505     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1506
1507   if (icon_view->priv->hadjustment && (icon_view->priv->hadjustment != hadj))
1508     {
1509       g_signal_handlers_disconnect_matched (icon_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
1510                                            0, 0, NULL, NULL, icon_view);
1511       g_object_unref (icon_view->priv->hadjustment);
1512     }
1513
1514   if (icon_view->priv->vadjustment && (icon_view->priv->vadjustment != vadj))
1515     {
1516       g_signal_handlers_disconnect_matched (icon_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
1517                                             0, 0, NULL, NULL, icon_view);
1518       g_object_unref (icon_view->priv->vadjustment);
1519     }
1520
1521   if (icon_view->priv->hadjustment != hadj)
1522     {
1523       icon_view->priv->hadjustment = hadj;
1524       g_object_ref (icon_view->priv->hadjustment);
1525       gtk_object_sink (GTK_OBJECT (icon_view->priv->hadjustment));
1526
1527       g_signal_connect (icon_view->priv->hadjustment, "value_changed",
1528                         G_CALLBACK (gtk_icon_view_adjustment_changed),
1529                         icon_view);
1530       need_adjust = TRUE;
1531     }
1532
1533   if (icon_view->priv->vadjustment != vadj)
1534     {
1535       icon_view->priv->vadjustment = vadj;
1536       g_object_ref (icon_view->priv->vadjustment);
1537       gtk_object_sink (GTK_OBJECT (icon_view->priv->vadjustment));
1538
1539       g_signal_connect (icon_view->priv->vadjustment, "value_changed",
1540                         G_CALLBACK (gtk_icon_view_adjustment_changed),
1541                         icon_view);
1542       need_adjust = TRUE;
1543     }
1544
1545   if (need_adjust)
1546     gtk_icon_view_adjustment_changed (NULL, icon_view);
1547 }
1548
1549 static void
1550 gtk_icon_view_real_select_all (GtkIconView *icon_view)
1551 {
1552   gtk_icon_view_select_all (icon_view);
1553 }
1554
1555 static void
1556 gtk_icon_view_real_unselect_all (GtkIconView *icon_view)
1557 {
1558   gtk_icon_view_unselect_all (icon_view);
1559 }
1560
1561 static void
1562 gtk_icon_view_real_select_cursor_item (GtkIconView *icon_view)
1563 {
1564   gtk_icon_view_unselect_all (icon_view);
1565   
1566   if (icon_view->priv->cursor_item != NULL)
1567     gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1568 }
1569
1570 static gboolean
1571 gtk_icon_view_real_activate_cursor_item (GtkIconView *icon_view)
1572 {
1573   GtkTreePath *path;
1574   
1575   if (!icon_view->priv->cursor_item)
1576     return FALSE;
1577
1578   path = gtk_tree_path_new_from_indices (icon_view->priv->cursor_item->index, -1);
1579   
1580   gtk_icon_view_item_activated (icon_view, path);
1581
1582   gtk_tree_path_free (path);
1583
1584   return TRUE;
1585 }
1586
1587 static void
1588 gtk_icon_view_real_toggle_cursor_item (GtkIconView *icon_view)
1589 {
1590   if (!icon_view->priv->cursor_item)
1591     return;
1592
1593   switch (icon_view->priv->selection_mode)
1594     {
1595     case GTK_SELECTION_NONE:
1596       break;
1597     case GTK_SELECTION_BROWSE:
1598       gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1599       break;
1600     case GTK_SELECTION_SINGLE:
1601       if (icon_view->priv->cursor_item->selected)
1602         gtk_icon_view_unselect_item (icon_view, icon_view->priv->cursor_item);
1603       else
1604         gtk_icon_view_select_item (icon_view, icon_view->priv->cursor_item);
1605       break;
1606     case GTK_SELECTION_MULTIPLE:
1607       icon_view->priv->cursor_item->selected = !icon_view->priv->cursor_item->selected;
1608       g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0); 
1609       
1610       gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
1611       break;
1612     }
1613 }
1614
1615 /* Internal functions */
1616 static void
1617 gtk_icon_view_adjustment_changed (GtkAdjustment *adjustment,
1618                                   GtkIconView   *icon_view)
1619 {
1620   if (GTK_WIDGET_REALIZED (icon_view))
1621     {
1622       gdk_window_move (icon_view->priv->bin_window,
1623                        - icon_view->priv->hadjustment->value,
1624                        - icon_view->priv->vadjustment->value);
1625
1626       if (icon_view->priv->doing_rubberband)
1627         gtk_icon_view_update_rubberband (GTK_WIDGET (icon_view));
1628
1629       gdk_window_process_updates (icon_view->priv->bin_window, TRUE);
1630     }
1631 }
1632
1633 static GList *
1634 gtk_icon_view_layout_single_row (GtkIconView *icon_view, 
1635                                  GList       *first_item, 
1636                                  gint         item_width,
1637                                  gint         row,
1638                                  gint        *y, 
1639                                  gint        *maximum_width)
1640 {
1641   gint focus_width, focus_pad;
1642   gint x, current_width, max_height, max_pixbuf_height;
1643   GList *items, *last_item;
1644   gint col;
1645   gint colspan;
1646   gboolean rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
1647
1648   x = 0;
1649   col = 0;
1650   max_height = 0;
1651   max_pixbuf_height = 0;
1652   items = first_item;
1653   current_width = 0;
1654
1655   gtk_widget_style_get (GTK_WIDGET (icon_view),
1656                         "focus-line-width", &focus_width,
1657                         "focus-padding", &focus_pad,
1658                         NULL);
1659
1660   x += icon_view->priv->margin;
1661   current_width += 2 * icon_view->priv->margin;
1662   items = first_item;
1663
1664   while (items)
1665     {
1666       GtkIconViewItem *item = items->data;
1667
1668       gtk_icon_view_calculate_item_size (icon_view, item, item_width);
1669
1670       colspan = 1 + (item->width - 1) / (item_width + icon_view->priv->column_spacing);
1671       current_width += colspan * (item_width + icon_view->priv->column_spacing);
1672         
1673       if (items != first_item)
1674         {
1675           if ((icon_view->priv->columns <= 0 && current_width > GTK_WIDGET (icon_view)->allocation.width) ||
1676               (icon_view->priv->columns > 0 && col >= icon_view->priv->columns))
1677             break;
1678         }
1679
1680       item->y = *y;
1681       item->x = rtl ? GTK_WIDGET (icon_view)->allocation.width - MAX (item_width, item->width) - x : x;
1682
1683       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1684         {
1685           if (rtl)
1686             {
1687               item->layout_x = item->x + ICON_TEXT_PADDING + focus_width + focus_pad;
1688               if (icon_view->priv->text_column != -1 ||
1689                   icon_view->priv->markup_column != -1)
1690                 item->pixbuf_x = item->x + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad) + icon_view->priv->spacing + item->layout_width;
1691               else
1692                 item->pixbuf_x = item->x;
1693             }
1694           else 
1695             {
1696               item->pixbuf_x = item->x;
1697               if (icon_view->priv->pixbuf_column != -1)
1698                 item->layout_x = item->x + item->pixbuf_width + icon_view->priv->spacing + ICON_TEXT_PADDING + focus_width + focus_pad;
1699               else
1700                 item->layout_x = item->x + ICON_TEXT_PADDING + focus_width + focus_pad;
1701             }
1702         }
1703       else
1704         {
1705           if (item->width < colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing)
1706             item->x += (colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing - item->width) / 2;
1707
1708           item->pixbuf_x = item->x + (item->width - item->pixbuf_width) / 2;
1709           item->layout_x = item->x + (item->width - item->layout_width) / 2;
1710         }
1711
1712       x = current_width - icon_view->priv->margin; 
1713
1714       max_height = MAX (max_height, item->height);
1715       max_pixbuf_height = MAX (max_pixbuf_height, item->pixbuf_height);
1716       
1717       if (current_width > *maximum_width)
1718         *maximum_width = current_width;
1719
1720       item->row = row;
1721       item->col = col;
1722
1723       col += colspan;
1724       items = items->next;
1725     }
1726
1727   last_item = items;
1728
1729   *y += max_height + icon_view->priv->row_spacing;
1730
1731   /* Now go through the row again and align the icons */
1732   for (items = first_item; items != last_item; items = items->next)
1733     {
1734       GtkIconViewItem *item = items->data;
1735
1736       if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1737         {
1738           item->pixbuf_y = item->y;
1739           item->layout_y = item->y + ICON_TEXT_PADDING + focus_width + focus_pad;
1740         }
1741       else 
1742         {
1743           item->pixbuf_y = item->y + (max_pixbuf_height - item->pixbuf_height);
1744           if (icon_view->priv->pixbuf_column != -1)
1745             item->layout_y = item->pixbuf_y + item->pixbuf_height + icon_view->priv->spacing + ICON_TEXT_PADDING + focus_width + focus_pad;
1746           else
1747             item->layout_y = item->y + ICON_TEXT_PADDING + focus_width + focus_pad;
1748       }
1749       /* Update the bounding box */
1750       item->y = item->pixbuf_y;
1751
1752       /* We may want to readjust the new y coordinate. */
1753       if (item->y + item->height > *y)
1754         *y = item->y + item->height;
1755
1756       if (rtl)
1757         item->col = col - 1 - item->col;
1758     }
1759   
1760   return last_item;
1761 }
1762
1763 static void
1764 gtk_icon_view_set_adjustment_upper (GtkAdjustment *adj,
1765                                     gdouble        upper)
1766 {
1767   if (upper != adj->upper)
1768     {
1769       gdouble min = MAX (0.0, upper - adj->page_size);
1770       gboolean value_changed = FALSE;
1771       
1772       adj->upper = upper;
1773
1774       if (adj->value > min)
1775         {
1776           adj->value = min;
1777           value_changed = TRUE;
1778         }
1779       
1780       gtk_adjustment_changed (adj);
1781       
1782       if (value_changed)
1783         gtk_adjustment_value_changed (adj);
1784     }
1785 }
1786
1787 static void
1788 gtk_icon_view_layout (GtkIconView *icon_view)
1789 {
1790   gint y = 0, maximum_width = 0;
1791   GList *icons;
1792   GtkWidget *widget;
1793   gint row;
1794   gint item_width;
1795
1796   if (!VALID_MODEL_AND_COLUMNS (icon_view))
1797     return;
1798
1799   widget = GTK_WIDGET (icon_view);
1800
1801   item_width = icon_view->priv->item_width;
1802
1803   if (item_width < 0)
1804     {
1805       for (icons = icon_view->priv->items; icons; icons = icons->next)
1806         {
1807           GtkIconViewItem *item = icons->data;
1808           gtk_icon_view_calculate_item_size (icon_view, item, -1);
1809           item_width = MAX (item_width, item->width);
1810           gtk_icon_view_item_invalidate_size (item);
1811         }
1812     }
1813
1814   icons = icon_view->priv->items;
1815   y += icon_view->priv->margin;
1816   row = 0;
1817   
1818   do
1819     {
1820       icons = gtk_icon_view_layout_single_row (icon_view, icons, 
1821                                                item_width, row,
1822                                                &y, &maximum_width);
1823       row++;
1824     }
1825   while (icons != NULL);
1826
1827   if (maximum_width != icon_view->priv->width)
1828     {
1829       icon_view->priv->width = maximum_width;
1830     }
1831   y += icon_view->priv->margin;
1832   
1833   if (y != icon_view->priv->height)
1834     {
1835       icon_view->priv->height = y;
1836     }
1837
1838   gtk_icon_view_set_adjustment_upper (icon_view->priv->hadjustment, icon_view->priv->width);
1839   gtk_icon_view_set_adjustment_upper (icon_view->priv->vadjustment, icon_view->priv->height);
1840
1841   if (GTK_WIDGET_REALIZED (icon_view))
1842     {
1843       gdk_window_resize (icon_view->priv->bin_window,
1844                          MAX (icon_view->priv->width, widget->allocation.width),
1845                          MAX (icon_view->priv->height, widget->allocation.height));
1846     }
1847
1848   if (icon_view->priv->layout_idle_id != 0)
1849     {
1850       g_source_remove (icon_view->priv->layout_idle_id);
1851       icon_view->priv->layout_idle_id = 0;
1852     }
1853
1854   gtk_widget_queue_draw (GTK_WIDGET (icon_view));
1855 }
1856
1857 /* Updates the pango layout and calculates the size */
1858 static void
1859 gtk_icon_view_calculate_item_size (GtkIconView     *icon_view,
1860                                    GtkIconViewItem *item,
1861                                    gint             item_width)
1862 {
1863   gint focus_width, focus_pad;
1864   gint layout_width, layout_height;
1865   gint maximum_layout_width;
1866   gint spacing, padding;
1867   gint colspan;
1868   GdkPixbuf *pixbuf;
1869   
1870   if (item->width != -1 && item->height != -1) 
1871     return;
1872
1873   gtk_widget_style_get (GTK_WIDGET (icon_view),
1874                         "focus-line-width", &focus_width,
1875                         "focus-padding", &focus_pad,
1876                         NULL);
1877
1878   spacing = icon_view->priv->spacing;
1879
1880   if (icon_view->priv->pixbuf_column != -1)
1881     {
1882       pixbuf = gtk_icon_view_get_item_icon (icon_view, item);
1883       item->pixbuf_width = gdk_pixbuf_get_width (pixbuf);
1884       item->pixbuf_height = gdk_pixbuf_get_height (pixbuf);
1885       g_object_unref (pixbuf);
1886     }
1887   else
1888     {
1889       item->pixbuf_width = 0;
1890       item->pixbuf_height = 0;
1891       spacing = 0;
1892     }
1893   
1894   if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
1895       item_width > 0)
1896     {
1897       colspan = item->pixbuf_width / item_width + 1;
1898       maximum_layout_width = MAX (colspan * item_width - item->pixbuf_width - icon_view->priv->spacing - 2 * (ICON_TEXT_PADDING + focus_width + focus_pad), 50);
1899     }
1900   else
1901     maximum_layout_width = MAX (item_width, item->pixbuf_width);
1902     
1903   if (icon_view->priv->markup_column != -1 ||
1904       icon_view->priv->text_column != -1)
1905     {
1906       gtk_icon_view_update_item_text (icon_view, item);
1907
1908       pango_layout_set_alignment (icon_view->priv->layout, PANGO_ALIGN_CENTER);
1909       pango_layout_set_width (icon_view->priv->layout, maximum_layout_width * PANGO_SCALE);
1910       
1911       pango_layout_get_pixel_size (icon_view->priv->layout, &layout_width, &layout_height);
1912       
1913       item->layout_width = layout_width;
1914       item->layout_height = layout_height;
1915       padding = 2 * (ICON_TEXT_PADDING + focus_width + focus_pad);
1916     }
1917   else
1918     {
1919       item->layout_width = 0;
1920       item->layout_height = 0;
1921       spacing = 0;
1922       padding = 0;
1923     }
1924
1925   if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1926     {
1927       item->width = item->layout_width + padding + spacing + item->pixbuf_width;
1928       item->height = MAX (item->layout_height + padding, item->pixbuf_height);
1929     }
1930   else
1931     {
1932       item->width = MAX (item->layout_width + padding, item->pixbuf_width);
1933       item->height = item->layout_height + padding + spacing + item->pixbuf_height;
1934     }
1935 }
1936
1937 static void
1938 gtk_icon_view_invalidate_sizes (GtkIconView *icon_view)
1939 {
1940   g_list_foreach (icon_view->priv->items,
1941                   (GFunc)gtk_icon_view_item_invalidate_size, NULL);
1942 }
1943
1944 static void
1945 gtk_icon_view_item_invalidate_size (GtkIconViewItem *item)
1946 {
1947   item->width = -1;
1948   item->height = -1;
1949 }
1950
1951 static GdkPixbuf *
1952 create_colorized_pixbuf (GdkPixbuf *src, GdkColor *new_color)
1953 {
1954         gint i, j;
1955         gint width, height, has_alpha, src_row_stride, dst_row_stride;
1956         gint red_value, green_value, blue_value;
1957         guchar *target_pixels;
1958         guchar *original_pixels;
1959         guchar *pixsrc;
1960         guchar *pixdest;
1961         GdkPixbuf *dest;
1962
1963         red_value = new_color->red / 255.0;
1964         green_value = new_color->green / 255.0;
1965         blue_value = new_color->blue / 255.0;
1966
1967         dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
1968                                gdk_pixbuf_get_has_alpha (src),
1969                                gdk_pixbuf_get_bits_per_sample (src),
1970                                gdk_pixbuf_get_width (src),
1971                                gdk_pixbuf_get_height (src));
1972         
1973         has_alpha = gdk_pixbuf_get_has_alpha (src);
1974         width = gdk_pixbuf_get_width (src);
1975         height = gdk_pixbuf_get_height (src);
1976         src_row_stride = gdk_pixbuf_get_rowstride (src);
1977         dst_row_stride = gdk_pixbuf_get_rowstride (dest);
1978         target_pixels = gdk_pixbuf_get_pixels (dest);
1979         original_pixels = gdk_pixbuf_get_pixels (src);
1980
1981         for (i = 0; i < height; i++) {
1982                 pixdest = target_pixels + i*dst_row_stride;
1983                 pixsrc = original_pixels + i*src_row_stride;
1984                 for (j = 0; j < width; j++) {           
1985                         *pixdest++ = (*pixsrc++ * red_value) >> 8;
1986                         *pixdest++ = (*pixsrc++ * green_value) >> 8;
1987                         *pixdest++ = (*pixsrc++ * blue_value) >> 8;
1988                         if (has_alpha) {
1989                                 *pixdest++ = *pixsrc++;
1990                         }
1991                 }
1992         }
1993         return dest;
1994 }
1995
1996 static void
1997 gtk_icon_view_paint_item (GtkIconView     *icon_view,
1998                           GtkIconViewItem *item,
1999                           GdkRectangle    *area)
2000 {
2001   gint focus_width, focus_pad;
2002   GdkPixbuf *pixbuf, *tmp;
2003   GtkStateType state;
2004   gboolean rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
2005   
2006   if (!VALID_MODEL_AND_COLUMNS (icon_view))
2007     return;
2008   
2009   gtk_widget_style_get (GTK_WIDGET (icon_view),
2010                         "focus-line-width", &focus_width,
2011                         "focus-padding", &focus_pad,
2012                         NULL);
2013
2014   if (GTK_WIDGET_HAS_FOCUS (icon_view))
2015     state = GTK_STATE_SELECTED;
2016   else
2017     state = GTK_STATE_ACTIVE;
2018
2019   if (icon_view->priv->pixbuf_column != -1)
2020     {
2021       tmp = gtk_icon_view_get_item_icon (icon_view, item);
2022       if (item->selected)
2023         {
2024           pixbuf = create_colorized_pixbuf (tmp,
2025                                             &GTK_WIDGET (icon_view)->style->base[state]);
2026           g_object_unref (tmp);
2027         }
2028       else
2029         pixbuf = tmp;
2030       
2031       gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
2032                        0, 0,
2033                        item->pixbuf_x, item->pixbuf_y,
2034                        item->pixbuf_width, item->pixbuf_height,
2035                        GDK_RGB_DITHER_NORMAL,
2036                        item->pixbuf_width, item->pixbuf_height);
2037       g_object_unref (pixbuf);
2038     }
2039
2040   if (icon_view->priv->text_column != -1 ||
2041       icon_view->priv->markup_column != -1)
2042     {
2043       if (item->selected)
2044         {
2045           gdk_draw_rectangle (icon_view->priv->bin_window,
2046                               GTK_WIDGET (icon_view)->style->base_gc[state],
2047                               TRUE,
2048                               item->layout_x - ICON_TEXT_PADDING,
2049                               item->layout_y - ICON_TEXT_PADDING,
2050                               item->layout_width + 2 * ICON_TEXT_PADDING,
2051                               item->layout_height + 2 * ICON_TEXT_PADDING);
2052         }
2053
2054       gtk_icon_view_update_item_text (icon_view, item);
2055       pango_layout_set_alignment (icon_view->priv->layout, rtl ? PANGO_ALIGN_RIGHT: PANGO_ALIGN_LEFT);
2056       pango_layout_set_width (icon_view->priv->layout, item->layout_width * PANGO_SCALE);
2057       gtk_paint_layout (GTK_WIDGET (icon_view)->style,
2058                         icon_view->priv->bin_window,
2059                         item->selected ? state : GTK_STATE_NORMAL,
2060                         TRUE, area, GTK_WIDGET (icon_view), "icon_view",
2061                         item->layout_x,
2062                         item->layout_y,
2063                         icon_view->priv->layout);
2064
2065       if (GTK_WIDGET_HAS_FOCUS (icon_view) &&
2066           item == icon_view->priv->cursor_item)
2067         gtk_paint_focus (GTK_WIDGET (icon_view)->style,
2068                          icon_view->priv->bin_window,
2069                          GTK_STATE_NORMAL,
2070                          area,
2071                          GTK_WIDGET (icon_view),
2072                          "icon_view",
2073                          item->layout_x - ICON_TEXT_PADDING - focus_width - focus_pad,
2074                          item->layout_y - ICON_TEXT_PADDING - focus_width - focus_pad,
2075                          item->layout_width + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad),
2076                          item->layout_height + 2 * (ICON_TEXT_PADDING + focus_width + focus_pad));
2077     }
2078 }
2079
2080 static guint32
2081 gtk_gdk_color_to_rgb (const GdkColor *color)
2082 {
2083   guint32 result;
2084   result = (0xff0000 | (color->red & 0xff00));
2085   result <<= 8;
2086   result |= ((color->green & 0xff00) | (color->blue >> 8));
2087   return result;
2088 }
2089
2090 static void
2091 gtk_icon_view_paint_rubberband (GtkIconView     *icon_view,
2092                                 GdkRectangle    *area)
2093 {
2094   GdkRectangle rect;
2095   GdkPixbuf *pixbuf;
2096   GdkGC *gc;
2097   GdkRectangle rubber_rect;
2098   GdkColor *fill_color_gdk;
2099   guint fill_color;
2100   guchar fill_color_alpha;
2101
2102   rubber_rect.x = MIN (icon_view->priv->rubberband_x1, icon_view->priv->rubberband_x2);
2103   rubber_rect.y = MIN (icon_view->priv->rubberband_y1, icon_view->priv->rubberband_y2);
2104   rubber_rect.width = ABS (icon_view->priv->rubberband_x1 - icon_view->priv->rubberband_x2) + 1;
2105   rubber_rect.height = ABS (icon_view->priv->rubberband_y1 - icon_view->priv->rubberband_y2) + 1;
2106
2107   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
2108     return;
2109
2110   gtk_widget_style_get (GTK_WIDGET (icon_view),
2111                         "selection_box_color", &fill_color_gdk,
2112                         "selection_box_alpha", &fill_color_alpha,
2113                         NULL);
2114
2115   if (!fill_color_gdk) {
2116     fill_color_gdk = gdk_color_copy (&GTK_WIDGET (icon_view)->style->base[GTK_STATE_SELECTED]);
2117   }
2118
2119   fill_color = gtk_gdk_color_to_rgb (fill_color_gdk) << 8 | fill_color_alpha;
2120
2121   if (!gdk_draw_rectangle_alpha_libgtk_only (icon_view->priv->bin_window,
2122                                              rect.x, rect.y, rect.width, rect.height,
2123                                              fill_color_gdk,
2124                                              fill_color_alpha << 8 | fill_color_alpha))
2125     {
2126       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, rect.width, rect.height);
2127       gdk_pixbuf_fill (pixbuf, fill_color);
2128       
2129       gdk_draw_pixbuf (icon_view->priv->bin_window, NULL, pixbuf,
2130                        0, 0, 
2131                        rect.x,rect.y,
2132                        rect.width, rect.height,
2133                        GDK_RGB_DITHER_NONE,
2134                        0, 0);
2135       g_object_unref (pixbuf);
2136     }
2137
2138   gc = gdk_gc_new (icon_view->priv->bin_window);
2139   gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
2140   gdk_gc_set_clip_rectangle (gc, &rect);
2141   gdk_draw_rectangle (icon_view->priv->bin_window,
2142                       gc, FALSE,
2143                       rubber_rect.x, rubber_rect.y,
2144                       rubber_rect.width - 1, rubber_rect.height - 1);
2145   gdk_color_free (fill_color_gdk);
2146   g_object_unref (gc);
2147 }
2148
2149 static void
2150 gtk_icon_view_queue_draw_item (GtkIconView     *icon_view,
2151                                GtkIconViewItem *item)
2152 {
2153   GdkRectangle rect;
2154
2155   rect.x = item->x;
2156   rect.y = item->y;
2157   rect.width = item->width;
2158   rect.height = item->height;
2159
2160   if (icon_view->priv->bin_window)
2161     gdk_window_invalidate_rect (icon_view->priv->bin_window, &rect, TRUE);
2162 }
2163
2164 static gboolean
2165 layout_callback (gpointer user_data)
2166 {
2167   GtkIconView *icon_view;
2168
2169   GDK_THREADS_ENTER ();
2170
2171   icon_view = GTK_ICON_VIEW (user_data);
2172   
2173   icon_view->priv->layout_idle_id = 0;
2174
2175   gtk_icon_view_layout (icon_view);
2176   
2177   GDK_THREADS_LEAVE();
2178
2179   return FALSE;
2180 }
2181
2182 static void
2183 gtk_icon_view_queue_layout (GtkIconView *icon_view)
2184 {
2185   if (icon_view->priv->layout_idle_id != 0)
2186     return;
2187
2188   icon_view->priv->layout_idle_id = g_idle_add (layout_callback, icon_view);
2189 }
2190
2191 static void
2192 gtk_icon_view_set_cursor_item (GtkIconView     *icon_view,
2193                                GtkIconViewItem *item)
2194 {
2195   AtkObject *obj;
2196   AtkObject *item_obj;
2197
2198   if (icon_view->priv->cursor_item == item)
2199     return;
2200
2201   if (icon_view->priv->cursor_item != NULL)
2202     gtk_icon_view_queue_draw_item (icon_view, icon_view->priv->cursor_item);
2203   
2204   icon_view->priv->cursor_item = item;
2205   gtk_icon_view_queue_draw_item (icon_view, item);
2206   
2207   /* Notify that accessible focus object has changed */
2208   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
2209   item_obj = atk_object_ref_accessible_child (obj, item->index);
2210
2211   if (item_obj != NULL)
2212     {
2213       atk_focus_tracker_notify (item_obj);
2214       g_object_unref (item_obj); 
2215     }
2216 }
2217
2218
2219 static GtkIconViewItem *
2220 gtk_icon_view_item_new (void)
2221 {
2222   GtkIconViewItem *item;
2223
2224   item = g_new0 (GtkIconViewItem, 1);
2225
2226   item->width = -1;
2227   item->height = -1;
2228   
2229   return item;
2230 }
2231
2232 static void
2233 gtk_icon_view_item_free (GtkIconViewItem *item)
2234 {
2235   g_return_if_fail (item != NULL);
2236
2237   g_free (item);
2238 }
2239
2240 static void
2241 gtk_icon_view_update_item_text (GtkIconView     *icon_view,
2242                                 GtkIconViewItem *item)
2243 {
2244   gboolean iters_persist;
2245   GtkTreeIter iter;
2246   GtkTreePath *path;
2247   gchar *text;
2248   
2249   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2250   
2251   if (!iters_persist)
2252     {
2253       path = gtk_tree_path_new_from_indices (item->index, -1);
2254       gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2255       gtk_tree_path_free (path);
2256     }
2257   else
2258     iter = item->iter;
2259
2260   if (icon_view->priv->markup_column != -1)
2261     {
2262       gtk_tree_model_get (icon_view->priv->model, &iter,
2263                           icon_view->priv->markup_column, &text,
2264                           -1);
2265       pango_layout_set_markup (icon_view->priv->layout, text, -1);
2266       g_free (text);        
2267     }
2268   else if (icon_view->priv->text_column != -1)
2269     {
2270       gtk_tree_model_get (icon_view->priv->model, &iter,
2271                           icon_view->priv->text_column, &text,
2272                           -1);
2273       pango_layout_set_text (icon_view->priv->layout, text, -1);
2274       g_free (text);        
2275     }
2276   else
2277       pango_layout_set_text (icon_view->priv->layout, "", -1);
2278 }
2279
2280 static GdkPixbuf *
2281 gtk_icon_view_get_item_icon (GtkIconView      *icon_view,
2282                              GtkIconViewItem  *item)
2283 {
2284   gboolean iters_persist;
2285   GtkTreeIter iter;
2286   GtkTreePath *path;
2287   GdkPixbuf *pixbuf;
2288   
2289   g_return_val_if_fail (item != NULL, NULL);
2290
2291   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2292   
2293   if (!iters_persist)
2294     {
2295       path = gtk_tree_path_new_from_indices (item->index, -1);
2296       gtk_tree_model_get_iter (icon_view->priv->model, &iter, path);
2297       gtk_tree_path_free (path);
2298     }
2299   else
2300     iter = item->iter;
2301   
2302   gtk_tree_model_get (icon_view->priv->model, &iter,
2303                       icon_view->priv->pixbuf_column, &pixbuf,
2304                       -1);
2305
2306   return pixbuf;
2307 }
2308
2309
2310 static GtkIconViewItem *
2311 gtk_icon_view_get_item_at_pos (GtkIconView *icon_view,
2312                                gint         x,
2313                                gint         y)
2314 {
2315   GList *items;
2316   
2317   for (items = icon_view->priv->items; items; items = items->next)
2318     {
2319       GtkIconViewItem *item = items->data;
2320       
2321       if (x > item->x && x < item->x + item->width &&
2322           y > item->y && y < item->y + item->height)
2323         {
2324           /* Check if the mouse is inside the icon or the label */
2325           if ((x > item->pixbuf_x && x < item->pixbuf_x + item->pixbuf_width &&
2326                y > item->pixbuf_y && y < item->pixbuf_y + item->pixbuf_height) ||
2327               (x > item->layout_x - ICON_TEXT_PADDING &&
2328                x < item->layout_x + item->layout_width + ICON_TEXT_PADDING &&
2329                y > item->layout_y - ICON_TEXT_PADDING &&
2330                y < item->layout_y + item->layout_height + ICON_TEXT_PADDING))
2331             return item;
2332         }
2333     }
2334
2335   return NULL;
2336 }
2337
2338 static void
2339 gtk_icon_view_select_item (GtkIconView      *icon_view,
2340                            GtkIconViewItem  *item)
2341 {
2342   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2343   g_return_if_fail (item != NULL);
2344
2345   if (item->selected)
2346     return;
2347   
2348   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
2349     return;
2350   else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2351     gtk_icon_view_unselect_all_internal (icon_view);
2352
2353   item->selected = TRUE;
2354
2355   gtk_icon_view_queue_draw_item (icon_view, item);
2356
2357   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2358 }
2359
2360
2361 static void
2362 gtk_icon_view_unselect_item (GtkIconView      *icon_view,
2363                              GtkIconViewItem  *item)
2364 {
2365   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
2366   g_return_if_fail (item != NULL);
2367
2368   if (!item->selected)
2369     return;
2370   
2371   if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
2372       icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
2373     return;
2374   
2375   item->selected = FALSE;
2376
2377   g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2378
2379   gtk_icon_view_queue_draw_item (icon_view, item);
2380 }
2381
2382 static void
2383 verify_items (GtkIconView *icon_view)
2384 {
2385   GList *items;
2386   int i = 0;
2387
2388   for (items = icon_view->priv->items; items; items = items->next)
2389     {
2390       GtkIconViewItem *item = items->data;
2391
2392       if (item->index != i)
2393         g_error ("List item does not match its index: item index %d and list index %d\n", item->index, i);
2394
2395       i++;
2396     }
2397 }
2398
2399 static void
2400 gtk_icon_view_row_changed (GtkTreeModel *model,
2401                            GtkTreePath  *path,
2402                            GtkTreeIter  *iter,
2403                            gpointer      data)
2404 {
2405   GtkIconViewItem *item;
2406   gint index;
2407   GtkIconView *icon_view;
2408
2409   icon_view = GTK_ICON_VIEW (data);
2410   
2411   index = gtk_tree_path_get_indices(path)[0];
2412   item = g_list_nth (icon_view->priv->items, index)->data;
2413
2414   gtk_icon_view_item_invalidate_size (item);
2415   gtk_icon_view_queue_layout (icon_view);
2416
2417   verify_items (icon_view);
2418 }
2419
2420 static void
2421 gtk_icon_view_row_inserted (GtkTreeModel *model,
2422                             GtkTreePath  *path,
2423                             GtkTreeIter  *iter,
2424                             gpointer      data)
2425 {
2426   gint length, index;
2427   GtkIconViewItem *item;
2428   gboolean iters_persist;
2429   GtkIconView *icon_view;
2430   GList *list;
2431   
2432   icon_view = GTK_ICON_VIEW (data);
2433   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2434   
2435   length = gtk_tree_model_iter_n_children (model, NULL);
2436   index = gtk_tree_path_get_indices(path)[0];
2437
2438   item = gtk_icon_view_item_new ();
2439
2440   if (iters_persist)
2441     item->iter = *iter;
2442
2443   item->index = index;
2444
2445   /* FIXME: We can be more efficient here,
2446      we can store a tail pointer and use that when
2447      appending (which is a rather common operation)
2448   */
2449   icon_view->priv->items = g_list_insert (icon_view->priv->items,
2450                                          item, index);
2451   
2452   list = g_list_nth (icon_view->priv->items, index + 1);
2453   for (; list; list = list->next)
2454     {
2455       item = list->data;
2456
2457       item->index++;
2458     }
2459     
2460   verify_items (icon_view);
2461 }
2462
2463 static void
2464 gtk_icon_view_row_deleted (GtkTreeModel *model,
2465                            GtkTreePath  *path,
2466                            gpointer      data)
2467 {
2468   gint index;
2469   GtkIconView *icon_view;
2470   GtkIconViewItem *item;
2471   GList *list, *next;
2472   gboolean emit = FALSE;
2473   
2474   icon_view = GTK_ICON_VIEW (data);
2475
2476   index = gtk_tree_path_get_indices(path)[0];
2477
2478   list = g_list_nth (icon_view->priv->items, index);
2479   item = list->data;
2480
2481   if (item == icon_view->priv->anchor_item)
2482     icon_view->priv->anchor_item = NULL;
2483
2484   if (item == icon_view->priv->cursor_item)
2485     icon_view->priv->cursor_item = NULL;
2486
2487   if (item->selected)
2488     emit = TRUE;
2489   
2490   gtk_icon_view_item_free (item);
2491
2492   for (next = list->next; next; next = next->next)
2493     {
2494       item = next->data;
2495
2496       item->index--;
2497     }
2498   
2499   icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
2500
2501   gtk_icon_view_queue_layout (icon_view);
2502
2503   verify_items (icon_view);  
2504   
2505   if (emit)
2506     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2507 }
2508
2509 static void
2510 gtk_icon_view_rows_reordered (GtkTreeModel *model,
2511                               GtkTreePath  *parent,
2512                               GtkTreeIter  *iter,
2513                               gint         *new_order,
2514                               gpointer      data)
2515 {
2516   int i;
2517   int length;
2518   GtkIconView *icon_view;
2519   GList *items = NULL, *list;
2520   GtkIconViewItem **item_array;
2521   gint *order;
2522   
2523   icon_view = GTK_ICON_VIEW (data);
2524
2525   length = gtk_tree_model_iter_n_children (model, NULL);
2526
2527   order = g_new (gint, length);
2528   for (i = 0; i < length; i++)
2529     order [new_order[i]] = i;
2530
2531   item_array = g_new (GtkIconViewItem *, length);
2532   for (i = 0, list = icon_view->priv->items; list != NULL; list = list->next, i++)
2533     item_array[order[i]] = list->data;
2534   g_free (order);
2535
2536   for (i = length - 1; i >= 0; i--)
2537     {
2538       item_array[i]->index = i;
2539       items = g_list_prepend (items, item_array[i]);
2540     }
2541   
2542   g_free (item_array);
2543   g_list_free (icon_view->priv->items);
2544   icon_view->priv->items = items;
2545
2546   verify_items (icon_view);  
2547 }
2548
2549 static void
2550 gtk_icon_view_build_items (GtkIconView *icon_view)
2551 {
2552   GtkTreeIter iter;
2553   int i;
2554   gboolean iters_persist;
2555   GList *items = NULL;
2556
2557   iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
2558   
2559   if (!gtk_tree_model_get_iter_first (icon_view->priv->model,
2560                                       &iter))
2561     return;
2562
2563   i = 0;
2564   
2565   do
2566     {
2567       GtkIconViewItem *item = gtk_icon_view_item_new ();
2568
2569       if (iters_persist)
2570         item->iter = iter;
2571
2572       item->index = i;
2573       
2574       i++;
2575
2576       items = g_list_prepend (items, item);
2577       
2578     } while (gtk_tree_model_iter_next (icon_view->priv->model, &iter));
2579
2580   icon_view->priv->items = g_list_reverse (items);
2581 }
2582
2583 static void
2584 gtk_icon_view_add_move_binding (GtkBindingSet  *binding_set,
2585                                 guint           keyval,
2586                                 guint           modmask,
2587                                 GtkMovementStep step,
2588                                 gint            count)
2589 {
2590   
2591   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
2592                                 "move_cursor", 2,
2593                                 G_TYPE_ENUM, step,
2594                                 G_TYPE_INT, count);
2595
2596   gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
2597                                 "move_cursor", 2,
2598                                 G_TYPE_ENUM, step,
2599                                 G_TYPE_INT, count);
2600
2601   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2602    return;
2603
2604   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
2605                                 "move_cursor", 2,
2606                                 G_TYPE_ENUM, step,
2607                                 G_TYPE_INT, count);
2608
2609   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
2610                                 "move_cursor", 2,
2611                                 G_TYPE_ENUM, step,
2612                                 G_TYPE_INT, count);
2613 }
2614
2615 static gboolean
2616 gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
2617                                 GtkMovementStep  step,
2618                                 gint             count)
2619 {
2620   GdkModifierType state;
2621
2622   g_return_val_if_fail (GTK_ICON_VIEW (icon_view), FALSE);
2623   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
2624                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
2625                         step == GTK_MOVEMENT_DISPLAY_LINES ||
2626                         step == GTK_MOVEMENT_PAGES ||
2627                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
2628
2629   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (icon_view)))
2630     return FALSE;
2631
2632   gtk_widget_grab_focus (GTK_WIDGET (icon_view));
2633
2634   if (gtk_get_current_event_state (&state))
2635     {
2636       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2637         icon_view->priv->ctrl_pressed = TRUE;
2638       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2639         icon_view->priv->shift_pressed = TRUE;
2640     }
2641   /* else we assume not pressed */
2642
2643   switch (step)
2644     {
2645     case GTK_MOVEMENT_LOGICAL_POSITIONS:
2646     case GTK_MOVEMENT_VISUAL_POSITIONS:
2647       gtk_icon_view_move_cursor_left_right (icon_view, count);
2648       break;
2649     case GTK_MOVEMENT_DISPLAY_LINES:
2650       gtk_icon_view_move_cursor_up_down (icon_view, count);
2651       break;
2652     case GTK_MOVEMENT_PAGES:
2653       gtk_icon_view_move_cursor_page_up_down (icon_view, count);
2654       break;
2655     case GTK_MOVEMENT_BUFFER_ENDS:
2656       gtk_icon_view_move_cursor_start_end (icon_view, count);
2657       break;
2658     default:
2659       g_assert_not_reached ();
2660     }
2661
2662   icon_view->priv->ctrl_pressed = FALSE;
2663   icon_view->priv->shift_pressed = FALSE;
2664
2665   return TRUE;
2666 }
2667
2668 static GtkIconViewItem *
2669 find_item (GtkIconView     *icon_view,
2670            GtkIconViewItem *current,
2671            gint             row_ofs,
2672            gint             col_ofs)
2673 {
2674   gint row, col;
2675   GList *items;
2676   GtkIconViewItem *item;
2677
2678   /* FIXME: this could be more efficient 
2679    */
2680   row = current->row + row_ofs;
2681   col = current->col + col_ofs;
2682
2683   for (items = icon_view->priv->items; items; items = items->next)
2684     {
2685       item = items->data;
2686       if (item->row == row && item->col == col)
2687         return item;
2688     }
2689   
2690   return NULL;
2691 }
2692
2693
2694 static GtkIconViewItem *
2695 find_item_page_up_down (GtkIconView     *icon_view,
2696                         GtkIconViewItem *current,
2697                         gint             count)
2698 {
2699   GList *item, *next;
2700   gint y, col;
2701   
2702   col = current->col;
2703   y = current->y + count * icon_view->priv->vadjustment->page_size;
2704
2705   item = g_list_find (icon_view->priv->items, current);
2706   if (count > 0)
2707     {
2708       while (item)
2709         {
2710           for (next = item->next; next; next = next->next)
2711             {
2712               if (((GtkIconViewItem *)next->data)->col == col)
2713                 break;
2714             }
2715           if (!next || ((GtkIconViewItem *)next->data)->y > y)
2716             break;
2717
2718           item = next;
2719         }
2720     }
2721   else 
2722     {
2723       while (item)
2724         {
2725           for (next = item->prev; next; next = next->prev)
2726             {
2727               if (((GtkIconViewItem *)next->data)->col == col)
2728                 break;
2729             }
2730           if (!next || ((GtkIconViewItem *)next->data)->y < y)
2731             break;
2732
2733           item = next;
2734         }
2735     }
2736
2737   if (item)
2738     return item->data;
2739
2740   return NULL;
2741 }
2742
2743 static gboolean
2744 gtk_icon_view_select_all_between (GtkIconView     *icon_view,
2745                                   GtkIconViewItem *anchor,
2746                                   GtkIconViewItem *cursor)
2747 {
2748   GList *items;
2749   GtkIconViewItem *item;
2750   gint row1, row2, col1, col2;
2751   gboolean dirty = FALSE;
2752   
2753   if (anchor->row < cursor->row)
2754     {
2755       row1 = anchor->row;
2756       row2 = cursor->row;
2757     }
2758   else
2759     {
2760       row1 = cursor->row;
2761       row2 = anchor->row;
2762     }
2763
2764   if (anchor->col < cursor->col)
2765     {
2766       col1 = anchor->col;
2767       col2 = cursor->col;
2768     }
2769   else
2770     {
2771       col1 = cursor->col;
2772       col2 = anchor->col;
2773     }
2774
2775   for (items = icon_view->priv->items; items; items = items->next)
2776     {
2777       item = items->data;
2778
2779       if (row1 <= item->row && item->row <= row2 &&
2780           col1 <= item->col && item->col <= col2)
2781         {
2782           if (!item->selected)
2783             dirty = TRUE;
2784
2785           item->selected = TRUE;
2786           
2787           gtk_icon_view_queue_draw_item (icon_view, item);
2788         }
2789     }
2790
2791   return dirty;
2792 }
2793
2794 static void 
2795 gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
2796                                    gint         count)
2797 {
2798   GtkIconViewItem *item;
2799   gboolean dirty = FALSE;
2800   
2801   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2802     return;
2803   
2804   if (!icon_view->priv->cursor_item)
2805     {
2806       GList *list;
2807
2808       if (count > 0)
2809         list = icon_view->priv->items;
2810       else
2811         list = g_list_last (icon_view->priv->items);
2812
2813       item = list ? list->data : NULL;
2814     }
2815   else
2816     item = find_item (icon_view, 
2817                       icon_view->priv->cursor_item,
2818                       count, 0);
2819
2820   if (!item)
2821     return;
2822
2823   if (icon_view->priv->ctrl_pressed ||
2824       !icon_view->priv->shift_pressed ||
2825       !icon_view->priv->anchor_item ||
2826       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2827     icon_view->priv->anchor_item = item;
2828
2829   gtk_icon_view_set_cursor_item (icon_view, item);
2830
2831   if (!icon_view->priv->ctrl_pressed &&
2832       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2833     {
2834       gtk_icon_view_unselect_all_internal (icon_view);
2835       dirty = gtk_icon_view_select_all_between (icon_view, 
2836                                                 icon_view->priv->anchor_item,
2837                                                 item);
2838     }
2839
2840   gtk_icon_view_scroll_to_item (icon_view, item);
2841
2842   if (dirty)
2843     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2844 }
2845
2846 static void 
2847 gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
2848                                         gint         count)
2849 {
2850   GtkIconViewItem *item;
2851   gboolean dirty = FALSE;
2852   
2853   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2854     return;
2855   
2856   if (!icon_view->priv->cursor_item)
2857     {
2858       GList *list;
2859
2860       if (count > 0)
2861         list = icon_view->priv->items;
2862       else
2863         list = g_list_last (icon_view->priv->items);
2864
2865       item = list ? list->data : NULL;
2866     }
2867   else
2868     item = find_item_page_up_down (icon_view, 
2869                                    icon_view->priv->cursor_item,
2870                                    count);
2871
2872   if (!item)
2873     return;
2874
2875   if (icon_view->priv->ctrl_pressed ||
2876       !icon_view->priv->shift_pressed ||
2877       !icon_view->priv->anchor_item ||
2878       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2879     icon_view->priv->anchor_item = item;
2880
2881   gtk_icon_view_set_cursor_item (icon_view, item);
2882
2883   if (!icon_view->priv->ctrl_pressed &&
2884       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2885     {
2886       gtk_icon_view_unselect_all_internal (icon_view);
2887       dirty = gtk_icon_view_select_all_between (icon_view, 
2888                                                 icon_view->priv->anchor_item,
2889                                                 item);
2890     }
2891
2892   gtk_icon_view_scroll_to_item (icon_view, item);
2893
2894   if (dirty)
2895     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);  
2896 }
2897
2898 static void 
2899 gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
2900                                       gint         count)
2901 {
2902   GtkIconViewItem *item;
2903   gboolean dirty = FALSE;
2904   
2905   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2906     return;
2907   
2908   if (!icon_view->priv->cursor_item)
2909     {
2910       GList *list;
2911
2912       if (count > 0)
2913         list = icon_view->priv->items;
2914       else
2915         list = g_list_last (icon_view->priv->items);
2916
2917       item = list ? list->data : NULL;
2918     }
2919   else
2920     item = find_item (icon_view, 
2921                       icon_view->priv->cursor_item,
2922                       0, count);
2923
2924   if (!item)
2925     return;
2926
2927   if (icon_view->priv->ctrl_pressed ||
2928       !icon_view->priv->shift_pressed ||
2929       !icon_view->priv->anchor_item ||
2930       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2931     icon_view->priv->anchor_item = item;
2932
2933   gtk_icon_view_set_cursor_item (icon_view, item);
2934
2935   if (!icon_view->priv->ctrl_pressed &&
2936       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2937     {
2938       gtk_icon_view_unselect_all_internal (icon_view);
2939       dirty = gtk_icon_view_select_all_between (icon_view, 
2940                                                 icon_view->priv->anchor_item,
2941                                                 item);
2942     }
2943
2944   gtk_icon_view_scroll_to_item (icon_view, item);
2945
2946   if (dirty)
2947     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2948 }
2949
2950 static void 
2951 gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
2952                                      gint         count)
2953 {
2954   GtkIconViewItem *item;
2955   GList *list;
2956   gboolean dirty = FALSE;
2957   
2958   if (!GTK_WIDGET_HAS_FOCUS (icon_view))
2959     return;
2960   
2961   if (count < 0)
2962     list = icon_view->priv->items;
2963   else
2964     list = g_list_last (icon_view->priv->items);
2965   
2966   item = list ? list->data : NULL;
2967
2968   if (!item)
2969     return;
2970
2971   if (icon_view->priv->ctrl_pressed ||
2972       !icon_view->priv->shift_pressed ||
2973       !icon_view->priv->anchor_item ||
2974       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
2975     icon_view->priv->anchor_item = item;
2976
2977   gtk_icon_view_set_cursor_item (icon_view, item);
2978
2979   if (!icon_view->priv->ctrl_pressed &&
2980       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
2981     {
2982       gtk_icon_view_unselect_all (icon_view);
2983       dirty = gtk_icon_view_select_all_between (icon_view, 
2984                                                 icon_view->priv->anchor_item,
2985                                                 item);
2986     }
2987
2988   gtk_icon_view_scroll_to_item (icon_view, item);
2989
2990   if (dirty)
2991     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
2992 }
2993
2994 static void     
2995 gtk_icon_view_scroll_to_item (GtkIconView     *icon_view, 
2996                               GtkIconViewItem *item)
2997 {
2998   gint y, height;
2999   gdouble value;
3000
3001   gdk_drawable_get_size (GDK_DRAWABLE (icon_view->priv->bin_window), NULL, &height);
3002   gdk_window_get_position (icon_view->priv->bin_window, NULL, &y);
3003
3004   if (y + item->y < 0)
3005     {
3006       value = icon_view->priv->vadjustment->value + y + item->y;
3007       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
3008     }
3009   else if (y + item->y + item->height > GTK_WIDGET (icon_view)->allocation.height)
3010     {
3011       value = icon_view->priv->vadjustment->value + y + item->y + item->height 
3012         - GTK_WIDGET (icon_view)->allocation.height;
3013       gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
3014     }
3015 }
3016
3017 /* Public API */
3018
3019
3020 /**
3021  * gtk_icon_view_new:
3022  * 
3023  * Creates a new #GtkIconView widget
3024  * 
3025  * Return value: A newly created #GtkIconView widget
3026  *
3027  * Since: 2.6
3028  **/
3029 GtkWidget *
3030 gtk_icon_view_new (void)
3031 {
3032   return g_object_new (GTK_TYPE_ICON_VIEW, NULL);
3033 }
3034
3035 /**
3036  * gtk_icon_view_new_with_model:
3037  * @model: The model.
3038  * 
3039  * Creates a new #GtkIconView widget with the model @model.
3040  * 
3041  * Return value: A newly created #GtkIconView widget.
3042  *
3043  * Since: 2.6 
3044  **/
3045 GtkWidget *
3046 gtk_icon_view_new_with_model (GtkTreeModel *model)
3047 {
3048   return g_object_new (GTK_TYPE_ICON_VIEW, "model", model, NULL);
3049 }
3050
3051
3052 /**
3053  * gtk_icon_view_get_path_at_pos:
3054  * @icon_view: A #GtkIconView.
3055  * @x: The x position to be identified
3056  * @y: The y position to be identified
3057  * 
3058  * Finds the path at the point (@x, @y), relative to widget coordinates.
3059  * 
3060  * Return value: The #GtkTreePath corresponding to the icon or %NULL
3061  * if no icon exists at that position.
3062  *
3063  * Since: 2.6 
3064  **/
3065 GtkTreePath *
3066 gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
3067                                gint         x,
3068                                gint         y)
3069 {
3070   GtkIconViewItem *item;
3071   GtkTreePath *path;
3072   
3073   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3074
3075   item = gtk_icon_view_get_item_at_pos (icon_view, x, y);
3076
3077   if (!item)
3078     return NULL;
3079
3080   path = gtk_tree_path_new_from_indices (item->index, -1);
3081
3082   return path;
3083 }
3084
3085 /**
3086  * gtk_icon_view_selected_foreach:
3087  * @icon_view: A #GtkIconView.
3088  * @func: The funcion to call for each selected icon.
3089  * @data: User data to pass to the function.
3090  * 
3091  * Calls a function for each selected icon. Note that the model or
3092  * selection cannot be modified from within this function.
3093  *
3094  * Since: 2.6 
3095  **/
3096 void
3097 gtk_icon_view_selected_foreach (GtkIconView           *icon_view,
3098                                 GtkIconViewForeachFunc func,
3099                                 gpointer               data)
3100 {
3101   GList *list;
3102   
3103   for (list = icon_view->priv->items; list; list = list->next)
3104     {
3105       GtkIconViewItem *item = list->data;
3106       GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
3107
3108       if (item->selected)
3109         (* func) (icon_view, path, data);
3110
3111       gtk_tree_path_free (path);
3112     }
3113 }
3114
3115 /**
3116  * gtk_icon_view_set_selection_mode:
3117  * @icon_view: A #GtkIconView.
3118  * @mode: The selection mode
3119  * 
3120  * Sets the selection mode of the @icon_view.
3121  *
3122  * Since: 2.6 
3123  **/
3124 void
3125 gtk_icon_view_set_selection_mode (GtkIconView      *icon_view,
3126                                   GtkSelectionMode  mode)
3127 {
3128   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3129
3130   if (mode == icon_view->priv->selection_mode)
3131     return;
3132   
3133   if (mode == GTK_SELECTION_NONE ||
3134       icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
3135     gtk_icon_view_unselect_all (icon_view);
3136   
3137   icon_view->priv->selection_mode = mode;
3138
3139   g_object_notify (G_OBJECT (icon_view), "selection_mode");
3140 }
3141
3142 /**
3143  * gtk_icon_view_get_selection_mode:
3144  * @icon_view: A #GtkIconView.
3145  * 
3146  * Gets the selection mode of the @icon_view.
3147  *
3148  * Return value: the current selection mode
3149  *
3150  * Since: 2.6 
3151  **/
3152 GtkSelectionMode
3153 gtk_icon_view_get_selection_mode (GtkIconView *icon_view)
3154 {
3155   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
3156
3157   return icon_view->priv->selection_mode;
3158 }
3159
3160 /**
3161  * gtk_icon_view_set_model:
3162  * @icon_view: A #GtkIconView.
3163  * @model: The model.
3164  *
3165  * Sets the model for a #GtkIconView.  
3166  * If the @icon_view already has a model set, it will remove 
3167  * it before setting the new model.  If @model is %NULL, then
3168  * it will unset the old model.
3169  *
3170  * Since: 2.6 
3171  **/
3172 void
3173 gtk_icon_view_set_model (GtkIconView *icon_view,
3174                          GtkTreeModel *model)
3175 {
3176   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3177   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
3178   
3179   if (icon_view->priv->model == model)
3180     return;
3181
3182   if (model)
3183     {
3184       GType column_type;
3185       
3186       g_return_if_fail (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY);
3187
3188       if (icon_view->priv->pixbuf_column != -1)
3189         {
3190           column_type = gtk_tree_model_get_column_type (model,
3191                                                         icon_view->priv->pixbuf_column);          
3192
3193           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
3194         }
3195
3196       if (icon_view->priv->text_column != -1)
3197         {
3198           column_type = gtk_tree_model_get_column_type (model,
3199                                                         icon_view->priv->text_column);    
3200
3201           g_return_if_fail (column_type == G_TYPE_STRING);
3202         }
3203
3204       if (icon_view->priv->markup_column != -1)
3205         {
3206           column_type = gtk_tree_model_get_column_type (model,
3207                                                         icon_view->priv->markup_column);          
3208
3209           g_return_if_fail (column_type == G_TYPE_STRING);
3210         }
3211       
3212     }
3213   
3214   if (icon_view->priv->model)
3215     {
3216       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3217                                             gtk_icon_view_row_changed,
3218                                             icon_view);
3219       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3220                                             gtk_icon_view_row_inserted,
3221                                             icon_view);
3222       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3223                                             gtk_icon_view_row_deleted,
3224                                             icon_view);
3225       g_signal_handlers_disconnect_by_func (icon_view->priv->model,
3226                                             gtk_icon_view_rows_reordered,
3227                                             icon_view);
3228
3229       g_object_unref (icon_view->priv->model);
3230       
3231       g_list_foreach (icon_view->priv->items, (GFunc)gtk_icon_view_item_free, NULL);
3232       g_list_free (icon_view->priv->items);
3233       icon_view->priv->items = NULL;
3234       icon_view->priv->anchor_item = NULL;
3235       icon_view->priv->cursor_item = NULL;
3236       icon_view->priv->last_single_clicked = NULL;
3237     }
3238
3239   icon_view->priv->model = model;
3240
3241   if (icon_view->priv->model)
3242     {
3243       g_object_ref (icon_view->priv->model);
3244       g_signal_connect (icon_view->priv->model,
3245                         "row_changed",
3246                         G_CALLBACK (gtk_icon_view_row_changed),
3247                         icon_view);
3248       g_signal_connect (icon_view->priv->model,
3249                         "row_inserted",
3250                         G_CALLBACK (gtk_icon_view_row_inserted),
3251                         icon_view);
3252       g_signal_connect (icon_view->priv->model,
3253                         "row_deleted",
3254                         G_CALLBACK (gtk_icon_view_row_deleted),
3255                         icon_view);
3256       g_signal_connect (icon_view->priv->model,
3257                         "rows_reordered",
3258                         G_CALLBACK (gtk_icon_view_rows_reordered),
3259                         icon_view);
3260
3261       gtk_icon_view_build_items (icon_view);
3262     }
3263
3264   gtk_icon_view_queue_layout (icon_view);
3265
3266   g_object_notify (G_OBJECT (icon_view), "model");  
3267 }
3268
3269 /**
3270  * gtk_icon_view_get_model:
3271  * @icon_view: a #GtkIconView
3272  *
3273  * Returns the model the #GtkIconView is based on.  Returns %NULL if the
3274  * model is unset.
3275  *
3276  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
3277  *
3278  * Since: 2.6 
3279  **/
3280 GtkTreeModel *
3281 gtk_icon_view_get_model (GtkIconView *icon_view)
3282 {
3283   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3284
3285   return icon_view->priv->model;
3286 }
3287
3288 /**
3289  * gtk_icon_view_set_text_column:
3290  * @icon_view: A #GtkIconView.
3291  * @column: A column in the currently used model.
3292  * 
3293  * Sets the column with text for @icon_view to be @column. The text
3294  * column must be of type #G_TYPE_STRING.
3295  *
3296  * Since: 2.6 
3297  **/
3298 void
3299 gtk_icon_view_set_text_column (GtkIconView *icon_view,
3300                                gint          column)
3301 {
3302   if (column == icon_view->priv->text_column)
3303     return;
3304   
3305   if (column == -1)
3306     icon_view->priv->text_column = -1;
3307   else
3308     {
3309       if (icon_view->priv->model != NULL)
3310         {
3311           GType column_type;
3312           
3313           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3314
3315           g_return_if_fail (column_type == G_TYPE_STRING);
3316         }
3317       
3318       icon_view->priv->text_column = column;
3319     }
3320
3321   gtk_icon_view_invalidate_sizes (icon_view);
3322   gtk_icon_view_queue_layout (icon_view);
3323   
3324   g_object_notify (G_OBJECT (icon_view), "text_column");
3325 }
3326
3327 /**
3328  * gtk_icon_view_get_text_column:
3329  * @icon_view: A #GtkIconView.
3330  *
3331  * Returns the column with text for @icon_view.
3332  *
3333  * Returns: the text column, or -1 if it's unset.
3334  *
3335  * Since: 2.6
3336  */
3337 gint
3338 gtk_icon_view_get_text_column (GtkIconView  *icon_view)
3339 {
3340   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3341
3342   return icon_view->priv->text_column;
3343 }
3344
3345 /**
3346  * gtk_icon_view_set_markup_column:
3347  * @icon_view: A #GtkIconView.
3348  * @column: A column in the currently used model.
3349  * 
3350  * Sets the column with markup information for @icon_view to be
3351  * @column. The markup column must be of type #G_TYPE_STRING.
3352  * If the markup column is set to something, it overrides
3353  * the text column set by gtk_icon_view_set_text_column().
3354  *
3355  * Since: 2.6
3356  **/
3357 void
3358 gtk_icon_view_set_markup_column (GtkIconView *icon_view,
3359                                  gint         column)
3360 {
3361   if (column == icon_view->priv->markup_column)
3362     return;
3363   
3364   if (column == -1)
3365     icon_view->priv->markup_column = -1;
3366   else
3367     {
3368       if (icon_view->priv->model != NULL)
3369         {
3370           GType column_type;
3371           
3372           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3373
3374           g_return_if_fail (column_type == G_TYPE_STRING);
3375         }
3376       
3377       icon_view->priv->markup_column = column;
3378     }
3379
3380   gtk_icon_view_invalidate_sizes (icon_view);
3381   gtk_icon_view_queue_layout (icon_view);
3382   
3383   g_object_notify (G_OBJECT (icon_view), "markup_column");
3384 }
3385
3386 /**
3387  * gtk_icon_view_get_markup_column:
3388  * @icon_view: A #GtkIconView.
3389  *
3390  * Returns the column with markup text for @icon_view.
3391  *
3392  * Returns: the markup column, or -1 if it's unset.
3393  *
3394  * Since: 2.6
3395  */
3396 gint
3397 gtk_icon_view_get_markup_column (GtkIconView  *icon_view)
3398 {
3399   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3400
3401   return icon_view->priv->markup_column;
3402 }
3403
3404 /**
3405  * gtk_icon_view_set_pixbuf_column:
3406  * @icon_view: A #GtkIconView.
3407  * @column: A column in the currently used model.
3408  * 
3409  * Sets the column with pixbufs for @icon_view to be @column. The pixbuf
3410  * column must be of type #GDK_TYPE_PIXBUF
3411  *
3412  * Since: 2.6 
3413  **/
3414 void
3415 gtk_icon_view_set_pixbuf_column (GtkIconView *icon_view,
3416                                  gint         column)
3417 {
3418   if (column == icon_view->priv->pixbuf_column)
3419     return;
3420   
3421   if (column == -1)
3422     icon_view->priv->pixbuf_column = -1;
3423   else
3424     {
3425       if (icon_view->priv->model != NULL)
3426         {
3427           GType column_type;
3428           
3429           column_type = gtk_tree_model_get_column_type (icon_view->priv->model, column);
3430
3431           g_return_if_fail (column_type == GDK_TYPE_PIXBUF);
3432         }
3433       
3434       icon_view->priv->pixbuf_column = column;
3435     }
3436
3437   gtk_icon_view_invalidate_sizes (icon_view);
3438   gtk_icon_view_queue_layout (icon_view);
3439   
3440   g_object_notify (G_OBJECT (icon_view), "pixbuf_column");
3441   
3442 }
3443
3444 /**
3445  * gtk_icon_view_get_pixbuf_column:
3446  * @icon_view: A #GtkIconView.
3447  *
3448  * Returns the column with pixbufs for @icon_view.
3449  *
3450  * Returns: the pixbuf column, or -1 if it's unset.
3451  *
3452  * Since: 2.6
3453  */
3454 gint
3455 gtk_icon_view_get_pixbuf_column (GtkIconView  *icon_view)
3456 {
3457   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3458
3459   return icon_view->priv->pixbuf_column;
3460 }
3461
3462 /**
3463  * gtk_icon_view_select_path:
3464  * @icon_view: A #GtkIconView.
3465  * @path: The #GtkTreePath to be selected.
3466  * 
3467  * Selects the row at @path.
3468  *
3469  * Since: 2.6
3470  **/
3471 void
3472 gtk_icon_view_select_path (GtkIconView *icon_view,
3473                            GtkTreePath *path)
3474 {
3475   GtkIconViewItem *item;
3476   
3477   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3478   g_return_if_fail (icon_view->priv->model != NULL);
3479   g_return_if_fail (path != NULL);
3480
3481   item = g_list_nth (icon_view->priv->items,
3482                      gtk_tree_path_get_indices(path)[0])->data;
3483
3484   if (!item)
3485     return;
3486   
3487   gtk_icon_view_select_item (icon_view, item);
3488 }
3489
3490 /**
3491  * gtk_icon_view_unselect_path:
3492  * @icon_view: A #GtkIconView.
3493  * @path: The #GtkTreePath to be unselected.
3494  * 
3495  * Unselects the row at @path.
3496  *
3497  * Since: 2.6
3498  **/
3499 void
3500 gtk_icon_view_unselect_path (GtkIconView *icon_view,
3501                              GtkTreePath *path)
3502 {
3503   GtkIconViewItem *item;
3504   
3505   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3506   g_return_if_fail (icon_view->priv->model != NULL);
3507   g_return_if_fail (path != NULL);
3508
3509   item = g_list_nth (icon_view->priv->items,
3510                      gtk_tree_path_get_indices(path)[0])->data;
3511
3512   if (!item)
3513     return;
3514   
3515   gtk_icon_view_unselect_item (icon_view, item);
3516 }
3517
3518 /**
3519  * gtk_icon_view_get_selected_items:
3520  * @icon_view: A #GtkIconView.
3521  *
3522  * Creates a list of paths of all selected items. Additionally, if you are
3523  * planning on modifying the model after calling this function, you may
3524  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
3525  * To do this, you can use gtk_tree_row_reference_new().
3526  *
3527  * To free the return value, use:
3528  * <informalexample><programlisting>
3529  * g_list_foreach (list, gtk_tree_path_free, NULL);
3530  * g_list_free (list);
3531  * </programlisting></informalexample>
3532  *
3533  * Return value: A #GList containing a #GtkTreePath for each selected row.
3534  *
3535  * Since: 2.6
3536  **/
3537 GList *
3538 gtk_icon_view_get_selected_items (GtkIconView *icon_view)
3539 {
3540   GList *list;
3541   GList *selected = NULL;
3542   
3543   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
3544   
3545   for (list = icon_view->priv->items; list != NULL; list = list->next)
3546     {
3547       GtkIconViewItem *item = list->data;
3548
3549       if (item->selected)
3550         {
3551           GtkTreePath *path = gtk_tree_path_new_from_indices (item->index, -1);
3552
3553           selected = g_list_prepend (selected, path);
3554         }
3555     }
3556
3557   return selected;
3558 }
3559
3560 /**
3561  * gtk_icon_view_select_all:
3562  * @icon_view: A #GtkIconView.
3563  * 
3564  * Selects all the icons. @icon_view must has its selection mode set
3565  * to #GTK_SELECTION_MULTIPLE.
3566  *
3567  * Since: 2.6
3568  **/
3569 void
3570 gtk_icon_view_select_all (GtkIconView *icon_view)
3571 {
3572   GList *items;
3573   gboolean dirty = FALSE;
3574   
3575   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3576
3577   if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
3578     return;
3579
3580   for (items = icon_view->priv->items; items; items = items->next)
3581     {
3582       GtkIconViewItem *item = items->data;
3583       
3584       if (!item->selected)
3585         {
3586           dirty = TRUE;
3587           item->selected = TRUE;
3588           gtk_icon_view_queue_draw_item (icon_view, item);
3589         }
3590     }
3591
3592   if (dirty)
3593     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3594 }
3595
3596 /**
3597  * gtk_icon_view_unselect_all:
3598  * @icon_view: A #GtkIconView.
3599  * 
3600  * Unselects all the icons.
3601  *
3602  * Since: 2.6
3603  **/
3604 void
3605 gtk_icon_view_unselect_all (GtkIconView *icon_view)
3606 {
3607   gboolean dirty = FALSE;
3608   
3609   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3610
3611   if (icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
3612     return;
3613
3614   dirty = gtk_icon_view_unselect_all_internal (icon_view);
3615
3616   if (dirty)
3617     g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
3618 }
3619
3620 /**
3621  * gtk_icon_view_path_is_selected:
3622  * @icon_view: A #GtkIconView.
3623  * @path: A #GtkTreePath to check selection on.
3624  * 
3625  * Returns %TRUE if the icon pointed to by @path is currently
3626  * selected. If @icon does not point to a valid location, %FALSE is returned.
3627  * 
3628  * Return value: %TRUE if @path is selected.
3629  *
3630  * Since: 2.6
3631  **/
3632 gboolean
3633 gtk_icon_view_path_is_selected (GtkIconView *icon_view,
3634                                 GtkTreePath *path)
3635 {
3636   GtkIconViewItem *item;
3637   
3638   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), FALSE);
3639   g_return_val_if_fail (icon_view->priv->model != NULL, FALSE);
3640   g_return_val_if_fail (path != NULL, FALSE);
3641   
3642   item = g_list_nth (icon_view->priv->items,
3643                      gtk_tree_path_get_indices(path)[0])->data;
3644
3645   if (!item)
3646     return FALSE;
3647   
3648   return item->selected;
3649 }
3650
3651 /**
3652  * gtk_icon_view_item_activated:
3653  * @icon_view: A #GtkIconView
3654  * @path: The #GtkTreePath to be activated
3655  * 
3656  * Activates the item determined by @path.
3657  *
3658  * Since: 2.6
3659  **/
3660 void
3661 gtk_icon_view_item_activated (GtkIconView      *icon_view,
3662                               GtkTreePath      *path)
3663 {
3664   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3665   g_return_if_fail (path != NULL);
3666   
3667   g_signal_emit (icon_view, icon_view_signals[ITEM_ACTIVATED], 0, path);
3668 }
3669
3670 /**
3671  * gtk_icon_view_set_orientation:
3672  * @icon_view: a #GtkIconView
3673  * @orientation: the relative position of texts and icons 
3674  * 
3675  * Sets the ::orientation property which determines whether the labels 
3676  * are drawn beside the icons instead of below.
3677  *
3678  * Since: 2.6
3679  **/
3680 void 
3681 gtk_icon_view_set_orientation (GtkIconView    *icon_view,
3682                                GtkOrientation  orientation)
3683 {
3684   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3685
3686   if (icon_view->priv->orientation != orientation)
3687     {
3688       icon_view->priv->orientation = orientation;
3689
3690       gtk_icon_view_invalidate_sizes (icon_view);
3691       gtk_icon_view_queue_layout (icon_view);
3692       
3693       g_object_notify (G_OBJECT (icon_view), "orientation");
3694     }
3695 }
3696
3697 /**
3698  * gtk_icon_view_get_orientation:
3699  * @icon_view: a #GtkIconView
3700  * 
3701  * Returns the value of the ::orientation property which determines 
3702  * whether the labels are drawn beside the icons instead of below. 
3703  * 
3704  * Return value: the relative position of texts and icons 
3705  *
3706  * Since: 2.6
3707  **/
3708 GtkOrientation
3709 gtk_icon_view_get_orientation (GtkIconView *icon_view)
3710 {
3711   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 
3712                         GTK_ORIENTATION_VERTICAL);
3713
3714   return icon_view->priv->orientation;
3715 }
3716
3717 void gtk_icon_view_set_columns (GtkIconView *icon_view,
3718                                 gint         columns)
3719 {
3720   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3721   
3722   if (icon_view->priv->columns != columns)
3723     {
3724       icon_view->priv->columns = columns;
3725
3726       gtk_icon_view_queue_layout (icon_view);
3727       
3728       g_object_notify (G_OBJECT (icon_view), "columns");
3729     }  
3730 }
3731
3732 gint
3733 gtk_icon_view_get_columns (GtkIconView *icon_view)
3734 {
3735   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3736
3737   return icon_view->priv->columns;
3738 }
3739
3740 void gtk_icon_view_set_item_width (GtkIconView *icon_view,
3741                                    gint         item_width)
3742 {
3743   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3744   
3745   if (icon_view->priv->item_width != item_width)
3746     {
3747       icon_view->priv->item_width = item_width;
3748
3749       gtk_icon_view_invalidate_sizes (icon_view);
3750       gtk_icon_view_queue_layout (icon_view);
3751       
3752       g_object_notify (G_OBJECT (icon_view), "item-width");
3753     }  
3754 }
3755
3756 gint
3757 gtk_icon_view_get_item_width (GtkIconView *icon_view)
3758 {
3759   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3760
3761   return icon_view->priv->item_width;
3762 }
3763
3764
3765 void gtk_icon_view_set_spacing (GtkIconView *icon_view,
3766                                 gint         spacing)
3767 {
3768   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3769   
3770   if (icon_view->priv->spacing != spacing)
3771     {
3772       icon_view->priv->spacing = spacing;
3773
3774       gtk_icon_view_invalidate_sizes (icon_view);
3775       gtk_icon_view_queue_layout (icon_view);
3776       
3777       g_object_notify (G_OBJECT (icon_view), "spacing");
3778     }  
3779 }
3780
3781 gint
3782 gtk_icon_view_get_spacing (GtkIconView *icon_view)
3783 {
3784   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3785
3786   return icon_view->priv->spacing;
3787 }
3788
3789 void gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
3790                                     gint         row_spacing)
3791 {
3792   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3793   
3794   if (icon_view->priv->row_spacing != row_spacing)
3795     {
3796       icon_view->priv->row_spacing = row_spacing;
3797
3798       gtk_icon_view_invalidate_sizes (icon_view);
3799       gtk_icon_view_queue_layout (icon_view);
3800       
3801       g_object_notify (G_OBJECT (icon_view), "row-spacing");
3802     }  
3803 }
3804
3805 gint
3806 gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
3807 {
3808   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3809
3810   return icon_view->priv->row_spacing;
3811 }
3812
3813 void gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
3814                                        gint         column_spacing)
3815 {
3816   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3817   
3818   if (icon_view->priv->column_spacing != column_spacing)
3819     {
3820       icon_view->priv->column_spacing = column_spacing;
3821
3822       gtk_icon_view_invalidate_sizes (icon_view);
3823       gtk_icon_view_queue_layout (icon_view);
3824       
3825       g_object_notify (G_OBJECT (icon_view), "column-spacing");
3826     }  
3827 }
3828
3829 gint
3830 gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
3831 {
3832   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3833
3834   return icon_view->priv->column_spacing;
3835 }
3836
3837 void gtk_icon_view_set_margin (GtkIconView *icon_view,
3838                                gint         margin)
3839 {
3840   g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
3841   
3842   if (icon_view->priv->margin != margin)
3843     {
3844       icon_view->priv->margin = margin;
3845
3846       gtk_icon_view_invalidate_sizes (icon_view);
3847       gtk_icon_view_queue_layout (icon_view);
3848       
3849       g_object_notify (G_OBJECT (icon_view), "margin");
3850     }  
3851 }
3852
3853 gint
3854 gtk_icon_view_get_margin (GtkIconView *icon_view)
3855 {
3856   g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
3857
3858   return icon_view->priv->margin;
3859 }
3860
3861
3862 /* Accessibility Support */
3863
3864 static gpointer accessible_parent_class;
3865 static gpointer accessible_item_parent_class;
3866 static GQuark accessible_private_data_quark = 0;
3867
3868 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (gtk_icon_view_item_accessible_get_type ())
3869 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
3870 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
3871
3872 static GType gtk_icon_view_item_accessible_get_type (void);
3873
3874 enum {
3875     ACTION_ACTIVATE,
3876     LAST_ACTION
3877 };
3878
3879 typedef struct
3880 {
3881   AtkObject parent;
3882
3883   GtkIconViewItem *item;
3884
3885   GtkWidget *widget;
3886
3887   AtkStateSet *state_set;
3888
3889   gchar *text;
3890
3891   GtkTextBuffer *text_buffer;
3892
3893   gchar *action_descriptions[LAST_ACTION];
3894   gchar *image_description;
3895   guint action_idle_handler;
3896 } GtkIconViewItemAccessible;
3897
3898 static const gchar *const gtk_icon_view_item_accessible_action_names[] = 
3899 {
3900   "activate",
3901   NULL
3902 };
3903
3904 static const gchar *const gtk_icon_view_item_accessible_action_descriptions[] =
3905 {
3906   "Activate item",
3907   NULL
3908 };
3909 typedef struct _GtkIconViewItemAccessibleClass
3910 {
3911   AtkObjectClass parent_class;
3912
3913 } GtkIconViewItemAccessibleClass;
3914
3915 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
3916
3917 static gboolean
3918 gtk_icon_view_item_accessible_idle_do_action (gpointer data)
3919 {
3920   GtkIconViewItemAccessible *item;
3921   GtkIconView *icon_view;
3922   GtkTreePath *path;
3923
3924   GDK_THREADS_ENTER ();
3925
3926   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
3927   item->action_idle_handler = 0;
3928
3929   if (item->widget != NULL)
3930     {
3931       icon_view = GTK_ICON_VIEW (item->widget);
3932       path = gtk_tree_path_new_from_indices (item->item->index, -1);
3933       gtk_icon_view_item_activated (icon_view, path);
3934       gtk_tree_path_free (path);
3935     }
3936
3937   GDK_THREADS_LEAVE ();
3938
3939   return FALSE;
3940 }
3941
3942 static gboolean
3943 gtk_icon_view_item_accessible_action_do_action (AtkAction *action,
3944                                                 gint       i)
3945 {
3946   GtkIconViewItemAccessible *item;
3947   GtkIconView *icon_view;
3948
3949   if (i < 0 || i >= LAST_ACTION) 
3950     return FALSE;
3951
3952   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
3953
3954   if (!GTK_IS_ICON_VIEW (item->widget))
3955     return FALSE;
3956
3957   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
3958     return FALSE;
3959
3960   icon_view = GTK_ICON_VIEW (item->widget);
3961
3962   switch (i)
3963     {
3964     case ACTION_ACTIVATE:
3965       if (!item->action_idle_handler)
3966         item->action_idle_handler = g_idle_add (gtk_icon_view_item_accessible_idle_do_action, item);
3967       break;
3968     default:
3969       g_assert_not_reached ();
3970       return FALSE;
3971
3972     }        
3973   return TRUE;
3974 }
3975
3976 static gint
3977 gtk_icon_view_item_accessible_action_get_n_actions (AtkAction *action)
3978 {
3979         return LAST_ACTION;
3980 }
3981
3982 static const gchar *
3983 gtk_icon_view_item_accessible_action_get_description (AtkAction *action,
3984                                                       gint       i)
3985 {
3986   GtkIconViewItemAccessible *item;
3987
3988   if (i < 0 || i >= LAST_ACTION) 
3989     return NULL;
3990
3991   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
3992
3993   if (item->action_descriptions[i])
3994     return item->action_descriptions[i];
3995   else
3996     return gtk_icon_view_item_accessible_action_descriptions[i];
3997 }
3998
3999 static const gchar *
4000 gtk_icon_view_item_accessible_action_get_name (AtkAction *action,
4001                                                gint       i)
4002 {
4003   if (i < 0 || i >= LAST_ACTION) 
4004     return NULL;
4005
4006   return gtk_icon_view_item_accessible_action_names[i];
4007 }
4008
4009 static gboolean
4010 gtk_icon_view_item_accessible_action_set_description (AtkAction   *action,
4011                                                       gint         i,
4012                                                       const gchar *description)
4013 {
4014   GtkIconViewItemAccessible *item;
4015
4016   if (i < 0 || i >= LAST_ACTION) 
4017     return FALSE;
4018
4019   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
4020
4021   if (item->action_descriptions[i])
4022     g_free (item->action_descriptions[i]);
4023
4024   item->action_descriptions[i] = g_strdup (description);
4025
4026   return TRUE;
4027 }
4028
4029 static void
4030 atk_action_item_interface_init (AtkActionIface *iface)
4031 {
4032   iface->do_action = gtk_icon_view_item_accessible_action_do_action;
4033   iface->get_n_actions = gtk_icon_view_item_accessible_action_get_n_actions;
4034   iface->get_description = gtk_icon_view_item_accessible_action_get_description;
4035   iface->get_name = gtk_icon_view_item_accessible_action_get_name;
4036   iface->set_description = gtk_icon_view_item_accessible_action_set_description;
4037 }
4038
4039 static const gchar *
4040 gtk_icon_view_item_accessible_image_get_image_description (AtkImage *image)
4041 {
4042   GtkIconViewItemAccessible *item;
4043
4044   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4045
4046   return item->image_description;
4047 }
4048
4049 static gboolean
4050 gtk_icon_view_item_accessible_image_set_image_description (AtkImage    *image,
4051                                                            const gchar *description)
4052 {
4053   GtkIconViewItemAccessible *item;
4054
4055   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4056
4057   g_free (item->image_description);
4058   item->image_description = g_strdup (item->image_description);
4059
4060   return TRUE;
4061 }
4062
4063 static void
4064 gtk_icon_view_item_accessible_image_get_image_size (AtkImage *image,
4065                                                     gint     *width,
4066                                                     gint     *height)
4067 {
4068   GtkIconViewItemAccessible *item;
4069
4070   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4071
4072   if (!GTK_IS_ICON_VIEW (item->widget))
4073     return;
4074
4075   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4076     return;
4077
4078   *width = item->item->pixbuf_width;  
4079   *height = item->item->pixbuf_height;  
4080 }
4081
4082 static void
4083 gtk_icon_view_item_accessible_image_get_image_position (AtkImage    *image,
4084                                                         gint        *x,
4085                                                         gint        *y,
4086                                                         AtkCoordType coord_type)
4087 {
4088   GtkIconViewItemAccessible *item;
4089
4090   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
4091
4092   if (!GTK_IS_ICON_VIEW (item->widget))
4093     return;
4094
4095   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4096     return;
4097
4098   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
4099   *x+= item->item->pixbuf_x - item->item->x;
4100   *y+= item->item->pixbuf_y - item->item->y;
4101 }
4102
4103 static void
4104 atk_image_item_interface_init (AtkImageIface *iface)
4105 {
4106   iface->get_image_description = gtk_icon_view_item_accessible_image_get_image_description;
4107   iface->set_image_description = gtk_icon_view_item_accessible_image_set_image_description;
4108   iface->get_image_size = gtk_icon_view_item_accessible_image_get_image_size;
4109   iface->get_image_position = gtk_icon_view_item_accessible_image_get_image_position;
4110 }
4111
4112 static gchar *
4113 gtk_icon_view_item_accessible_text_get_text (AtkText *text,
4114                                              gint     start_pos,
4115                                              gint     end_pos)
4116 {
4117   GtkIconViewItemAccessible *item;
4118   GtkTextIter start, end;
4119   GtkTextBuffer *buffer;
4120
4121   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4122
4123   if (!GTK_IS_ICON_VIEW (item->widget))
4124     return NULL;
4125
4126   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4127     return NULL;
4128
4129   buffer = item->text_buffer;
4130   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
4131   if (end_pos < 0)
4132     gtk_text_buffer_get_end_iter (buffer, &end);
4133   else
4134     gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
4135
4136   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4137 }
4138
4139 static gunichar
4140 gtk_icon_view_item_accessible_text_get_character_at_offset (AtkText *text,
4141                                                             gint     offset)
4142 {
4143   GtkIconViewItemAccessible *item;
4144   GtkTextIter start, end;
4145   GtkTextBuffer *buffer;
4146   gchar *string;
4147   gunichar unichar;
4148
4149   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4150
4151   if (!GTK_IS_ICON_VIEW (item->widget))
4152     return '\0';
4153
4154   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4155     return '\0';
4156
4157   buffer = item->text_buffer;
4158   if (offset >= gtk_text_buffer_get_char_count (buffer))
4159     return '\0';
4160
4161   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4162   end = start;
4163   gtk_text_iter_forward_char (&end);
4164   string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
4165   unichar = g_utf8_get_char (string);
4166   g_free(string);
4167
4168   return unichar;
4169 }
4170
4171 static void
4172 get_pango_text_offsets (PangoLayout     *layout,
4173                         GtkTextBuffer   *buffer,
4174                         gint             function,
4175                         AtkTextBoundary  boundary_type,
4176                         gint             offset,
4177                         gint            *start_offset,
4178                         gint            *end_offset,
4179                         GtkTextIter     *start_iter,
4180                         GtkTextIter     *end_iter)
4181 {
4182   PangoLayoutIter *iter;
4183   PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
4184   gint index, start_index, end_index;
4185   const gchar *text;
4186   gboolean found = FALSE;
4187
4188   text = pango_layout_get_text (layout);
4189   index = g_utf8_offset_to_pointer (text, offset) - text;
4190   iter = pango_layout_get_iter (layout);
4191   do
4192     {
4193       line = pango_layout_iter_get_line (iter);
4194       start_index = line->start_index;
4195       end_index = start_index + line->length;
4196
4197       if (index >= start_index && index <= end_index)
4198         {
4199           /*
4200            * Found line for offset
4201            */
4202           switch (function)
4203             {
4204             case 0:
4205                   /*
4206                    * We want the previous line
4207                    */
4208               if (prev_line)
4209                 {
4210                   switch (boundary_type)
4211                     {
4212                     case ATK_TEXT_BOUNDARY_LINE_START:
4213                       end_index = start_index;
4214                       start_index = prev_line->start_index;
4215                       break;
4216                     case ATK_TEXT_BOUNDARY_LINE_END:
4217                       if (prev_prev_line)
4218                         start_index = prev_prev_line->start_index + 
4219                                   prev_prev_line->length;
4220                       end_index = prev_line->start_index + prev_line->length;
4221                       break;
4222                     default:
4223                       g_assert_not_reached();
4224                     }
4225                 }
4226               else
4227                 start_index = end_index = 0;
4228               break;
4229             case 1:
4230               switch (boundary_type)
4231                 {
4232                 case ATK_TEXT_BOUNDARY_LINE_START:
4233                   if (pango_layout_iter_next_line (iter))
4234                     end_index = pango_layout_iter_get_line (iter)->start_index;
4235                   break;
4236                 case ATK_TEXT_BOUNDARY_LINE_END:
4237                   if (prev_line)
4238                     start_index = prev_line->start_index + 
4239                                   prev_line->length;
4240                   break;
4241                 default:
4242                   g_assert_not_reached();
4243                 }
4244               break;
4245             case 2:
4246                /*
4247                 * We want the next line
4248                 */
4249               if (pango_layout_iter_next_line (iter))
4250                 {
4251                   line = pango_layout_iter_get_line (iter);
4252                   switch (boundary_type)
4253                     {
4254                     case ATK_TEXT_BOUNDARY_LINE_START:
4255                       start_index = line->start_index;
4256                       if (pango_layout_iter_next_line (iter))
4257                         end_index = pango_layout_iter_get_line (iter)->start_index;
4258                       else
4259                         end_index = start_index + line->length;
4260                       break;
4261                     case ATK_TEXT_BOUNDARY_LINE_END:
4262                       start_index = end_index;
4263                       end_index = line->start_index + line->length;
4264                       break;
4265                     default:
4266                       g_assert_not_reached();
4267                     }
4268                 }
4269               else
4270                 start_index = end_index;
4271               break;
4272             }
4273           found = TRUE;
4274           break;
4275         }
4276       prev_prev_line = prev_line; 
4277       prev_line = line; 
4278     }
4279   while (pango_layout_iter_next_line (iter));
4280
4281   if (!found)
4282     {
4283       start_index = prev_line->start_index + prev_line->length;
4284       end_index = start_index;
4285     }
4286   pango_layout_iter_free (iter);
4287   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
4288   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
4289  
4290   gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
4291   gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
4292 }
4293
4294 static gchar*
4295 gtk_icon_view_item_accessible_text_get_text_before_offset (AtkText         *text,
4296                                                            gint            offset,
4297                                                            AtkTextBoundary boundary_type,
4298                                                            gint            *start_offset,
4299                                                            gint            *end_offset)
4300 {
4301   GtkIconViewItemAccessible *item;
4302   GtkTextIter start, end;
4303   GtkTextBuffer *buffer;
4304   GtkIconView *icon_view;
4305
4306   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4307
4308   if (!GTK_IS_ICON_VIEW (item->widget))
4309     return NULL;
4310
4311   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4312     return NULL;
4313
4314   buffer = item->text_buffer;
4315
4316   if (!gtk_text_buffer_get_char_count (buffer))
4317     {
4318       *start_offset = 0;
4319       *end_offset = 0;
4320       return g_strdup ("");
4321     }
4322   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4323    
4324   end = start;
4325
4326   switch (boundary_type)
4327     {
4328     case ATK_TEXT_BOUNDARY_CHAR:
4329       gtk_text_iter_backward_char(&start);
4330       break;
4331     case ATK_TEXT_BOUNDARY_WORD_START:
4332       if (!gtk_text_iter_starts_word (&start))
4333         gtk_text_iter_backward_word_start (&start);
4334       end = start;
4335       gtk_text_iter_backward_word_start(&start);
4336       break;
4337     case ATK_TEXT_BOUNDARY_WORD_END:
4338       if (gtk_text_iter_inside_word (&start) &&
4339           !gtk_text_iter_starts_word (&start))
4340         gtk_text_iter_backward_word_start (&start);
4341       while (!gtk_text_iter_ends_word (&start))
4342         {
4343           if (!gtk_text_iter_backward_char (&start))
4344             break;
4345         }
4346       end = start;
4347       gtk_text_iter_backward_word_start(&start);
4348       while (!gtk_text_iter_ends_word (&start))
4349         {
4350           if (!gtk_text_iter_backward_char (&start))
4351             break;
4352         }
4353       break;
4354     case ATK_TEXT_BOUNDARY_SENTENCE_START:
4355       if (!gtk_text_iter_starts_sentence (&start))
4356         gtk_text_iter_backward_sentence_start (&start);
4357       end = start;
4358       gtk_text_iter_backward_sentence_start (&start);
4359       break;
4360     case ATK_TEXT_BOUNDARY_SENTENCE_END:
4361       if (gtk_text_iter_inside_sentence (&start) &&
4362           !gtk_text_iter_starts_sentence (&start))
4363         gtk_text_iter_backward_sentence_start (&start);
4364       while (!gtk_text_iter_ends_sentence (&start))
4365         {
4366           if (!gtk_text_iter_backward_char (&start))
4367             break;
4368         }
4369       end = start;
4370       gtk_text_iter_backward_sentence_start (&start);
4371       while (!gtk_text_iter_ends_sentence (&start))
4372         {
4373           if (!gtk_text_iter_backward_char (&start))
4374             break;
4375         }
4376       break;
4377    case ATK_TEXT_BOUNDARY_LINE_START:
4378    case ATK_TEXT_BOUNDARY_LINE_END:
4379       icon_view = GTK_ICON_VIEW (item->widget);
4380       gtk_icon_view_update_item_text (icon_view, item->item);
4381       get_pango_text_offsets (icon_view->priv->layout,
4382                               buffer,
4383                               0,
4384                               boundary_type,
4385                               offset,
4386                               start_offset,
4387                               end_offset,
4388                               &start,
4389                               &end);
4390       break;
4391     }
4392
4393   *start_offset = gtk_text_iter_get_offset (&start);
4394   *end_offset = gtk_text_iter_get_offset (&end);
4395
4396   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4397 }
4398
4399 static gchar*
4400 gtk_icon_view_item_accessible_text_get_text_at_offset (AtkText         *text,
4401                                                        gint            offset,
4402                                                        AtkTextBoundary boundary_type,
4403                                                        gint            *start_offset,
4404                                                        gint            *end_offset)
4405 {
4406   GtkIconViewItemAccessible *item;
4407   GtkTextIter start, end;
4408   GtkTextBuffer *buffer;
4409   GtkIconView *icon_view;
4410
4411   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4412
4413   if (!GTK_IS_ICON_VIEW (item->widget))
4414     return NULL;
4415
4416   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4417     return NULL;
4418
4419   buffer = item->text_buffer;
4420
4421   if (!gtk_text_buffer_get_char_count (buffer))
4422     {
4423       *start_offset = 0;
4424       *end_offset = 0;
4425       return g_strdup ("");
4426     }
4427   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4428    
4429   end = start;
4430
4431   switch (boundary_type)
4432     {
4433     case ATK_TEXT_BOUNDARY_CHAR:
4434       gtk_text_iter_forward_char (&end);
4435       break;
4436     case ATK_TEXT_BOUNDARY_WORD_START:
4437       if (!gtk_text_iter_starts_word (&start))
4438         gtk_text_iter_backward_word_start (&start);
4439       if (gtk_text_iter_inside_word (&end))
4440         gtk_text_iter_forward_word_end (&end);
4441       while (!gtk_text_iter_starts_word (&end))
4442         {
4443           if (!gtk_text_iter_forward_char (&end))
4444             break;
4445         }
4446       break;
4447     case ATK_TEXT_BOUNDARY_WORD_END:
4448       if (gtk_text_iter_inside_word (&start) &&
4449           !gtk_text_iter_starts_word (&start))
4450         gtk_text_iter_backward_word_start (&start);
4451       while (!gtk_text_iter_ends_word (&start))
4452         {
4453           if (!gtk_text_iter_backward_char (&start))
4454             break;
4455         }
4456       gtk_text_iter_forward_word_end (&end);
4457       break;
4458     case ATK_TEXT_BOUNDARY_SENTENCE_START:
4459       if (!gtk_text_iter_starts_sentence (&start))
4460         gtk_text_iter_backward_sentence_start (&start);
4461       if (gtk_text_iter_inside_sentence (&end))
4462         gtk_text_iter_forward_sentence_end (&end);
4463       while (!gtk_text_iter_starts_sentence (&end))
4464         {
4465           if (!gtk_text_iter_forward_char (&end))
4466             break;
4467         }
4468       break;
4469     case ATK_TEXT_BOUNDARY_SENTENCE_END:
4470       if (gtk_text_iter_inside_sentence (&start) &&
4471           !gtk_text_iter_starts_sentence (&start))
4472         gtk_text_iter_backward_sentence_start (&start);
4473       while (!gtk_text_iter_ends_sentence (&start))
4474         {
4475           if (!gtk_text_iter_backward_char (&start))
4476             break;
4477         }
4478       gtk_text_iter_forward_sentence_end (&end);
4479       break;
4480    case ATK_TEXT_BOUNDARY_LINE_START:
4481    case ATK_TEXT_BOUNDARY_LINE_END:
4482       icon_view = GTK_ICON_VIEW (item->widget);
4483       gtk_icon_view_update_item_text (icon_view, item->item);
4484       get_pango_text_offsets (icon_view->priv->layout,
4485                               buffer,
4486                               1,
4487                               boundary_type,
4488                               offset,
4489                               start_offset,
4490                               end_offset,
4491                               &start,
4492                               &end);
4493       break;
4494     }
4495
4496
4497   *start_offset = gtk_text_iter_get_offset (&start);
4498   *end_offset = gtk_text_iter_get_offset (&end);
4499
4500   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4501 }
4502
4503 static gchar*
4504 gtk_icon_view_item_accessible_text_get_text_after_offset (AtkText         *text,
4505                                                           gint            offset,
4506                                                           AtkTextBoundary boundary_type,
4507                                                           gint            *start_offset,
4508                                                           gint            *end_offset)
4509 {
4510   GtkIconViewItemAccessible *item;
4511   GtkTextIter start, end;
4512   GtkTextBuffer *buffer;
4513   GtkIconView *icon_view;
4514
4515   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4516
4517   if (!GTK_IS_ICON_VIEW (item->widget))
4518     return NULL;
4519
4520   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4521     return NULL;
4522
4523   buffer = item->text_buffer;
4524
4525   if (!gtk_text_buffer_get_char_count (buffer))
4526     {
4527       *start_offset = 0;
4528       *end_offset = 0;
4529       return g_strdup ("");
4530     }
4531   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
4532    
4533   end = start;
4534
4535   switch (boundary_type)
4536     {
4537     case ATK_TEXT_BOUNDARY_CHAR:
4538       gtk_text_iter_forward_char(&start);
4539       gtk_text_iter_forward_chars(&end, 2);
4540       break;
4541     case ATK_TEXT_BOUNDARY_WORD_START:
4542       if (gtk_text_iter_inside_word (&end))
4543         gtk_text_iter_forward_word_end (&end);
4544       while (!gtk_text_iter_starts_word (&end))
4545         {
4546           if (!gtk_text_iter_forward_char (&end))
4547             break;
4548         }
4549       start = end;
4550       if (!gtk_text_iter_is_end (&end))
4551         {
4552           gtk_text_iter_forward_word_end (&end);
4553           while (!gtk_text_iter_starts_word (&end))
4554             {
4555               if (!gtk_text_iter_forward_char (&end))
4556                 break;
4557             }
4558         }
4559       break;
4560     case ATK_TEXT_BOUNDARY_WORD_END:
4561       gtk_text_iter_forward_word_end (&end);
4562       start = end;
4563       if (!gtk_text_iter_is_end (&end))
4564         gtk_text_iter_forward_word_end (&end);
4565       break;
4566     case ATK_TEXT_BOUNDARY_SENTENCE_START:
4567       if (gtk_text_iter_inside_sentence (&end))
4568         gtk_text_iter_forward_sentence_end (&end);
4569       while (!gtk_text_iter_starts_sentence (&end))
4570         {
4571           if (!gtk_text_iter_forward_char (&end))
4572             break;
4573         }
4574       start = end;
4575       if (!gtk_text_iter_is_end (&end))
4576         {
4577           gtk_text_iter_forward_sentence_end (&end);
4578           while (!gtk_text_iter_starts_sentence (&end))
4579             {
4580               if (!gtk_text_iter_forward_char (&end))
4581                 break;
4582             }
4583         }
4584       break;
4585     case ATK_TEXT_BOUNDARY_SENTENCE_END:
4586       gtk_text_iter_forward_sentence_end (&end);
4587       start = end;
4588       if (!gtk_text_iter_is_end (&end))
4589         gtk_text_iter_forward_sentence_end (&end);
4590       break;
4591    case ATK_TEXT_BOUNDARY_LINE_START:
4592    case ATK_TEXT_BOUNDARY_LINE_END:
4593       icon_view = GTK_ICON_VIEW (item->widget);
4594       gtk_icon_view_update_item_text (icon_view, item->item);
4595       get_pango_text_offsets (icon_view->priv->layout,
4596                               buffer,
4597                               2,
4598                               boundary_type,
4599                               offset,
4600                               start_offset,
4601                               end_offset,
4602                               &start,
4603                               &end);
4604       break;
4605     }
4606   *start_offset = gtk_text_iter_get_offset (&start);
4607   *end_offset = gtk_text_iter_get_offset (&end);
4608
4609   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
4610 }
4611
4612 static gint
4613 gtk_icon_view_item_accessible_text_get_character_count (AtkText *text)
4614 {
4615   GtkIconViewItemAccessible *item;
4616
4617   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4618
4619   if (!GTK_IS_ICON_VIEW (item->widget))
4620     return 0;
4621
4622   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4623     return 0;
4624
4625   return gtk_text_buffer_get_char_count (item->text_buffer);
4626 }
4627
4628 static void
4629 gtk_icon_view_item_accessible_text_get_character_extents (AtkText      *text,
4630                                                           gint         offset,
4631                                                           gint         *x,
4632                                                           gint         *y,
4633                                                           gint         *width,
4634                                                           gint         *height,
4635                                                           AtkCoordType coord_type)
4636 {
4637   GtkIconViewItemAccessible *item;
4638   GtkIconView *icon_view;
4639   PangoRectangle char_rect;
4640   const gchar *item_text;
4641   gint index;
4642
4643   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4644
4645   if (!GTK_IS_ICON_VIEW (item->widget))
4646     return;
4647
4648   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4649     return;
4650
4651   icon_view = GTK_ICON_VIEW (item->widget);
4652   gtk_icon_view_update_item_text (icon_view, item->item);
4653   item_text = pango_layout_get_text (icon_view->priv->layout);
4654   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
4655   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
4656
4657   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
4658   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
4659   /* Look at gtk_icon_view_paint_item() to see where the text is. */
4660   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
4661   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
4662   *width = char_rect.width / PANGO_SCALE;
4663   *height = char_rect.height / PANGO_SCALE;
4664 }
4665
4666 static gint
4667 gtk_icon_view_item_accessible_text_get_offset_at_point (AtkText      *text,
4668                                                         gint          x,
4669                                                         gint          y,
4670                                                         AtkCoordType coord_type)
4671 {
4672   GtkIconViewItemAccessible *item;
4673   GtkIconView *icon_view;
4674   const gchar *item_text;
4675   gint index;
4676   gint offset;
4677   gint l_x, l_y;
4678
4679   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
4680
4681   if (!GTK_IS_ICON_VIEW (item->widget))
4682     return -1;
4683
4684   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4685     return -1;
4686
4687   icon_view = GTK_ICON_VIEW (item->widget);
4688   gtk_icon_view_update_item_text (icon_view, item->item);
4689   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
4690   x -= l_x + item->item->layout_x - item->item->x;
4691   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
4692   y -= l_y + item->item->layout_y - item->item->y;
4693   item_text = pango_layout_get_text (icon_view->priv->layout);
4694   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
4695                                 x * PANGO_SCALE,
4696                                 y * PANGO_SCALE,
4697                                 &index, NULL))
4698     {
4699       if (x < 0 || y < 0)
4700         index = 0;
4701       else
4702         index = -1;
4703     } 
4704   if (index == -1)
4705     offset = g_utf8_strlen (item_text, -1);
4706   else
4707     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
4708
4709   return offset;
4710 }
4711
4712 static void
4713 atk_text_item_interface_init (AtkTextIface *iface)
4714 {
4715   iface->get_text = gtk_icon_view_item_accessible_text_get_text;
4716   iface->get_character_at_offset = gtk_icon_view_item_accessible_text_get_character_at_offset;
4717   iface->get_text_before_offset = gtk_icon_view_item_accessible_text_get_text_before_offset;
4718   iface->get_text_at_offset = gtk_icon_view_item_accessible_text_get_text_at_offset;
4719   iface->get_text_after_offset = gtk_icon_view_item_accessible_text_get_text_after_offset;
4720   iface->get_character_count = gtk_icon_view_item_accessible_text_get_character_count;
4721   iface->get_character_extents = gtk_icon_view_item_accessible_text_get_character_extents;
4722   iface->get_offset_at_point = gtk_icon_view_item_accessible_text_get_offset_at_point;
4723 }
4724
4725 static void
4726 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
4727                                            gint         *x,
4728                                            gint         *y,
4729                                            gint         *width,
4730                                            gint         *height,
4731                                            AtkCoordType  coord_type)
4732 {
4733   GtkIconViewItemAccessible *item;
4734   AtkObject *parent_obj;
4735   gint l_x, l_y;
4736
4737   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
4738
4739   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
4740   if (!GTK_IS_WIDGET (item->widget))
4741     return;
4742
4743   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
4744     return;
4745
4746   *width = item->item->width;
4747   *height = item->item->height;
4748   if (gtk_icon_view_item_accessible_is_showing (item))
4749     {
4750       parent_obj = gtk_widget_get_accessible (item->widget);
4751       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
4752       *x = l_x + item->item->x;
4753       *y = l_y + item->item->y;
4754     }
4755   else
4756     {
4757       *x = G_MININT;
4758       *y = G_MININT;
4759     }
4760 }
4761
4762 static gboolean
4763 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
4764 {
4765   GtkIconViewItemAccessible *item;
4766   GtkWidget *toplevel;
4767
4768   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
4769
4770   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
4771   if (!GTK_IS_WIDGET (item->widget))
4772     return FALSE;
4773
4774   gtk_widget_grab_focus (item->widget);
4775   gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item);
4776   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
4777   if (GTK_WIDGET_TOPLEVEL (toplevel))
4778     gtk_window_present (GTK_WINDOW (toplevel));
4779
4780   return TRUE;
4781 }
4782
4783 static void
4784 atk_component_item_interface_init (AtkComponentIface *iface)
4785 {
4786   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
4787   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
4788 }
4789
4790 static gboolean
4791 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
4792                                          AtkStateType               state_type,
4793                                          gboolean                   emit_signal)
4794 {
4795   gboolean rc;
4796
4797   rc = atk_state_set_add_state (item->state_set, state_type);
4798   /*
4799    * The signal should only be generated if the value changed,
4800    * not when the item is set up.  So states that are set
4801    * initially should pass FALSE as the emit_signal argument.
4802    */
4803
4804   if (emit_signal)
4805     {
4806       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
4807       /* If state_type is ATK_STATE_VISIBLE, additional notification */
4808       if (state_type == ATK_STATE_VISIBLE)
4809         g_signal_emit_by_name (item, "visible_data_changed");
4810     }
4811
4812   return rc;
4813 }
4814
4815 static gboolean
4816 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
4817                                             AtkStateType               state_type,
4818                                             gboolean                   emit_signal)
4819 {
4820   if (atk_state_set_contains_state (item->state_set, state_type))
4821     {
4822       gboolean rc;
4823
4824       rc = atk_state_set_remove_state (item->state_set, state_type);
4825       /*
4826        * The signal should only be generated if the value changed,
4827        * not when the item is set up.  So states that are set
4828        * initially should pass FALSE as the emit_signal argument.
4829        */
4830
4831       if (emit_signal)
4832         {
4833           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
4834           /* If state_type is ATK_STATE_VISIBLE, additional notification */
4835           if (state_type == ATK_STATE_VISIBLE)
4836             g_signal_emit_by_name (item, "visible_data_changed");
4837         }
4838
4839       return rc;
4840     }
4841   else
4842     return FALSE;
4843 }
4844
4845 static gboolean
4846 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
4847 {
4848   GtkIconView *icon_view;
4849   GdkRectangle visible_rect;
4850   gboolean is_showing;
4851
4852   /*
4853    * An item is considered "SHOWING" if any part of the item is in the
4854    * visible rectangle.
4855    */
4856
4857   if (!GTK_IS_ICON_VIEW (item->widget))
4858     return FALSE;
4859
4860   if (item->item == NULL)
4861     return FALSE;
4862
4863   icon_view = GTK_ICON_VIEW (item->widget);
4864   visible_rect.x = 0;
4865   if (icon_view->priv->hadjustment)
4866     visible_rect.x += icon_view->priv->hadjustment->value;
4867   visible_rect.y = 0;
4868   if (icon_view->priv->hadjustment)
4869     visible_rect.y += icon_view->priv->vadjustment->value;
4870   visible_rect.width = item->widget->allocation.width;
4871   visible_rect.height = item->widget->allocation.height;
4872
4873   if (((item->item->x + item->item->width) < visible_rect.x) ||
4874      ((item->item->y + item->item->height) < (visible_rect.y)) ||
4875      (item->item->x > (visible_rect.x + visible_rect.width)) ||
4876      (item->item->y > (visible_rect.y + visible_rect.height)))
4877     is_showing =  FALSE;
4878   else
4879     is_showing = TRUE;
4880
4881   return is_showing;
4882 }
4883
4884 static gboolean
4885 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
4886                                               gboolean                   emit_signal)
4887 {
4888   if (gtk_icon_view_item_accessible_is_showing (item))
4889     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
4890                                                     emit_signal);
4891   else
4892     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
4893                                                        emit_signal);
4894 }
4895
4896 static void
4897 gtk_icon_view_item_accessible_object_init (GtkIconViewItemAccessible *item)
4898 {
4899   gint i;
4900
4901   item->state_set = atk_state_set_new ();
4902
4903   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
4904   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
4905   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
4906   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
4907   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
4908
4909   for (i = 0; i < LAST_ACTION; i++)
4910     item->action_descriptions[i] = NULL;
4911
4912   item->image_description = NULL;
4913
4914   item->action_idle_handler = 0;
4915 }
4916
4917 static void
4918 gtk_icon_view_item_accessible_finalize (GObject *object)
4919 {
4920   GtkIconViewItemAccessible *item;
4921   gint i;
4922
4923   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (object));
4924
4925   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
4926
4927   if (item->widget)
4928     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
4929
4930   if (item->state_set)
4931     g_object_unref (item->state_set);
4932
4933   if (item->text_buffer)
4934      g_object_unref (item->text_buffer);
4935
4936   for (i = 0; i < LAST_ACTION; i++)
4937     g_free (item->action_descriptions[i]);
4938
4939   g_free (item->image_description);
4940
4941   if (item->action_idle_handler)
4942     {
4943       g_source_remove (item->action_idle_handler);
4944       item->action_idle_handler = 0;
4945     }
4946
4947   G_OBJECT_CLASS (accessible_item_parent_class)->finalize (object);
4948 }
4949
4950 static G_CONST_RETURN gchar*
4951 gtk_icon_view_item_accessible_get_name (AtkObject *obj)
4952 {
4953   if (obj->name)
4954     return obj->name;
4955   else
4956     {
4957       GtkIconViewItemAccessible *item;
4958       GtkTextIter start_iter;
4959       GtkTextIter end_iter;
4960
4961       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
4962  
4963       gtk_text_buffer_get_start_iter (item->text_buffer, &start_iter); 
4964       gtk_text_buffer_get_end_iter (item->text_buffer, &end_iter); 
4965
4966       return gtk_text_buffer_get_text (item->text_buffer, &start_iter, &end_iter, FALSE);
4967     }
4968 }
4969
4970 static AtkObject*
4971 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
4972 {
4973   GtkIconViewItemAccessible *item;
4974
4975   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
4976   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
4977
4978   if (item->widget)
4979     return gtk_widget_get_accessible (item->widget);
4980   else
4981     return NULL;
4982 }
4983
4984 static gint
4985 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
4986 {
4987   GtkIconViewItemAccessible *item;
4988
4989   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
4990   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
4991
4992   return item->item->index; 
4993 }
4994
4995 static AtkStateSet *
4996 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
4997 {
4998   GtkIconViewItemAccessible *item;
4999   GtkIconView *icon_view;
5000
5001   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
5002   g_return_val_if_fail (item->state_set, NULL);
5003
5004   if (!item->widget)
5005     return NULL;
5006
5007   icon_view = GTK_ICON_VIEW (item->widget);
5008   if (icon_view->priv->cursor_item == item->item)
5009     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
5010   else
5011     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
5012
5013   return g_object_ref (item->state_set);
5014 }
5015
5016 static void
5017 gtk_icon_view_item_accessible_class_init (AtkObjectClass *klass)
5018 {
5019   GObjectClass *gobject_class;
5020
5021   accessible_item_parent_class = g_type_class_peek_parent (klass);
5022
5023   gobject_class = (GObjectClass *)klass;
5024
5025   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
5026
5027   klass->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent; 
5028   klass->get_name = gtk_icon_view_item_accessible_get_name; 
5029   klass->get_parent = gtk_icon_view_item_accessible_get_parent; 
5030   klass->ref_state_set = gtk_icon_view_item_accessible_ref_state_set; 
5031 }
5032
5033 static GType
5034 gtk_icon_view_item_accessible_get_type (void)
5035 {
5036   static GType type = 0;
5037
5038   if (!type)
5039     {
5040       static const GTypeInfo tinfo =
5041       {
5042         sizeof (GtkIconViewItemAccessibleClass),
5043         (GBaseInitFunc) NULL, /* base init */
5044         (GBaseFinalizeFunc) NULL, /* base finalize */
5045         (GClassInitFunc) gtk_icon_view_item_accessible_class_init, /* class init */
5046         (GClassFinalizeFunc) NULL, /* class finalize */
5047         NULL, /* class data */
5048         sizeof (GtkIconViewItemAccessible), /* instance size */
5049         0, /* nb preallocs */
5050         (GInstanceInitFunc) gtk_icon_view_item_accessible_object_init, /* instance init */
5051         NULL /* value table */
5052       };
5053
5054       static const GInterfaceInfo atk_component_info =
5055       {
5056         (GInterfaceInitFunc) atk_component_item_interface_init,
5057         (GInterfaceFinalizeFunc) NULL,
5058         NULL
5059       };
5060       static const GInterfaceInfo atk_action_info =
5061       {
5062         (GInterfaceInitFunc) atk_action_item_interface_init,
5063         (GInterfaceFinalizeFunc) NULL,
5064         NULL
5065       };
5066       static const GInterfaceInfo atk_image_info =
5067       {
5068         (GInterfaceInitFunc) atk_image_item_interface_init,
5069         (GInterfaceFinalizeFunc) NULL,
5070         NULL
5071       };
5072       static const GInterfaceInfo atk_text_info =
5073       {
5074         (GInterfaceInitFunc) atk_text_item_interface_init,
5075         (GInterfaceFinalizeFunc) NULL,
5076         NULL
5077       };
5078
5079       type = g_type_register_static (ATK_TYPE_OBJECT,
5080                                      "GtkIconViewItemAccessible", &tinfo, 0);
5081       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
5082                                    &atk_component_info);
5083       g_type_add_interface_static (type, ATK_TYPE_ACTION,
5084                                    &atk_action_info);
5085       g_type_add_interface_static (type, ATK_TYPE_IMAGE,
5086                                    &atk_image_info);
5087       g_type_add_interface_static (type, ATK_TYPE_TEXT,
5088                                    &atk_text_info);
5089     }
5090
5091   return type;
5092 }
5093
5094 #define GTK_TYPE_ICON_VIEW_ACCESSIBLE      (gtk_icon_view_accessible_get_type ())
5095 #define GTK_ICON_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE, GtkIconViewAccessible))
5096 #define GTK_IS_ICON_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ACCESSIBLE))
5097
5098 static GType gtk_icon_view_accessible_get_type (void);
5099
5100 typedef struct
5101 {
5102    AtkObject parent;
5103 } GtkIconViewAccessible;
5104
5105 typedef struct
5106 {
5107   AtkObject *item;
5108   gint       index;
5109 } GtkIconViewItemAccessibleInfo;
5110
5111 typedef struct
5112 {
5113   GList *items;
5114
5115   GtkAdjustment *old_hadj;
5116   GtkAdjustment *old_vadj;
5117
5118   GtkTreeModel *model;
5119
5120 } GtkIconViewAccessiblePrivate;
5121
5122 static GtkIconViewAccessiblePrivate *
5123 gtk_icon_view_accessible_get_priv (AtkObject *accessible)
5124 {
5125   return g_object_get_qdata (G_OBJECT (accessible),
5126                              accessible_private_data_quark);
5127 }
5128
5129 static void
5130 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
5131                                         AtkObject *item,
5132                                         gint       index)
5133 {
5134   GtkIconViewItemAccessibleInfo *info;
5135   GtkIconViewItemAccessibleInfo *tmp_info;
5136   GtkIconViewAccessiblePrivate *priv;
5137   GList *items;
5138
5139   info = g_new (GtkIconViewItemAccessibleInfo, 1);
5140   info->item = item;
5141   info->index = index;
5142
5143   priv = gtk_icon_view_accessible_get_priv (accessible);
5144   items = priv->items;
5145   while (items)
5146     {
5147       tmp_info = items->data;
5148       if (tmp_info->index > index)
5149         break;
5150       items = items->next;
5151     }
5152   priv->items = g_list_insert_before (priv->items, items, info);
5153   priv->old_hadj = NULL;
5154   priv->old_vadj = NULL;
5155 }
5156
5157 static gint
5158 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
5159 {
5160   GtkIconView *icon_view;
5161   GtkWidget *widget;
5162
5163   widget = GTK_ACCESSIBLE (accessible)->widget;
5164   if (!widget)
5165       return 0;
5166
5167   icon_view = GTK_ICON_VIEW (widget);
5168
5169   return g_list_length (icon_view->priv->items);
5170 }
5171
5172 static AtkObject *
5173 gtk_icon_view_accessible_find_child (AtkObject *accessible,
5174                                      gint       index)
5175 {
5176   GtkIconViewAccessiblePrivate *priv;
5177   GtkIconViewItemAccessibleInfo *info;
5178   GList *items;
5179
5180   priv = gtk_icon_view_accessible_get_priv (accessible);
5181   items = priv->items;
5182
5183   while (items)
5184     {
5185       info = items->data;
5186       if (info->index == index)
5187         return info->item;
5188       items = items->next; 
5189     }
5190   return NULL;
5191 }
5192
5193 static AtkObject *
5194 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
5195                                     gint       index)
5196 {
5197   GtkIconView *icon_view;
5198   GtkWidget *widget;
5199   GList *icons;
5200   AtkObject *obj;
5201   GtkIconViewItemAccessible *a11y_item;
5202
5203   widget = GTK_ACCESSIBLE (accessible)->widget;
5204   if (!widget)
5205     return NULL;
5206
5207   icon_view = GTK_ICON_VIEW (widget);
5208   icons = g_list_nth (icon_view->priv->items, index);
5209   obj = NULL;
5210   if (icons)
5211     {
5212       GtkIconViewItem *item = icons->data;
5213    
5214       g_return_val_if_fail (item->index == index, NULL);
5215       obj = gtk_icon_view_accessible_find_child (accessible, index);
5216       if (!obj)
5217         {
5218           obj = g_object_new (gtk_icon_view_item_accessible_get_type (), NULL);
5219           gtk_icon_view_item_accessible_info_new (accessible,
5220                                                   obj,
5221                                                   index);
5222           obj->role = ATK_ROLE_ICON;
5223           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
5224           a11y_item->item = item;
5225           a11y_item->widget = widget;
5226           a11y_item->text_buffer = gtk_text_buffer_new (NULL);
5227           gtk_icon_view_update_item_text (icon_view, item);
5228           gtk_text_buffer_set_text (a11y_item->text_buffer, 
5229                                     pango_layout_get_text (icon_view->priv->layout), 
5230                                     -1);
5231           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
5232           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
5233        }
5234       g_object_ref (obj);
5235     }
5236   return obj;
5237 }
5238
5239 static void
5240 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
5241                                          GList                 *list)
5242 {
5243   GtkIconViewAccessiblePrivate *priv;
5244   GtkIconViewItemAccessibleInfo *info;
5245   GtkIconViewItemAccessible *item;
5246   GList *items;
5247   
5248   priv =  gtk_icon_view_accessible_get_priv (ATK_OBJECT (view));
5249   if (priv->items)
5250     {
5251       GtkWidget *widget;
5252       gboolean act_on_item;
5253
5254       widget = GTK_ACCESSIBLE (view)->widget;
5255       if (widget == NULL)
5256         return;
5257
5258       items = priv->items;
5259
5260       act_on_item = (list == NULL);
5261
5262       while (items)
5263         {
5264
5265           info = (GtkIconViewItemAccessibleInfo *)items->data;
5266           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5267
5268           if (act_on_item == FALSE && list == items)
5269             act_on_item = TRUE;
5270
5271           if (act_on_item)
5272             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
5273
5274           items = items->next;
5275        }
5276    }
5277 }
5278
5279 static void
5280 gtk_icon_view_accessible_adjustment_changed (GtkAdjustment *adjustment,
5281                                              GtkIconView   *icon_view)
5282 {
5283   AtkObject *obj;
5284   GtkIconViewAccessible *view;
5285
5286   /*
5287    * The scrollbars have changed
5288    */
5289   obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
5290   view = GTK_ICON_VIEW_ACCESSIBLE (obj);
5291
5292   gtk_icon_view_accessible_traverse_items (view, NULL);
5293 }
5294
5295 static void
5296 gtk_icon_view_accessible_set_scroll_adjustments (GtkWidget      *widget,
5297                                                  GtkAdjustment *hadj,
5298                                                  GtkAdjustment *vadj)
5299 {
5300   AtkObject *atk_obj;
5301   GtkIconViewAccessiblePrivate *priv;
5302
5303   atk_obj = gtk_widget_get_accessible (widget);
5304   priv = gtk_icon_view_accessible_get_priv (atk_obj);
5305
5306   if (priv->old_hadj != hadj)
5307     {
5308       if (priv->old_hadj)
5309         {
5310           g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
5311                                         (gpointer *)&priv->old_hadj);
5312           
5313           g_signal_handlers_disconnect_by_func (priv->old_hadj,
5314                                                 (gpointer) gtk_icon_view_accessible_adjustment_changed,
5315                                                 widget);
5316         }
5317       priv->old_hadj = hadj;
5318       if (priv->old_hadj)
5319         {
5320           g_object_add_weak_pointer (G_OBJECT (priv->old_hadj),
5321                                      (gpointer *)&priv->old_hadj);
5322           g_signal_connect (hadj,
5323                             "value-changed",
5324                             G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5325                             widget);
5326         }
5327     }
5328   if (priv->old_vadj != vadj)
5329     {
5330       if (priv->old_vadj)
5331         {
5332           g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
5333                                         (gpointer *)&priv->old_vadj);
5334           
5335           g_signal_handlers_disconnect_by_func (priv->old_vadj,
5336                                                 (gpointer) gtk_icon_view_accessible_adjustment_changed,
5337                                                 widget);
5338         }
5339       priv->old_vadj = vadj;
5340       if (priv->old_vadj)
5341         {
5342           g_object_add_weak_pointer (G_OBJECT (priv->old_vadj),
5343                                      (gpointer *)&priv->old_vadj);
5344           g_signal_connect (vadj,
5345                             "value-changed",
5346                             G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5347                             widget);
5348         }
5349     }
5350 }
5351
5352 static void
5353 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
5354                                             GtkTreePath  *path,
5355                                             GtkTreeIter  *iter,
5356                                             gpointer     user_data)
5357 {
5358   AtkObject *atk_obj;
5359
5360   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5361   g_signal_emit_by_name (atk_obj, "visible-data-changed");
5362
5363   return;
5364 }
5365
5366 static void
5367 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
5368                                              GtkTreePath  *path,
5369                                              GtkTreeIter  *iter,
5370                                              gpointer     user_data)
5371 {
5372   GtkIconViewAccessiblePrivate *priv;
5373   GtkIconViewItemAccessibleInfo *info;
5374   GtkIconViewAccessible *view;
5375   GtkIconViewItemAccessible *item;
5376   GList *items;
5377   GList *tmp_list;
5378   AtkObject *atk_obj;
5379   gint index;
5380
5381   index = gtk_tree_path_get_indices(path)[0];
5382   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5383   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5384   priv = gtk_icon_view_accessible_get_priv (atk_obj);
5385
5386   items = priv->items;
5387   tmp_list = NULL;
5388   while (items)
5389     {
5390       info = items->data;
5391       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5392       if (info->index != item->item->index)
5393         {
5394           if (info->index < index)
5395             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
5396  
5397           if (tmp_list == NULL)
5398             tmp_list = items;
5399    
5400           info->index = item->item->index;
5401         }
5402
5403       items = items->next;
5404     }
5405   gtk_icon_view_accessible_traverse_items (view, tmp_list);
5406   g_signal_emit_by_name (atk_obj, "children_changed::add",
5407                          index, NULL, NULL);
5408   return;
5409 }
5410
5411 static void
5412 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
5413                                             GtkTreePath  *path,
5414                                             gpointer     user_data)
5415 {
5416   GtkIconViewAccessiblePrivate *priv;
5417   GtkIconViewItemAccessibleInfo *info;
5418   GtkIconViewAccessible *view;
5419   GtkIconViewItemAccessible *item;
5420   GList *items;
5421   GList *tmp_list;
5422   GList *deleted_item;
5423   AtkObject *atk_obj;
5424   gint index;
5425
5426   index = gtk_tree_path_get_indices(path)[0];
5427   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5428   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5429   priv = gtk_icon_view_accessible_get_priv (atk_obj);
5430
5431   items = priv->items;
5432   tmp_list = NULL;
5433   deleted_item = NULL;
5434   info = NULL;
5435   while (items)
5436     {
5437       info = items->data;
5438       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5439       if (info->index == index)
5440         {
5441           deleted_item = items;
5442         }
5443       if (info->index != item->item->index)
5444         {
5445           if (tmp_list == NULL)
5446             tmp_list = items;
5447           else    
5448             info->index = item->item->index;
5449         }
5450
5451       items = items->next;
5452     }
5453   gtk_icon_view_accessible_traverse_items (view, tmp_list);
5454   if (deleted_item)
5455     {
5456       info = deleted_item->data;
5457       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
5458     }
5459   g_signal_emit_by_name (atk_obj, "children_changed::remove",
5460                          index, NULL, NULL);
5461   if (deleted_item)
5462     {
5463       priv->items = g_list_remove_link (priv->items, deleted_item);
5464       g_free (info);
5465     }
5466
5467   return;
5468 }
5469
5470 static gint
5471 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
5472                                        GtkIconViewItemAccessibleInfo *i2)
5473 {
5474   return i1->index - i2->index;
5475 }
5476
5477 static void
5478 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
5479                                                GtkTreePath  *path,
5480                                                GtkTreeIter  *iter,
5481                                                gint         *new_order,
5482                                                gpointer     user_data)
5483 {
5484   GtkIconViewAccessiblePrivate *priv;
5485   GtkIconViewItemAccessibleInfo *info;
5486   GtkIconViewAccessible *view;
5487   GtkIconView *icon_view;
5488   GtkIconViewItemAccessible *item;
5489   GList *items;
5490   GList *tmp_list;
5491   AtkObject *atk_obj;
5492
5493   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
5494   icon_view = GTK_ICON_VIEW (user_data);
5495   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5496   priv = gtk_icon_view_accessible_get_priv (atk_obj);
5497
5498   items = priv->items;
5499   tmp_list = NULL;
5500   while (items)
5501     {
5502       info = items->data;
5503       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
5504       info->index = new_order[info->index];
5505       tmp_list = g_list_nth (icon_view->priv->items, info->index);
5506       item->item = tmp_list->data;
5507       items = items->next;
5508     }
5509   priv->items = g_list_sort (priv->items, 
5510                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
5511
5512   return;
5513 }
5514
5515 static void
5516 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
5517                                                    GtkWidget *widget)
5518 {
5519   GObject *obj;
5520
5521   obj = G_OBJECT (model);
5522   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
5523   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
5524   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
5525   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
5526 }
5527
5528 static void
5529 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
5530 {
5531   GObject *obj;
5532
5533   obj = G_OBJECT (icon_view->priv->model);
5534   g_signal_connect_data (obj, "row-changed",
5535                          (GCallback) gtk_icon_view_accessible_model_row_changed,
5536                          icon_view, NULL, 0);
5537   g_signal_connect_data (obj, "row-inserted",
5538                          (GCallback) gtk_icon_view_accessible_model_row_inserted, 
5539                          icon_view, NULL, G_CONNECT_AFTER);
5540   g_signal_connect_data (obj, "row-deleted",
5541                          (GCallback) gtk_icon_view_accessible_model_row_deleted, 
5542                          icon_view, NULL, G_CONNECT_AFTER);
5543   g_signal_connect_data (obj, "rows-reordered",
5544                          (GCallback) gtk_icon_view_accessible_model_rows_reordered, 
5545                          icon_view, NULL, G_CONNECT_AFTER);
5546 }
5547
5548 static void
5549 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessiblePrivate *priv)
5550 {
5551   GtkIconViewItemAccessibleInfo *info;
5552   GList *items;
5553
5554   items = priv->items;
5555   while (items)
5556     {
5557       info = (GtkIconViewItemAccessibleInfo *) items->data;
5558       g_object_unref (info->item);
5559       g_free (items->data);
5560       items = items->next;
5561     }
5562   g_list_free (priv->items);
5563   priv->items = NULL;
5564 }
5565
5566 static void
5567 gtk_icon_view_accessible_notify_gtk (GObject *obj,
5568                                      GParamSpec *pspec)
5569 {
5570   GtkIconView *icon_view;
5571   GtkWidget *widget;
5572   AtkObject *atk_obj;
5573   GtkIconViewAccessible *view;
5574   GtkIconViewAccessiblePrivate *priv;
5575
5576   if (strcmp (pspec->name, "model") == 0)
5577     {
5578       widget = GTK_WIDGET (obj); 
5579       atk_obj = gtk_widget_get_accessible (widget);
5580       view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
5581       priv = gtk_icon_view_accessible_get_priv (atk_obj);
5582       if (priv->model)
5583         {
5584           g_object_remove_weak_pointer (G_OBJECT (priv->model),
5585                                         (gpointer *)&priv->model);
5586           gtk_icon_view_accessible_disconnect_model_signals (priv->model, widget);
5587         }
5588       gtk_icon_view_accessible_clear_cache (priv);
5589
5590       icon_view = GTK_ICON_VIEW (obj);
5591       priv->model = icon_view->priv->model;
5592       /* If there is no model the GtkIconView is probably being destroyed */
5593       if (priv->model)
5594         {
5595           g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
5596           gtk_icon_view_accessible_connect_model_signals (icon_view);
5597         }
5598     }
5599
5600   return;
5601 }
5602
5603 static void
5604 gtk_icon_view_accessible_initialize (AtkObject *accessible,
5605                                      gpointer   data)
5606 {
5607   GtkIconViewAccessiblePrivate *priv;
5608   GtkIconView *icon_view;
5609
5610   if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize)
5611     ATK_OBJECT_CLASS (accessible_parent_class)->initialize (accessible, data);
5612
5613   priv = g_new0 (GtkIconViewAccessiblePrivate, 1);
5614   g_object_set_qdata (G_OBJECT (accessible),
5615                       accessible_private_data_quark,
5616                       priv);
5617
5618   icon_view = GTK_ICON_VIEW (data);
5619   if (icon_view->priv->hadjustment)
5620     {
5621       priv->old_hadj = icon_view->priv->hadjustment;
5622       g_object_add_weak_pointer (G_OBJECT (priv->old_hadj), (gpointer *)&priv->old_hadj);
5623       g_signal_connect (icon_view->priv->hadjustment,
5624                         "value-changed",
5625                         G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5626                         icon_view);
5627     } 
5628   if (icon_view->priv->vadjustment)
5629     {
5630       priv->old_vadj = icon_view->priv->vadjustment;
5631       g_object_add_weak_pointer (G_OBJECT (priv->old_vadj), (gpointer *)&priv->old_vadj);
5632       g_signal_connect (icon_view->priv->vadjustment,
5633                         "value-changed",
5634                         G_CALLBACK (gtk_icon_view_accessible_adjustment_changed),
5635                         icon_view);
5636     }
5637   g_signal_connect_after (data,
5638                           "set_scroll_adjustments",
5639                           G_CALLBACK (gtk_icon_view_accessible_set_scroll_adjustments),
5640                           NULL);
5641   g_signal_connect (data,
5642                     "notify",
5643                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk),
5644                     NULL);
5645
5646   priv->model = icon_view->priv->model;
5647   if (priv->model)
5648     {
5649       g_object_add_weak_pointer (G_OBJECT (priv->model), (gpointer *)&priv->model);
5650       gtk_icon_view_accessible_connect_model_signals (icon_view);
5651     }
5652                           
5653   accessible->role = ATK_ROLE_LAYERED_PANE;
5654 }
5655
5656 static void
5657 gtk_icon_view_accessible_finalize (GObject *object)
5658 {
5659   GtkIconViewAccessiblePrivate *priv;
5660
5661   priv = gtk_icon_view_accessible_get_priv (ATK_OBJECT (object));
5662   gtk_icon_view_accessible_clear_cache (priv);
5663
5664   g_free (priv);
5665
5666   G_OBJECT_CLASS (accessible_parent_class)->finalize (object);
5667 }
5668
5669 static void
5670 gtk_icon_view_accessible_destroyed (GtkWidget *widget,
5671                                     GtkAccessible *accessible)
5672 {
5673   AtkObject *atk_obj;
5674   GtkIconViewAccessiblePrivate *priv;
5675
5676   atk_obj = ATK_OBJECT (accessible);
5677   priv = gtk_icon_view_accessible_get_priv (atk_obj);
5678   if (priv->old_hadj)
5679     {
5680       g_object_remove_weak_pointer (G_OBJECT (priv->old_hadj),
5681                                     (gpointer *)&priv->old_hadj);
5682           
5683       g_signal_handlers_disconnect_by_func (priv->old_hadj,
5684                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
5685                                             widget);
5686       priv->old_hadj = NULL;
5687     }
5688   if (priv->old_vadj)
5689     {
5690       g_object_remove_weak_pointer (G_OBJECT (priv->old_vadj),
5691                                     (gpointer *)&priv->old_vadj);
5692           
5693       g_signal_handlers_disconnect_by_func (priv->old_vadj,
5694                                             (gpointer) gtk_icon_view_accessible_adjustment_changed,
5695                                             widget);
5696       priv->old_vadj = NULL;
5697     }
5698 }
5699
5700 static void
5701 gtk_icon_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
5702 {
5703   if (accessible->widget)
5704     {
5705       g_signal_connect_after (accessible->widget,
5706                               "destroy",
5707                               G_CALLBACK (gtk_icon_view_accessible_destroyed),
5708                               accessible);
5709     }
5710   GTK_ACCESSIBLE_CLASS (accessible_parent_class)->connect_widget_destroyed (accessible);
5711 }
5712
5713 static void
5714 gtk_icon_view_accessible_class_init (AtkObjectClass *klass)
5715 {
5716   GObjectClass *gobject_class;
5717   GtkAccessibleClass *accessible_class;
5718
5719   accessible_parent_class = g_type_class_peek_parent (klass);
5720
5721   gobject_class = (GObjectClass *)klass;
5722   accessible_class = (GtkAccessibleClass *)klass;
5723
5724   gobject_class->finalize = gtk_icon_view_accessible_finalize;
5725
5726   klass->get_n_children = gtk_icon_view_accessible_get_n_children;
5727   klass->ref_child = gtk_icon_view_accessible_ref_child;
5728   klass->initialize = gtk_icon_view_accessible_initialize;
5729
5730   accessible_class->connect_widget_destroyed = gtk_icon_view_accessible_connect_widget_destroyed;
5731
5732   accessible_private_data_quark = g_quark_from_static_string ("icon_view-accessible-private-data");
5733 }
5734
5735 static AtkObject*
5736 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
5737                                                   gint          x,
5738                                                   gint          y,
5739                                                   AtkCoordType  coord_type)
5740 {
5741   GtkWidget *widget;
5742   GtkIconView *icon_view;
5743   GtkIconViewItem *item;
5744   gint x_pos, y_pos;
5745
5746   widget = GTK_ACCESSIBLE (component)->widget;
5747   if (widget == NULL)
5748   /* State is defunct */
5749     return NULL;
5750
5751   icon_view = GTK_ICON_VIEW (widget);
5752   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
5753   item = gtk_icon_view_get_item_at_pos (icon_view, x - x_pos, y - y_pos);
5754   if (item)
5755     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
5756
5757   return NULL;
5758 }
5759
5760 static void
5761 atk_component_interface_init (AtkComponentIface *iface)
5762 {
5763   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
5764 }
5765
5766 static gboolean
5767 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
5768                                         gint i)
5769 {
5770   GtkWidget *widget;
5771   GtkIconView *icon_view;
5772   GtkIconViewItem *item;
5773   GList *l;
5774
5775   widget = GTK_ACCESSIBLE (selection)->widget;
5776   if (widget == NULL)
5777     return FALSE;
5778
5779   icon_view = GTK_ICON_VIEW (widget);
5780
5781   l = g_list_nth (icon_view->priv->items, i);
5782   if (!l)
5783     return FALSE;
5784
5785   item = l->data;
5786   gtk_icon_view_select_item (icon_view, item);
5787
5788   return TRUE;
5789 }
5790
5791 static gboolean
5792 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
5793 {
5794   GtkWidget *widget;
5795   GtkIconView *icon_view;
5796
5797   widget = GTK_ACCESSIBLE (selection)->widget;
5798   if (widget == NULL)
5799     return FALSE;
5800
5801   icon_view = GTK_ICON_VIEW (widget);
5802   gtk_icon_view_unselect_all (icon_view);
5803
5804   return TRUE;
5805 }
5806
5807 static AtkObject*
5808 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
5809                                         gint          i)
5810 {
5811   GtkWidget *widget;
5812   GtkIconView *icon_view;
5813   GtkIconViewItem *item;
5814   GList *l;
5815
5816   widget = GTK_ACCESSIBLE (selection)->widget;
5817   if (widget == NULL)
5818     return NULL;
5819
5820   icon_view = GTK_ICON_VIEW (widget);
5821
5822   l = icon_view->priv->items;
5823   while (l)
5824     {
5825       item = l->data;
5826       if (item->selected)
5827         {
5828           if (i == 0)
5829             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
5830           else
5831             i--;
5832         }
5833       l = l->next;
5834     }
5835
5836   return NULL;
5837 }
5838
5839 static gint
5840 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
5841 {
5842   GtkWidget *widget;
5843   GtkIconView *icon_view;
5844   GtkIconViewItem *item;
5845   GList *l;
5846   gint count;
5847
5848   widget = GTK_ACCESSIBLE (selection)->widget;
5849   if (widget == NULL)
5850     return 0;
5851
5852   icon_view = GTK_ICON_VIEW (widget);
5853
5854   l = icon_view->priv->items;
5855   count = 0;
5856   while (l)
5857     {
5858       item = l->data;
5859
5860       if (item->selected)
5861         count++;
5862
5863       l = l->next;
5864     }
5865
5866   return count;
5867 }
5868
5869 static gboolean
5870 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
5871                                             gint          i)
5872 {
5873   GtkWidget *widget;
5874   GtkIconView *icon_view;
5875   GtkIconViewItem *item;
5876   GList *l;
5877
5878   widget = GTK_ACCESSIBLE (selection)->widget;
5879   if (widget == NULL)
5880     return FALSE;
5881
5882   icon_view = GTK_ICON_VIEW (widget);
5883   l = g_list_nth (icon_view->priv->items, i);
5884   if (!l)
5885     return FALSE;
5886
5887   item = l->data;
5888
5889   return item->selected;
5890 }
5891
5892 static gboolean
5893 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
5894                                            gint          i)
5895 {
5896   GtkWidget *widget;
5897   GtkIconView *icon_view;
5898   GtkIconViewItem *item;
5899   GList *l;
5900   gint count;
5901
5902   widget = GTK_ACCESSIBLE (selection)->widget;
5903   if (widget == NULL)
5904     return FALSE;
5905
5906   icon_view = GTK_ICON_VIEW (widget);
5907   l = icon_view->priv->items;
5908   count = 0;
5909   while (l)
5910     {
5911       item = l->data;
5912       if (item->selected)
5913         {
5914           if (count == i)
5915             {
5916               gtk_icon_view_unselect_item (icon_view, item);
5917               return TRUE;
5918             }
5919           count++;
5920         }
5921       l = l->next;
5922     }
5923
5924   return FALSE;
5925 }
5926  
5927 static gboolean
5928 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
5929 {
5930   GtkWidget *widget;
5931   GtkIconView *icon_view;
5932
5933   widget = GTK_ACCESSIBLE (selection)->widget;
5934   if (widget == NULL)
5935     return FALSE;
5936
5937   icon_view = GTK_ICON_VIEW (widget);
5938   gtk_icon_view_select_all (icon_view);
5939   return TRUE;
5940 }
5941
5942 static void
5943 gtk_icon_view_accessible_selection_interface_init (AtkSelectionIface *iface)
5944 {
5945   iface->add_selection = gtk_icon_view_accessible_add_selection;
5946   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
5947   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
5948   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
5949   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
5950   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
5951   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
5952 }
5953
5954 static GType
5955 gtk_icon_view_accessible_get_type (void)
5956 {
5957   static GType type = 0;
5958
5959   if (!type)
5960     {
5961       static GTypeInfo tinfo =
5962       {
5963         0, /* class size */
5964         (GBaseInitFunc) NULL, /* base init */
5965         (GBaseFinalizeFunc) NULL, /* base finalize */
5966         (GClassInitFunc) gtk_icon_view_accessible_class_init,
5967         (GClassFinalizeFunc) NULL, /* class finalize */
5968         NULL, /* class data */
5969         0, /* instance size */
5970         0, /* nb preallocs */
5971         (GInstanceInitFunc) NULL, /* instance init */
5972         NULL /* value table */
5973       };
5974       static const GInterfaceInfo atk_component_info =
5975       {
5976         (GInterfaceInitFunc) atk_component_interface_init,
5977         (GInterfaceFinalizeFunc) NULL,
5978         NULL
5979       };
5980       static const GInterfaceInfo atk_selection_info = 
5981       {
5982         (GInterfaceInitFunc) gtk_icon_view_accessible_selection_interface_init,
5983         (GInterfaceFinalizeFunc) NULL,
5984         NULL
5985       };
5986
5987       /*
5988        * Figure out the size of the class and instance
5989        * we are deriving from
5990        */
5991       AtkObjectFactory *factory;
5992       GType derived_type;
5993       GTypeQuery query;
5994       GType derived_atk_type;
5995
5996       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
5997       factory = atk_registry_get_factory (atk_get_default_registry (), 
5998                                           derived_type);
5999       derived_atk_type = atk_object_factory_get_accessible_type (factory);
6000       g_type_query (derived_atk_type, &query);
6001       tinfo.class_size = query.class_size;
6002       tinfo.instance_size = query.instance_size;
6003  
6004       type = g_type_register_static (derived_atk_type, 
6005                                      "GtkIconViewAccessible", 
6006                                      &tinfo, 0);
6007       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
6008                                    &atk_component_info);
6009       g_type_add_interface_static (type, ATK_TYPE_SELECTION,
6010                                    &atk_selection_info);
6011     }
6012   return type;
6013 }
6014
6015 static AtkObject *
6016 gtk_icon_view_accessible_new (GObject *obj)
6017 {
6018   AtkObject *accessible;
6019
6020   g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
6021
6022   accessible = g_object_new (gtk_icon_view_accessible_get_type (), NULL);
6023   atk_object_initialize (accessible, obj);
6024
6025   return accessible;
6026 }
6027
6028 static GType
6029 gtk_icon_view_accessible_factory_get_accessible_type (void)
6030 {
6031   return gtk_icon_view_accessible_get_type ();
6032 }
6033
6034 static AtkObject*
6035 gtk_icon_view_accessible_factory_create_accessible (GObject *obj)
6036 {
6037   return gtk_icon_view_accessible_new (obj);
6038 }
6039
6040 static void
6041 gtk_icon_view_accessible_factory_class_init (AtkObjectFactoryClass *klass)
6042 {
6043   klass->create_accessible = gtk_icon_view_accessible_factory_create_accessible;
6044   klass->get_accessible_type = gtk_icon_view_accessible_factory_get_accessible_type;
6045 }
6046
6047 static GType
6048 gtk_icon_view_accessible_factory_get_type (void)
6049 {
6050   static GType type = 0;
6051
6052   if (!type)
6053     {
6054       static const GTypeInfo tinfo =
6055       {
6056         sizeof (AtkObjectFactoryClass),
6057         NULL,           /* base_init */
6058         NULL,           /* base_finalize */
6059         (GClassInitFunc) gtk_icon_view_accessible_factory_class_init,
6060         NULL,           /* class_finalize */
6061         NULL,           /* class_data */
6062         sizeof (AtkObjectFactory),
6063         0,             /* n_preallocs */
6064         NULL, NULL
6065       };
6066
6067       type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, 
6068                                     "GtkIconViewAccessibleFactory",
6069                                     &tinfo, 0);
6070     }
6071   return type;
6072 }
6073
6074 static AtkObject *
6075 gtk_icon_view_get_accessible (GtkWidget *widget)
6076 {
6077   static gboolean first_time = TRUE;
6078
6079   if (first_time)
6080     {
6081       AtkObjectFactory *factory;
6082       AtkRegistry *registry;
6083       GType derived_type; 
6084       GType derived_atk_type; 
6085
6086       /*
6087        * Figure out whether accessibility is enabled by looking at the
6088        * type of the accessible object which would be created for
6089        * the parent type of GtkIconView.
6090        */
6091       derived_type = g_type_parent (GTK_TYPE_ICON_VIEW);
6092
6093       registry = atk_get_default_registry ();
6094       factory = atk_registry_get_factory (registry,
6095                                           derived_type);
6096       derived_atk_type = atk_object_factory_get_accessible_type (factory);
6097       if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
6098         atk_registry_set_factory_type (registry, 
6099                                        GTK_TYPE_ICON_VIEW,
6100                                        gtk_icon_view_accessible_factory_get_type ());
6101       first_time = FALSE;
6102     } 
6103   return GTK_WIDGET_CLASS (parent_class)->get_accessible (widget);
6104 }
6105