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