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