]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailwidget.c
Makefile.am add GTK_DISABLE_DEPRECATED to CFLAGS.
[~andy/gtk] / modules / other / gail / gailwidget.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 #undef GTK_DISABLE_DEPRECATED
25
26 #include <gtk/gtk.h>
27 #ifdef GDK_WINDOWING_X11
28 #include <gdk/x11/gdkx.h>
29 #endif
30 #include "gailwidget.h"
31 #include "gailnotebookpage.h"
32 #include "gail-private-macros.h"
33
34 extern GtkWidget *focus_widget;
35
36 static void gail_widget_class_init (GailWidgetClass *klass);
37 static void gail_widget_init                     (GailWidget       *accessible);
38 static void gail_widget_connect_widget_destroyed (GtkAccessible    *accessible);
39 static void gail_widget_destroyed                (GtkWidget        *widget,
40                                                   GtkAccessible    *accessible);
41
42 static G_CONST_RETURN gchar* gail_widget_get_description (AtkObject *accessible);
43 static AtkObject* gail_widget_get_parent (AtkObject *accessible);
44 static AtkStateSet* gail_widget_ref_state_set (AtkObject *accessible);
45 static AtkRelationSet* gail_widget_ref_relation_set (AtkObject *accessible);
46 static gint gail_widget_get_index_in_parent (AtkObject *accessible);
47
48 static void atk_component_interface_init (AtkComponentIface *iface);
49
50 static guint    gail_widget_add_focus_handler
51                                            (AtkComponent    *component,
52                                             AtkFocusHandler handler);
53
54 static void     gail_widget_get_extents    (AtkComponent    *component,
55                                             gint            *x,
56                                             gint            *y,
57                                             gint            *width,
58                                             gint            *height,
59                                             AtkCoordType    coord_type);
60
61 static void     gail_widget_get_size       (AtkComponent    *component,
62                                             gint            *width,
63                                             gint            *height);
64
65 static AtkLayer gail_widget_get_layer      (AtkComponent *component);
66
67 static gboolean gail_widget_grab_focus     (AtkComponent    *component);
68
69
70 static void     gail_widget_remove_focus_handler 
71                                            (AtkComponent    *component,
72                                             guint           handler_id);
73
74 static gboolean gail_widget_set_extents    (AtkComponent    *component,
75                                             gint            x,
76                                             gint            y,
77                                             gint            width,
78                                             gint            height,
79                                             AtkCoordType    coord_type);
80
81 static gboolean gail_widget_set_position   (AtkComponent    *component,
82                                             gint            x,
83                                             gint            y,
84                                             AtkCoordType    coord_type);
85
86 static gboolean gail_widget_set_size       (AtkComponent    *component,
87                                             gint            width,
88                                             gint            height);
89
90 static gint       gail_widget_map_gtk            (GtkWidget     *widget);
91 static void       gail_widget_real_notify_gtk    (GObject       *obj,
92                                                   GParamSpec    *pspec);
93 static void       gail_widget_notify_gtk         (GObject       *obj,
94                                                   GParamSpec    *pspec);
95 static gboolean   gail_widget_focus_gtk          (GtkWidget     *widget,
96                                                   GdkEventFocus *event);
97 static gboolean   gail_widget_real_focus_gtk     (GtkWidget     *widget,
98                                                   GdkEventFocus *event);
99 static void       gail_widget_size_allocate_gtk  (GtkWidget     *widget,
100                                                   GtkAllocation *allocation);
101
102 static void       gail_widget_focus_event        (AtkObject     *obj,
103                                                   gboolean      focus_in);
104
105 static void       gail_widget_real_initialize    (AtkObject     *obj,
106                                                   gpointer      data);
107 static GtkWidget* gail_widget_find_viewport      (GtkWidget     *widget);
108 static gboolean   gail_widget_on_screen          (GtkWidget     *widget);
109
110 G_DEFINE_TYPE_WITH_CODE (GailWidget, gail_widget, GTK_TYPE_ACCESSIBLE,
111                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init))
112
113 static void
114 gail_widget_class_init (GailWidgetClass *klass)
115 {
116   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
117   GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
118
119   klass->notify_gtk = gail_widget_real_notify_gtk;
120   klass->focus_gtk = gail_widget_real_focus_gtk;
121
122   accessible_class->connect_widget_destroyed = gail_widget_connect_widget_destroyed;
123
124   class->get_description = gail_widget_get_description;
125   class->get_parent = gail_widget_get_parent;
126   class->ref_relation_set = gail_widget_ref_relation_set;
127   class->ref_state_set = gail_widget_ref_state_set;
128   class->get_index_in_parent = gail_widget_get_index_in_parent;
129   class->initialize = gail_widget_real_initialize;
130 }
131
132 static void
133 gail_widget_init (GailWidget *accessible)
134 {
135 }
136
137 /**
138  * This function  specifies the GtkWidget for which the GailWidget was created 
139  * and specifies a handler to be called when the GtkWidget is destroyed.
140  **/
141 static void 
142 gail_widget_real_initialize (AtkObject *obj,
143                              gpointer  data)
144 {
145   GtkAccessible *accessible;
146   GtkWidget *widget;
147
148   g_return_if_fail (GTK_IS_WIDGET (data));
149
150   widget = GTK_WIDGET (data);
151
152   accessible = GTK_ACCESSIBLE (obj);
153   accessible->widget = widget;
154   gtk_accessible_connect_widget_destroyed (accessible);
155   g_signal_connect_after (widget,
156                           "focus-in-event",
157                           G_CALLBACK (gail_widget_focus_gtk),
158                           NULL);
159   g_signal_connect_after (widget,
160                           "focus-out-event",
161                           G_CALLBACK (gail_widget_focus_gtk),
162                           NULL);
163   g_signal_connect (widget,
164                     "notify",
165                     G_CALLBACK (gail_widget_notify_gtk),
166                     NULL);
167   g_signal_connect (widget,
168                     "size_allocate",
169                     G_CALLBACK (gail_widget_size_allocate_gtk),
170                     NULL);
171   atk_component_add_focus_handler (ATK_COMPONENT (accessible),
172                                    gail_widget_focus_event);
173   /*
174    * Add signal handlers for GTK signals required to support property changes
175    */
176   g_signal_connect (widget,
177                     "map",
178                     G_CALLBACK (gail_widget_map_gtk),
179                     NULL);
180   g_signal_connect (widget,
181                     "unmap",
182                     G_CALLBACK (gail_widget_map_gtk),
183                     NULL);
184   g_object_set_data (G_OBJECT (obj), "atk-component-layer",
185                      GINT_TO_POINTER (ATK_LAYER_WIDGET));
186
187   obj->role = ATK_ROLE_UNKNOWN;
188 }
189
190 AtkObject* 
191 gail_widget_new (GtkWidget *widget)
192 {
193   GObject *object;
194   AtkObject *accessible;
195
196   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
197
198   object = g_object_new (GAIL_TYPE_WIDGET, NULL);
199
200   accessible = ATK_OBJECT (object);
201   atk_object_initialize (accessible, widget);
202
203   return accessible;
204 }
205
206 /*
207  * This function specifies the function to be called when the widget
208  * is destroyed
209  */
210 static void
211 gail_widget_connect_widget_destroyed (GtkAccessible *accessible)
212 {
213   if (accessible->widget)
214     {
215       g_signal_connect_after (accessible->widget,
216                               "destroy",
217                               G_CALLBACK (gail_widget_destroyed),
218                               accessible);
219     }
220 }
221
222 /*
223  * This function is called when the widget is destroyed.
224  * It sets the widget field in the GtkAccessible structure to NULL
225  * and emits a state-change signal for the state ATK_STATE_DEFUNCT
226  */
227 static void 
228 gail_widget_destroyed (GtkWidget     *widget,
229                        GtkAccessible *accessible)
230 {
231   accessible->widget = NULL;
232   atk_object_notify_state_change (ATK_OBJECT (accessible), ATK_STATE_DEFUNCT,
233                                   TRUE);
234 }
235
236 static G_CONST_RETURN gchar*
237 gail_widget_get_description (AtkObject *accessible)
238 {
239   if (accessible->description)
240     return accessible->description;
241   else
242     {
243       /* Get the tooltip from the widget */
244       GtkAccessible *obj = GTK_ACCESSIBLE (accessible);
245       GtkTooltipsData *data;
246
247       gail_return_val_if_fail (obj, NULL);
248
249       if (obj->widget == NULL)
250         /*
251          * Object is defunct
252          */
253         return NULL;
254  
255       gail_return_val_if_fail (GTK_WIDGET (obj->widget), NULL);
256     
257       data = gtk_tooltips_data_get (obj->widget);
258       if (data == NULL)
259         return NULL;
260
261       return data->tip_text;
262     }
263 }
264
265 static AtkObject* 
266 gail_widget_get_parent (AtkObject *accessible)
267 {
268   AtkObject *parent;
269
270   parent = accessible->accessible_parent;
271
272   if (parent != NULL)
273     g_return_val_if_fail (ATK_IS_OBJECT (parent), NULL);
274   else
275     {
276       GtkWidget *widget, *parent_widget;
277
278       widget = GTK_ACCESSIBLE (accessible)->widget;
279       if (widget == NULL)
280         /*
281          * State is defunct
282          */
283         return NULL;
284       gail_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
285
286       parent_widget = widget->parent;
287       if (parent_widget == NULL)
288         return NULL;
289
290       /*
291        * For a widget whose parent is a GtkNoteBook, we return the
292        * accessible object corresponding the GtkNotebookPage containing
293        * the widget as the accessible parent.
294        */
295       if (GTK_IS_NOTEBOOK (parent_widget))
296         {
297           gint page_num;
298           GtkWidget *child;
299           GtkNotebook *notebook;
300
301           page_num = 0;
302           notebook = GTK_NOTEBOOK (parent_widget);
303           while (TRUE)
304             {
305               child = gtk_notebook_get_nth_page (notebook, page_num);
306               if (!child)
307                 break;
308               if (child == widget)
309                 {
310                   parent = gtk_widget_get_accessible (parent_widget);
311                   parent = atk_object_ref_accessible_child (parent, page_num);
312                   g_object_unref (parent);
313                   return parent;
314                 }
315               page_num++;
316             }
317         }
318
319       parent = gtk_widget_get_accessible (parent_widget);
320     }
321   return parent;
322 }
323
324 static GtkWidget*
325 find_label (GtkWidget *widget)
326 {
327   GList *labels;
328   GtkWidget *label;
329   GtkWidget *temp_widget;
330
331   labels = gtk_widget_list_mnemonic_labels (widget);
332   label = NULL;
333   if (labels)
334     {
335       if (labels->data)
336         {
337           if (labels->next)
338             {
339               g_warning ("Widget (%s) has more than one label", G_OBJECT_TYPE_NAME (widget));
340               
341             }
342           else
343             {
344               label = labels->data;
345             }
346         }
347       g_list_free (labels);
348     }
349
350   /*
351    * Ignore a label within a button; bug #136602
352    */
353   if (label && GTK_IS_BUTTON (widget))
354     {
355       temp_widget = label;
356       while (temp_widget)
357         {
358           if (temp_widget == widget)
359             {
360               label = NULL;
361               break;
362             }
363           temp_widget = gtk_widget_get_parent (temp_widget);
364         }
365     } 
366   return label;
367 }
368
369 static AtkRelationSet*
370 gail_widget_ref_relation_set (AtkObject *obj)
371 {
372   GtkWidget *widget;
373   AtkRelationSet *relation_set;
374   GtkWidget *label;
375   AtkObject *array[1];
376   AtkRelation* relation;
377
378   gail_return_val_if_fail (GAIL_IS_WIDGET (obj), NULL);
379
380   widget = GTK_ACCESSIBLE (obj)->widget;
381   if (widget == NULL)
382     /*
383      * State is defunct
384      */
385     return NULL;
386
387   relation_set = ATK_OBJECT_CLASS (gail_widget_parent_class)->ref_relation_set (obj);
388
389   if (GTK_IS_BOX (widget) && !GTK_IS_COMBO (widget))
390       /*
391        * Do not report labelled-by for a GtkBox which could be a 
392        * GnomeFileEntry.
393        */
394     return relation_set;
395
396   if (!atk_relation_set_contains (relation_set, ATK_RELATION_LABELLED_BY))
397     {
398       label = find_label (widget);
399       if (label == NULL)
400         {
401           if (GTK_IS_BUTTON (widget))
402             /*
403              * Handle the case where GnomeIconEntry is the mnemonic widget.
404              * The GtkButton which is a grandchild of the GnomeIconEntry
405              * should really be the mnemonic widget. See bug #133967.
406              */
407             {
408               GtkWidget *temp_widget;
409
410               temp_widget = gtk_widget_get_parent (widget);
411
412               if (GTK_IS_ALIGNMENT (temp_widget))
413                 {
414                   temp_widget = gtk_widget_get_parent (temp_widget);
415                   if (GTK_IS_BOX (temp_widget))
416                     {
417                       label = find_label (temp_widget);
418                  
419                       if (!label)
420                         label = find_label (gtk_widget_get_parent (temp_widget));
421                     }
422                 }
423             }
424           else if (GTK_IS_COMBO (widget))
425             /*
426              * Handle the case when GnomeFileEntry is the mnemonic widget.
427              * The GnomeEntry which is a grandchild of the GnomeFileEntry
428              * should be the mnemonic widget. See bug #137584.
429              */
430             {
431               GtkWidget *temp_widget;
432
433               temp_widget = gtk_widget_get_parent (widget);
434
435               if (GTK_IS_HBOX (temp_widget))
436                 {
437                   temp_widget = gtk_widget_get_parent (temp_widget);
438                   if (GTK_IS_BOX (temp_widget))
439                     {
440                       label = find_label (temp_widget);
441                     }
442                 }
443             }
444           else if (GTK_IS_COMBO_BOX (widget))
445             /*
446              * Handle the case when GtkFileChooserButton is the mnemonic
447              * widget.  The GtkComboBox which is a child of the
448              * GtkFileChooserButton should be the mnemonic widget.
449              * See bug #359843.
450              */
451             {
452               GtkWidget *temp_widget;
453
454               temp_widget = gtk_widget_get_parent (widget);
455               if (GTK_IS_HBOX (temp_widget))
456                 {
457                   label = find_label (temp_widget);
458                 }
459             }
460         }
461
462       if (label)
463         {
464           array [0] = gtk_widget_get_accessible (label);
465
466           relation = atk_relation_new (array, 1, ATK_RELATION_LABELLED_BY);
467           atk_relation_set_add (relation_set, relation);
468           g_object_unref (relation);
469         }
470     }
471
472   return relation_set;
473 }
474
475 static AtkStateSet*
476 gail_widget_ref_state_set (AtkObject *accessible)
477 {
478   GtkWidget *widget = GTK_ACCESSIBLE (accessible)->widget;
479   AtkStateSet *state_set;
480
481   state_set = ATK_OBJECT_CLASS (gail_widget_parent_class)->ref_state_set (accessible);
482
483   if (widget == NULL)
484     {
485       atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
486     }
487   else
488     {
489       if (GTK_WIDGET_IS_SENSITIVE (widget))
490         {
491           atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
492           atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
493         }
494   
495       if (GTK_WIDGET_CAN_FOCUS (widget))
496         {
497           atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
498         }
499       /*
500        * We do not currently generate notifications when an ATK object 
501        * corresponding to a GtkWidget changes visibility by being scrolled 
502        * on or off the screen.  The testcase for this is the main window 
503        * of the testgtk application in which a set of buttons in a GtkVBox 
504        * is in a scrooled window with a viewport.
505        *
506        * To generate the notifications we would need to do the following: 
507        * 1) Find the GtkViewPort among the antecendents of the objects
508        * 2) Create an accesible for the GtkViewPort
509        * 3) Connect to the value-changed signal on the viewport
510        * 4) When the signal is received we need to traverse the children 
511        * of the viewport and check whether the children are visible or not 
512        * visible; we may want to restrict this to the widgets for which 
513        * accessible objects have been created.
514        * 5) We probably need to store a variable on_screen in the 
515        * GailWidget data structure so we can determine whether the value has 
516        * changed.
517        */
518       if (GTK_WIDGET_VISIBLE (widget))
519         {
520           atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
521           if (gail_widget_on_screen (widget) &&
522               GTK_WIDGET_MAPPED (widget))
523             {
524               atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
525             }
526         }
527   
528       if (GTK_WIDGET_HAS_FOCUS (widget) && (widget == focus_widget))
529         {
530           AtkObject *focus_obj;
531
532           focus_obj = g_object_get_data (G_OBJECT (accessible), "gail-focus-object");
533           if (focus_obj == NULL)
534             atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
535         }
536       if (GTK_WIDGET_HAS_DEFAULT(widget))
537         {
538           atk_state_set_add_state (state_set, ATK_STATE_DEFAULT);
539         }
540     }
541   return state_set;
542 }
543
544 static gint
545 gail_widget_get_index_in_parent (AtkObject *accessible)
546 {
547   GtkWidget *widget;
548   GtkWidget *parent_widget;
549   gint index;
550   GList *children;
551   GType type;
552
553   type = g_type_from_name ("GailCanvasWidget");
554   widget = GTK_ACCESSIBLE (accessible)->widget;
555
556   if (widget == NULL)
557     /*
558      * State is defunct
559      */
560     return -1;
561
562   if (accessible->accessible_parent)
563     {
564       AtkObject *parent;
565
566       parent = accessible->accessible_parent;
567
568       if (GAIL_IS_NOTEBOOK_PAGE (parent) ||
569           G_TYPE_CHECK_INSTANCE_TYPE ((parent), type))
570         return 0;
571       else
572         {
573           gint n_children, i;
574           gboolean found = FALSE;
575
576           n_children = atk_object_get_n_accessible_children (parent);
577           for (i = 0; i < n_children; i++)
578             {
579               AtkObject *child;
580
581               child = atk_object_ref_accessible_child (parent, i);
582               if (child == accessible)
583                 found = TRUE;
584
585               g_object_unref (child); 
586               if (found)
587                 return i;
588             }
589         }
590     }
591
592   gail_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
593   parent_widget = widget->parent;
594   if (parent_widget == NULL)
595     return -1;
596   gail_return_val_if_fail (GTK_IS_CONTAINER (parent_widget), -1);
597
598   children = gtk_container_get_children (GTK_CONTAINER (parent_widget));
599
600   index = g_list_index (children, widget);
601   g_list_free (children);
602   return index;  
603 }
604
605 static void 
606 atk_component_interface_init (AtkComponentIface *iface)
607 {
608   /*
609    * Use default implementation for contains and get_position
610    */
611   iface->add_focus_handler = gail_widget_add_focus_handler;
612   iface->get_extents = gail_widget_get_extents;
613   iface->get_size = gail_widget_get_size;
614   iface->get_layer = gail_widget_get_layer;
615   iface->grab_focus = gail_widget_grab_focus;
616   iface->remove_focus_handler = gail_widget_remove_focus_handler;
617   iface->set_extents = gail_widget_set_extents;
618   iface->set_position = gail_widget_set_position;
619   iface->set_size = gail_widget_set_size;
620 }
621
622 static guint 
623 gail_widget_add_focus_handler (AtkComponent    *component,
624                                AtkFocusHandler handler)
625 {
626   GSignalMatchType match_type;
627   gulong ret;
628   guint signal_id;
629
630   match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
631   signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
632
633   ret = g_signal_handler_find (component, match_type, signal_id, 0, NULL,
634                                (gpointer) handler, NULL);
635   if (!ret)
636     {
637       return g_signal_connect_closure_by_id (component, 
638                                              signal_id, 0,
639                                              g_cclosure_new (
640                                              G_CALLBACK (handler), NULL,
641                                              (GClosureNotify) NULL),
642                                              FALSE);
643     }
644   else
645     {
646       return 0;
647     }
648 }
649
650 static void 
651 gail_widget_get_extents (AtkComponent   *component,
652                          gint           *x,
653                          gint           *y,
654                          gint           *width,
655                          gint           *height,
656                          AtkCoordType   coord_type)
657 {
658   GdkWindow *window;
659   gint x_window, y_window;
660   gint x_toplevel, y_toplevel;
661   GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
662
663   if (widget == NULL)
664     /*
665      * Object is defunct
666      */
667     return;
668
669   gail_return_if_fail (GTK_IS_WIDGET (widget));
670
671   *width = widget->allocation.width;
672   *height = widget->allocation.height;
673   if (!gail_widget_on_screen (widget) || (!GTK_WIDGET_DRAWABLE (widget)))
674     {
675       *x = G_MININT;
676       *y = G_MININT;
677       return;
678     }
679
680   if (widget->parent)
681     {
682       *x = widget->allocation.x;
683       *y = widget->allocation.y;
684       window = gtk_widget_get_parent_window (widget);
685     }
686   else
687     {
688       *x = 0;
689       *y = 0;
690       window = widget->window;
691     }
692   gdk_window_get_origin (window, &x_window, &y_window);
693   *x += x_window;
694   *y += y_window;
695
696  
697  if (coord_type == ATK_XY_WINDOW) 
698     { 
699       window = gdk_window_get_toplevel (widget->window);
700       gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
701
702       *x -= x_toplevel;
703       *y -= y_toplevel;
704     }
705 }
706
707 static void 
708 gail_widget_get_size (AtkComponent   *component,
709                       gint           *width,
710                       gint           *height)
711 {
712   GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
713
714   if (widget == NULL)
715     /*
716      * Object is defunct
717      */
718     return;
719
720   gail_return_if_fail (GTK_IS_WIDGET (widget));
721
722   *width = widget->allocation.width;
723   *height = widget->allocation.height;
724 }
725
726 static AtkLayer
727 gail_widget_get_layer (AtkComponent *component)
728 {
729   gint layer;
730   layer = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (component), "atk-component-layer"));
731
732   return (AtkLayer) layer;
733 }
734
735 static gboolean 
736 gail_widget_grab_focus (AtkComponent   *component)
737 {
738   GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
739   GtkWidget *toplevel;
740
741   gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
742   if (GTK_WIDGET_CAN_FOCUS (widget))
743     {
744       gtk_widget_grab_focus (widget);
745       toplevel = gtk_widget_get_toplevel (widget);
746       if (GTK_WIDGET_TOPLEVEL (toplevel))
747         {
748 #ifdef GDK_WINDOWING_X11
749           gtk_window_present_with_time (GTK_WINDOW (toplevel), gdk_x11_get_server_time (widget->window));
750 #else
751           gtk_window_present (GTK_WINDOW (toplevel));
752 #endif
753         }
754       return TRUE;
755     }
756   else
757     return FALSE;
758 }
759
760 static void 
761 gail_widget_remove_focus_handler (AtkComponent   *component,
762                                   guint          handler_id)
763 {
764   g_signal_handler_disconnect (component, handler_id);
765 }
766
767 static gboolean 
768 gail_widget_set_extents (AtkComponent   *component,
769                          gint           x,
770                          gint           y,
771                          gint           width,
772                          gint           height,
773                          AtkCoordType   coord_type)
774 {
775   GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
776
777   if (widget == NULL)
778     /*
779      * Object is defunct
780      */
781     return FALSE;
782   gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
783
784   if (GTK_WIDGET_TOPLEVEL (widget))
785     {
786       if (coord_type == ATK_XY_WINDOW)
787         {
788           gint x_current, y_current;
789           GdkWindow *window = widget->window;
790
791           gdk_window_get_origin (window, &x_current, &y_current);
792           x_current += x;
793           y_current += y;
794           if (x_current < 0 || y_current < 0)
795             return FALSE;
796           else
797             {
798               gtk_widget_set_uposition (widget, x_current, y_current);
799               gtk_widget_set_size_request (widget, width, height);
800               return TRUE;
801             }
802         }
803       else if (coord_type == ATK_XY_SCREEN)
804         {  
805           gtk_widget_set_uposition (widget, x, y);
806           gtk_widget_set_size_request (widget, width, height);
807           return TRUE;
808         }
809     }
810   return FALSE;
811 }
812
813 static gboolean
814 gail_widget_set_position (AtkComponent   *component,
815                           gint           x,
816                           gint           y,
817                           AtkCoordType   coord_type)
818 {
819   GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
820
821   if (widget == NULL)
822     /*
823      * Object is defunct
824      */
825     return FALSE;
826   gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
827
828   if (GTK_WIDGET_TOPLEVEL (widget))
829     {
830       if (coord_type == ATK_XY_WINDOW)
831         {
832           gint x_current, y_current;
833           GdkWindow *window = widget->window;
834
835           gdk_window_get_origin (window, &x_current, &y_current);
836           x_current += x;
837           y_current += y;
838           if (x_current < 0 || y_current < 0)
839             return FALSE;
840           else
841             {
842               gtk_widget_set_uposition (widget, x_current, y_current);
843               return TRUE;
844             }
845         }
846       else if (coord_type == ATK_XY_SCREEN)
847         {  
848           gtk_widget_set_uposition (widget, x, y);
849           return TRUE;
850         }
851     }
852   return FALSE;
853 }
854
855 static gboolean 
856 gail_widget_set_size (AtkComponent   *component,
857                       gint           width,
858                       gint           height)
859 {
860   GtkWidget *widget = GTK_ACCESSIBLE (component)->widget;
861
862   if (widget == NULL)
863     /*
864      * Object is defunct
865      */
866     return FALSE;
867   gail_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
868
869   if (GTK_WIDGET_TOPLEVEL (widget))
870     {
871       gtk_widget_set_size_request (widget, width, height);
872       return TRUE;
873     }
874   else
875    return FALSE;
876 }
877
878 /*
879  * This function is a signal handler for notify_in_event and focus_out_event
880  * signal which gets emitted on a GtkWidget.
881  */
882 static gboolean
883 gail_widget_focus_gtk (GtkWidget     *widget,
884                        GdkEventFocus *event)
885 {
886   GailWidget *gail_widget;
887   GailWidgetClass *klass;
888
889   gail_widget = GAIL_WIDGET (gtk_widget_get_accessible (widget));
890   klass = GAIL_WIDGET_GET_CLASS (gail_widget);
891   if (klass->focus_gtk)
892     return klass->focus_gtk (widget, event);
893   else
894     return FALSE;
895 }
896
897 /*
898  * This function is the signal handler defined for focus_in_event and
899  * focus_out_event got GailWidget.
900  *
901  * It emits a focus-event signal on the GailWidget.
902  */
903 static gboolean
904 gail_widget_real_focus_gtk (GtkWidget     *widget,
905                             GdkEventFocus *event)
906 {
907   AtkObject* accessible;
908   gboolean return_val;
909   return_val = FALSE;
910
911   accessible = gtk_widget_get_accessible (widget);
912   g_signal_emit_by_name (accessible, "focus_event", event->in, &return_val);
913   return FALSE;
914 }
915
916 static void
917 gail_widget_size_allocate_gtk (GtkWidget     *widget,
918                                GtkAllocation *allocation)
919 {
920   AtkObject* accessible;
921   AtkRectangle rect;
922
923   accessible = gtk_widget_get_accessible (widget);
924   if (ATK_IS_COMPONENT (accessible))
925     {
926       rect.x = allocation->x;
927       rect.y = allocation->y;
928       rect.width = allocation->width;
929       rect.height = allocation->height;
930       g_signal_emit_by_name (accessible, "bounds_changed", &rect);
931     }
932 }
933
934 /*
935  * This function is the signal handler defined for map and unmap signals.
936  */
937 static gint
938 gail_widget_map_gtk (GtkWidget     *widget)
939 {
940   AtkObject* accessible;
941
942   accessible = gtk_widget_get_accessible (widget);
943   atk_object_notify_state_change (accessible, ATK_STATE_SHOWING,
944                                   GTK_WIDGET_MAPPED (widget));
945   return 1;
946 }
947
948 /*
949  * This function is a signal handler for notify signal which gets emitted 
950  * when a property changes value on the GtkWidget associated with the object.
951  *
952  * It calls a function for the GailWidget type
953  */
954 static void 
955 gail_widget_notify_gtk (GObject     *obj,
956                         GParamSpec  *pspec)
957 {
958   GailWidget *widget;
959   GailWidgetClass *klass;
960
961   widget = GAIL_WIDGET (gtk_widget_get_accessible (GTK_WIDGET (obj)));
962   klass = GAIL_WIDGET_GET_CLASS (widget);
963   if (klass->notify_gtk)
964     klass->notify_gtk (obj, pspec);
965 }
966
967 /*
968  * This function is a signal handler for notify signal which gets emitted 
969  * when a property changes value on the GtkWidget associated with a GailWidget.
970  *
971  * It constructs an AtkPropertyValues structure and emits a "property_changed"
972  * signal which causes the user specified AtkPropertyChangeHandler
973  * to be called.
974  */
975 static void 
976 gail_widget_real_notify_gtk (GObject     *obj,
977                              GParamSpec  *pspec)
978 {
979   GtkWidget* widget = GTK_WIDGET (obj);
980   AtkObject* atk_obj = gtk_widget_get_accessible (widget);
981   AtkState state;
982   gboolean value;
983
984   if (strcmp (pspec->name, "has-focus") == 0)
985     /*
986      * We use focus-in-event and focus-out-event signals to catch
987      * focus changes so we ignore this.
988      */
989     return;
990   else if (strcmp (pspec->name, "visible") == 0)
991     {
992       state = ATK_STATE_VISIBLE;
993       value = GTK_WIDGET_VISIBLE (widget);
994     }
995   else if (strcmp (pspec->name, "sensitive") == 0)
996     {
997       state = ATK_STATE_SENSITIVE;
998       value = GTK_WIDGET_SENSITIVE (widget);
999     }
1000   else
1001     return;
1002
1003   atk_object_notify_state_change (atk_obj, state, value);
1004 }
1005
1006 static void 
1007 gail_widget_focus_event (AtkObject   *obj,
1008                          gboolean    focus_in)
1009 {
1010   AtkObject *focus_obj;
1011
1012   focus_obj = g_object_get_data (G_OBJECT (obj), "gail-focus-object");
1013   if (focus_obj == NULL)
1014     focus_obj = obj;
1015   atk_object_notify_state_change (focus_obj, ATK_STATE_FOCUSED, focus_in);
1016 }
1017
1018 static GtkWidget*
1019 gail_widget_find_viewport (GtkWidget *widget)
1020 {
1021   /*
1022    * Find an antecedent which is a GtkViewPort
1023    */
1024   GtkWidget *parent;
1025
1026   parent = widget->parent;
1027   while (parent != NULL)
1028     {
1029       if (GTK_IS_VIEWPORT (parent))
1030         break;
1031       parent = parent->parent;
1032     }
1033   return parent;
1034 }
1035
1036 /*
1037  * This function checks whether the widget has an antecedent which is 
1038  * a GtkViewport and, if so, whether any part of the widget intersects
1039  * the visible rectangle of the GtkViewport.
1040  */ 
1041 static gboolean gail_widget_on_screen (GtkWidget *widget)
1042 {
1043   GtkWidget *viewport;
1044   gboolean return_value;
1045
1046   viewport = gail_widget_find_viewport (widget);
1047   if (viewport)
1048     {
1049       GtkAdjustment *adjustment;
1050       GdkRectangle visible_rect;
1051
1052       adjustment = gtk_viewport_get_vadjustment (GTK_VIEWPORT (viewport));
1053       visible_rect.y = adjustment->value;
1054       adjustment = gtk_viewport_get_hadjustment (GTK_VIEWPORT (viewport));
1055       visible_rect.x = adjustment->value;
1056       visible_rect.width = viewport->allocation.width;
1057       visible_rect.height = viewport->allocation.height;
1058              
1059       if (((widget->allocation.x + widget->allocation.width) < visible_rect.x) ||
1060          ((widget->allocation.y + widget->allocation.height) < visible_rect.y) ||
1061          (widget->allocation.x > (visible_rect.x + visible_rect.width)) ||
1062          (widget->allocation.y > (visible_rect.y + visible_rect.height)))
1063         return_value = FALSE;
1064       else
1065         return_value = TRUE;
1066     }
1067   else
1068     {
1069       /*
1070        * Check whether the widget has been placed of the screen. The
1071        * widget may be MAPPED as when toolbar items do not fit on the toolbar.
1072        */
1073       if (widget->allocation.x + widget->allocation.width <= 0 &&
1074           widget->allocation.y + widget->allocation.height <= 0)
1075         return_value = FALSE;
1076       else 
1077         return_value = TRUE;
1078     }
1079
1080   return return_value;
1081 }