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