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