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