]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkbuttonaccessible.c
filechooser: Show FUSE mounted locations in shortcuts
[~andy/gtk] / gtk / a11y / gtkbuttonaccessible.c
1 /* GTK+ - accessibility implementations
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 <string.h>
21 #include <gtk/gtk.h>
22 #include <glib/gi18n-lib.h>
23 #include "gtkbuttonaccessible.h"
24
25
26 static void atk_action_interface_init (AtkActionIface *iface);
27 static void atk_image_interface_init  (AtkImageIface  *iface);
28
29 G_DEFINE_TYPE_WITH_CODE (GtkButtonAccessible, gtk_button_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
30                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
31                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE, atk_image_interface_init))
32
33 static void
34 state_changed_cb (GtkWidget *widget, GtkStateFlags previous_flags)
35 {
36   AtkObject *accessible;
37   GtkStateFlags flags;
38   gboolean was_active;
39   gboolean active;
40
41   flags = gtk_widget_get_state_flags (widget);
42
43   was_active = (previous_flags & GTK_STATE_FLAG_ACTIVE) != 0;
44   active = (flags & GTK_STATE_FLAG_ACTIVE) != 0;
45
46   accessible = gtk_widget_get_accessible (widget);
47   if (active && !was_active)
48     atk_object_notify_state_change (accessible, ATK_STATE_ARMED, TRUE);
49   else if (!active && was_active)
50     atk_object_notify_state_change (accessible, ATK_STATE_ARMED, FALSE);
51 }
52
53 static void
54 gtk_button_accessible_initialize (AtkObject *obj,
55                                   gpointer   data)
56 {
57   GtkWidget *parent;
58
59   ATK_OBJECT_CLASS (gtk_button_accessible_parent_class)->initialize (obj, data);
60
61   g_signal_connect (data, "state-flags-changed", G_CALLBACK (state_changed_cb), NULL);
62
63   parent = gtk_widget_get_parent (gtk_accessible_get_widget (GTK_ACCESSIBLE (obj)));
64   if (GTK_IS_TREE_VIEW (parent))
65     {
66       /* Even though the accessible parent of the column header will
67        * be reported as the table because the parent widget of the
68        * GtkTreeViewColumn's button is the GtkTreeView we set
69        * the accessible parent for column header to be the table
70        * to ensure that atk_object_get_index_in_parent() returns
71        * the correct value; see gail_widget_get_index_in_parent().
72        */
73       atk_object_set_parent (obj, gtk_widget_get_accessible (parent));
74       obj->role = ATK_ROLE_TABLE_COLUMN_HEADER;
75     }
76   else
77     obj->role = ATK_ROLE_PUSH_BUTTON;
78 }
79
80 static GtkWidget *
81 get_image_from_button (GtkWidget *button)
82 {
83   GtkWidget *image;
84
85   image = gtk_button_get_image (GTK_BUTTON (button));
86   if (GTK_IS_IMAGE (image))
87     return image;
88
89   return NULL;
90 }
91
92 static GtkWidget *
93 find_label_child (GtkContainer *container)
94 {
95   GList *children, *tmp_list;
96   GtkWidget *child;
97
98   children = gtk_container_get_children (container);
99
100   child = NULL;
101   for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
102     {
103       if (GTK_IS_LABEL (tmp_list->data))
104         {
105           child = GTK_WIDGET (tmp_list->data);
106           break;
107         }
108       else if (GTK_IS_CONTAINER (tmp_list->data))
109         {
110           child = find_label_child (GTK_CONTAINER (tmp_list->data));
111           if (child)
112             break;
113         }
114     }
115   g_list_free (children);
116   return child;
117 }
118
119 static GtkWidget *
120 get_label_from_button (GtkWidget *button)
121 {
122   GtkWidget *child;
123
124   child = gtk_bin_get_child (GTK_BIN (button));
125   if (GTK_IS_ALIGNMENT (child))
126     child = gtk_bin_get_child (GTK_BIN (child));
127
128   if (GTK_IS_CONTAINER (child))
129     child = find_label_child (GTK_CONTAINER (child));
130   else if (!GTK_IS_LABEL (child))
131     child = NULL;
132
133   return child;
134 }
135
136 static const gchar *
137 gtk_button_accessible_get_name (AtkObject *obj)
138 {
139   const gchar *name = NULL;
140   GtkWidget *widget;
141   GtkWidget *child;
142
143   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
144   if (widget == NULL)
145     return NULL;
146
147   name = ATK_OBJECT_CLASS (gtk_button_accessible_parent_class)->get_name (obj);
148   if (name != NULL)
149     return name;
150
151   child = get_label_from_button (widget);
152   if (GTK_IS_LABEL (child))
153     name = gtk_label_get_text (GTK_LABEL (child));
154   else
155     {
156       GtkWidget *image;
157
158       image = get_image_from_button (widget);
159       if (GTK_IS_IMAGE (image))
160         {
161           AtkObject *atk_obj;
162
163           atk_obj = gtk_widget_get_accessible (image);
164           name = atk_object_get_name (atk_obj);
165         }
166     }
167
168   return name;
169 }
170
171 static gint
172 gtk_button_accessible_get_n_children (AtkObject* obj)
173 {
174   return 0;
175 }
176
177 static AtkObject *
178 gtk_button_accessible_ref_child (AtkObject *obj,
179                                  gint       i)
180 {
181   return NULL;
182 }
183
184 static AtkStateSet *
185 gtk_button_accessible_ref_state_set (AtkObject *obj)
186 {
187   AtkStateSet *state_set;
188   GtkWidget *widget;
189
190   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
191   if (widget == NULL)
192     return NULL;
193
194   state_set = ATK_OBJECT_CLASS (gtk_button_accessible_parent_class)->ref_state_set (obj);
195
196   if ((gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_ACTIVE) != 0)
197     atk_state_set_add_state (state_set, ATK_STATE_ARMED);
198
199   if (!gtk_widget_get_can_focus (widget))
200     atk_state_set_remove_state (state_set, ATK_STATE_SELECTABLE);
201
202   return state_set;
203 }
204
205 static void
206 gtk_button_accessible_notify_gtk (GObject    *obj,
207                                   GParamSpec *pspec)
208 {
209   GtkWidget *widget = GTK_WIDGET (obj);
210   AtkObject *atk_obj = gtk_widget_get_accessible (widget);
211
212   if (strcmp (pspec->name, "label") == 0)
213     {
214       if (atk_obj->name == NULL)
215         g_object_notify (G_OBJECT (atk_obj), "accessible-name");
216
217       g_signal_emit_by_name (atk_obj, "visible-data-changed");
218     }
219   else
220     GTK_WIDGET_ACCESSIBLE_CLASS (gtk_button_accessible_parent_class)->notify_gtk (obj, pspec);
221 }
222
223 static void
224 gtk_button_accessible_class_init (GtkButtonAccessibleClass *klass)
225 {
226   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
227   GtkContainerAccessibleClass *container_class = (GtkContainerAccessibleClass*)klass;
228   GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
229
230   class->get_name = gtk_button_accessible_get_name;
231   class->get_n_children = gtk_button_accessible_get_n_children;
232   class->ref_child = gtk_button_accessible_ref_child;
233   class->ref_state_set = gtk_button_accessible_ref_state_set;
234   class->initialize = gtk_button_accessible_initialize;
235
236   widget_class->notify_gtk = gtk_button_accessible_notify_gtk;
237
238   container_class->add_gtk = NULL;
239   container_class->remove_gtk = NULL;
240 }
241
242 static void
243 gtk_button_accessible_init (GtkButtonAccessible *button)
244 {
245 }
246
247 static gboolean
248 gtk_button_accessible_do_action (AtkAction *action,
249                                  gint       i)
250 {
251   GtkWidget *widget;
252
253   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
254   if (widget == NULL)
255     return FALSE;
256
257   if (i != 0)
258     return FALSE;
259
260   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
261     return FALSE;
262
263   gtk_button_clicked (GTK_BUTTON (widget));
264   return TRUE;
265 }
266
267 static gint
268 gtk_button_accessible_get_n_actions (AtkAction *action)
269 {
270   return 1;
271 }
272
273 static const gchar *
274 gtk_button_accessible_get_keybinding (AtkAction *action,
275                                       gint       i)
276 {
277   gchar *return_value = NULL;
278   GtkWidget *widget;
279   GtkWidget *label;
280   guint key_val;
281
282   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
283   if (widget == NULL)
284     return NULL;
285
286   if (i != 0)
287     return NULL;
288
289   label = get_label_from_button (widget);
290   if (GTK_IS_LABEL (label))
291     {
292       key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
293       if (key_val != GDK_KEY_VoidSymbol)
294         return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
295     }
296   if (return_value == NULL)
297     {
298       /* Find labelled-by relation */
299       AtkRelationSet *set;
300       AtkRelation *relation;
301       GPtrArray *target;
302       gpointer target_object;
303
304       set = atk_object_ref_relation_set (ATK_OBJECT (action));
305       if (set)
306         {
307           relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
308           if (relation)
309             {
310               target = atk_relation_get_target (relation);
311               target_object = g_ptr_array_index (target, 0);
312               label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
313             }
314           g_object_unref (set);
315         }
316
317       if (GTK_IS_LABEL (label))
318         {
319           key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
320           if (key_val != GDK_KEY_VoidSymbol)
321             return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
322         }
323     }
324   return return_value;
325 }
326
327 static const gchar *
328 gtk_button_accessible_action_get_name (AtkAction *action,
329                                        gint       i)
330 {
331   if (i == 0)
332     return "click";
333   return NULL;
334 }
335
336 static const gchar *
337 gtk_button_accessible_action_get_localized_name (AtkAction *action,
338                                                  gint       i)
339 {
340   if (i == 0)
341     return C_("Action name", "Click");
342   return NULL;
343 }
344
345 static const gchar *
346 gtk_button_accessible_action_get_description (AtkAction *action,
347                                               gint       i)
348 {
349   if (i == 0)
350     return C_("Action description", "Clicks the button");
351   return NULL;
352 }
353
354 static void
355 atk_action_interface_init (AtkActionIface *iface)
356 {
357   iface->do_action = gtk_button_accessible_do_action;
358   iface->get_n_actions = gtk_button_accessible_get_n_actions;
359   iface->get_keybinding = gtk_button_accessible_get_keybinding;
360   iface->get_name = gtk_button_accessible_action_get_name;
361   iface->get_localized_name = gtk_button_accessible_action_get_localized_name;
362   iface->get_description = gtk_button_accessible_action_get_description;
363 }
364
365 static const gchar *
366 gtk_button_accessible_get_image_description (AtkImage *image)
367 {
368   GtkWidget *widget;
369   GtkWidget  *button_image;
370   AtkObject *obj;
371
372   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
373   if (widget == NULL)
374     return NULL;
375
376   button_image = get_image_from_button (widget);
377   if (GTK_IS_IMAGE (button_image))
378     {
379       obj = gtk_widget_get_accessible (button_image);
380       return atk_image_get_image_description (ATK_IMAGE (obj));
381     }
382
383   return NULL;
384 }
385
386 static void
387 gtk_button_accessible_get_image_position (AtkImage     *image,
388                                           gint         *x,
389                                           gint         *y,
390                                           AtkCoordType  coord_type)
391 {
392   GtkWidget *widget;
393   GtkWidget *button_image;
394   AtkObject *obj;
395
396   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
397   if (widget == NULL)
398     {
399       *x = G_MININT;
400       *y = G_MININT;
401       return;
402     }
403
404   button_image = get_image_from_button (widget);
405   if (button_image != NULL)
406     {
407       obj = gtk_widget_get_accessible (button_image);
408       atk_component_get_position (ATK_COMPONENT (obj), x, y, coord_type);
409     }
410   else
411     {
412       *x = G_MININT;
413       *y = G_MININT;
414     }
415 }
416
417 static void
418 gtk_button_accessible_get_image_size (AtkImage *image,
419                                       gint     *width,
420                                       gint     *height)
421 {
422   GtkWidget *widget;
423   GtkWidget *button_image;
424   AtkObject *obj;
425
426   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
427   if (widget == NULL)
428     {
429       *width = -1;
430       *height = -1;
431       return;
432     }
433
434   button_image = get_image_from_button (widget);
435   if (GTK_IS_IMAGE (button_image))
436     {
437       obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
438       atk_image_get_image_size (ATK_IMAGE (obj), width, height);
439     }
440   else
441     {
442       *width = -1;
443       *height = -1;
444     }
445 }
446
447 static gboolean
448 gtk_button_accessible_set_image_description (AtkImage    *image,
449                                              const gchar *description)
450 {
451   GtkWidget *widget;
452   GtkWidget *button_image;
453   AtkObject *obj;
454
455   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
456
457   if (widget == NULL)
458     return FALSE;
459
460   button_image = get_image_from_button (widget);
461   if (GTK_IMAGE (button_image))
462     {
463       obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
464       return atk_image_set_image_description (ATK_IMAGE (obj), description);
465     }
466
467   return FALSE;
468 }
469
470 static void
471 atk_image_interface_init (AtkImageIface *iface)
472 {
473   iface->get_image_description = gtk_button_accessible_get_image_description;
474   iface->get_image_position = gtk_button_accessible_get_image_position;
475   iface->get_image_size = gtk_button_accessible_get_image_size;
476   iface->set_image_description = gtk_button_accessible_set_image_description;
477 }