]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkwindowaccessible.c
Convert GailWindow to GtkWindowAccessible
[~andy/gtk] / gtk / a11y / gtkwindowaccessible.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/gtkx.h>
25
26 #include "gtkwindowaccessible.h"
27 #include "gailtoplevel.h"
28
29 enum {
30   ACTIVATE,
31   CREATE,
32   DEACTIVATE,
33   DESTROY,
34   MAXIMIZE,
35   MINIMIZE,
36   MOVE,
37   RESIZE,
38   RESTORE,
39   LAST_SIGNAL
40 };
41
42
43 /* atkcomponent.h */
44
45 static void                  gtk_window_accessible_get_extents      (AtkComponent         *component,
46                                                            gint                 *x,
47                                                            gint                 *y,
48                                                            gint                 *width,
49                                                            gint                 *height,
50                                                            AtkCoordType         coord_type);
51 static void                  gtk_window_accessible_get_size         (AtkComponent         *component,
52                                                            gint                 *width,
53                                                            gint                 *height);
54
55 static guint gtk_window_accessible_signals [LAST_SIGNAL] = { 0, };
56
57 static void atk_component_interface_init (AtkComponentIface *iface);
58
59 G_DEFINE_TYPE_WITH_CODE (GtkWindowAccessible, gtk_window_accessible, GAIL_TYPE_CONTAINER,
60                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init))
61
62
63 static gboolean
64 gtk_window_accessible_focus_gtk (GtkWidget     *widget,
65                                  GdkEventFocus *event)
66 {
67   AtkObject* obj;
68
69   obj = gtk_widget_get_accessible (widget);
70   atk_object_notify_state_change (obj, ATK_STATE_ACTIVE, event->in);
71
72   return FALSE;
73 }
74
75 static void
76 gtk_window_accessible_notify_gtk (GObject    *obj,
77                                   GParamSpec *pspec)
78 {
79   GtkWidget *widget = GTK_WIDGET (obj);
80   AtkObject* atk_obj = gtk_widget_get_accessible (widget);
81
82   if (strcmp (pspec->name, "title") == 0)
83     {
84       g_object_notify (G_OBJECT (atk_obj), "accessible-name");
85       g_signal_emit_by_name (atk_obj, "visible_data_changed");
86     }
87   else
88     GAIL_WIDGET_CLASS (gtk_window_accessible_parent_class)->notify_gtk (obj, pspec);
89 }
90
91 static gboolean
92 window_state_event_cb (GtkWidget           *widget,
93                        GdkEventWindowState *event)
94 {
95   AtkObject* obj;
96
97   obj = gtk_widget_get_accessible (widget);
98   atk_object_notify_state_change (obj, ATK_STATE_ICONIFIED,
99                                   (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) != 0);
100
101   return FALSE;
102 }
103
104 static void
105 gtk_window_accessible_initialize (AtkObject *obj,
106                                   gpointer   data)
107 {
108   GtkWidget *widget = GTK_WIDGET (data);
109
110   /* A GtkWindowAccessible can be created for a GtkHandleBox or a GtkWindow */
111   if (!GTK_IS_WINDOW (widget) && !GTK_IS_HANDLE_BOX (widget))
112     return;
113
114   ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->initialize (obj, data);
115
116   g_signal_connect (data, "window_state_event", G_CALLBACK (window_state_event_cb), NULL);
117   g_object_set_data (G_OBJECT (obj), "atk-component-layer", GINT_TO_POINTER (ATK_LAYER_WINDOW));
118
119   if (GTK_IS_FILE_CHOOSER_DIALOG (widget))
120     obj->role = ATK_ROLE_FILE_CHOOSER;
121   else if (GTK_IS_COLOR_SELECTION_DIALOG (widget))
122     obj->role = ATK_ROLE_COLOR_CHOOSER;
123   else if (GTK_IS_FONT_SELECTION_DIALOG (widget))
124     obj->role = ATK_ROLE_FONT_CHOOSER;
125   else if (GTK_IS_MESSAGE_DIALOG (widget))
126     obj->role = ATK_ROLE_ALERT;
127   else if (GTK_IS_DIALOG (widget))
128     obj->role = ATK_ROLE_DIALOG;
129   else
130     {
131       const gchar *name;
132
133       name = gtk_widget_get_name (widget);
134
135       if (!g_strcmp0 (name, "gtk-tooltip"))
136         obj->role = ATK_ROLE_TOOL_TIP;
137 #ifdef  GDK_WINDOWING_X11
138       else if (GTK_IS_PLUG (widget))
139         obj->role = ATK_ROLE_PANEL;
140 #endif
141       else if (gtk_window_get_window_type (GTK_WINDOW (widget)) == GTK_WINDOW_POPUP)
142         obj->role = ATK_ROLE_WINDOW;
143       else
144         obj->role = ATK_ROLE_FRAME;
145     }
146
147   /* Notify that tooltip is showing */
148   if (obj->role == ATK_ROLE_TOOL_TIP && gtk_widget_get_mapped (widget))
149     atk_object_notify_state_change (obj, ATK_STATE_SHOWING, 1);
150 }
151
152 static GtkWidget *
153 find_label_child (GtkContainer *container)
154 {
155   GList *children, *tmp_list;
156   GtkWidget *child;
157
158   children = gtk_container_get_children (container);
159
160   child = NULL;
161   for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
162     {
163       if (GTK_IS_LABEL (tmp_list->data))
164         {
165           child = GTK_WIDGET (tmp_list->data);
166           break;
167         }
168       else if (GTK_IS_CONTAINER (tmp_list->data))
169         {
170           child = find_label_child (GTK_CONTAINER (tmp_list->data));
171           if (child)
172             break;
173         }
174    }
175   g_list_free (children);
176   return child;
177 }
178
179 static const gchar *
180 gtk_window_accessible_get_name (AtkObject *accessible)
181 {
182   const gchar* name;
183   GtkWidget* widget;
184
185   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
186   if (widget == NULL)
187     return NULL;
188
189   name = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->get_name (accessible);
190   if (name != NULL)
191     return name;
192
193   if (GTK_IS_WINDOW (widget))
194     {
195       GtkWindow *window = GTK_WINDOW (widget);
196
197       name = gtk_window_get_title (window);
198       if (name == NULL && accessible->role == ATK_ROLE_TOOL_TIP)
199         {
200           GtkWidget *child;
201
202           child = find_label_child (GTK_CONTAINER (window));
203           if (GTK_IS_LABEL (child))
204             name = gtk_label_get_text (GTK_LABEL (child));
205         }
206     }
207   return name;
208 }
209
210 static gint
211 gtk_window_accessible_get_index_in_parent (AtkObject *accessible)
212 {
213   GtkWidget* widget;
214   AtkObject* atk_obj;
215   gint index = -1;
216
217   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
218   if (widget == NULL)
219     return -1;
220
221   index = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->get_index_in_parent (accessible);
222   if (index != -1)
223     return index;
224
225   atk_obj = atk_get_root ();
226
227   if (GTK_IS_WINDOW (widget))
228     {
229       GtkWindow *window = GTK_WINDOW (widget);
230       if (GAIL_IS_TOPLEVEL (atk_obj))
231         {
232           GailToplevel* toplevel = GAIL_TOPLEVEL (atk_obj);
233           index = g_list_index (toplevel->window_list, window);
234         }
235       else
236         {
237           gint i, sibling_count;
238
239           sibling_count = atk_object_get_n_accessible_children (atk_obj);
240           for (i = 0; i < sibling_count && index == -1; ++i)
241             {
242               AtkObject *child = atk_object_ref_accessible_child (atk_obj, i);
243               if (accessible == child)
244                 index = i;
245               g_object_unref (G_OBJECT (child));
246             }
247         }
248     }
249   return index;
250 }
251
252 static AtkRelationSet *
253 gtk_window_accessible_ref_relation_set (AtkObject *obj)
254 {
255   GtkWidget *widget;
256   AtkRelationSet *relation_set;
257   AtkObject *array[1];
258   AtkRelation* relation;
259   GtkWidget *current_widget;
260
261   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
262   if (widget == NULL)
263     return NULL;
264
265   relation_set = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->ref_relation_set (obj);
266
267   if (atk_object_get_role (obj) == ATK_ROLE_TOOL_TIP)
268     {
269       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_POPUP_FOR);
270       if (relation)
271         atk_relation_set_remove (relation_set, relation);
272
273       if (0) /* FIXME need a way to go from tooltip window to widget */
274         {
275           array[0] = gtk_widget_get_accessible (current_widget);
276           relation = atk_relation_new (array, 1, ATK_RELATION_POPUP_FOR);
277           atk_relation_set_add (relation_set, relation);
278           g_object_unref (relation);
279         }
280     }
281   return relation_set;
282 }
283
284 static AtkStateSet *
285 gtk_window_accessible_ref_state_set (AtkObject *accessible)
286 {
287   AtkStateSet *state_set;
288   GtkWidget *widget;
289   GtkWindow *window;
290   GdkWindow *gdk_window;
291   GdkWindowState state;
292
293   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
294   if (widget == NULL)
295     return NULL;
296
297   state_set = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->ref_state_set (accessible);
298
299   window = GTK_WINDOW (widget);
300
301   if (gtk_window_has_toplevel_focus (window) && gtk_window_is_active (window))
302     atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
303
304   gdk_window = gtk_widget_get_window (widget);
305   if (window)
306     {
307       state = gdk_window_get_state (gdk_window);
308       if (state & GDK_WINDOW_STATE_ICONIFIED)
309         atk_state_set_add_state (state_set, ATK_STATE_ICONIFIED);
310     }
311   if (gtk_window_get_modal (window))
312     atk_state_set_add_state (state_set, ATK_STATE_MODAL);
313
314   if (gtk_window_get_resizable (window))
315     atk_state_set_add_state (state_set, ATK_STATE_RESIZABLE);
316
317   return state_set;
318 }
319
320 static void
321 gtk_window_accessible_class_init (GtkWindowAccessibleClass *klass)
322 {
323   GailWidgetClass *widget_class = (GailWidgetClass*)klass;
324   AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
325
326   widget_class->focus_gtk = gtk_window_accessible_focus_gtk;
327   widget_class->notify_gtk = gtk_window_accessible_notify_gtk;
328
329   class->get_name = gtk_window_accessible_get_name;
330   class->get_index_in_parent = gtk_window_accessible_get_index_in_parent;
331   class->ref_relation_set = gtk_window_accessible_ref_relation_set;
332   class->ref_state_set = gtk_window_accessible_ref_state_set;
333   class->initialize = gtk_window_accessible_initialize;
334
335   gtk_window_accessible_signals [ACTIVATE] =
336     g_signal_new ("activate",
337                   G_TYPE_FROM_CLASS (klass),
338                   G_SIGNAL_RUN_LAST,
339                   0,
340                   NULL, NULL,
341                   g_cclosure_marshal_VOID__VOID,
342                   G_TYPE_NONE, 0);
343   gtk_window_accessible_signals [CREATE] =
344     g_signal_new ("create",
345                   G_TYPE_FROM_CLASS (klass),
346                   G_SIGNAL_RUN_LAST,
347                   0,
348                   NULL, NULL,
349                   g_cclosure_marshal_VOID__VOID,
350                   G_TYPE_NONE, 0);
351   gtk_window_accessible_signals [DEACTIVATE] =
352     g_signal_new ("deactivate",
353                   G_TYPE_FROM_CLASS (klass),
354                   G_SIGNAL_RUN_LAST,
355                   0,
356                   NULL, NULL,
357                   g_cclosure_marshal_VOID__VOID,
358                   G_TYPE_NONE, 0);
359   gtk_window_accessible_signals [DESTROY] =
360     g_signal_new ("destroy",
361                   G_TYPE_FROM_CLASS (klass),
362                   G_SIGNAL_RUN_LAST,
363                   0,
364                   NULL, NULL,
365                   g_cclosure_marshal_VOID__VOID,
366                   G_TYPE_NONE, 0);
367   gtk_window_accessible_signals [MAXIMIZE] =
368     g_signal_new ("maximize",
369                   G_TYPE_FROM_CLASS (klass),
370                   G_SIGNAL_RUN_LAST,
371                   0,
372                   NULL, NULL,
373                   g_cclosure_marshal_VOID__VOID,
374                   G_TYPE_NONE, 0);
375   gtk_window_accessible_signals [MINIMIZE] =
376     g_signal_new ("minimize",
377                   G_TYPE_FROM_CLASS (klass),
378                   G_SIGNAL_RUN_LAST,
379                   0,
380                   NULL, NULL,
381                   g_cclosure_marshal_VOID__VOID,
382                   G_TYPE_NONE, 0);
383   gtk_window_accessible_signals [MOVE] =
384     g_signal_new ("move",
385                   G_TYPE_FROM_CLASS (klass),
386                   G_SIGNAL_RUN_LAST,
387                   0,
388                   NULL, NULL,
389                   g_cclosure_marshal_VOID__VOID,
390                   G_TYPE_NONE, 0);
391   gtk_window_accessible_signals [RESIZE] =
392     g_signal_new ("resize",
393                   G_TYPE_FROM_CLASS (klass),
394                   G_SIGNAL_RUN_LAST,
395                   0,
396                   NULL, NULL,
397                   g_cclosure_marshal_VOID__VOID,
398                   G_TYPE_NONE, 0);
399   gtk_window_accessible_signals [RESTORE] =
400     g_signal_new ("restore",
401                   G_TYPE_FROM_CLASS (klass),
402                   G_SIGNAL_RUN_LAST,
403                   0,
404                   NULL, NULL,
405                   g_cclosure_marshal_VOID__VOID,
406                   G_TYPE_NONE, 0);
407 }
408
409 static void
410 gtk_window_accessible_init (GtkWindowAccessible *accessible)
411 {
412 }
413
414 static void
415 gtk_window_accessible_get_extents (AtkComponent  *component,
416                                    gint          *x,
417                                    gint          *y,
418                                    gint          *width,
419                                    gint          *height,
420                                    AtkCoordType   coord_type)
421 {
422   GtkWidget *widget;
423   GdkRectangle rect;
424   gint x_toplevel, y_toplevel;
425
426   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
427   if (widget == NULL)
428     return;
429
430   if (!gtk_widget_is_toplevel (widget))
431     {
432       AtkComponentIface *parent_iface;
433
434       parent_iface = (AtkComponentIface *) g_type_interface_peek_parent (ATK_COMPONENT_GET_IFACE (component));
435       parent_iface->get_extents (component, x, y, width, height, coord_type);
436       return;
437     }
438
439   gdk_window_get_frame_extents (gtk_widget_get_window (widget), &rect);
440
441   *width = rect.width;
442   *height = rect.height;
443   if (!gtk_widget_is_drawable (widget))
444     {
445       *x = G_MININT;
446       *y = G_MININT;
447       return;
448     }
449
450   *x = rect.x;
451   *y = rect.y;
452   if (coord_type == ATK_XY_WINDOW)
453     {
454       gdk_window_get_origin (gtk_widget_get_window (widget),
455                              &x_toplevel, &y_toplevel);
456       *x -= x_toplevel;
457       *y -= y_toplevel;
458     }
459 }
460
461 static void
462 gtk_window_accessible_get_size (AtkComponent *component,
463                                 gint         *width,
464                                 gint         *height)
465 {
466   GtkWidget *widget;
467   GdkRectangle rect;
468
469   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
470   if (widget == NULL)
471     return;
472
473   if (!gtk_widget_is_toplevel (widget))
474     {
475       AtkComponentIface *parent_iface;
476
477       parent_iface = (AtkComponentIface *) g_type_interface_peek_parent (ATK_COMPONENT_GET_IFACE (component));
478       parent_iface->get_size (component, width, height);
479       return;
480     }
481
482   gdk_window_get_frame_extents (gtk_widget_get_window (widget), &rect);
483
484   *width = rect.width;
485   *height = rect.height;
486 }
487
488 static void
489 atk_component_interface_init (AtkComponentIface *iface)
490 {
491   iface->get_extents = gtk_window_accessible_get_extents;
492   iface->get_size = gtk_window_accessible_get_size;
493 }