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