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