]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailtoplevel.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~andy/gtk] / modules / other / gail / gailtoplevel.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 <stdlib.h>
23 #include <string.h>
24
25 #undef GTK_DISABLE_DEPRECATED
26
27 #include <gtk/gtk.h>
28
29 #include "gailtoplevel.h"
30
31 static void             gail_toplevel_class_init        (GailToplevelClass      *klass);
32 static void             gail_toplevel_init              (GailToplevel           *toplevel);
33 static void             gail_toplevel_initialize        (AtkObject              *accessible,
34                                                          gpointer                data);
35 static void             gail_toplevel_object_finalize   (GObject                *obj);
36
37 /* atkobject.h */
38
39 static gint             gail_toplevel_get_n_children    (AtkObject              *obj);
40 static AtkObject*       gail_toplevel_ref_child         (AtkObject              *obj,
41                                                         gint                    i);
42 static AtkObject*       gail_toplevel_get_parent        (AtkObject              *obj);
43
44 /* Callbacks */
45
46
47 static void             gail_toplevel_window_destroyed  (GtkWindow              *window,
48                                                         GailToplevel            *text);
49 static gboolean         gail_toplevel_hide_event_watcher (GSignalInvocationHint *ihint,
50                                                         guint                   n_param_values,
51                                                         const GValue            *param_values,
52                                                         gpointer                data);
53 static gboolean         gail_toplevel_show_event_watcher (GSignalInvocationHint *ihint,
54                                                         guint                   n_param_values,
55                                                         const GValue            *param_values,
56                                                         gpointer                data);
57
58 /* Misc */
59
60 static void      _gail_toplevel_remove_child            (GailToplevel           *toplevel,
61                                                         GtkWindow               *window);
62 static gboolean  is_attached_menu_window                (GtkWidget              *widget);
63 static gboolean  is_combo_window                        (GtkWidget              *widget);
64
65
66 G_DEFINE_TYPE (GailToplevel, gail_toplevel, ATK_TYPE_OBJECT)
67
68 static void
69 gail_toplevel_class_init (GailToplevelClass *klass)
70 {
71   AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
72   GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
73
74   class->initialize = gail_toplevel_initialize;
75   class->get_n_children = gail_toplevel_get_n_children;
76   class->ref_child = gail_toplevel_ref_child;
77   class->get_parent = gail_toplevel_get_parent;
78
79   g_object_class->finalize = gail_toplevel_object_finalize;
80 }
81
82 static void
83 gail_toplevel_init (GailToplevel *toplevel)
84 {
85   GtkWindow *window;
86   GtkWidget *widget;
87   GList *l;
88   guint signal_id;
89   
90   l = toplevel->window_list = gtk_window_list_toplevels ();
91
92   while (l)
93     {
94       window = GTK_WINDOW (l->data);
95       widget = GTK_WIDGET (window);
96       if (!window || 
97           !gtk_widget_get_visible (widget) ||
98           is_attached_menu_window (widget) ||
99           GTK_WIDGET (window)->parent ||
100           GTK_IS_PLUG (window))
101         {
102           GList *temp_l  = l->next;
103
104           toplevel->window_list = g_list_delete_link (toplevel->window_list, l);
105           l = temp_l;
106         }
107       else
108         {
109           g_signal_connect (G_OBJECT (window), 
110                             "destroy",
111                             G_CALLBACK (gail_toplevel_window_destroyed),
112                             toplevel);
113           l = l->next;
114         }
115     }
116
117   g_type_class_ref (GTK_TYPE_WINDOW);
118
119   signal_id  = g_signal_lookup ("show", GTK_TYPE_WINDOW);
120   g_signal_add_emission_hook (signal_id, 0,
121     gail_toplevel_show_event_watcher, toplevel, (GDestroyNotify) NULL);
122
123   signal_id  = g_signal_lookup ("hide", GTK_TYPE_WINDOW);
124   g_signal_add_emission_hook (signal_id, 0,
125     gail_toplevel_hide_event_watcher, toplevel, (GDestroyNotify) NULL);
126 }
127
128 static void
129 gail_toplevel_initialize (AtkObject *accessible,
130                           gpointer  data)
131 {
132   ATK_OBJECT_CLASS (gail_toplevel_parent_class)->initialize (accessible, data);
133
134   accessible->role = ATK_ROLE_APPLICATION;
135   accessible->name = g_get_prgname();
136   accessible->accessible_parent = NULL;
137 }
138
139 static void
140 gail_toplevel_object_finalize (GObject *obj)
141 {
142   GailToplevel *toplevel = GAIL_TOPLEVEL (obj);
143
144   if (toplevel->window_list)
145     g_list_free (toplevel->window_list);
146
147   G_OBJECT_CLASS (gail_toplevel_parent_class)->finalize (obj);
148 }
149
150 static AtkObject*
151 gail_toplevel_get_parent (AtkObject *obj)
152 {
153     return NULL;
154 }
155
156 static gint
157 gail_toplevel_get_n_children (AtkObject *obj)
158 {
159   GailToplevel *toplevel = GAIL_TOPLEVEL (obj);
160
161   gint rc = g_list_length (toplevel->window_list);
162   return rc;
163 }
164
165 static AtkObject*
166 gail_toplevel_ref_child (AtkObject *obj,
167                          gint      i)
168 {
169   GailToplevel *toplevel;
170   gpointer ptr;
171   GtkWidget *widget;
172   AtkObject *atk_obj;
173
174   toplevel = GAIL_TOPLEVEL (obj);
175   ptr = g_list_nth_data (toplevel->window_list, i);
176   if (!ptr)
177     return NULL;
178   widget = GTK_WIDGET (ptr);
179   atk_obj = gtk_widget_get_accessible (widget);
180
181   g_object_ref (atk_obj);
182   return atk_obj;
183 }
184
185 /*
186  * Window destroy events on GtkWindow cause a child to be removed
187  * from the toplevel
188  */
189 static void
190 gail_toplevel_window_destroyed (GtkWindow    *window,
191                                 GailToplevel *toplevel)
192 {
193   _gail_toplevel_remove_child (toplevel, window);
194 }
195
196 /*
197  * Show events cause a child to be added to the toplevel
198  */
199 static gboolean
200 gail_toplevel_show_event_watcher (GSignalInvocationHint *ihint,
201                                   guint                  n_param_values,
202                                   const GValue          *param_values,
203                                   gpointer               data)
204 {
205   GailToplevel *toplevel = GAIL_TOPLEVEL (data);
206   AtkObject *atk_obj = ATK_OBJECT (toplevel);
207   GObject *object;
208   GtkWidget *widget;
209   gint n_children;
210   AtkObject *child;
211
212   object = g_value_get_object (param_values + 0);
213
214   if (!GTK_IS_WINDOW (object))
215     return TRUE;
216
217   widget = GTK_WIDGET (object);
218   if (widget->parent || 
219       is_attached_menu_window (widget) ||
220       is_combo_window (widget) ||
221       GTK_IS_PLUG (widget))
222     return TRUE;
223
224   child = gtk_widget_get_accessible (widget);
225   if (!strcmp (atk_role_get_name (atk_object_get_role (child)), "redundant object"))
226     {
227       return TRUE;
228     }
229
230   child = gtk_widget_get_accessible (widget);
231   if (!strcmp (atk_role_get_name (atk_object_get_role (child)), "redundant object"))
232     {
233       return TRUE;
234     }
235
236   /* 
237    * Add the window to the list & emit the signal.
238    * Don't do this for tooltips (Bug #150649).
239    */
240   if (atk_object_get_role (child) != ATK_ROLE_TOOL_TIP)
241   {
242       toplevel->window_list = g_list_append (toplevel->window_list, widget);
243
244       n_children = g_list_length (toplevel->window_list);
245
246       /*
247        * Must subtract 1 from the n_children since the index is 0-based
248        * but g_list_length is 1-based.
249        */
250       atk_object_set_parent (child, atk_obj);
251       g_signal_emit_by_name (atk_obj, "children-changed::add",
252                              n_children - 1, 
253                              child, NULL);
254   }
255
256   /* Connect destroy signal callback */
257   g_signal_connect (G_OBJECT(object), 
258                     "destroy",
259                     G_CALLBACK (gail_toplevel_window_destroyed),
260                     toplevel);
261
262   return TRUE;
263 }
264
265 /*
266  * Hide events on GtkWindow cause a child to be removed from the toplevel
267  */
268 static gboolean
269 gail_toplevel_hide_event_watcher (GSignalInvocationHint *ihint,
270                                   guint                  n_param_values,
271                                   const GValue          *param_values,
272                                   gpointer               data)
273 {
274   GailToplevel *toplevel = GAIL_TOPLEVEL (data);
275   GObject *object;
276
277   object = g_value_get_object (param_values + 0);
278
279   if (!GTK_IS_WINDOW (object))
280     return TRUE;
281
282   _gail_toplevel_remove_child (toplevel, GTK_WINDOW (object));
283   return TRUE;
284 }
285
286 /*
287  * Common code used by destroy and hide events on GtkWindow
288  */
289 static void
290 _gail_toplevel_remove_child (GailToplevel *toplevel, 
291                              GtkWindow    *window)
292 {
293   AtkObject *atk_obj = ATK_OBJECT (toplevel);
294   GList *l;
295   guint window_count = 0;
296   AtkObject *child;
297
298   if (toplevel->window_list)
299     {
300         GtkWindow *tmp_window;
301
302         /* Must loop through them all */
303         for (l = toplevel->window_list; l; l = l->next)
304         {
305           tmp_window = GTK_WINDOW (l->data);
306
307           if (window == tmp_window)
308             {
309               /* Remove the window from the window_list & emit the signal */
310               toplevel->window_list = g_list_remove (toplevel->window_list,
311                                                      l->data);
312               child = gtk_widget_get_accessible (GTK_WIDGET (window));
313               g_signal_emit_by_name (atk_obj, "children-changed::remove",
314                                      window_count, 
315                                      child, NULL);
316               atk_object_set_parent (child, NULL);
317               break;
318             }
319
320           window_count++;
321         }
322     }
323 }
324
325 static gboolean
326 is_attached_menu_window (GtkWidget *widget)
327 {
328   GtkWidget *child = GTK_BIN (widget)->child;
329   gboolean ret = FALSE;
330
331   if (GTK_IS_MENU (child))
332     {
333       GtkWidget *attach;
334
335       attach = gtk_menu_get_attach_widget (GTK_MENU (child));
336       /* Allow for menu belonging to the Panel Menu, which is a GtkButton */
337       if (GTK_IS_MENU_ITEM (attach) ||
338           GTK_IS_OPTION_MENU (attach) ||
339           GTK_IS_BUTTON (attach))
340         ret = TRUE;
341     }
342   return ret;
343 }
344
345 static gboolean
346 is_combo_window (GtkWidget *widget)
347 {
348   GtkWidget *child = GTK_BIN (widget)->child;
349   AtkObject *obj;
350   GtkAccessible *accessible;
351
352   if (!GTK_IS_EVENT_BOX (child))
353     return FALSE;
354
355   child = GTK_BIN (child)->child;
356
357   if (!GTK_IS_FRAME (child))
358     return FALSE;
359
360   child = GTK_BIN (child)->child;
361
362   if (!GTK_IS_SCROLLED_WINDOW (child))
363     return FALSE;
364
365   obj = gtk_widget_get_accessible (child);
366   obj = atk_object_get_parent (obj);
367   accessible = GTK_ACCESSIBLE (obj);
368   if (GTK_IS_COMBO (accessible->widget))
369     return TRUE;
370
371   return  FALSE;
372 }