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