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