]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gailsubmenuitem.c
gail: No need to include modules/other in CFLAGS anymore
[~andy/gtk] / gtk / a11y / gailsubmenuitem.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 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/gtk.h>
23 #include "gailsubmenuitem.h"
24
25 static void         gail_sub_menu_item_class_init       (GailSubMenuItemClass *klass);
26 static void         gail_sub_menu_item_init             (GailSubMenuItem *item);
27 static void         gail_sub_menu_item_real_initialize  (AtkObject      *obj,
28                                                          gpointer       data);
29
30 static void         atk_selection_interface_init        (AtkSelectionIface  *iface);
31 static gboolean     gail_sub_menu_item_add_selection    (AtkSelection   *selection,
32                                                          gint           i);
33 static gboolean     gail_sub_menu_item_clear_selection  (AtkSelection   *selection);
34 static AtkObject*   gail_sub_menu_item_ref_selection    (AtkSelection   *selection,
35                                                          gint           i);
36 static gint         gail_sub_menu_item_get_selection_count
37                                                         (AtkSelection   *selection);
38 static gboolean     gail_sub_menu_item_is_child_selected
39                                                         (AtkSelection   *selection,
40                                                          gint           i);
41 static gboolean     gail_sub_menu_item_remove_selection (AtkSelection   *selection,
42                                                          gint           i);
43 static gint         menu_item_add_gtk                   (GtkContainer   *container,
44                                                          GtkWidget      *widget);
45 static gint         menu_item_remove_gtk                (GtkContainer   *container,
46                                                          GtkWidget      *widget);
47
48 G_DEFINE_TYPE_WITH_CODE (GailSubMenuItem, gail_sub_menu_item, GAIL_TYPE_MENU_ITEM,
49                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
50
51 static void
52 gail_sub_menu_item_class_init (GailSubMenuItemClass *klass)
53 {
54   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
55
56   class->initialize = gail_sub_menu_item_real_initialize;
57 }
58
59 static void
60 gail_sub_menu_item_init (GailSubMenuItem *item)
61 {
62 }
63
64 static void
65 gail_sub_menu_item_real_initialize (AtkObject *obj,
66                                    gpointer   data)
67 {
68   GtkWidget *submenu;
69
70   ATK_OBJECT_CLASS (gail_sub_menu_item_parent_class)->initialize (obj, data);
71
72   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (data));
73   g_return_if_fail (submenu);
74
75   g_signal_connect (submenu,
76                     "add",
77                     G_CALLBACK (menu_item_add_gtk),
78                     NULL);
79   g_signal_connect (submenu,
80                     "remove",
81                     G_CALLBACK (menu_item_remove_gtk),
82                     NULL);
83
84   obj->role = ATK_ROLE_MENU;
85 }
86
87 AtkObject*
88 gail_sub_menu_item_new (GtkWidget *widget)
89 {
90   GObject *object;
91   AtkObject *accessible;
92
93   g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), NULL);
94
95   object = g_object_new (GAIL_TYPE_SUB_MENU_ITEM, NULL);
96
97   accessible = ATK_OBJECT (object);
98   atk_object_initialize (accessible, widget);
99
100   return accessible;
101 }
102
103 static void
104 atk_selection_interface_init (AtkSelectionIface *iface)
105 {
106   iface->add_selection = gail_sub_menu_item_add_selection;
107   iface->clear_selection = gail_sub_menu_item_clear_selection;
108   iface->ref_selection = gail_sub_menu_item_ref_selection;
109   iface->get_selection_count = gail_sub_menu_item_get_selection_count;
110   iface->is_child_selected = gail_sub_menu_item_is_child_selected;
111   iface->remove_selection = gail_sub_menu_item_remove_selection;
112   /*
113    * select_all_selection does not make sense for a submenu of a menu item
114    * so no implementation is provided.
115    */
116 }
117
118 static gboolean
119 gail_sub_menu_item_add_selection (AtkSelection *selection,
120                                   gint          i)
121 {
122   GtkMenuShell *shell;
123   GList *kids;
124   guint length;
125   GtkWidget *widget;
126   GtkWidget *submenu;
127   GtkWidget *child;
128
129   widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
130   if (widget == NULL)
131     /* State is defunct */
132     return FALSE;
133
134   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
135   g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
136   shell = GTK_MENU_SHELL (submenu);
137   kids = gtk_container_get_children (GTK_CONTAINER (shell));
138   length = g_list_length (kids);
139   if (i < 0 || i > length)
140     {
141       g_list_free (kids);
142       return FALSE;
143     }
144
145   child = g_list_nth_data (kids, i);
146   g_list_free (kids);
147   g_return_val_if_fail (GTK_IS_MENU_ITEM(child), FALSE);
148   gtk_menu_shell_select_item (shell, GTK_WIDGET (child));
149   return TRUE;
150 }
151
152 static gboolean
153 gail_sub_menu_item_clear_selection (AtkSelection   *selection)
154 {
155   GtkMenuShell *shell;
156   GtkWidget *widget;
157   GtkWidget *submenu;
158
159   widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
160   if (widget == NULL)
161     /* State is defunct */
162     return FALSE;
163
164   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
165   g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
166   shell = GTK_MENU_SHELL (submenu);
167
168   gtk_menu_shell_deselect (shell);
169   return TRUE;
170 }
171
172 static AtkObject*
173 gail_sub_menu_item_ref_selection (AtkSelection   *selection,
174                                   gint           i)
175 {
176   GtkMenuShell *shell;
177   AtkObject *obj;
178   GtkWidget *widget;
179   GtkWidget *submenu;
180   GtkWidget *item;
181
182   if (i != 0)
183     return NULL;
184
185   widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
186   if (widget == NULL)
187     /* State is defunct */
188     return NULL;
189
190   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
191   g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), NULL);
192   shell = GTK_MENU_SHELL (submenu);
193
194   item = gtk_menu_shell_get_selected_item (shell);
195   if (item != NULL)
196     {
197       obj = gtk_widget_get_accessible (item);
198       g_object_ref (obj);
199       return obj;
200     }
201   else
202     {
203       return NULL;
204     }
205 }
206
207 static gint
208 gail_sub_menu_item_get_selection_count (AtkSelection   *selection)
209 {
210   GtkMenuShell *shell;
211   GtkWidget *widget;
212   GtkWidget *submenu;
213
214   widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
215   if (widget == NULL)
216     /* State is defunct */
217     return 0;
218
219   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
220   g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
221   shell = GTK_MENU_SHELL (submenu);
222
223   /*
224    * Identifies the currently selected menu item
225    */
226   if (gtk_menu_shell_get_selected_item (shell) == NULL)
227     return 0;
228   else
229     return 1;
230 }
231
232 static gboolean
233 gail_sub_menu_item_is_child_selected (AtkSelection   *selection,
234                                        gint           i)
235 {
236   GtkMenuShell *shell;
237   gint j;
238   GtkWidget *widget;
239   GtkWidget *submenu;
240   GtkWidget *item;
241   GList *kids;
242
243   widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
244   if (widget == NULL)
245     /* State is defunct */
246     return FALSE;
247
248   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
249   g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
250   shell = GTK_MENU_SHELL (submenu);
251
252   item = gtk_menu_shell_get_selected_item (shell);
253   if (item == NULL)
254     return FALSE;
255
256   kids = gtk_container_get_children (GTK_CONTAINER (shell));
257   j = g_list_index (kids, item);
258   g_list_free (kids);
259
260   return (j==i);
261 }
262
263 static gboolean
264 gail_sub_menu_item_remove_selection (AtkSelection   *selection,
265                                   gint           i)
266 {
267   GtkMenuShell *shell;
268   GtkWidget *widget;
269   GtkWidget *submenu;
270   GtkWidget *item;
271
272   if (i != 0)
273     return FALSE;
274
275   widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
276   if (widget == NULL)
277     /* State is defunct */
278     return FALSE;
279
280   submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
281   g_return_val_if_fail (GTK_IS_MENU_SHELL (submenu), FALSE);
282   shell = GTK_MENU_SHELL (submenu);
283
284   item = gtk_menu_shell_get_selected_item (shell);
285   if (item && gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)))
286     {
287     /*
288      * Menu item contains a menu and it is the selected menu item
289      * so deselect it.
290      */
291       gtk_menu_shell_deselect (shell);
292     }
293   return TRUE;
294 }
295
296 static gint
297 menu_item_add_gtk (GtkContainer *container,
298                    GtkWidget    *widget)
299 {
300   GtkWidget *parent_widget;
301   AtkObject *atk_parent;
302   AtkObject *atk_child;
303   GailContainer *gail_container;
304   gint index;
305
306   g_return_val_if_fail (GTK_IS_MENU (container), 1);
307
308   parent_widget = gtk_menu_get_attach_widget (GTK_MENU (container));
309   if (GTK_IS_MENU_ITEM (parent_widget))
310     {
311       atk_parent = gtk_widget_get_accessible (parent_widget);
312       atk_child = gtk_widget_get_accessible (widget);
313
314       gail_container = GAIL_CONTAINER (atk_parent);
315       g_object_notify (G_OBJECT (atk_child), "accessible_parent");
316
317       g_list_free (gail_container->children);
318       gail_container->children = gtk_container_get_children (container);
319       index = g_list_index (gail_container->children, widget);
320       g_signal_emit_by_name (atk_parent, "children_changed::add",
321                              index, atk_child, NULL);
322     }
323   return 1;
324 }
325
326 static gint
327 menu_item_remove_gtk (GtkContainer *container,
328                       GtkWidget    *widget)
329 {
330   GtkWidget *parent_widget;
331   AtkObject *atk_parent;
332   AtkObject *atk_child;
333   GailContainer *gail_container;
334   AtkPropertyValues values = { NULL };
335   gint index;
336   gint list_length;
337
338   g_return_val_if_fail (GTK_IS_MENU (container), 1);
339
340   parent_widget = gtk_menu_get_attach_widget (GTK_MENU (container));
341   if (GTK_IS_MENU_ITEM (parent_widget))
342     {
343       atk_parent = gtk_widget_get_accessible (parent_widget);
344       atk_child = gtk_widget_get_accessible (widget);
345
346       gail_container = GAIL_CONTAINER (atk_parent);
347       g_value_init (&values.old_value, G_TYPE_POINTER);
348       g_value_set_pointer (&values.old_value, atk_parent);
349       values.property_name = "accessible-parent";
350       g_signal_emit_by_name (atk_child,
351                              "property_change::accessible-parent", &values, NULL);
352
353       index = g_list_index (gail_container->children, widget);
354       list_length = g_list_length (gail_container->children);
355       g_list_free (gail_container->children);
356       gail_container->children = gtk_container_get_children (container);
357       if (index >= 0 && index <= list_length)
358         g_signal_emit_by_name (atk_parent, "children_changed::remove",
359                                index, atk_child, NULL);
360     }
361   return 1;
362 }