]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkwindowaccessible.c
a60d499d6baa20d903333804d7ad7d29c5b37447
[~andy/gtk] / gtk / a11y / gtkwindowaccessible.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2011, F123 Consulting & Mais Diferenças
3  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include <gtk/gtk.h>
24
25 #include "gtkwindowaccessible.h"
26 #include "gtktoplevelaccessible.h"
27
28 /* atkcomponent.h */
29
30 static void                  gtk_window_accessible_get_extents      (AtkComponent         *component,
31                                                            gint                 *x,
32                                                            gint                 *y,
33                                                            gint                 *width,
34                                                            gint                 *height,
35                                                            AtkCoordType         coord_type);
36 static void                  gtk_window_accessible_get_size         (AtkComponent         *component,
37                                                            gint                 *width,
38                                                            gint                 *height);
39
40 static void atk_component_interface_init (AtkComponentIface *iface);
41 static void atk_window_interface_init (AtkWindowIface *iface);
42
43 G_DEFINE_TYPE_WITH_CODE (GtkWindowAccessible,
44                          _gtk_window_accessible,
45                          GTK_TYPE_CONTAINER_ACCESSIBLE,
46                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
47                                                 atk_component_interface_init)
48                          G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW,
49                                                 atk_window_interface_init));
50
51
52 static void
53 gtk_window_accessible_focus_event (AtkObject *obj,
54                                    gboolean   focus_in)
55 {
56   atk_object_notify_state_change (obj, ATK_STATE_ACTIVE, focus_in);
57 }
58
59 static void
60 gtk_window_accessible_notify_gtk (GObject    *obj,
61                                   GParamSpec *pspec)
62 {
63   GtkWidget *widget = GTK_WIDGET (obj);
64   AtkObject* atk_obj = gtk_widget_get_accessible (widget);
65
66   if (g_strcmp0 (pspec->name, "title") == 0)
67     {
68       g_object_notify (G_OBJECT (atk_obj), "accessible-name");
69       g_signal_emit_by_name (atk_obj, "visible-data-changed");
70     }
71   else
72     GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_window_accessible_parent_class)->notify_gtk (obj, pspec);
73 }
74
75 static gboolean
76 window_state_event_cb (GtkWidget           *widget,
77                        GdkEventWindowState *event)
78 {
79   AtkObject* obj;
80
81   obj = gtk_widget_get_accessible (widget);
82   atk_object_notify_state_change (obj, ATK_STATE_ICONIFIED,
83                                   (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) != 0);
84
85   return FALSE;
86 }
87
88 static void
89 gtk_window_accessible_initialize (AtkObject *obj,
90                                   gpointer   data)
91 {
92   GtkWidget *widget = GTK_WIDGET (data);
93   const gchar *name;
94
95   ATK_OBJECT_CLASS (_gtk_window_accessible_parent_class)->initialize (obj, data);
96
97   g_signal_connect (data, "window-state-event", G_CALLBACK (window_state_event_cb), NULL);
98   GTK_WIDGET_ACCESSIBLE (obj)->layer = ATK_LAYER_WINDOW;
99
100   name = gtk_widget_get_name (widget);
101
102   if (!g_strcmp0 (name, "gtk-tooltip"))
103     obj->role = ATK_ROLE_TOOL_TIP;
104   else if (gtk_window_get_window_type (GTK_WINDOW (widget)) == GTK_WINDOW_POPUP)
105     obj->role = ATK_ROLE_WINDOW;
106   else
107     obj->role = ATK_ROLE_FRAME;
108
109   /* Notify that tooltip is showing */
110   if (obj->role == ATK_ROLE_TOOL_TIP && gtk_widget_get_mapped (widget))
111     atk_object_notify_state_change (obj, ATK_STATE_SHOWING, 1);
112 }
113
114 static GtkWidget *
115 find_label_child (GtkContainer *container)
116 {
117   GList *children, *tmp_list;
118   GtkWidget *child;
119
120   children = gtk_container_get_children (container);
121
122   child = NULL;
123   for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
124     {
125       if (GTK_IS_LABEL (tmp_list->data))
126         {
127           child = GTK_WIDGET (tmp_list->data);
128           break;
129         }
130       else if (GTK_IS_CONTAINER (tmp_list->data))
131         {
132           child = find_label_child (GTK_CONTAINER (tmp_list->data));
133           if (child)
134             break;
135         }
136    }
137   g_list_free (children);
138   return child;
139 }
140
141 static const gchar *
142 gtk_window_accessible_get_name (AtkObject *accessible)
143 {
144   const gchar* name;
145   GtkWidget* widget;
146
147   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
148   if (widget == NULL)
149     return NULL;
150
151   name = ATK_OBJECT_CLASS (_gtk_window_accessible_parent_class)->get_name (accessible);
152   if (name != NULL)
153     return name;
154
155   if (GTK_IS_WINDOW (widget))
156     {
157       GtkWindow *window = GTK_WINDOW (widget);
158
159       name = gtk_window_get_title (window);
160       if (name == NULL && accessible->role == ATK_ROLE_TOOL_TIP)
161         {
162           GtkWidget *child;
163
164           child = find_label_child (GTK_CONTAINER (window));
165           if (GTK_IS_LABEL (child))
166             name = gtk_label_get_text (GTK_LABEL (child));
167         }
168     }
169   return name;
170 }
171
172 static gint
173 gtk_window_accessible_get_index_in_parent (AtkObject *accessible)
174 {
175   GtkWidget* widget;
176   AtkObject* atk_obj;
177   gint index = -1;
178
179   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
180   if (widget == NULL)
181     return -1;
182
183   index = ATK_OBJECT_CLASS (_gtk_window_accessible_parent_class)->get_index_in_parent (accessible);
184   if (index != -1)
185     return index;
186
187   atk_obj = atk_get_root ();
188
189   if (GTK_IS_WINDOW (widget))
190     {
191       GtkWindow *window = GTK_WINDOW (widget);
192       if (GTK_IS_TOPLEVEL_ACCESSIBLE (atk_obj))
193         {
194           GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (atk_obj);
195           index = g_list_index (toplevel->window_list, window);
196         }
197       else
198         {
199           gint i, sibling_count;
200
201           sibling_count = atk_object_get_n_accessible_children (atk_obj);
202           for (i = 0; i < sibling_count && index == -1; ++i)
203             {
204               AtkObject *child = atk_object_ref_accessible_child (atk_obj, i);
205               if (accessible == child)
206                 index = i;
207               g_object_unref (G_OBJECT (child));
208             }
209         }
210     }
211   return index;
212 }
213
214 static AtkRelationSet *
215 gtk_window_accessible_ref_relation_set (AtkObject *obj)
216 {
217   GtkWidget *widget;
218   AtkRelationSet *relation_set;
219   AtkObject *array[1];
220   AtkRelation* relation;
221   GtkWidget *current_widget;
222
223   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
224   if (widget == NULL)
225     return NULL;
226
227   relation_set = ATK_OBJECT_CLASS (_gtk_window_accessible_parent_class)->ref_relation_set (obj);
228
229   if (atk_object_get_role (obj) == ATK_ROLE_TOOL_TIP)
230     {
231       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_POPUP_FOR);
232       if (relation)
233         atk_relation_set_remove (relation_set, relation);
234
235       if (0) /* FIXME need a way to go from tooltip window to widget */
236         {
237           array[0] = gtk_widget_get_accessible (current_widget);
238           relation = atk_relation_new (array, 1, ATK_RELATION_POPUP_FOR);
239           atk_relation_set_add (relation_set, relation);
240           g_object_unref (relation);
241         }
242     }
243   return relation_set;
244 }
245
246 static AtkStateSet *
247 gtk_window_accessible_ref_state_set (AtkObject *accessible)
248 {
249   AtkStateSet *state_set;
250   GtkWidget *widget;
251   GtkWindow *window;
252   GdkWindow *gdk_window;
253   GdkWindowState state;
254
255   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
256   if (widget == NULL)
257     return NULL;
258
259   state_set = ATK_OBJECT_CLASS (_gtk_window_accessible_parent_class)->ref_state_set (accessible);
260
261   window = GTK_WINDOW (widget);
262
263   if (gtk_window_has_toplevel_focus (window) && gtk_window_is_active (window))
264     atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
265
266   gdk_window = gtk_widget_get_window (widget);
267   if (window)
268     {
269       state = gdk_window_get_state (gdk_window);
270       if (state & GDK_WINDOW_STATE_ICONIFIED)
271         atk_state_set_add_state (state_set, ATK_STATE_ICONIFIED);
272     }
273   if (gtk_window_get_modal (window))
274     atk_state_set_add_state (state_set, ATK_STATE_MODAL);
275
276   if (gtk_window_get_resizable (window))
277     atk_state_set_add_state (state_set, ATK_STATE_RESIZABLE);
278
279   return state_set;
280 }
281
282 static void
283 _gtk_window_accessible_class_init (GtkWindowAccessibleClass *klass)
284 {
285   GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
286   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
287
288   widget_class->notify_gtk = gtk_window_accessible_notify_gtk;
289
290   class->get_name = gtk_window_accessible_get_name;
291   class->get_index_in_parent = gtk_window_accessible_get_index_in_parent;
292   class->ref_relation_set = gtk_window_accessible_ref_relation_set;
293   class->ref_state_set = gtk_window_accessible_ref_state_set;
294   class->initialize = gtk_window_accessible_initialize;
295   class->focus_event = gtk_window_accessible_focus_event;
296 }
297
298 static void
299 _gtk_window_accessible_init (GtkWindowAccessible *accessible)
300 {
301 }
302
303 static void
304 gtk_window_accessible_get_extents (AtkComponent  *component,
305                                    gint          *x,
306                                    gint          *y,
307                                    gint          *width,
308                                    gint          *height,
309                                    AtkCoordType   coord_type)
310 {
311   GtkWidget *widget;
312   GdkRectangle rect;
313   gint x_toplevel, y_toplevel;
314
315   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
316   if (widget == NULL)
317     return;
318
319   if (!gtk_widget_is_toplevel (widget))
320     {
321       AtkComponentIface *parent_iface;
322
323       parent_iface = (AtkComponentIface *) g_type_interface_peek_parent (ATK_COMPONENT_GET_IFACE (component));
324       parent_iface->get_extents (component, x, y, width, height, coord_type);
325       return;
326     }
327
328   gdk_window_get_frame_extents (gtk_widget_get_window (widget), &rect);
329
330   *width = rect.width;
331   *height = rect.height;
332   if (!gtk_widget_is_drawable (widget))
333     {
334       *x = G_MININT;
335       *y = G_MININT;
336       return;
337     }
338
339   *x = rect.x;
340   *y = rect.y;
341   if (coord_type == ATK_XY_WINDOW)
342     {
343       gdk_window_get_origin (gtk_widget_get_window (widget),
344                              &x_toplevel, &y_toplevel);
345       *x -= x_toplevel;
346       *y -= y_toplevel;
347     }
348 }
349
350 static void
351 gtk_window_accessible_get_size (AtkComponent *component,
352                                 gint         *width,
353                                 gint         *height)
354 {
355   GtkWidget *widget;
356   GdkRectangle rect;
357
358   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
359   if (widget == NULL)
360     return;
361
362   if (!gtk_widget_is_toplevel (widget))
363     {
364       AtkComponentIface *parent_iface;
365
366       parent_iface = (AtkComponentIface *) g_type_interface_peek_parent (ATK_COMPONENT_GET_IFACE (component));
367       parent_iface->get_size (component, width, height);
368       return;
369     }
370
371   gdk_window_get_frame_extents (gtk_widget_get_window (widget), &rect);
372
373   *width = rect.width;
374   *height = rect.height;
375 }
376
377 static void
378 atk_component_interface_init (AtkComponentIface *iface)
379 {
380   iface->get_extents = gtk_window_accessible_get_extents;
381   iface->get_size = gtk_window_accessible_get_size;
382 }
383
384 static void
385 atk_window_interface_init (AtkWindowIface *iface)
386 {
387   /* At this moment AtkWindow is just about signals */
388 }