]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkcomboboxaccessible.c
6b1581fd64cbf8b7685e37176c6d0210eca7265f
[~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 = G_VALUE_INIT;
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     return FALSE;
227
228   combo_box = GTK_COMBO_BOX (widget);
229   g_object_get (combo_box, "popup-shown", &popup_shown, NULL);
230   if (popup_shown)
231     gtk_combo_box_popdown (combo_box);
232   else
233     gtk_combo_box_popup (combo_box);
234
235   return TRUE;
236 }
237
238 static gint
239 gtk_combo_box_accessible_get_n_actions (AtkAction *action)
240 {
241   return 1;
242 }
243
244 static const gchar *
245 gtk_combo_box_accessible_get_keybinding (AtkAction *action,
246                                          gint       i)
247 {
248   GtkComboBoxAccessible *combo_box;
249   GtkWidget *widget;
250   GtkWidget *label;
251   AtkRelationSet *set;
252   AtkRelation *relation;
253   GPtrArray *target;
254   gpointer target_object;
255   guint key_val;
256   gchar *return_value = NULL;
257
258   if (i != 0)
259     return NULL;
260
261   combo_box = GTK_COMBO_BOX_ACCESSIBLE (action);
262   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (combo_box));
263   if (widget == NULL)
264     return NULL;
265
266   set = atk_object_ref_relation_set (ATK_OBJECT (action));
267   if (set == NULL)
268     return NULL;
269
270   label = NULL;
271   relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
272   if (relation)
273     {
274       target = atk_relation_get_target (relation);
275       target_object = g_ptr_array_index (target, 0);
276       label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
277     }
278   g_object_unref (set);
279   if (GTK_IS_LABEL (label))
280     {
281       key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
282       if (key_val != GDK_KEY_VoidSymbol)
283         return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
284     }
285
286   return return_value;
287 }
288
289 static const gchar *
290 gtk_combo_box_accessible_action_get_name (AtkAction *action,
291                                           gint       i)
292 {
293   if (i != 0)
294     return NULL;
295
296   return "press";
297 }
298
299 static void
300 atk_action_interface_init (AtkActionIface *iface)
301 {
302   iface->do_action = gtk_combo_box_accessible_do_action;
303   iface->get_n_actions = gtk_combo_box_accessible_get_n_actions;
304   iface->get_keybinding = gtk_combo_box_accessible_get_keybinding;
305   iface->get_name = gtk_combo_box_accessible_action_get_name;
306 }
307
308 static gboolean
309 gtk_combo_box_accessible_add_selection (AtkSelection *selection,
310                                         gint          i)
311 {
312   GtkWidget *widget;
313
314   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
315   if (widget == NULL)
316     return FALSE;
317
318   gtk_combo_box_set_active (GTK_COMBO_BOX (widget), i);
319
320   return TRUE;
321 }
322
323 static gboolean
324 gtk_combo_box_accessible_clear_selection (AtkSelection *selection)
325 {
326   GtkWidget *widget;
327
328   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
329   if (widget == NULL)
330     return FALSE;
331
332   gtk_combo_box_set_active (GTK_COMBO_BOX (widget), -1);
333
334   return TRUE;
335 }
336
337 static AtkObject *
338 gtk_combo_box_accessible_ref_selection (AtkSelection *selection,
339                                         gint          i)
340 {
341   GtkComboBox *combo_box;
342   GtkWidget *widget;
343   AtkObject *obj;
344   gint index;
345
346   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
347   if (widget == NULL)
348     return NULL;
349
350   if (i != 0)
351     return NULL;
352
353   combo_box = GTK_COMBO_BOX (widget);
354
355   obj = gtk_combo_box_get_popup_accessible (combo_box);
356   index = gtk_combo_box_get_active (combo_box);
357
358   return atk_object_ref_accessible_child (obj, index);
359 }
360
361 static gint
362 gtk_combo_box_accessible_get_selection_count (AtkSelection *selection)
363 {
364   GtkWidget *widget;
365
366   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
367   if (widget == NULL)
368     return 0;
369
370   return (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1) ? 0 : 1;
371 }
372
373 static gboolean
374 gtk_combo_box_accessible_is_child_selected (AtkSelection *selection,
375                                             gint          i)
376 {
377   GtkWidget *widget;
378   gint j;
379
380   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
381
382   if (widget == NULL)
383     return FALSE;
384
385   j = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
386
387   return (j == i);
388 }
389
390 static gboolean
391 gtk_combo_box_accessible_remove_selection (AtkSelection *selection,
392                                            gint          i)
393 {
394   if (atk_selection_is_child_selected (selection, i))
395     atk_selection_clear_selection (selection);
396
397   return TRUE;
398 }
399
400 static void
401 atk_selection_interface_init (AtkSelectionIface *iface)
402 {
403   iface->add_selection = gtk_combo_box_accessible_add_selection;
404   iface->clear_selection = gtk_combo_box_accessible_clear_selection;
405   iface->ref_selection = gtk_combo_box_accessible_ref_selection;
406   iface->get_selection_count = gtk_combo_box_accessible_get_selection_count;
407   iface->is_child_selected = gtk_combo_box_accessible_is_child_selected;
408   iface->remove_selection = gtk_combo_box_accessible_remove_selection;
409 }