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