]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtktoplevelaccessible.c
GtkImageCellAccessible: add a private struct
[~andy/gtk] / gtk / a11y / gtktoplevelaccessible.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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <gtk/gtkx.h>
24 #include <gtk/gtkeventbox.h>
25 #include <gtk/gtkscrolledwindow.h>
26 #include <gtk/gtkframe.h>
27 #include <gtk/gtkmenu.h>
28 #include <gtk/gtkmenuitem.h>
29 #include <gtk/gtkbutton.h>
30
31 #include "gtktoplevelaccessible.h"
32
33
34 G_DEFINE_TYPE (GtkToplevelAccessible, _gtk_toplevel_accessible, ATK_TYPE_OBJECT)
35
36 static void
37 gtk_toplevel_accessible_initialize (AtkObject *accessible,
38                                     gpointer   data)
39 {
40   ATK_OBJECT_CLASS (_gtk_toplevel_accessible_parent_class)->initialize (accessible, data);
41
42   accessible->role = ATK_ROLE_APPLICATION;
43   accessible->name = g_get_prgname ();
44   accessible->accessible_parent = NULL;
45 }
46
47 static void
48 gtk_toplevel_accessible_object_finalize (GObject *obj)
49 {
50   GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (obj);
51
52   if (toplevel->window_list)
53     g_list_free (toplevel->window_list);
54
55   G_OBJECT_CLASS (_gtk_toplevel_accessible_parent_class)->finalize (obj);
56 }
57
58 static gint
59 gtk_toplevel_accessible_get_n_children (AtkObject *obj)
60 {
61   GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (obj);
62
63   return g_list_length (toplevel->window_list);
64 }
65
66 static AtkObject *
67 gtk_toplevel_accessible_ref_child (AtkObject *obj,
68                                    gint       i)
69 {
70   GtkToplevelAccessible *toplevel;
71   GtkWidget *widget;
72   AtkObject *atk_obj;
73
74   toplevel = GTK_TOPLEVEL_ACCESSIBLE (obj);
75   widget = g_list_nth_data (toplevel->window_list, i);
76   if (!widget)
77     return NULL;
78
79   atk_obj = gtk_widget_get_accessible (widget);
80
81   g_object_ref (atk_obj);
82
83   return atk_obj;
84 }
85
86 static gboolean
87 is_combo_window (GtkWidget *widget)
88 {
89   GtkWidget *child;
90   AtkObject *obj;
91
92   child = gtk_bin_get_child (GTK_BIN (widget));
93
94   if (!GTK_IS_EVENT_BOX (child))
95     return FALSE;
96
97   child = gtk_bin_get_child (GTK_BIN (child));
98
99   if (!GTK_IS_FRAME (child))
100     return FALSE;
101
102   child = gtk_bin_get_child (GTK_BIN (child));
103
104   if (!GTK_IS_SCROLLED_WINDOW (child))
105     return FALSE;
106
107   obj = gtk_widget_get_accessible (child);
108   obj = atk_object_get_parent (obj);
109
110   return FALSE;
111 }
112
113 static gboolean
114 is_attached_menu_window (GtkWidget *widget)
115 {
116   GtkWidget *child;
117
118   child = gtk_bin_get_child (GTK_BIN (widget));
119   if (GTK_IS_MENU (child))
120     {
121       GtkWidget *attach;
122
123       attach = gtk_menu_get_attach_widget (GTK_MENU (child));
124       /* Allow for menu belonging to the Panel Menu, which is a GtkButton */
125       if (GTK_IS_MENU_ITEM (attach) || GTK_IS_BUTTON (attach))
126         return TRUE;
127     }
128
129   return FALSE;
130 }
131
132 static void
133 _gtk_toplevel_accessible_class_init (GtkToplevelAccessibleClass *klass)
134 {
135   AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
136   GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
137
138   class->initialize = gtk_toplevel_accessible_initialize;
139   class->get_n_children = gtk_toplevel_accessible_get_n_children;
140   class->ref_child = gtk_toplevel_accessible_ref_child;
141   class->get_parent = NULL;
142
143   g_object_class->finalize = gtk_toplevel_accessible_object_finalize;
144 }
145
146 static void
147 remove_child (GtkToplevelAccessible *toplevel,
148               GtkWindow             *window)
149 {
150   AtkObject *atk_obj = ATK_OBJECT (toplevel);
151   GList *l;
152   guint window_count = 0;
153   AtkObject *child;
154
155   if (toplevel->window_list)
156     {
157       GtkWindow *tmp_window;
158
159       for (l = toplevel->window_list; l; l = l->next)
160         {
161           tmp_window = GTK_WINDOW (l->data);
162
163           if (window == tmp_window)
164             {
165               /* Remove the window from the window_list & emit the signal */
166               toplevel->window_list = g_list_delete_link (toplevel->window_list, l);
167               child = gtk_widget_get_accessible (GTK_WIDGET (window));
168               g_signal_emit_by_name (atk_obj, "children-changed::remove",
169                                      window_count, child, NULL);
170               atk_object_set_parent (child, NULL);
171               break;
172             }
173
174           window_count++;
175         }
176     }
177 }
178
179 static gboolean
180 show_event_watcher (GSignalInvocationHint *ihint,
181                     guint                  n_param_values,
182                     const GValue          *param_values,
183                     gpointer               data)
184 {
185   GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (data);
186   AtkObject *atk_obj = ATK_OBJECT (toplevel);
187   GObject *object;
188   GtkWidget *widget;
189   gint n_children;
190   AtkObject *child;
191
192   object = g_value_get_object (param_values + 0);
193
194   if (!GTK_IS_WINDOW (object))
195     return TRUE;
196
197   widget = GTK_WIDGET (object);
198   if (gtk_widget_get_parent (widget) ||
199       is_attached_menu_window (widget) ||
200 #ifdef GDK_WINDOWING_X11
201       GTK_IS_PLUG (widget) ||
202 #endif
203       is_combo_window (widget))
204     return TRUE;
205
206   child = gtk_widget_get_accessible (widget);
207   if (atk_object_get_role (child) == ATK_ROLE_REDUNDANT_OBJECT ||
208       atk_object_get_role (child) == ATK_ROLE_TOOL_TIP)
209     return TRUE;
210
211   /* Add the window to the list & emit the signal */
212   toplevel->window_list = g_list_append (toplevel->window_list, widget);
213   n_children = g_list_length (toplevel->window_list);
214
215   atk_object_set_parent (child, atk_obj);
216   g_signal_emit_by_name (atk_obj, "children-changed::add",
217                          n_children - 1, child, NULL);
218
219   g_signal_connect_swapped (G_OBJECT(object), "destroy",
220                             G_CALLBACK (remove_child), toplevel);
221
222   return TRUE;
223 }
224
225 static gboolean
226 hide_event_watcher (GSignalInvocationHint *ihint,
227                     guint                  n_param_values,
228                     const GValue          *param_values,
229                     gpointer               data)
230 {
231   GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (data);
232   GObject *object;
233
234   object = g_value_get_object (param_values + 0);
235
236   if (!GTK_IS_WINDOW (object))
237     return TRUE;
238
239   remove_child (toplevel, GTK_WINDOW (object));
240   return TRUE;
241 }
242
243 static void
244 _gtk_toplevel_accessible_init (GtkToplevelAccessible *toplevel)
245 {
246   GtkWindow *window;
247   GtkWidget *widget;
248   GList *l;
249   guint signal_id;
250
251   l = toplevel->window_list = gtk_window_list_toplevels ();
252
253   while (l)
254     {
255       window = GTK_WINDOW (l->data);
256       widget = GTK_WIDGET (window);
257       if (!window ||
258           !gtk_widget_get_visible (widget) ||
259           is_attached_menu_window (widget) ||
260 #ifdef GDK_WINDOWING_X11
261           GTK_IS_PLUG (window) ||
262 #endif
263           gtk_widget_get_parent (GTK_WIDGET (window)))
264         {
265           GList *temp_l  = l->next;
266
267           toplevel->window_list = g_list_delete_link (toplevel->window_list, l);
268           l = temp_l;
269         }
270       else
271         {
272           g_signal_connect_swapped (G_OBJECT (window), "destroy",
273                                     G_CALLBACK (remove_child), toplevel);
274           l = l->next;
275         }
276     }
277
278   g_type_class_ref (GTK_TYPE_WINDOW);
279
280   signal_id  = g_signal_lookup ("show", GTK_TYPE_WINDOW);
281   g_signal_add_emission_hook (signal_id, 0,
282                               show_event_watcher, toplevel, (GDestroyNotify) NULL);
283
284   signal_id  = g_signal_lookup ("hide", GTK_TYPE_WINDOW);
285   g_signal_add_emission_hook (signal_id, 0,
286                               hide_event_watcher, toplevel, (GDestroyNotify) NULL);
287 }