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