]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkwidgetaccessible.c
gtk: Always load the atk-bridge
[~andy/gtk] / gtk / a11y / gtkwidgetaccessible.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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 <gtk/gtk.h>
21 #ifdef GDK_WINDOWING_X11
22 #include <gdk/x11/gdkx.h>
23 #endif
24 #include "gtkwidgetaccessible.h"
25 #include "gtknotebookpageaccessible.h"
26
27 extern GtkWidget *_focus_widget;
28
29
30 static gboolean gtk_widget_accessible_on_screen           (GtkWidget *widget);
31 static gboolean gtk_widget_accessible_all_parents_visible (GtkWidget *widget);
32
33 static void atk_component_interface_init (AtkComponentIface *iface);
34
35 G_DEFINE_TYPE_WITH_CODE (GtkWidgetAccessible, _gtk_widget_accessible, GTK_TYPE_ACCESSIBLE,
36                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init))
37
38 /* Translate GtkWidget::focus-in/out-event to AtkObject::focus-event */
39 static gboolean
40 focus_cb (GtkWidget     *widget,
41           GdkEventFocus *event)
42 {
43   AtkObject *obj;
44
45   obj = gtk_widget_get_accessible (widget);
46
47   g_signal_emit_by_name (obj, "focus-event", event->in);
48
49   return FALSE;
50 }
51
52 /* Translate GtkWidget property change notification to the notify_gtk vfunc */
53 static void
54 notify_cb (GObject    *obj,
55            GParamSpec *pspec)
56 {
57   GtkWidgetAccessible *widget;
58   GtkWidgetAccessibleClass *klass;
59
60   widget = GTK_WIDGET_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (obj)));
61   klass = GTK_WIDGET_ACCESSIBLE_GET_CLASS (widget);
62   if (klass->notify_gtk)
63     klass->notify_gtk (obj, pspec);
64 }
65
66 /* Translate GtkWidget::size-allocate to AtkComponent::bounds-changed */
67 static void
68 size_allocate_cb (GtkWidget     *widget,
69                   GtkAllocation *allocation)
70 {
71   AtkObject* accessible;
72   AtkRectangle rect;
73
74   accessible = gtk_widget_get_accessible (widget);
75   if (ATK_IS_COMPONENT (accessible))
76     {
77       rect.x = allocation->x;
78       rect.y = allocation->y;
79       rect.width = allocation->width;
80       rect.height = allocation->height;
81       g_signal_emit_by_name (accessible, "bounds-changed", &rect);
82     }
83 }
84
85 /* Translate GtkWidget mapped state into AtkObject showing */
86 static gint
87 map_cb (GtkWidget *widget)
88 {
89   AtkObject *accessible;
90
91   accessible = gtk_widget_get_accessible (widget);
92   atk_object_notify_state_change (accessible, ATK_STATE_SHOWING,
93                                   gtk_widget_get_mapped (widget));
94   return 1;
95 }
96
97 static void
98 gtk_widget_accessible_focus_event (AtkObject *obj,
99                                    gboolean   focus_in)
100 {
101   AtkObject *focus_obj;
102
103   focus_obj = g_object_get_data (G_OBJECT (obj), "gail-focus-object");
104   if (focus_obj == NULL)
105     focus_obj = obj;
106   atk_object_notify_state_change (focus_obj, ATK_STATE_FOCUSED, focus_in);
107 }
108
109 static void
110 gtk_widget_accessible_initialize (AtkObject *obj,
111                                   gpointer   data)
112 {
113   GtkWidget *widget;
114
115   widget = GTK_WIDGET (data);
116
117   g_signal_connect_after (widget, "focus-in-event", G_CALLBACK (focus_cb), NULL);
118   g_signal_connect_after (widget, "focus-out-event", G_CALLBACK (focus_cb), NULL);
119   g_signal_connect (widget, "notify", G_CALLBACK (notify_cb), NULL);
120   g_signal_connect (widget, "size-allocate", G_CALLBACK (size_allocate_cb), NULL);
121   g_signal_connect (widget, "map", G_CALLBACK (map_cb), NULL);
122   g_signal_connect (widget, "unmap", G_CALLBACK (map_cb), NULL);
123
124   GTK_WIDGET_ACCESSIBLE (obj)->layer = ATK_LAYER_WIDGET;
125   obj->role = ATK_ROLE_UNKNOWN;
126 }
127
128 static const gchar *
129 gtk_widget_accessible_get_description (AtkObject *accessible)
130 {
131   GtkWidget *widget;
132
133   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
134   if (widget == NULL)
135     return NULL;
136
137   if (accessible->description)
138     return accessible->description;
139
140   return gtk_widget_get_tooltip_text (widget);
141 }
142
143 static AtkObject *
144 gtk_widget_accessible_get_parent (AtkObject *accessible)
145 {
146   AtkObject *parent;
147   GtkWidget *widget, *parent_widget;
148
149   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
150   if (widget == NULL)
151     return NULL;
152
153   parent = accessible->accessible_parent;
154   if (parent != NULL)
155     return parent;
156
157   parent_widget = gtk_widget_get_parent (widget);
158   if (parent_widget == NULL)
159     return NULL;
160
161   /* For a widget whose parent is a GtkNoteBook, we return the
162    * accessible object corresponding the GtkNotebookPage containing
163    * the widget as the accessible parent.
164    */
165   if (GTK_IS_NOTEBOOK (parent_widget))
166     {
167       gint page_num;
168       GtkWidget *child;
169       GtkNotebook *notebook;
170
171       page_num = 0;
172       notebook = GTK_NOTEBOOK (parent_widget);
173       while (TRUE)
174         {
175           child = gtk_notebook_get_nth_page (notebook, page_num);
176           if (!child)
177             break;
178           if (child == widget)
179             {
180               parent = gtk_widget_get_accessible (parent_widget);
181               parent = atk_object_ref_accessible_child (parent, page_num);
182               g_object_unref (parent);
183               return parent;
184             }
185           page_num++;
186         }
187     }
188   parent = gtk_widget_get_accessible (parent_widget);
189   return parent;
190 }
191
192 static GtkWidget *
193 find_label (GtkWidget *widget)
194 {
195   GList *labels;
196   GtkWidget *label;
197   GtkWidget *temp_widget;
198   GList *ptr;
199
200   labels = gtk_widget_list_mnemonic_labels (widget);
201   label = NULL;
202   ptr = labels;
203   while (ptr)
204     {
205       if (ptr->data)
206         {
207           label = ptr->data;
208           break;
209         }
210       ptr = ptr->next;
211     }
212   g_list_free (labels);
213
214   /* Ignore a label within a button; bug #136602 */
215   if (label && GTK_IS_BUTTON (widget))
216     {
217       temp_widget = label;
218       while (temp_widget)
219         {
220           if (temp_widget == widget)
221             {
222               label = NULL;
223               break;
224             }
225           temp_widget = gtk_widget_get_parent (temp_widget);
226         }
227     }
228   return label;
229 }
230
231 static AtkRelationSet *
232 gtk_widget_accessible_ref_relation_set (AtkObject *obj)
233 {
234   GtkWidget *widget;
235   AtkRelationSet *relation_set;
236   GtkWidget *label;
237   AtkObject *array[1];
238   AtkRelation* relation;
239
240   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
241   if (widget == NULL)
242     return NULL;
243
244   relation_set = ATK_OBJECT_CLASS (_gtk_widget_accessible_parent_class)->ref_relation_set (obj);
245
246   if (GTK_IS_BOX (widget))
247     return relation_set;
248
249   if (!atk_relation_set_contains (relation_set, ATK_RELATION_LABELLED_BY))
250     {
251       label = find_label (widget);
252       if (label == NULL)
253         {
254           if (GTK_IS_BUTTON (widget))
255             /*
256              * Handle the case where GnomeIconEntry is the mnemonic widget.
257              * The GtkButton which is a grandchild of the GnomeIconEntry
258              * should really be the mnemonic widget. See bug #133967.
259              */
260             {
261               GtkWidget *temp_widget;
262
263               temp_widget = gtk_widget_get_parent (widget);
264
265               if (GTK_IS_ALIGNMENT (temp_widget))
266                 {
267                   temp_widget = gtk_widget_get_parent (temp_widget);
268                   if (GTK_IS_BOX (temp_widget))
269                     {
270                       label = find_label (temp_widget);
271                       if (!label)
272                         label = find_label (gtk_widget_get_parent (temp_widget));
273                     }
274                 }
275             }
276           else if (GTK_IS_COMBO_BOX (widget))
277             /*
278              * Handle the case when GtkFileChooserButton is the mnemonic
279              * widget.  The GtkComboBox which is a child of the
280              * GtkFileChooserButton should be the mnemonic widget.
281              * See bug #359843.
282              */
283             {
284               GtkWidget *temp_widget;
285
286               temp_widget = gtk_widget_get_parent (widget);
287               if (GTK_IS_BOX (temp_widget))
288                 {
289                   label = find_label (temp_widget);
290                 }
291             }
292         }
293
294       if (label)
295         {
296           array[0] = gtk_widget_get_accessible (label);
297
298           relation = atk_relation_new (array, 1, ATK_RELATION_LABELLED_BY);
299           atk_relation_set_add (relation_set, relation);
300           g_object_unref (relation);
301         }
302     }
303
304   return relation_set;
305 }
306
307 static AtkStateSet *
308 gtk_widget_accessible_ref_state_set (AtkObject *accessible)
309 {
310   GtkWidget *widget;
311   AtkStateSet *state_set;
312
313   state_set = ATK_OBJECT_CLASS (_gtk_widget_accessible_parent_class)->ref_state_set (accessible);
314
315   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
316   if (widget == NULL)
317     atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
318   else
319     {
320       if (gtk_widget_is_sensitive (widget))
321         {
322           atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
323           atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
324         }
325   
326       if (gtk_widget_get_can_focus (widget))
327         {
328           atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
329         }
330       /*
331        * We do not currently generate notifications when an ATK object
332        * corresponding to a GtkWidget changes visibility by being scrolled
333        * on or off the screen.  The testcase for this is the main window
334        * of the testgtk application in which a set of buttons in a GtkVBox
335        * is in a scrolled window with a viewport.
336        *
337        * To generate the notifications we would need to do the following:
338        * 1) Find the GtkViewport among the ancestors of the objects
339        * 2) Create an accessible for the viewport
340        * 3) Connect to the value-changed signal on the viewport
341        * 4) When the signal is received we need to traverse the children
342        *    of the viewport and check whether the children are visible or not
343        *    visible; we may want to restrict this to the widgets for which
344        *    accessible objects have been created.
345        * 5) We probably need to store a variable on_screen in the
346        *    GtkWidgetAccessible data structure so we can determine whether
347        *    the value has changed.
348        */
349       if (gtk_widget_get_visible (widget))
350         {
351           atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
352           if (gtk_widget_accessible_on_screen (widget) &&
353               gtk_widget_get_mapped (widget) &&
354               gtk_widget_accessible_all_parents_visible (widget))
355             atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
356         }
357
358       if (gtk_widget_has_focus (widget) && (widget == _focus_widget))
359         {
360           AtkObject *focus_obj;
361
362           focus_obj = g_object_get_data (G_OBJECT (accessible), "gail-focus-object");
363           if (focus_obj == NULL)
364             atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
365         }
366
367       if (gtk_widget_has_default (widget))
368         atk_state_set_add_state (state_set, ATK_STATE_DEFAULT);
369
370       if (GTK_IS_ORIENTABLE (widget))
371         {
372           if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL)
373             atk_state_set_add_state (state_set, ATK_STATE_HORIZONTAL);
374           else
375             atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
376         }
377     }
378   return state_set;
379 }
380
381 static gint
382 gtk_widget_accessible_get_index_in_parent (AtkObject *accessible)
383 {
384   GtkWidget *widget;
385   GtkWidget *parent_widget;
386   gint index;
387   GList *children;
388
389   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
390
391   if (widget == NULL)
392     return -1;
393
394   if (accessible->accessible_parent)
395     {
396       AtkObject *parent;
397
398       parent = accessible->accessible_parent;
399
400       if (GTK_IS_NOTEBOOK_PAGE_ACCESSIBLE (parent))
401         return 0;
402       else
403         {
404           gint n_children, i;
405           gboolean found = FALSE;
406
407           n_children = atk_object_get_n_accessible_children (parent);
408           for (i = 0; i < n_children; i++)
409             {
410               AtkObject *child;
411
412               child = atk_object_ref_accessible_child (parent, i);
413               if (child == accessible)
414                 found = TRUE;
415
416               g_object_unref (child);
417               if (found)
418                 return i;
419             }
420         }
421     }
422
423   if (!GTK_IS_WIDGET (widget))
424     return -1;
425   parent_widget = gtk_widget_get_parent (widget);
426   if (!GTK_IS_CONTAINER (parent_widget))
427     return -1;
428
429   children = gtk_container_get_children (GTK_CONTAINER (parent_widget));
430
431   index = g_list_index (children, widget);
432   g_list_free (children);
433   return index;
434 }
435
436 /* This function is the default implementation for the notify_gtk
437  * vfunc which gets called when a property changes value on the
438  * GtkWidget associated with a GtkWidgetAccessible. It constructs
439  * an AtkPropertyValues structure and emits a "property_changed"
440  * signal which causes the user specified AtkPropertyChangeHandler
441  * to be called.
442  */
443 static void
444 gtk_widget_accessible_notify_gtk (GObject    *obj,
445                                   GParamSpec *pspec)
446 {
447   GtkWidget* widget = GTK_WIDGET (obj);
448   AtkObject* atk_obj = gtk_widget_get_accessible (widget);
449   AtkState state;
450   gboolean value;
451
452   if (g_strcmp0 (pspec->name, "has-focus") == 0)
453     /*
454      * We use focus-in-event and focus-out-event signals to catch
455      * focus changes so we ignore this.
456      */
457     return;
458   else if (g_strcmp0 (pspec->name, "visible") == 0)
459     {
460       state = ATK_STATE_VISIBLE;
461       value = gtk_widget_get_visible (widget);
462     }
463   else if (g_strcmp0 (pspec->name, "sensitive") == 0)
464     {
465       state = ATK_STATE_SENSITIVE;
466       value = gtk_widget_get_sensitive (widget);
467     }
468   else if (g_strcmp0 (pspec->name, "orientation") == 0 &&
469            GTK_IS_ORIENTABLE (widget))
470     {
471       GtkOrientable *orientable;
472
473       orientable = GTK_ORIENTABLE (widget);
474
475       state = ATK_STATE_HORIZONTAL;
476       value = (gtk_orientable_get_orientation (orientable) == GTK_ORIENTATION_HORIZONTAL);
477     }
478   else
479     return;
480
481   atk_object_notify_state_change (atk_obj, state, value);
482   if (state == ATK_STATE_SENSITIVE)
483     atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED, value);
484
485   if (state == ATK_STATE_HORIZONTAL)
486     atk_object_notify_state_change (atk_obj, ATK_STATE_VERTICAL, !value);
487 }
488
489 static AtkAttributeSet *
490 gtk_widget_accessible_get_attributes (AtkObject *obj)
491 {
492   AtkAttributeSet *attributes;
493   AtkAttribute *toolkit;
494
495   toolkit = g_new (AtkAttribute, 1);
496   toolkit->name = g_strdup ("toolkit");
497   toolkit->value = g_strdup ("gtk");
498
499   attributes = g_slist_append (NULL, toolkit);
500
501   return attributes;
502 }
503
504 static void
505 _gtk_widget_accessible_class_init (GtkWidgetAccessibleClass *klass)
506 {
507   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
508
509   klass->notify_gtk = gtk_widget_accessible_notify_gtk;
510
511   class->get_description = gtk_widget_accessible_get_description;
512   class->get_parent = gtk_widget_accessible_get_parent;
513   class->ref_relation_set = gtk_widget_accessible_ref_relation_set;
514   class->ref_state_set = gtk_widget_accessible_ref_state_set;
515   class->get_index_in_parent = gtk_widget_accessible_get_index_in_parent;
516   class->initialize = gtk_widget_accessible_initialize;
517   class->get_attributes = gtk_widget_accessible_get_attributes;
518   class->focus_event = gtk_widget_accessible_focus_event;
519 }
520
521 static void
522 _gtk_widget_accessible_init (GtkWidgetAccessible *accessible)
523 {
524 }
525
526 static void
527 gtk_widget_accessible_get_extents (AtkComponent   *component,
528                                    gint           *x,
529                                    gint           *y,
530                                    gint           *width,
531                                    gint           *height,
532                                    AtkCoordType    coord_type)
533 {
534   GdkWindow *window;
535   gint x_window, y_window;
536   gint x_toplevel, y_toplevel;
537   GtkWidget *widget;
538   GtkAllocation allocation;
539
540   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
541   if (widget == NULL)
542     return;
543
544   gtk_widget_get_allocation (widget, &allocation);
545   *width = allocation.width;
546   *height = allocation.height;
547   if (!gtk_widget_accessible_on_screen (widget) || (!gtk_widget_is_drawable (widget)))
548     {
549       *x = G_MININT;
550       *y = G_MININT;
551       return;
552     }
553
554   if (gtk_widget_get_parent (widget))
555     {
556       *x = allocation.x;
557       *y = allocation.y;
558       window = gtk_widget_get_parent_window (widget);
559     }
560   else
561     {
562       *x = 0;
563       *y = 0;
564       window = gtk_widget_get_window (widget);
565     }
566   gdk_window_get_origin (window, &x_window, &y_window);
567   *x += x_window;
568   *y += y_window;
569
570   if (coord_type == ATK_XY_WINDOW)
571     {
572       window = gdk_window_get_toplevel (gtk_widget_get_window (widget));
573       gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
574
575       *x -= x_toplevel;
576       *y -= y_toplevel;
577     }
578 }
579
580 static void
581 gtk_widget_accessible_get_size (AtkComponent *component,
582                                 gint         *width,
583                                 gint         *height)
584 {
585   GtkWidget *widget;
586
587   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
588   if (widget == NULL)
589     return;
590
591   *width = gtk_widget_get_allocated_width (widget);
592   *height = gtk_widget_get_allocated_height (widget);
593 }
594
595 static AtkLayer
596 gtk_widget_accessible_get_layer (AtkComponent *component)
597 {
598   GtkWidgetAccessible *accessible = GTK_WIDGET_ACCESSIBLE (component);
599
600   return accessible->layer;
601 }
602
603 static gboolean
604 gtk_widget_accessible_grab_focus (AtkComponent *component)
605 {
606   GtkWidget *widget;
607   GtkWidget *toplevel;
608
609   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
610   if (!widget)
611     return FALSE;
612
613   if (!gtk_widget_get_can_focus (widget))
614     return FALSE;
615
616   gtk_widget_grab_focus (widget);
617   toplevel = gtk_widget_get_toplevel (widget);
618   if (gtk_widget_is_toplevel (toplevel))
619     {
620 #ifdef GDK_WINDOWING_X11
621       gtk_window_present_with_time (GTK_WINDOW (toplevel),
622       gdk_x11_get_server_time (gtk_widget_get_window (widget)));
623 #else
624       gtk_window_present (GTK_WINDOW (toplevel));
625 #endif
626     }
627   return TRUE;
628 }
629
630 static gboolean
631 gtk_widget_accessible_set_extents (AtkComponent *component,
632                                    gint          x,
633                                    gint          y,
634                                    gint          width,
635                                    gint          height,
636                                    AtkCoordType  coord_type)
637 {
638   GtkWidget *widget;
639
640   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
641   if (widget == NULL)
642     return FALSE;
643
644   if (!gtk_widget_is_toplevel (widget))
645     return FALSE;
646
647   if (coord_type == ATK_XY_WINDOW)
648     {
649       gint x_current, y_current;
650       GdkWindow *window = gtk_widget_get_window (widget);
651
652       gdk_window_get_origin (window, &x_current, &y_current);
653       x_current += x;
654       y_current += y;
655       if (x_current < 0 || y_current < 0)
656         return FALSE;
657       else
658         {
659           gtk_window_move (GTK_WINDOW (widget), x_current, y_current);
660           gtk_widget_set_size_request (widget, width, height);
661           return TRUE;
662         }
663     }
664   else if (coord_type == ATK_XY_SCREEN)
665     {
666       gtk_window_move (GTK_WINDOW (widget), x, y);
667       gtk_widget_set_size_request (widget, width, height);
668       return TRUE;
669     }
670   return FALSE;
671 }
672
673 static gboolean
674 gtk_widget_accessible_set_position (AtkComponent *component,
675                                     gint          x,
676                                     gint          y,
677                                     AtkCoordType  coord_type)
678 {
679   GtkWidget *widget;
680
681   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
682   if (widget == NULL)
683     return FALSE;
684
685   if (gtk_widget_is_toplevel (widget))
686     {
687       if (coord_type == ATK_XY_WINDOW)
688         {
689           gint x_current, y_current;
690           GdkWindow *window = gtk_widget_get_window (widget);
691
692           gdk_window_get_origin (window, &x_current, &y_current);
693           x_current += x;
694           y_current += y;
695           if (x_current < 0 || y_current < 0)
696             return FALSE;
697           else
698             {
699               gtk_window_move (GTK_WINDOW (widget), x_current, y_current);
700               return TRUE;
701             }
702         }
703       else if (coord_type == ATK_XY_SCREEN)
704         {
705           gtk_window_move (GTK_WINDOW (widget), x, y);
706           return TRUE;
707         }
708     }
709   return FALSE;
710 }
711
712 static gboolean
713 gtk_widget_accessible_set_size (AtkComponent *component,
714                                 gint          width,
715                                 gint          height)
716 {
717   GtkWidget *widget;
718
719   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
720   if (widget == NULL)
721     return FALSE;
722
723   if (gtk_widget_is_toplevel (widget))
724     {
725       gtk_widget_set_size_request (widget, width, height);
726       return TRUE;
727     }
728   else
729    return FALSE;
730 }
731
732 static void
733 atk_component_interface_init (AtkComponentIface *iface)
734 {
735   iface->get_extents = gtk_widget_accessible_get_extents;
736   iface->get_size = gtk_widget_accessible_get_size;
737   iface->get_layer = gtk_widget_accessible_get_layer;
738   iface->grab_focus = gtk_widget_accessible_grab_focus;
739   iface->set_extents = gtk_widget_accessible_set_extents;
740   iface->set_position = gtk_widget_accessible_set_position;
741   iface->set_size = gtk_widget_accessible_set_size;
742 }
743
744 /* This function checks whether the widget has an ancestor which is
745  * a GtkViewport and, if so, whether any part of the widget intersects
746  * the visible rectangle of the GtkViewport.
747  */
748 static gboolean
749 gtk_widget_accessible_on_screen (GtkWidget *widget)
750 {
751   GtkAllocation allocation;
752   GtkWidget *viewport;
753   gboolean return_value;
754
755   gtk_widget_get_allocation (widget, &allocation);
756
757   viewport = gtk_widget_get_ancestor (widget, GTK_TYPE_VIEWPORT);
758   if (viewport)
759     {
760       GtkAllocation viewport_allocation;
761       GtkAdjustment *adjustment;
762       GdkRectangle visible_rect;
763
764       gtk_widget_get_allocation (viewport, &viewport_allocation);
765
766       adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (viewport));
767       visible_rect.y = gtk_adjustment_get_value (adjustment);
768       adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (viewport));
769       visible_rect.x = gtk_adjustment_get_value (adjustment);
770       visible_rect.width = viewport_allocation.width;
771       visible_rect.height = viewport_allocation.height;
772
773       if (((allocation.x + allocation.width) < visible_rect.x) ||
774          ((allocation.y + allocation.height) < visible_rect.y) ||
775          (allocation.x > (visible_rect.x + visible_rect.width)) ||
776          (allocation.y > (visible_rect.y + visible_rect.height)))
777         return_value = FALSE;
778       else
779         return_value = TRUE;
780     }
781   else
782     {
783       /* Check whether the widget has been placed of the screen.
784        * The widget may be MAPPED as when toolbar items do not
785        * fit on the toolbar.
786        */
787       if (allocation.x + allocation.width <= 0 &&
788           allocation.y + allocation.height <= 0)
789         return_value = FALSE;
790       else
791         return_value = TRUE;
792     }
793
794   return return_value;
795 }
796
797 /* Checks if all the predecessors (the parent widget, his parent, etc)
798  * are visible Used to check properly the SHOWING state.
799  */
800 static gboolean
801 gtk_widget_accessible_all_parents_visible (GtkWidget *widget)
802 {
803   GtkWidget *iter_parent = NULL;
804   gboolean result = TRUE;
805
806   for (iter_parent = gtk_widget_get_parent (widget); iter_parent;
807        iter_parent = gtk_widget_get_parent (iter_parent))
808     {
809       if (!gtk_widget_get_visible (iter_parent))
810         {
811           result = FALSE;
812           break;
813         }
814     }
815
816   return result;
817 }