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