]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkiconviewaccessible.c
40333b7b8c3317c85c0259b0711718582ec4b8cd
[~andy/gtk] / gtk / a11y / gtkiconviewaccessible.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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19
20 #include "gtkiconviewaccessible.h"
21
22 #include <string.h>
23
24 #include "gtk/gtkadjustment.h"
25 #include "gtk/gtkiconviewprivate.h"
26 #include "gtk/gtkcellrendererpixbuf.h"
27 #include "gtk/gtkcellrenderertext.h"
28 #include "gtk/gtkpango.h"
29 #include "gtk/gtkwidgetprivate.h"
30
31 #define GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE      (_gtk_icon_view_item_accessible_get_type ())
32 #define GTK_ICON_VIEW_ITEM_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, GtkIconViewItemAccessible))
33 #define GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE))
34
35 typedef struct
36 {
37   AtkObject parent;
38
39   GtkIconViewItem *item;
40   GtkWidget *widget;
41   AtkStateSet *state_set;
42   gchar *text;
43   gchar *action_description;
44   gchar *image_description;
45   guint action_idle_handler;
46 } GtkIconViewItemAccessible;
47
48 typedef struct
49 {
50   AtkObjectClass parent_class;
51
52 } GtkIconViewItemAccessibleClass;
53
54 static gboolean gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item);
55
56 static void atk_component_item_interface_init (AtkComponentIface *iface);
57 static void atk_action_item_interface_init    (AtkActionIface    *iface);
58 static void atk_text_item_interface_init      (AtkTextIface      *iface);
59 static void atk_image_item_interface_init     (AtkImageIface     *iface);
60
61 G_DEFINE_TYPE_WITH_CODE (GtkIconViewItemAccessible, _gtk_icon_view_item_accessible, ATK_TYPE_OBJECT,
62                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_item_interface_init)
63                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_item_interface_init)
64                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_item_interface_init)
65                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE, atk_image_item_interface_init))
66
67
68 static gboolean
69 idle_do_action (gpointer data)
70 {
71   GtkIconViewItemAccessible *item;
72   GtkIconView *icon_view;
73   GtkTreePath *path;
74
75   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (data);
76   item->action_idle_handler = 0;
77
78   if (item->widget != NULL)
79     {
80       icon_view = GTK_ICON_VIEW (item->widget);
81       path = gtk_tree_path_new_from_indices (item->item->index, -1);
82       gtk_icon_view_item_activated (icon_view, path);
83       gtk_tree_path_free (path);
84     }
85
86   return FALSE;
87 }
88
89 static gboolean
90 gtk_icon_view_item_accessible_do_action (AtkAction *action,
91                                          gint       i)
92 {
93   GtkIconViewItemAccessible *item;
94
95   if (i != 0)
96     return FALSE;
97
98   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
99
100   if (!GTK_IS_ICON_VIEW (item->widget))
101     return FALSE;
102
103   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
104     return FALSE;
105
106   if (!item->action_idle_handler)
107     item->action_idle_handler = gdk_threads_add_idle (idle_do_action, item);
108
109   return TRUE;
110 }
111
112 static gint
113 gtk_icon_view_item_accessible_get_n_actions (AtkAction *action)
114 {
115         return 1;
116 }
117
118 static const gchar *
119 gtk_icon_view_item_accessible_get_description (AtkAction *action,
120                                                gint       i)
121 {
122   GtkIconViewItemAccessible *item;
123
124   if (i != 0)
125     return NULL;
126
127   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
128
129   if (item->action_description)
130     return item->action_description;
131   else
132     return "Activate item";
133 }
134
135 static const gchar *
136 gtk_icon_view_item_accessible_get_name (AtkAction *action,
137                                         gint       i)
138 {
139   if (i != 0)
140     return NULL;
141
142   return "activate";
143 }
144
145 static gboolean
146 gtk_icon_view_item_accessible_set_description (AtkAction   *action,
147                                                gint         i,
148                                                const gchar *description)
149 {
150   GtkIconViewItemAccessible *item;
151
152   if (i != 0)
153     return FALSE;
154
155   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (action);
156
157   g_free (item->action_description);
158   item->action_description = g_strdup (description);
159
160   return TRUE;
161 }
162
163 static void
164 atk_action_item_interface_init (AtkActionIface *iface)
165 {
166   iface->do_action = gtk_icon_view_item_accessible_do_action;
167   iface->set_description = gtk_icon_view_item_accessible_set_description;
168   iface->get_name = gtk_icon_view_item_accessible_get_name;
169   iface->get_n_actions = gtk_icon_view_item_accessible_get_n_actions;
170   iface->get_description = gtk_icon_view_item_accessible_get_description;
171 }
172
173 static const gchar *
174 gtk_icon_view_item_accessible_get_image_description (AtkImage *image)
175 {
176   GtkIconViewItemAccessible *item;
177
178   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
179
180   return item->image_description;
181 }
182
183 static gboolean
184 gtk_icon_view_item_accessible_set_image_description (AtkImage    *image,
185                                                      const gchar *description)
186 {
187   GtkIconViewItemAccessible *item;
188
189   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
190
191   g_free (item->image_description);
192   item->image_description = g_strdup (description);
193
194   return TRUE;
195 }
196
197 typedef struct {
198   GdkRectangle box;
199   gboolean     pixbuf_found;
200 } GetPixbufBoxData;
201
202 static gboolean
203 get_pixbuf_foreach (GtkCellRenderer    *renderer,
204                     const GdkRectangle *cell_area,
205                     const GdkRectangle *cell_background,
206                     GetPixbufBoxData   *data)
207 {
208   if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
209     {
210       data->box = *cell_area;
211       data->pixbuf_found = TRUE;
212     }
213   return (data->pixbuf_found != FALSE);
214 }
215
216 static gboolean
217 get_pixbuf_box (GtkIconView     *icon_view,
218                 GtkIconViewItem *item,
219                 GdkRectangle    *box)
220 {
221   GetPixbufBoxData data = { { 0, }, FALSE };
222   GtkCellAreaContext *context;
223
224   context = g_ptr_array_index (icon_view->priv->row_contexts, item->row);
225
226   _gtk_icon_view_set_cell_data (icon_view, item);
227   gtk_cell_area_foreach_alloc (icon_view->priv->cell_area, context,
228                                GTK_WIDGET (icon_view),
229                                &item->cell_area, &item->cell_area,
230                                (GtkCellAllocCallback)get_pixbuf_foreach, &data);
231
232   return data.pixbuf_found;
233 }
234
235 static gboolean
236 get_text_foreach (GtkCellRenderer  *renderer,
237                   gchar           **text)
238 {
239   if (GTK_IS_CELL_RENDERER_TEXT (renderer))
240     {
241       g_object_get (renderer, "text", text, NULL);
242       return TRUE;
243     }
244   return FALSE;
245 }
246
247 static gchar *
248 get_text (GtkIconView     *icon_view,
249           GtkIconViewItem *item)
250 {
251   gchar *text = NULL;
252
253   _gtk_icon_view_set_cell_data (icon_view, item);
254   gtk_cell_area_foreach (icon_view->priv->cell_area,
255                          (GtkCellCallback)get_text_foreach, &text);
256
257   return text;
258 }
259
260 static void
261 gtk_icon_view_item_accessible_get_image_size (AtkImage *image,
262                                               gint     *width,
263                                               gint     *height)
264 {
265   GtkIconViewItemAccessible *item;
266   GdkRectangle box;
267
268   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
269
270   if (!GTK_IS_ICON_VIEW (item->widget))
271     return;
272
273   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
274     return;
275
276   *width = 0;
277   *height = 0;
278
279   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
280     {
281       *width = box.width;
282       *height = box.height;
283     }
284 }
285
286 static void
287 gtk_icon_view_item_accessible_get_image_position (AtkImage    *image,
288                                                   gint        *x,
289                                                   gint        *y,
290                                                   AtkCoordType coord_type)
291 {
292   GtkIconViewItemAccessible *item;
293   GdkRectangle box;
294
295   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (image);
296
297   if (!GTK_IS_ICON_VIEW (item->widget))
298     return;
299
300   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
301     return;
302
303   atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
304
305   if (get_pixbuf_box (GTK_ICON_VIEW (item->widget), item->item, &box))
306     {
307       *x+= box.x - item->item->cell_area.x;
308       *y+= box.y - item->item->cell_area.y;
309     }
310
311 }
312
313 static void
314 atk_image_item_interface_init (AtkImageIface *iface)
315 {
316   iface->get_image_description = gtk_icon_view_item_accessible_get_image_description;
317   iface->set_image_description = gtk_icon_view_item_accessible_set_image_description;
318   iface->get_image_size = gtk_icon_view_item_accessible_get_image_size;
319   iface->get_image_position = gtk_icon_view_item_accessible_get_image_position;
320 }
321
322 static gchar *
323 gtk_icon_view_item_accessible_get_text (AtkText *text,
324                                         gint     start_pos,
325                                         gint     end_pos)
326 {
327   GtkIconViewItemAccessible *item;
328
329   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
330   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
331     return NULL;
332
333   if (item->text)
334     return g_utf8_substring (item->text, start_pos, end_pos > -1 ? end_pos : g_utf8_strlen (item->text, -1));
335   else
336     return g_strdup ("");
337 }
338
339 static gunichar
340 gtk_icon_view_item_accessible_get_character_at_offset (AtkText *text,
341                                                        gint     offset)
342 {
343   GtkIconViewItemAccessible *item;
344   gchar *string;
345   gchar *index;
346
347   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
348   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
349     return '\0';
350
351   string = item->text;
352
353   if (!string)
354     return '\0';
355
356   if (offset >= g_utf8_strlen (string, -1))
357     return '\0';
358
359   index = g_utf8_offset_to_pointer (string, offset);
360
361   return g_utf8_get_char (index);
362 }
363
364 static PangoLayout *
365 create_pango_layout (GtkIconViewItemAccessible *item)
366 {
367   PangoLayout *layout;
368
369   layout = gtk_widget_create_pango_layout (item->widget, item->text);
370
371   return layout;
372 }
373
374 static gchar *
375 gtk_icon_view_item_accessible_get_text_before_offset (AtkText         *atk_text,
376                                                       gint             offset,
377                                                       AtkTextBoundary  boundary_type,
378                                                       gint            *start_offset,
379                                                       gint            *end_offset)
380 {
381   GtkIconViewItemAccessible *item;
382   PangoLayout *layout;
383   gchar *text;
384
385   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (atk_text);
386   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
387     return NULL;
388
389   layout = create_pango_layout (item);
390   text = _gtk_pango_get_text_before (layout, boundary_type, offset, start_offset, end_offset);
391   g_object_unref (layout);
392
393   return text;
394 }
395
396 static gchar *
397 gtk_icon_view_item_accessible_get_text_at_offset (AtkText         *atk_text,
398                                                   gint             offset,
399                                                   AtkTextBoundary  boundary_type,
400                                                   gint            *start_offset,
401                                                   gint            *end_offset)
402 {
403   GtkIconViewItemAccessible *item;
404   PangoLayout *layout;
405   gchar *text;
406
407   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (atk_text);
408   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
409     return NULL;
410
411   layout = create_pango_layout (item);
412   text = _gtk_pango_get_text_at (layout, boundary_type, offset, start_offset, end_offset);
413   g_object_unref (layout);
414
415   return text;
416 }
417
418 static gchar *
419 gtk_icon_view_item_accessible_get_text_after_offset (AtkText         *atk_text,
420                                                      gint             offset,
421                                                      AtkTextBoundary  boundary_type,
422                                                      gint            *start_offset,
423                                                      gint            *end_offset)
424 {
425   GtkIconViewItemAccessible *item;
426   PangoLayout *layout;
427   gchar *text;
428
429   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (atk_text);
430   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
431     return NULL;
432
433   layout = create_pango_layout (item);
434   text = _gtk_pango_get_text_after (layout, boundary_type, offset, start_offset, end_offset);
435   g_object_unref (layout);
436
437   return text;
438 }
439
440 static gint
441 gtk_icon_view_item_accessible_get_character_count (AtkText *text)
442 {
443   GtkIconViewItemAccessible *item;
444
445   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
446   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
447     return 0;
448
449   if (item->text)
450     return g_utf8_strlen (item->text, -1);
451   else
452     return 0;
453 }
454
455 static void
456 gtk_icon_view_item_accessible_get_character_extents (AtkText      *text,
457                                                      gint         offset,
458                                                      gint         *x,
459                                                      gint         *y,
460                                                      gint         *width,
461                                                      gint         *height,
462                                                      AtkCoordType coord_type)
463 {
464   GtkIconViewItemAccessible *item;
465 #if 0
466   GtkIconView *icon_view;
467   PangoRectangle char_rect;
468   const gchar *item_text;
469   gint index;
470 #endif
471
472   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
473
474   if (!GTK_IS_ICON_VIEW (item->widget))
475     return;
476
477   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
478     return;
479
480 #if 0
481   icon_view = GTK_ICON_VIEW (item->widget);
482       /* FIXME we probably have to use GailTextCell to salvage this */
483   gtk_icon_view_update_item_text (icon_view, item->item);
484   item_text = pango_layout_get_text (icon_view->priv->layout);
485   index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
486   pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);
487
488   atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
489   *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
490   /* Look at gtk_icon_view_paint_item() to see where the text is. */
491   *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
492   *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
493   *width = char_rect.width / PANGO_SCALE;
494   *height = char_rect.height / PANGO_SCALE;
495 #endif
496 }
497
498 static gint
499 gtk_icon_view_item_accessible_get_offset_at_point (AtkText      *text,
500                                                    gint          x,
501                                                    gint          y,
502                                                    AtkCoordType coord_type)
503 {
504   GtkIconViewItemAccessible *item;
505   gint offset = 0;
506 #if 0
507   GtkIconView *icon_view;
508   const gchar *item_text;
509   gint index;
510   gint l_x, l_y;
511 #endif
512
513   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);
514
515   if (!GTK_IS_ICON_VIEW (item->widget))
516     return -1;
517
518   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
519     return -1;
520
521 #if 0
522   icon_view = GTK_ICON_VIEW (item->widget);
523       /* FIXME we probably have to use GailTextCell to salvage this */
524   gtk_icon_view_update_item_text (icon_view, item->item);
525   atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
526   x -= l_x + item->item->layout_x - item->item->x;
527   x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
528   y -= l_y + item->item->layout_y - item->item->y;
529   item_text = pango_layout_get_text (icon_view->priv->layout);
530   if (!pango_layout_xy_to_index (icon_view->priv->layout, 
531                                 x * PANGO_SCALE,
532                                 y * PANGO_SCALE,
533                                 &index, NULL))
534     {
535       if (x < 0 || y < 0)
536         index = 0;
537       else
538         index = -1;
539     } 
540   if (index == -1)
541     offset = g_utf8_strlen (item_text, -1);
542   else
543     offset = g_utf8_pointer_to_offset (item_text, item_text + index);
544 #endif
545   return offset;
546 }
547
548 static void
549 atk_text_item_interface_init (AtkTextIface *iface)
550 {
551   iface->get_text = gtk_icon_view_item_accessible_get_text;
552   iface->get_character_at_offset = gtk_icon_view_item_accessible_get_character_at_offset;
553   iface->get_text_before_offset = gtk_icon_view_item_accessible_get_text_before_offset;
554   iface->get_text_at_offset = gtk_icon_view_item_accessible_get_text_at_offset;
555   iface->get_text_after_offset = gtk_icon_view_item_accessible_get_text_after_offset;
556   iface->get_character_count = gtk_icon_view_item_accessible_get_character_count;
557   iface->get_character_extents = gtk_icon_view_item_accessible_get_character_extents;
558   iface->get_offset_at_point = gtk_icon_view_item_accessible_get_offset_at_point;
559 }
560
561 static void
562 gtk_icon_view_item_accessible_get_extents (AtkComponent *component,
563                                            gint         *x,
564                                            gint         *y,
565                                            gint         *width,
566                                            gint         *height,
567                                            AtkCoordType  coord_type)
568 {
569   GtkIconViewItemAccessible *item;
570   AtkObject *parent_obj;
571   gint l_x, l_y;
572
573   g_return_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component));
574
575   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
576   if (!GTK_IS_WIDGET (item->widget))
577     return;
578
579   if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
580     return;
581
582   *width = item->item->cell_area.width;
583   *height = item->item->cell_area.height;
584   if (gtk_icon_view_item_accessible_is_showing (item))
585     {
586       parent_obj = gtk_widget_get_accessible (item->widget);
587       atk_component_get_position (ATK_COMPONENT (parent_obj), &l_x, &l_y, coord_type);
588       *x = l_x + item->item->cell_area.x;
589       *y = l_y + item->item->cell_area.y;
590     }
591   else
592     {
593       *x = G_MININT;
594       *y = G_MININT;
595     }
596 }
597
598 static gboolean
599 gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
600 {
601   GtkIconViewItemAccessible *item;
602   GtkWidget *toplevel;
603
604   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
605
606   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (component);
607   if (!GTK_IS_WIDGET (item->widget))
608     return FALSE;
609
610   gtk_widget_grab_focus (item->widget);
611   _gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
612   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
613   if (gtk_widget_is_toplevel (toplevel))
614     gtk_window_present (GTK_WINDOW (toplevel));
615
616   return TRUE;
617 }
618
619 static void
620 atk_component_item_interface_init (AtkComponentIface *iface)
621 {
622   iface->get_extents = gtk_icon_view_item_accessible_get_extents;
623   iface->grab_focus = gtk_icon_view_item_accessible_grab_focus;
624 }
625
626 static gboolean
627 gtk_icon_view_item_accessible_add_state (GtkIconViewItemAccessible *item,
628                                          AtkStateType               state_type,
629                                          gboolean                   emit_signal)
630 {
631   gboolean rc;
632
633   rc = atk_state_set_add_state (item->state_set, state_type);
634
635   /* The signal should only be generated if the value changed,
636    * not when the item is set up. So states that are set
637    * initially should pass FALSE as the emit_signal argument.
638    */
639   if (emit_signal)
640     {
641       atk_object_notify_state_change (ATK_OBJECT (item), state_type, TRUE);
642       /* If state_type is ATK_STATE_VISIBLE, additional notification */
643       if (state_type == ATK_STATE_VISIBLE)
644         g_signal_emit_by_name (item, "visible-data-changed");
645     }
646
647   return rc;
648 }
649
650 static gboolean
651 gtk_icon_view_item_accessible_remove_state (GtkIconViewItemAccessible *item,
652                                             AtkStateType               state_type,
653                                             gboolean                   emit_signal)
654 {
655   if (atk_state_set_contains_state (item->state_set, state_type))
656     {
657       gboolean rc;
658
659       rc = atk_state_set_remove_state (item->state_set, state_type);
660
661       /* The signal should only be generated if the value changed,
662        * not when the item is set up. So states that are set
663        * initially should pass FALSE as the emit_signal argument.
664        */
665       if (emit_signal)
666         {
667           atk_object_notify_state_change (ATK_OBJECT (item), state_type, FALSE);
668           /* If state_type is ATK_STATE_VISIBLE, additional notification */
669           if (state_type == ATK_STATE_VISIBLE)
670             g_signal_emit_by_name (item, "visible-data-changed");
671         }
672
673       return rc;
674     }
675   else
676     return FALSE;
677 }
678
679 static gboolean
680 gtk_icon_view_item_accessible_is_showing (GtkIconViewItemAccessible *item)
681 {
682   GtkAllocation allocation;
683   GtkIconView *icon_view;
684   GdkRectangle visible_rect;
685   gboolean is_showing;
686
687   /* An item is considered "SHOWING" if any part of the item
688    * is in the visible rectangle.
689    */
690   if (!GTK_IS_ICON_VIEW (item->widget))
691     return FALSE;
692
693   if (item->item == NULL)
694     return FALSE;
695
696   gtk_widget_get_allocation (item->widget, &allocation);
697
698   icon_view = GTK_ICON_VIEW (item->widget);
699   visible_rect.x = 0;
700   if (icon_view->priv->hadjustment)
701     visible_rect.x += gtk_adjustment_get_value (icon_view->priv->hadjustment);
702   visible_rect.y = 0;
703   if (icon_view->priv->hadjustment)
704     visible_rect.y += gtk_adjustment_get_value (icon_view->priv->vadjustment);
705   visible_rect.width = allocation.width;
706   visible_rect.height = allocation.height;
707
708   if (((item->item->cell_area.x + item->item->cell_area.width) < visible_rect.x) ||
709      ((item->item->cell_area.y + item->item->cell_area.height) < (visible_rect.y)) ||
710      (item->item->cell_area.x > (visible_rect.x + visible_rect.width)) ||
711      (item->item->cell_area.y > (visible_rect.y + visible_rect.height)))
712     is_showing = FALSE;
713   else
714     is_showing = TRUE;
715
716   return is_showing;
717 }
718
719 static gboolean
720 gtk_icon_view_item_accessible_set_visibility (GtkIconViewItemAccessible *item,
721                                               gboolean                   emit_signal)
722 {
723   if (gtk_icon_view_item_accessible_is_showing (item))
724     return gtk_icon_view_item_accessible_add_state (item, ATK_STATE_SHOWING,
725                                                     emit_signal);
726   else
727     return gtk_icon_view_item_accessible_remove_state (item, ATK_STATE_SHOWING,
728                                                        emit_signal);
729 }
730
731 static void
732 _gtk_icon_view_item_accessible_init (GtkIconViewItemAccessible *item)
733 {
734   item->state_set = atk_state_set_new ();
735
736   atk_state_set_add_state (item->state_set, ATK_STATE_ENABLED);
737   atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSABLE);
738   atk_state_set_add_state (item->state_set, ATK_STATE_SENSITIVE);
739   atk_state_set_add_state (item->state_set, ATK_STATE_SELECTABLE);
740   atk_state_set_add_state (item->state_set, ATK_STATE_VISIBLE);
741
742   item->action_description = NULL;
743   item->image_description = NULL;
744
745   item->action_idle_handler = 0;
746 }
747
748 static void
749 gtk_icon_view_item_accessible_finalize (GObject *object)
750 {
751   GtkIconViewItemAccessible *item;
752
753   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (object);
754
755   if (item->widget)
756     g_object_remove_weak_pointer (G_OBJECT (item->widget), (gpointer) &item->widget);
757
758   if (item->state_set)
759     g_object_unref (item->state_set);
760
761
762   g_free (item->text);
763   g_free (item->action_description);
764   g_free (item->image_description);
765
766   if (item->action_idle_handler)
767     {
768       g_source_remove (item->action_idle_handler);
769       item->action_idle_handler = 0;
770     }
771
772   G_OBJECT_CLASS (_gtk_icon_view_item_accessible_parent_class)->finalize (object);
773 }
774
775 static AtkObject*
776 gtk_icon_view_item_accessible_get_parent (AtkObject *obj)
777 {
778   GtkIconViewItemAccessible *item;
779
780   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), NULL);
781   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
782
783   if (item->widget)
784     return gtk_widget_get_accessible (item->widget);
785   else
786     return NULL;
787 }
788
789 static gint
790 gtk_icon_view_item_accessible_get_index_in_parent (AtkObject *obj)
791 {
792   GtkIconViewItemAccessible *item;
793
794   g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (obj), 0);
795   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
796
797   return item->item->index;
798 }
799
800 static AtkStateSet *
801 gtk_icon_view_item_accessible_ref_state_set (AtkObject *obj)
802 {
803   GtkIconViewItemAccessible *item;
804   GtkIconView *icon_view;
805
806   item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
807   g_return_val_if_fail (item->state_set, NULL);
808
809   if (!item->widget)
810     return NULL;
811
812   icon_view = GTK_ICON_VIEW (item->widget);
813   if (icon_view->priv->cursor_item == item->item)
814     atk_state_set_add_state (item->state_set, ATK_STATE_FOCUSED);
815   else
816     atk_state_set_remove_state (item->state_set, ATK_STATE_FOCUSED);
817   if (item->item->selected)
818     atk_state_set_add_state (item->state_set, ATK_STATE_SELECTED);
819   else
820     atk_state_set_remove_state (item->state_set, ATK_STATE_SELECTED);
821
822   return g_object_ref (item->state_set);
823 }
824
825 static void
826 _gtk_icon_view_item_accessible_class_init (GtkIconViewItemAccessibleClass *klass)
827 {
828   GObjectClass *gobject_class;
829   AtkObjectClass *atk_class;
830
831   gobject_class = (GObjectClass *)klass;
832   atk_class = (AtkObjectClass *)klass;
833
834   gobject_class->finalize = gtk_icon_view_item_accessible_finalize;
835
836   atk_class->get_index_in_parent = gtk_icon_view_item_accessible_get_index_in_parent;
837   atk_class->get_parent = gtk_icon_view_item_accessible_get_parent;
838   atk_class->ref_state_set = gtk_icon_view_item_accessible_ref_state_set;
839 }
840
841 static void atk_component_interface_init (AtkComponentIface *iface);
842 static void atk_selection_interface_init (AtkSelectionIface *iface);
843
844 G_DEFINE_TYPE_WITH_CODE (GtkIconViewAccessible, _gtk_icon_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
845                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
846                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
847
848 typedef struct
849 {
850   AtkObject *item;
851   gint       index;
852 } GtkIconViewItemAccessibleInfo;
853
854
855 static void
856 gtk_icon_view_item_accessible_info_new (AtkObject *accessible,
857                                         AtkObject *item,
858                                         gint       index)
859 {
860   GtkIconViewAccessible *view = (GtkIconViewAccessible *)accessible;
861   GtkIconViewItemAccessibleInfo *info;
862   GtkIconViewItemAccessibleInfo *tmp_info;
863   GList *items;
864
865   info = g_new (GtkIconViewItemAccessibleInfo, 1);
866   info->item = item;
867   info->index = index;
868
869   items = view->items;
870   while (items)
871     {
872       tmp_info = items->data;
873       if (tmp_info->index > index)
874         break;
875       items = items->next;
876     }
877   view->items = g_list_insert_before (view->items, items, info);
878 }
879
880 static gint
881 gtk_icon_view_accessible_get_n_children (AtkObject *accessible)
882 {
883   GtkIconView *icon_view;
884   GtkWidget *widget;
885
886   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
887   if (!widget)
888       return 0;
889
890   icon_view = GTK_ICON_VIEW (widget);
891
892   return g_list_length (icon_view->priv->items);
893 }
894
895 static AtkObject *
896 gtk_icon_view_accessible_find_child (AtkObject *accessible,
897                                      gint       index)
898 {
899   GtkIconViewAccessible *view = (GtkIconViewAccessible*)accessible;
900   GtkIconViewItemAccessibleInfo *info;
901   GList *items;
902
903   items = view->items;
904
905   while (items)
906     {
907       info = items->data;
908       if (info->index == index)
909         return info->item;
910       items = items->next;
911     }
912
913   return NULL;
914 }
915
916 static AtkObject *
917 gtk_icon_view_accessible_ref_child (AtkObject *accessible,
918                                     gint       index)
919 {
920   GtkIconView *icon_view;
921   GtkWidget *widget;
922   GList *icons;
923   AtkObject *obj;
924   GtkIconViewItemAccessible *a11y_item;
925
926   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
927   if (!widget)
928     return NULL;
929
930   icon_view = GTK_ICON_VIEW (widget);
931   icons = g_list_nth (icon_view->priv->items, index);
932   obj = NULL;
933   if (icons)
934     {
935       GtkIconViewItem *item = icons->data;
936
937       g_return_val_if_fail (item->index == index, NULL);
938       obj = gtk_icon_view_accessible_find_child (accessible, index);
939       if (!obj)
940         {
941           obj = g_object_new (GTK_TYPE_ICON_VIEW_ITEM_ACCESSIBLE, NULL);
942           gtk_icon_view_item_accessible_info_new (accessible, obj, index);
943           obj->role = ATK_ROLE_ICON;
944           a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (obj);
945           a11y_item->item = item;
946           a11y_item->widget = widget;
947
948           g_free (a11y_item->text);
949           a11y_item->text = get_text (icon_view, item);
950
951           gtk_icon_view_item_accessible_set_visibility (a11y_item, FALSE);
952           g_object_add_weak_pointer (G_OBJECT (widget), (gpointer) &(a11y_item->widget));
953        }
954       g_object_ref (obj);
955     }
956   return obj;
957 }
958
959 static void
960 gtk_icon_view_accessible_traverse_items (GtkIconViewAccessible *view,
961                                          GList                 *list)
962 {
963   GtkIconViewItemAccessibleInfo *info;
964   GtkIconViewItemAccessible *item;
965   GList *items;
966
967   if (view->items)
968     {
969       GtkWidget *widget;
970       gboolean act_on_item;
971
972       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (view));
973       if (widget == NULL)
974         return;
975
976       items = view->items;
977
978       act_on_item = (list == NULL);
979
980       while (items)
981         {
982
983           info = (GtkIconViewItemAccessibleInfo *)items->data;
984           item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
985
986           if (act_on_item == FALSE && list == items)
987             act_on_item = TRUE;
988
989           if (act_on_item)
990             gtk_icon_view_item_accessible_set_visibility (item, TRUE);
991
992           items = items->next;
993        }
994    }
995 }
996
997 void
998 _gtk_icon_view_accessible_adjustment_changed (GtkIconView *icon_view)
999 {
1000   GtkIconViewAccessible *view;
1001
1002   view = GTK_ICON_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (icon_view)));
1003   if (view == NULL)
1004     return;
1005
1006   gtk_icon_view_accessible_traverse_items (view, NULL);
1007 }
1008
1009 static void
1010 gtk_icon_view_accessible_model_row_changed (GtkTreeModel *tree_model,
1011                                             GtkTreePath  *path,
1012                                             GtkTreeIter  *iter,
1013                                             gpointer      user_data)
1014 {
1015   AtkObject *atk_obj;
1016   gint index;
1017   GtkWidget *widget;
1018   GtkIconView *icon_view;
1019   GtkIconViewItem *item;
1020   GtkIconViewItemAccessible *a11y_item;
1021   const gchar *name;
1022
1023   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
1024   index = gtk_tree_path_get_indices(path)[0];
1025   a11y_item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (
1026       gtk_icon_view_accessible_find_child (atk_obj, index));
1027
1028   if (a11y_item)
1029     {
1030       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_obj));
1031       icon_view = GTK_ICON_VIEW (widget);
1032       item = a11y_item->item;
1033
1034       name = atk_object_get_name (ATK_OBJECT (a11y_item));
1035       if (!name || strcmp (name, "") == 0)
1036         {
1037           g_free (a11y_item->text);
1038           a11y_item->text = get_text (icon_view, item);
1039         }
1040     }
1041
1042   g_signal_emit_by_name (atk_obj, "visible-data-changed");
1043
1044   return;
1045 }
1046
1047 static void
1048 gtk_icon_view_accessible_model_row_inserted (GtkTreeModel *tree_model,
1049                                              GtkTreePath  *path,
1050                                              GtkTreeIter  *iter,
1051                                              gpointer     user_data)
1052 {
1053   GtkIconViewItemAccessibleInfo *info;
1054   GtkIconViewAccessible *view;
1055   GtkIconViewItemAccessible *item;
1056   GList *items;
1057   GList *tmp_list;
1058   AtkObject *atk_obj;
1059   gint index;
1060
1061   index = gtk_tree_path_get_indices(path)[0];
1062   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
1063   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
1064
1065   items = view->items;
1066   tmp_list = NULL;
1067   while (items)
1068     {
1069       info = items->data;
1070       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
1071       if (info->index != item->item->index)
1072         {
1073           if (info->index < index)
1074             g_warning ("Unexpected index value on insertion %d %d", index, info->index);
1075
1076           if (tmp_list == NULL)
1077             tmp_list = items;
1078
1079           info->index = item->item->index;
1080         }
1081
1082       items = items->next;
1083     }
1084   gtk_icon_view_accessible_traverse_items (view, tmp_list);
1085   g_signal_emit_by_name (atk_obj, "children-changed::add",
1086                          index, NULL, NULL);
1087   return;
1088 }
1089
1090 static void
1091 gtk_icon_view_accessible_model_row_deleted (GtkTreeModel *tree_model,
1092                                             GtkTreePath  *path,
1093                                             gpointer     user_data)
1094 {
1095   GtkIconViewItemAccessibleInfo *info;
1096   GtkIconViewAccessible *view;
1097   GtkIconViewItemAccessible *item;
1098   GList *items;
1099   GList *tmp_list;
1100   GList *deleted_item;
1101   AtkObject *atk_obj;
1102   gint index;
1103
1104   index = gtk_tree_path_get_indices(path)[0];
1105   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
1106   view = GTK_ICON_VIEW_ACCESSIBLE (atk_obj);
1107
1108   items = view->items;
1109   tmp_list = NULL;
1110   deleted_item = NULL;
1111   info = NULL;
1112   while (items)
1113     {
1114       info = items->data;
1115       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
1116       if (info->index == index)
1117         {
1118           deleted_item = items;
1119         }
1120       if (info->index != item->item->index)
1121         {
1122           if (tmp_list == NULL)
1123             tmp_list = items;
1124
1125           info->index = item->item->index;
1126         }
1127
1128       items = items->next;
1129     }
1130   gtk_icon_view_accessible_traverse_items (view, tmp_list);
1131   if (deleted_item)
1132     {
1133       info = deleted_item->data;
1134       gtk_icon_view_item_accessible_add_state (GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item), ATK_STATE_DEFUNCT, TRUE);
1135       g_signal_emit_by_name (atk_obj, "children-changed::remove",
1136                              index, NULL, NULL);
1137       view->items = g_list_remove_link (view->items, deleted_item);
1138       g_free (info);
1139     }
1140
1141   return;
1142 }
1143
1144 static gint
1145 gtk_icon_view_accessible_item_compare (GtkIconViewItemAccessibleInfo *i1,
1146                                        GtkIconViewItemAccessibleInfo *i2)
1147 {
1148   return i1->index - i2->index;
1149 }
1150
1151 static void
1152 gtk_icon_view_accessible_model_rows_reordered (GtkTreeModel *tree_model,
1153                                                GtkTreePath  *path,
1154                                                GtkTreeIter  *iter,
1155                                                gint         *new_order,
1156                                                gpointer     user_data)
1157 {
1158   GtkIconViewAccessible *view;
1159   GtkIconViewItemAccessibleInfo *info;
1160   GtkIconView *icon_view;
1161   GtkIconViewItemAccessible *item;
1162   GList *items;
1163   AtkObject *atk_obj;
1164   gint *order;
1165   gint length, i;
1166
1167   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (user_data));
1168   icon_view = GTK_ICON_VIEW (user_data);
1169   view = (GtkIconViewAccessible*)atk_obj;
1170
1171   length = gtk_tree_model_iter_n_children (tree_model, NULL);
1172
1173   order = g_new (gint, length);
1174   for (i = 0; i < length; i++)
1175     order [new_order[i]] = i;
1176
1177   items = view->items;
1178   while (items)
1179     {
1180       info = items->data;
1181       item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (info->item);
1182       info->index = order[info->index];
1183       item->item = g_list_nth_data (icon_view->priv->items, info->index);
1184       items = items->next;
1185     }
1186   g_free (order);
1187   view->items = g_list_sort (view->items,
1188                              (GCompareFunc)gtk_icon_view_accessible_item_compare);
1189
1190   return;
1191 }
1192
1193 static void
1194 gtk_icon_view_accessible_disconnect_model_signals (GtkTreeModel *model,
1195                                                    GtkWidget *widget)
1196 {
1197   GObject *obj;
1198
1199   obj = G_OBJECT (model);
1200   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_changed, widget);
1201   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_inserted, widget);
1202   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_row_deleted, widget);
1203   g_signal_handlers_disconnect_by_func (obj, (gpointer) gtk_icon_view_accessible_model_rows_reordered, widget);
1204 }
1205
1206 static void
1207 gtk_icon_view_accessible_connect_model_signals (GtkIconView *icon_view)
1208 {
1209   GObject *obj;
1210
1211   obj = G_OBJECT (icon_view->priv->model);
1212   g_signal_connect_data (obj, "row-changed",
1213                          (GCallback) gtk_icon_view_accessible_model_row_changed,
1214                          icon_view, NULL, 0);
1215   g_signal_connect_data (obj, "row-inserted",
1216                          (GCallback) gtk_icon_view_accessible_model_row_inserted,
1217                          icon_view, NULL, G_CONNECT_AFTER);
1218   g_signal_connect_data (obj, "row-deleted",
1219                          (GCallback) gtk_icon_view_accessible_model_row_deleted,
1220                          icon_view, NULL, G_CONNECT_AFTER);
1221   g_signal_connect_data (obj, "rows-reordered",
1222                          (GCallback) gtk_icon_view_accessible_model_rows_reordered,
1223                          icon_view, NULL, G_CONNECT_AFTER);
1224 }
1225
1226 static void
1227 gtk_icon_view_accessible_clear_cache (GtkIconViewAccessible *view)
1228 {
1229   GtkIconViewItemAccessibleInfo *info;
1230   GList *items;
1231
1232   items = view->items;
1233   while (items)
1234     {
1235       info = (GtkIconViewItemAccessibleInfo *) items->data;
1236       g_object_unref (info->item);
1237       g_free (items->data);
1238       items = items->next;
1239     }
1240   g_list_free (view->items);
1241   view->items = NULL;
1242 }
1243
1244 static void
1245 gtk_icon_view_accessible_notify_gtk (GObject    *obj,
1246                                      GParamSpec *pspec)
1247 {
1248   GtkIconView *icon_view;
1249   GtkWidget *widget;
1250   AtkObject *atk_obj;
1251   GtkIconViewAccessible *view;
1252
1253   if (strcmp (pspec->name, "model") == 0)
1254     {
1255       widget = GTK_WIDGET (obj);
1256       atk_obj = gtk_widget_get_accessible (widget);
1257       view = (GtkIconViewAccessible*)atk_obj;
1258       if (view->model)
1259         {
1260           g_object_remove_weak_pointer (G_OBJECT (view->model),
1261                                         (gpointer *)&view->model);
1262           gtk_icon_view_accessible_disconnect_model_signals (view->model, widget);
1263         }
1264       gtk_icon_view_accessible_clear_cache (view);
1265
1266       icon_view = GTK_ICON_VIEW (obj);
1267       view->model = icon_view->priv->model;
1268       /* If there is no model the GtkIconView is probably being destroyed */
1269       if (view->model)
1270         {
1271           g_object_add_weak_pointer (G_OBJECT (view->model), (gpointer *)&view->model);
1272           gtk_icon_view_accessible_connect_model_signals (icon_view);
1273         }
1274     }
1275
1276   return;
1277 }
1278
1279 static void
1280 gtk_icon_view_accessible_initialize (AtkObject *accessible,
1281                                      gpointer   data)
1282 {
1283   GtkIconViewAccessible *view;
1284   GtkIconView *icon_view;
1285
1286   if (ATK_OBJECT_CLASS (_gtk_icon_view_accessible_parent_class)->initialize)
1287     ATK_OBJECT_CLASS (_gtk_icon_view_accessible_parent_class)->initialize (accessible, data);
1288
1289   icon_view = (GtkIconView*)data;
1290   view = (GtkIconViewAccessible*)accessible;
1291
1292   g_signal_connect (data, "notify",
1293                     G_CALLBACK (gtk_icon_view_accessible_notify_gtk), NULL);
1294
1295   view->model = icon_view->priv->model;
1296   if (view->model)
1297     {
1298       g_object_add_weak_pointer (G_OBJECT (view->model), (gpointer *)&view->model);
1299       gtk_icon_view_accessible_connect_model_signals (icon_view);
1300     }
1301
1302   accessible->role = ATK_ROLE_LAYERED_PANE;
1303 }
1304
1305 static void
1306 gtk_icon_view_accessible_finalize (GObject *object)
1307 {
1308   GtkIconViewAccessible *view = (GtkIconViewAccessible*)object;
1309
1310   gtk_icon_view_accessible_clear_cache (view);
1311
1312   G_OBJECT_CLASS (_gtk_icon_view_accessible_parent_class)->finalize (object);
1313 }
1314
1315 static void
1316 _gtk_icon_view_accessible_class_init (GtkIconViewAccessibleClass *klass)
1317 {
1318   GObjectClass *gobject_class;
1319   AtkObjectClass *atk_class;
1320
1321   gobject_class = (GObjectClass *)klass;
1322   atk_class = (AtkObjectClass *)klass;
1323
1324   gobject_class->finalize = gtk_icon_view_accessible_finalize;
1325
1326   atk_class->get_n_children = gtk_icon_view_accessible_get_n_children;
1327   atk_class->ref_child = gtk_icon_view_accessible_ref_child;
1328   atk_class->initialize = gtk_icon_view_accessible_initialize;
1329 }
1330
1331 static void
1332 _gtk_icon_view_accessible_init (GtkIconViewAccessible *accessible)
1333 {
1334 }
1335
1336 static AtkObject*
1337 gtk_icon_view_accessible_ref_accessible_at_point (AtkComponent *component,
1338                                                   gint          x,
1339                                                   gint          y,
1340                                                   AtkCoordType  coord_type)
1341 {
1342   GtkWidget *widget;
1343   GtkIconView *icon_view;
1344   GtkIconViewItem *item;
1345   gint x_pos, y_pos;
1346
1347   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
1348   if (widget == NULL)
1349     return NULL;
1350
1351   icon_view = GTK_ICON_VIEW (widget);
1352   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
1353   item = _gtk_icon_view_get_item_at_coords (icon_view, x - x_pos, y - y_pos, TRUE, NULL);
1354   if (item)
1355     return gtk_icon_view_accessible_ref_child (ATK_OBJECT (component), item->index);
1356
1357   return NULL;
1358 }
1359
1360 static void
1361 atk_component_interface_init (AtkComponentIface *iface)
1362 {
1363   iface->ref_accessible_at_point = gtk_icon_view_accessible_ref_accessible_at_point;
1364 }
1365
1366 static gboolean
1367 gtk_icon_view_accessible_add_selection (AtkSelection *selection,
1368                                         gint          i)
1369 {
1370   GtkWidget *widget;
1371   GtkIconView *icon_view;
1372   GtkIconViewItem *item;
1373
1374   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1375   if (widget == NULL)
1376     return FALSE;
1377
1378   icon_view = GTK_ICON_VIEW (widget);
1379
1380   item = g_list_nth_data (icon_view->priv->items, i);
1381   if (!item)
1382     return FALSE;
1383
1384   _gtk_icon_view_select_item (icon_view, item);
1385
1386   return TRUE;
1387 }
1388
1389 static gboolean
1390 gtk_icon_view_accessible_clear_selection (AtkSelection *selection)
1391 {
1392   GtkWidget *widget;
1393   GtkIconView *icon_view;
1394
1395   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1396   if (widget == NULL)
1397     return FALSE;
1398
1399   icon_view = GTK_ICON_VIEW (widget);
1400   gtk_icon_view_unselect_all (icon_view);
1401
1402   return TRUE;
1403 }
1404
1405 static AtkObject*
1406 gtk_icon_view_accessible_ref_selection (AtkSelection *selection,
1407                                         gint          i)
1408 {
1409   GList *l;
1410   GtkWidget *widget;
1411   GtkIconView *icon_view;
1412   GtkIconViewItem *item;
1413
1414   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1415   if (widget == NULL)
1416     return NULL;
1417
1418   icon_view = GTK_ICON_VIEW (widget);
1419
1420   l = icon_view->priv->items;
1421   while (l)
1422     {
1423       item = l->data;
1424       if (item->selected)
1425         {
1426           if (i == 0)
1427             return atk_object_ref_accessible_child (gtk_widget_get_accessible (widget), item->index);
1428           else
1429             i--;
1430         }
1431       l = l->next;
1432     }
1433
1434   return NULL;
1435 }
1436
1437 static gint
1438 gtk_icon_view_accessible_get_selection_count (AtkSelection *selection)
1439 {
1440   GtkWidget *widget;
1441   GtkIconView *icon_view;
1442   GtkIconViewItem *item;
1443   GList *l;
1444   gint count;
1445
1446   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1447   if (widget == NULL)
1448     return 0;
1449
1450   icon_view = GTK_ICON_VIEW (widget);
1451
1452   l = icon_view->priv->items;
1453   count = 0;
1454   while (l)
1455     {
1456       item = l->data;
1457
1458       if (item->selected)
1459         count++;
1460
1461       l = l->next;
1462     }
1463
1464   return count;
1465 }
1466
1467 static gboolean
1468 gtk_icon_view_accessible_is_child_selected (AtkSelection *selection,
1469                                             gint          i)
1470 {
1471   GtkWidget *widget;
1472   GtkIconView *icon_view;
1473   GtkIconViewItem *item;
1474
1475   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1476   if (widget == NULL)
1477     return FALSE;
1478
1479   icon_view = GTK_ICON_VIEW (widget);
1480
1481   item = g_list_nth_data (icon_view->priv->items, i);
1482   if (!item)
1483     return FALSE;
1484
1485   return item->selected;
1486 }
1487
1488 static gboolean
1489 gtk_icon_view_accessible_remove_selection (AtkSelection *selection,
1490                                            gint          i)
1491 {
1492   GtkWidget *widget;
1493   GtkIconView *icon_view;
1494   GtkIconViewItem *item;
1495   GList *l;
1496   gint count;
1497
1498   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1499   if (widget == NULL)
1500     return FALSE;
1501
1502   icon_view = GTK_ICON_VIEW (widget);
1503   l = icon_view->priv->items;
1504   count = 0;
1505   while (l)
1506     {
1507       item = l->data;
1508       if (item->selected)
1509         {
1510           if (count == i)
1511             {
1512               _gtk_icon_view_unselect_item (icon_view, item);
1513               return TRUE;
1514             }
1515           count++;
1516         }
1517       l = l->next;
1518     }
1519
1520   return FALSE;
1521 }
1522  
1523 static gboolean
1524 gtk_icon_view_accessible_select_all_selection (AtkSelection *selection)
1525 {
1526   GtkWidget *widget;
1527   GtkIconView *icon_view;
1528
1529   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1530   if (widget == NULL)
1531     return FALSE;
1532
1533   icon_view = GTK_ICON_VIEW (widget);
1534   gtk_icon_view_select_all (icon_view);
1535   return TRUE;
1536 }
1537
1538 static void
1539 atk_selection_interface_init (AtkSelectionIface *iface)
1540 {
1541   iface->add_selection = gtk_icon_view_accessible_add_selection;
1542   iface->clear_selection = gtk_icon_view_accessible_clear_selection;
1543   iface->ref_selection = gtk_icon_view_accessible_ref_selection;
1544   iface->get_selection_count = gtk_icon_view_accessible_get_selection_count;
1545   iface->is_child_selected = gtk_icon_view_accessible_is_child_selected;
1546   iface->remove_selection = gtk_icon_view_accessible_remove_selection;
1547   iface->select_all_selection = gtk_icon_view_accessible_select_all_selection;
1548 }