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