]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtkcellaccessible.c
Merge branch 'bgo593793-filechooser-recent-folders-master'
[~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
95   cell = GTK_CELL_ACCESSIBLE (obj);
96   if (atk_state_set_contains_state (cell->state_set, ATK_STATE_STALE) &&
97       cell->refresh_index != NULL)
98     {
99       cell->refresh_index (cell);
100       atk_state_set_remove_state (cell->state_set, ATK_STATE_STALE);
101     }
102
103   return cell->index;
104 }
105
106 static AtkStateSet *
107 gtk_cell_accessible_ref_state_set (AtkObject *obj)
108 {
109   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (obj);
110
111   g_object_ref (cell->state_set);
112
113   return cell->state_set;
114 }
115
116 static void
117 _gtk_cell_accessible_class_init (GtkCellAccessibleClass *klass)
118 {
119   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
120   GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
121
122   g_object_class->finalize = gtk_cell_accessible_object_finalize;
123
124   class->get_index_in_parent = gtk_cell_accessible_get_index_in_parent;
125   class->ref_state_set = gtk_cell_accessible_ref_state_set;
126 }
127
128 static void
129 _gtk_cell_accessible_init (GtkCellAccessible *cell)
130 {
131   cell->widget = NULL;
132   cell->action_list = NULL;
133   cell->index = 0;
134   cell->refresh_index = NULL;
135   cell->state_set = atk_state_set_new ();
136   atk_state_set_add_state (cell->state_set, ATK_STATE_TRANSIENT);
137   atk_state_set_add_state (cell->state_set, ATK_STATE_ENABLED);
138   atk_state_set_add_state (cell->state_set, ATK_STATE_SENSITIVE);
139   atk_state_set_add_state (cell->state_set, ATK_STATE_SELECTABLE);
140 }
141
142 static void
143 widget_destroyed (GtkWidget         *widget,
144                   GtkCellAccessible *cell)
145 {
146   cell->widget = NULL;
147 }
148
149 void
150 _gtk_cell_accessible_initialise (GtkCellAccessible *cell,
151                                  GtkWidget         *widget,
152                                  AtkObject         *parent,
153                                  gint               index)
154 {
155   cell->widget = widget;
156   atk_object_set_parent (ATK_OBJECT (cell), parent);
157   cell->index = index;
158
159   g_signal_connect_object (G_OBJECT (widget), "destroy",
160                            G_CALLBACK (widget_destroyed), cell, 0);
161 }
162
163 gboolean
164 _gtk_cell_accessible_add_state (GtkCellAccessible *cell,
165                                 AtkStateType       state_type,
166                                 gboolean           emit_signal)
167 {
168   gboolean rc;
169   AtkObject *parent;
170
171   if (atk_state_set_contains_state (cell->state_set, state_type))
172     return FALSE;
173
174   rc = atk_state_set_add_state (cell->state_set, state_type);
175
176   /* The signal should only be generated if the value changed,
177    * not when the cell is set up. So states that are set
178    * initially should pass FALSE as the emit_signal argument.
179    */
180   if (emit_signal)
181     {
182       atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
183       /* If state_type is ATK_STATE_VISIBLE, additional notification */
184       if (state_type == ATK_STATE_VISIBLE)
185         g_signal_emit_by_name (cell, "visible-data-changed");
186     }
187
188   /* If the parent is a flyweight container cell, propagate the state
189    * change to it also
190    */
191   parent = atk_object_get_parent (ATK_OBJECT (cell));
192   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
193     _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
194
195   return rc;
196 }
197
198 gboolean
199 _gtk_cell_accessible_remove_state (GtkCellAccessible *cell,
200                                    AtkStateType       state_type,
201                                    gboolean           emit_signal)
202 {
203   gboolean rc;
204   AtkObject *parent;
205
206   if (!atk_state_set_contains_state (cell->state_set, state_type))
207     return FALSE;
208
209   parent = atk_object_get_parent (ATK_OBJECT (cell));
210
211   rc = atk_state_set_remove_state (cell->state_set, state_type);
212
213   /* The signal should only be generated if the value changed,
214    * not when the cell is set up.  So states that are set
215    * initially should pass FALSE as the emit_signal argument.
216    */
217   if (emit_signal)
218     {
219       atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
220       /* If state_type is ATK_STATE_VISIBLE, additional notification */
221       if (state_type == ATK_STATE_VISIBLE)
222         g_signal_emit_by_name (cell, "visible-data-changed");
223     }
224
225   /* If the parent is a flyweight container cell, propagate the state
226    * change to it also
227    */
228   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
229     _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
230
231   return rc;
232 }
233
234 gboolean
235 _gtk_cell_accessible_add_action (GtkCellAccessible *cell,
236                                  const gchar       *name,
237                                  const gchar       *description,
238                                  const gchar       *keybinding,
239                                  void (*func) (GtkCellAccessible *))
240 {
241   ActionInfo *info;
242
243   info = g_new (ActionInfo, 1);
244   info->name = g_strdup (name);
245   info->description = g_strdup (description);
246   info->keybinding = g_strdup (keybinding);
247   info->do_action_func = func;
248
249   cell->action_list = g_list_append (cell->action_list, info);
250
251   return TRUE;
252 }
253
254 gboolean
255 _gtk_cell_accessible_remove_action (GtkCellAccessible *cell,
256                                     gint               index)
257 {
258   GList *l;
259
260   l = g_list_nth (cell->action_list, index);
261   if (l == NULL)
262     return FALSE;
263
264   destroy_action_info (l->data);
265   cell->action_list = g_list_remove_link (cell->action_list, l);
266
267   return TRUE;
268 }
269
270
271 gboolean
272 _gtk_cell_accessible_remove_action_by_name (GtkCellAccessible *cell,
273                                             const gchar       *name)
274 {
275   GList *l;
276
277   for (l = cell->action_list; l; l = l->next)
278     {
279       ActionInfo *info = l->data;
280
281       if (g_strcmp0 (info->name, name) == 0)
282         break;
283     }
284
285   if (l == NULL)
286     return FALSE;
287
288   destroy_action_info (l->data);
289   cell->action_list = g_list_remove_link (cell->action_list, l);
290
291   return TRUE;
292 }
293
294 static ActionInfo *
295 get_action_info (GtkCellAccessible *cell,
296                  gint               index)
297 {
298   GList *l;
299
300   l = g_list_nth (cell->action_list, index);
301   if (l == NULL)
302     return NULL;
303
304   return (ActionInfo *) (l->data);
305 }
306
307 static gint
308 gtk_cell_accessible_action_get_n_actions (AtkAction *action)
309 {
310   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE(action);
311   if (cell->action_list != NULL)
312     return g_list_length (cell->action_list);
313   else
314     return 0;
315 }
316
317 static const gchar *
318 gtk_cell_accessible_action_get_name (AtkAction *action,
319                                      gint       index)
320 {
321   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
322   ActionInfo *info;
323
324   info = get_action_info (cell, index);
325   if (info == NULL)
326     return NULL;
327
328   return info->name;
329 }
330
331 static const gchar *
332 gtk_cell_accessible_action_get_description (AtkAction *action,
333                                             gint       index)
334 {
335   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
336   ActionInfo *info;
337
338   info = get_action_info (cell, index);
339   if (info == NULL)
340     return NULL;
341
342   return info->description;
343 }
344
345 static const gchar *
346 gtk_cell_accessible_action_get_keybinding (AtkAction *action,
347                                            gint       index)
348 {
349   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
350   ActionInfo *info;
351
352   info = get_action_info (cell, index);
353   if (info == NULL)
354     return NULL;
355
356   return info->keybinding;
357 }
358
359 static gboolean
360 gtk_cell_accessible_action_do_action (AtkAction *action,
361                                       gint       index)
362 {
363   GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
364   ActionInfo *info;
365
366   info = get_action_info (cell, index);
367   if (info == NULL)
368     return FALSE;
369
370   if (info->do_action_func == NULL)
371     return FALSE;
372
373   info->do_action_func (cell);
374
375   return TRUE;
376 }
377
378 static void
379 atk_action_interface_init (AtkActionIface *iface)
380 {
381   iface->get_n_actions = gtk_cell_accessible_action_get_n_actions;
382   iface->do_action = gtk_cell_accessible_action_do_action;
383   iface->get_name = gtk_cell_accessible_action_get_name;
384   iface->get_description = gtk_cell_accessible_action_get_description;
385   iface->get_keybinding = gtk_cell_accessible_action_get_keybinding;
386 }
387
388 static void
389 gtk_cell_accessible_get_extents (AtkComponent *component,
390                                  gint         *x,
391                                  gint         *y,
392                                  gint         *width,
393                                  gint         *height,
394                                  AtkCoordType  coord_type)
395 {
396   GtkCellAccessible *cell;
397   AtkObject *parent;
398
399   cell = GTK_CELL_ACCESSIBLE (component);
400   parent = gtk_widget_get_accessible (cell->widget);
401
402   _gtk_cell_accessible_parent_get_cell_extents (GTK_CELL_ACCESSIBLE_PARENT (parent),
403                                                 cell,
404                                                 x, y, width, height, coord_type);
405 }
406
407 static gboolean
408 gtk_cell_accessible_grab_focus (AtkComponent *component)
409 {
410   GtkCellAccessible *cell;
411   AtkObject *parent;
412
413   cell = GTK_CELL_ACCESSIBLE (component);
414   parent = gtk_widget_get_accessible (cell->widget);
415
416   return _gtk_cell_accessible_parent_grab_focus (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
417 }
418
419 static void
420 atk_component_interface_init (AtkComponentIface *iface)
421 {
422   iface->get_extents = gtk_cell_accessible_get_extents;
423   iface->grab_focus = gtk_cell_accessible_grab_focus;
424 }