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