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