]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkcellaccessible.c
a11y: Remove index from cellaccessible
[~andy/gtk] / gtk / a11y / gtkcellaccessible.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001 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 <gtk/gtk.h>
23 #include "gtkcontainercellaccessible.h"
24 #include "gtkcellaccessible.h"
25 #include "gtkcellaccessibleparent.h"
26
27 typedef struct _ActionInfo ActionInfo;
28 struct _ActionInfo {
29   gchar *name;
30   gchar *description;
31   gchar *keybinding;
32   void (*do_action_func) (GtkCellAccessible *cell);
33 };
34
35
36 static void atk_action_interface_init    (AtkActionIface    *iface);
37 static void atk_component_interface_init (AtkComponentIface *iface);
38
39 G_DEFINE_TYPE_WITH_CODE (GtkCellAccessible, _gtk_cell_accessible, ATK_TYPE_OBJECT,
40                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
41                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init))
42
43 static void
44 destroy_action_info (gpointer action_info)
45 {
46   ActionInfo *info = (ActionInfo *)action_info;
47
48   g_free (info->name);
49   g_free (info->description);
50   g_free (info->keybinding);
51   g_free (info);
52 }
53
54 static void
55 gtk_cell_accessible_object_finalize (GObject *obj)
56 {
57   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (obj);
58   AtkRelationSet *relation_set;
59   AtkRelation *relation;
60   GPtrArray *target;
61   gpointer target_object;
62   gint i;
63
64   if (cell->state_set)
65     g_object_unref (cell->state_set);
66
67   if (cell->action_list)
68     g_list_free_full (cell->action_list, destroy_action_info);
69
70   relation_set = atk_object_ref_relation_set (ATK_OBJECT (obj));
71   if (ATK_IS_RELATION_SET (relation_set))
72     {
73       relation = atk_relation_set_get_relation_by_type (relation_set,
74                                                         ATK_RELATION_NODE_CHILD_OF);
75       if (relation)
76         {
77           target = atk_relation_get_target (relation);
78           for (i = 0; i < target->len; i++)
79             {
80               target_object = g_ptr_array_index (target, i);
81               if (GTK_IS_CELL_ACCESSIBLE (target_object))
82                 g_object_unref (target_object);
83             }
84         }
85       g_object_unref (relation_set);
86     }
87   G_OBJECT_CLASS (_gtk_cell_accessible_parent_class)->finalize (obj);
88 }
89
90 static gint
91 gtk_cell_accessible_get_index_in_parent (AtkObject *obj)
92 {
93   GtkCellAccessible *cell;
94   AtkObject *parent;
95
96   cell = GTK_CELL_ACCESSIBLE (obj);
97
98   parent = atk_object_get_parent (obj);
99   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
100     return g_list_index (GTK_CONTAINER_CELL_ACCESSIBLE (parent)->children, obj);
101
102   parent = gtk_widget_get_accessible (cell->widget);
103   if (parent == NULL)
104     return -1;
105
106   return _gtk_cell_accessible_parent_get_child_index (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
107 }
108
109 static AtkStateSet *
110 gtk_cell_accessible_ref_state_set (AtkObject *obj)
111 {
112   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (obj);
113
114   g_object_ref (cell->state_set);
115
116   return cell->state_set;
117 }
118
119 static void
120 _gtk_cell_accessible_class_init (GtkCellAccessibleClass *klass)
121 {
122   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
123   GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
124
125   g_object_class->finalize = gtk_cell_accessible_object_finalize;
126
127   class->get_index_in_parent = gtk_cell_accessible_get_index_in_parent;
128   class->ref_state_set = gtk_cell_accessible_ref_state_set;
129 }
130
131 static void
132 _gtk_cell_accessible_init (GtkCellAccessible *cell)
133 {
134   cell->widget = NULL;
135   cell->action_list = NULL;
136   cell->state_set = atk_state_set_new ();
137   atk_state_set_add_state (cell->state_set, ATK_STATE_TRANSIENT);
138   atk_state_set_add_state (cell->state_set, ATK_STATE_ENABLED);
139   atk_state_set_add_state (cell->state_set, ATK_STATE_SENSITIVE);
140   atk_state_set_add_state (cell->state_set, ATK_STATE_SELECTABLE);
141 }
142
143 static void
144 widget_destroyed (GtkWidget         *widget,
145                   GtkCellAccessible *cell)
146 {
147   cell->widget = NULL;
148 }
149
150 void
151 _gtk_cell_accessible_initialise (GtkCellAccessible *cell,
152                                  GtkWidget         *widget,
153                                  AtkObject         *parent)
154 {
155   cell->widget = widget;
156   atk_object_set_parent (ATK_OBJECT (cell), parent);
157
158   g_signal_connect_object (G_OBJECT (widget), "destroy",
159                            G_CALLBACK (widget_destroyed), cell, 0);
160 }
161
162 gboolean
163 _gtk_cell_accessible_add_state (GtkCellAccessible *cell,
164                                 AtkStateType       state_type,
165                                 gboolean           emit_signal)
166 {
167   gboolean rc;
168   AtkObject *parent;
169
170   if (atk_state_set_contains_state (cell->state_set, state_type))
171     return FALSE;
172
173   rc = atk_state_set_add_state (cell->state_set, state_type);
174
175   /* The signal should only be generated if the value changed,
176    * not when the cell is set up. So states that are set
177    * initially should pass FALSE as the emit_signal argument.
178    */
179   if (emit_signal)
180     {
181       atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
182       /* If state_type is ATK_STATE_VISIBLE, additional notification */
183       if (state_type == ATK_STATE_VISIBLE)
184         g_signal_emit_by_name (cell, "visible-data-changed");
185     }
186
187   /* If the parent is a flyweight container cell, propagate the state
188    * change to it also
189    */
190   parent = atk_object_get_parent (ATK_OBJECT (cell));
191   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
192     _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
193
194   return rc;
195 }
196
197 gboolean
198 _gtk_cell_accessible_remove_state (GtkCellAccessible *cell,
199                                    AtkStateType       state_type,
200                                    gboolean           emit_signal)
201 {
202   gboolean rc;
203   AtkObject *parent;
204
205   if (!atk_state_set_contains_state (cell->state_set, state_type))
206     return FALSE;
207
208   parent = atk_object_get_parent (ATK_OBJECT (cell));
209
210   rc = atk_state_set_remove_state (cell->state_set, state_type);
211
212   /* The signal should only be generated if the value changed,
213    * not when the cell is set up.  So states that are set
214    * initially should pass FALSE as the emit_signal argument.
215    */
216   if (emit_signal)
217     {
218       atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
219       /* If state_type is ATK_STATE_VISIBLE, additional notification */
220       if (state_type == ATK_STATE_VISIBLE)
221         g_signal_emit_by_name (cell, "visible-data-changed");
222     }
223
224   /* If the parent is a flyweight container cell, propagate the state
225    * change to it also
226    */
227   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
228     _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
229
230   return rc;
231 }
232
233 gboolean
234 _gtk_cell_accessible_add_action (GtkCellAccessible *cell,
235                                  const gchar       *name,
236                                  const gchar       *description,
237                                  const gchar       *keybinding,
238                                  void (*func) (GtkCellAccessible *))
239 {
240   ActionInfo *info;
241
242   info = g_new (ActionInfo, 1);
243   info->name = g_strdup (name);
244   info->description = g_strdup (description);
245   info->keybinding = g_strdup (keybinding);
246   info->do_action_func = func;
247
248   cell->action_list = g_list_append (cell->action_list, info);
249
250   return TRUE;
251 }
252
253 gboolean
254 _gtk_cell_accessible_remove_action (GtkCellAccessible *cell,
255                                     gint               index)
256 {
257   GList *l;
258
259   l = g_list_nth (cell->action_list, index);
260   if (l == NULL)
261     return FALSE;
262
263   destroy_action_info (l->data);
264   cell->action_list = g_list_remove_link (cell->action_list, l);
265
266   return TRUE;
267 }
268
269
270 gboolean
271 _gtk_cell_accessible_remove_action_by_name (GtkCellAccessible *cell,
272                                             const gchar       *name)
273 {
274   GList *l;
275
276   for (l = cell->action_list; l; l = l->next)
277     {
278       ActionInfo *info = l->data;
279
280       if (g_strcmp0 (info->name, name) == 0)
281         break;
282     }
283
284   if (l == NULL)
285     return FALSE;
286
287   destroy_action_info (l->data);
288   cell->action_list = g_list_remove_link (cell->action_list, l);
289
290   return TRUE;
291 }
292
293 static ActionInfo *
294 get_action_info (GtkCellAccessible *cell,
295                  gint               index)
296 {
297   GList *l;
298
299   l = g_list_nth (cell->action_list, index);
300   if (l == NULL)
301     return NULL;
302
303   return (ActionInfo *) (l->data);
304 }
305
306 static gint
307 gtk_cell_accessible_action_get_n_actions (AtkAction *action)
308 {
309   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE(action);
310   if (cell->action_list != NULL)
311     return g_list_length (cell->action_list);
312   else
313     return 0;
314 }
315
316 static const gchar *
317 gtk_cell_accessible_action_get_name (AtkAction *action,
318                                      gint       index)
319 {
320   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
321   ActionInfo *info;
322
323   info = get_action_info (cell, index);
324   if (info == NULL)
325     return NULL;
326
327   return info->name;
328 }
329
330 static const gchar *
331 gtk_cell_accessible_action_get_description (AtkAction *action,
332                                             gint       index)
333 {
334   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
335   ActionInfo *info;
336
337   info = get_action_info (cell, index);
338   if (info == NULL)
339     return NULL;
340
341   return info->description;
342 }
343
344 static const gchar *
345 gtk_cell_accessible_action_get_keybinding (AtkAction *action,
346                                            gint       index)
347 {
348   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
349   ActionInfo *info;
350
351   info = get_action_info (cell, index);
352   if (info == NULL)
353     return NULL;
354
355   return info->keybinding;
356 }
357
358 static gboolean
359 gtk_cell_accessible_action_do_action (AtkAction *action,
360                                       gint       index)
361 {
362   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
363   ActionInfo *info;
364
365   info = get_action_info (cell, index);
366   if (info == NULL)
367     return FALSE;
368
369   if (info->do_action_func == NULL)
370     return FALSE;
371
372   info->do_action_func (cell);
373
374   return TRUE;
375 }
376
377 static void
378 atk_action_interface_init (AtkActionIface *iface)
379 {
380   iface->get_n_actions = gtk_cell_accessible_action_get_n_actions;
381   iface->do_action = gtk_cell_accessible_action_do_action;
382   iface->get_name = gtk_cell_accessible_action_get_name;
383   iface->get_description = gtk_cell_accessible_action_get_description;
384   iface->get_keybinding = gtk_cell_accessible_action_get_keybinding;
385 }
386
387 static void
388 gtk_cell_accessible_get_extents (AtkComponent *component,
389                                  gint         *x,
390                                  gint         *y,
391                                  gint         *width,
392                                  gint         *height,
393                                  AtkCoordType  coord_type)
394 {
395   GtkCellAccessible *cell;
396   AtkObject *parent;
397
398   cell = GTK_CELL_ACCESSIBLE (component);
399   parent = gtk_widget_get_accessible (cell->widget);
400
401   _gtk_cell_accessible_parent_get_cell_extents (GTK_CELL_ACCESSIBLE_PARENT (parent),
402                                                 cell,
403                                                 x, y, width, height, coord_type);
404 }
405
406 static gboolean
407 gtk_cell_accessible_grab_focus (AtkComponent *component)
408 {
409   GtkCellAccessible *cell;
410   AtkObject *parent;
411
412   cell = GTK_CELL_ACCESSIBLE (component);
413   parent = gtk_widget_get_accessible (cell->widget);
414
415   return _gtk_cell_accessible_parent_grab_focus (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
416 }
417
418 static void
419 atk_component_interface_init (AtkComponentIface *iface)
420 {
421   iface->get_extents = gtk_cell_accessible_get_extents;
422   iface->grab_focus = gtk_cell_accessible_grab_focus;
423 }