]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkcomboboxaccessible.c
Convert GailContainer to GtkContainerAccessible
[~andy/gtk] / gtk / a11y / gtkcomboboxaccessible.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2004 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 "gtkcomboboxaccessible.h"
24
25
26 static void atk_action_interface_init    (AtkActionIface    *iface);
27 static void atk_selection_interface_init (AtkSelectionIface *iface);
28
29 G_DEFINE_TYPE_WITH_CODE (GtkComboBoxAccessible, gtk_combo_box_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
30                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
31                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
32
33 static void
34 changed_cb (GtkWidget *widget)
35 {
36   GtkComboBox *combo_box;
37   AtkObject *obj;
38   GtkComboBoxAccessible *accessible;
39   gint index;
40
41   combo_box = GTK_COMBO_BOX (widget);
42
43   index = gtk_combo_box_get_active (combo_box);
44   obj = gtk_widget_get_accessible (widget);
45   accessible = GTK_COMBO_BOX_ACCESSIBLE (obj);
46   if (accessible->old_selection != index)
47     {
48       accessible->old_selection = index;
49       g_object_notify (G_OBJECT (obj), "accessible-name");
50       g_signal_emit_by_name (obj, "selection_changed");
51     }
52 }
53
54 static void
55 gtk_combo_box_accessible_initialize (AtkObject *obj,
56                                      gpointer   data)
57 {
58   GtkComboBox *combo_box;
59   GtkComboBoxAccessible *accessible;
60   AtkObject *popup;
61
62   ATK_OBJECT_CLASS (gtk_combo_box_accessible_parent_class)->initialize (obj, data);
63
64   combo_box = GTK_COMBO_BOX (data);
65   accessible = GTK_COMBO_BOX_ACCESSIBLE (obj);
66
67   g_signal_connect (combo_box, "changed", G_CALLBACK (changed_cb), NULL);
68   accessible->old_selection = gtk_combo_box_get_active (combo_box);
69
70   popup = gtk_combo_box_get_popup_accessible (combo_box);
71   if (popup)
72     {
73       atk_object_set_parent (popup, obj);
74       accessible->popup_set = TRUE;
75     }
76   if (gtk_combo_box_get_has_entry (combo_box))
77     atk_object_set_parent (gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (combo_box))), obj);
78
79   obj->role = ATK_ROLE_COMBO_BOX;
80 }
81
82 static void
83 gtk_combo_box_accessible_finalize (GObject *object)
84 {
85   GtkComboBoxAccessible *combo_box = GTK_COMBO_BOX_ACCESSIBLE (object);
86
87   g_free (combo_box->name);
88
89   G_OBJECT_CLASS (gtk_combo_box_accessible_parent_class)->finalize (object);
90 }
91
92 static const gchar*
93 gtk_combo_box_accessible_get_name (AtkObject *obj)
94 {
95   GtkWidget *widget;
96   GtkComboBox *combo_box;
97   GtkComboBoxAccessible *accessible;
98   GtkTreeIter iter;
99   const gchar *name;
100   GtkTreeModel *model;
101   gint n_columns;
102   gint i;
103
104   name = ATK_OBJECT_CLASS (gtk_combo_box_accessible_parent_class)->get_name (obj);
105   if (name)
106     return name;
107
108   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
109   if (widget == NULL)
110     return NULL;
111
112   combo_box = GTK_COMBO_BOX (widget);
113   accessible = GTK_COMBO_BOX_ACCESSIBLE (obj);
114   if (gtk_combo_box_get_active_iter (combo_box, &iter))
115     {
116       model = gtk_combo_box_get_model (combo_box);
117       n_columns = gtk_tree_model_get_n_columns (model);
118       for (i = 0; i < n_columns; i++)
119         {
120           GValue value = { 0, };
121
122           gtk_tree_model_get_value (model, &iter, i, &value);
123           if (G_VALUE_HOLDS_STRING (&value))
124             {
125               g_free (accessible->name);
126               accessible->name =  g_strdup (g_value_get_string (&value));
127               g_value_unset (&value);
128               break;
129             }
130           else
131             g_value_unset (&value);
132         }
133     }
134   return accessible->name;
135 }
136
137 static gint
138 gtk_combo_box_accessible_get_n_children (AtkObject* obj)
139 {
140   gint n_children = 0;
141   GtkWidget *widget;
142
143   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
144   if (widget == NULL)
145     return 0;
146
147   n_children++;
148   if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget)))
149     n_children++;
150
151   return n_children;
152 }
153
154 static AtkObject *
155 gtk_combo_box_accessible_ref_child (AtkObject *obj,
156                                     gint       i)
157 {
158   GtkWidget *widget;
159   AtkObject *child;
160   GtkComboBoxAccessible *box;
161
162   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
163   if (widget == NULL)
164     return NULL;
165
166   if (i == 0)
167     {
168       child = gtk_combo_box_get_popup_accessible (GTK_COMBO_BOX (widget));
169       box = GTK_COMBO_BOX_ACCESSIBLE (obj);
170       if (box->popup_set == FALSE)
171         {
172           atk_object_set_parent (child, obj);
173           box->popup_set = TRUE;
174         }
175     }
176   else if (i == 1 && gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget)))
177     {
178       child = gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (widget)));
179     }
180   else
181     {
182       return NULL;
183     }
184
185   return g_object_ref (child);
186 }
187
188 static void
189 gtk_combo_box_accessible_class_init (GtkComboBoxAccessibleClass *klass)
190 {
191   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
192   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
193
194   gobject_class->finalize = gtk_combo_box_accessible_finalize;
195
196   class->get_name = gtk_combo_box_accessible_get_name;
197   class->get_n_children = gtk_combo_box_accessible_get_n_children;
198   class->ref_child = gtk_combo_box_accessible_ref_child;
199   class->initialize = gtk_combo_box_accessible_initialize;
200 }
201
202 static void
203 gtk_combo_box_accessible_init (GtkComboBoxAccessible *combo_box)
204 {
205   combo_box->old_selection = -1;
206   combo_box->name = NULL;
207   combo_box->popup_set = FALSE;
208 }
209
210 static gboolean
211 gtk_combo_box_accessible_do_action (AtkAction *action,
212                                     gint       i)
213 {
214   GtkComboBox *combo_box;
215   GtkWidget *widget;
216   gboolean popup_shown;
217
218   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
219   if (widget == NULL)
220     return FALSE;
221
222   if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
223     return FALSE;
224
225   if (i == 0)
226     {
227       combo_box = GTK_COMBO_BOX (widget);
228       g_object_get (combo_box, "popup-shown", &popup_shown, NULL);
229       if (popup_shown)
230         gtk_combo_box_popdown (combo_box);
231       else
232         gtk_combo_box_popup (combo_box);
233       return TRUE;
234     }
235   else
236     return FALSE;
237 }
238
239 static gint
240 gtk_combo_box_accessible_get_n_actions (AtkAction *action)
241 {
242   return 1;
243 }
244
245 static const gchar *
246 gtk_combo_box_accessible_get_keybinding (AtkAction *action,
247                                          gint       i)
248 {
249   GtkComboBoxAccessible *combo_box;
250   GtkWidget *widget;
251   GtkWidget *label;
252   AtkRelationSet *set;
253   AtkRelation *relation;
254   GPtrArray *target;
255   gpointer target_object;
256   guint key_val;
257   gchar *return_value = NULL;
258
259   if (i != 0)
260     return NULL;
261
262   combo_box = GTK_COMBO_BOX_ACCESSIBLE (action);
263   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (combo_box));
264   if (widget == NULL)
265     return NULL;
266
267   set = atk_object_ref_relation_set (ATK_OBJECT (action));
268   if (set == NULL)
269     return NULL;
270
271   label = NULL;
272   relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
273   if (relation)
274     {
275       target = atk_relation_get_target (relation);
276       target_object = g_ptr_array_index (target, 0);
277       widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
278     }
279   g_object_unref (set);
280   if (GTK_IS_LABEL (label))
281     {
282       key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
283       if (key_val != GDK_KEY_VoidSymbol)
284         return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
285     }
286
287   return return_value;
288 }
289
290 static const gchar *
291 gtk_combo_box_accessible_action_get_name (AtkAction *action,
292                                           gint       i)
293 {
294   if (i != 0)
295     return NULL;
296
297   return "press";
298 }
299
300 static void
301 atk_action_interface_init (AtkActionIface *iface)
302 {
303   iface->do_action = gtk_combo_box_accessible_do_action;
304   iface->get_n_actions = gtk_combo_box_accessible_get_n_actions;
305   iface->get_keybinding = gtk_combo_box_accessible_get_keybinding;
306   iface->get_name = gtk_combo_box_accessible_action_get_name;
307 }
308
309 static gboolean
310 gtk_combo_box_accessible_add_selection (AtkSelection *selection,
311                                         gint          i)
312 {
313   GtkWidget *widget;
314
315   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
316   if (widget == NULL)
317     return FALSE;
318
319   gtk_combo_box_set_active (GTK_COMBO_BOX (widget), i);
320
321   return TRUE;
322 }
323
324 static gboolean
325 gtk_combo_box_accessible_clear_selection (AtkSelection *selection)
326 {
327   GtkWidget *widget;
328
329   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
330   if (widget == NULL)
331     return FALSE;
332
333   gtk_combo_box_set_active (GTK_COMBO_BOX (widget), -1);
334
335   return TRUE;
336 }
337
338 static AtkObject *
339 gtk_combo_box_accessible_ref_selection (AtkSelection *selection,
340                                         gint          i)
341 {
342   GtkComboBox *combo_box;
343   GtkWidget *widget;
344   AtkObject *obj;
345   gint index;
346
347   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
348   if (widget == NULL)
349     return NULL;
350
351   if (i != 0)
352     return NULL;
353
354   combo_box = GTK_COMBO_BOX (widget);
355
356   obj = gtk_combo_box_get_popup_accessible (combo_box);
357   index = gtk_combo_box_get_active (combo_box);
358
359   return atk_object_ref_accessible_child (obj, index);
360 }
361
362 static gint
363 gtk_combo_box_accessible_get_selection_count (AtkSelection *selection)
364 {
365   GtkWidget *widget;
366
367   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
368   if (widget == NULL)
369     return 0;
370
371   return (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1) ? 0 : 1;
372 }
373
374 static gboolean
375 gtk_combo_box_accessible_is_child_selected (AtkSelection *selection,
376                                             gint          i)
377 {
378   GtkWidget *widget;
379   gint j;
380
381   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
382
383   if (widget == NULL)
384     return FALSE;
385
386   j = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
387
388   return (j == i);
389 }
390
391 static gboolean
392 gtk_combo_box_accessible_remove_selection (AtkSelection *selection,
393                                            gint          i)
394 {
395   if (atk_selection_is_child_selected (selection, i))
396     atk_selection_clear_selection (selection);
397
398   return TRUE;
399 }
400
401 static void
402 atk_selection_interface_init (AtkSelectionIface *iface)
403 {
404   iface->add_selection = gtk_combo_box_accessible_add_selection;
405   iface->clear_selection = gtk_combo_box_accessible_clear_selection;
406   iface->ref_selection = gtk_combo_box_accessible_ref_selection;
407   iface->get_selection_count = gtk_combo_box_accessible_get_selection_count;
408   iface->is_child_selected = gtk_combo_box_accessible_is_child_selected;
409   iface->remove_selection = gtk_combo_box_accessible_remove_selection;
410 }