1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2001 Sun Microsystems Inc.
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.
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.
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.
23 #include "gtkcontainercellaccessible.h"
24 #include "gtkcellaccessible.h"
25 #include "gtkcellaccessibleparent.h"
27 typedef struct _ActionInfo ActionInfo;
32 void (*do_action_func) (GtkCellAccessible *cell);
37 GtkCellRendererState renderer_state;
40 { ATK_STATE_SENSITIVE, GTK_CELL_RENDERER_INSENSITIVE, TRUE },
41 { ATK_STATE_ENABLED, GTK_CELL_RENDERER_INSENSITIVE, TRUE },
42 { ATK_STATE_SELECTED, GTK_CELL_RENDERER_SELECTED, FALSE },
43 /* XXX: why do we map ACTIVE here? */
44 { ATK_STATE_ACTIVE, GTK_CELL_RENDERER_FOCUSED, FALSE },
45 { ATK_STATE_FOCUSED, GTK_CELL_RENDERER_FOCUSED, FALSE },
46 { ATK_STATE_EXPANDABLE,GTK_CELL_RENDERER_EXPANDABLE, FALSE },
47 { ATK_STATE_EXPANDED, GTK_CELL_RENDERER_EXPANDED, FALSE },
50 static void atk_action_interface_init (AtkActionIface *iface);
51 static void atk_component_interface_init (AtkComponentIface *iface);
53 G_DEFINE_TYPE_WITH_CODE (GtkCellAccessible, _gtk_cell_accessible, ATK_TYPE_OBJECT,
54 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
55 G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init))
58 destroy_action_info (gpointer action_info)
60 ActionInfo *info = (ActionInfo *)action_info;
63 g_free (info->description);
64 g_free (info->keybinding);
69 gtk_cell_accessible_object_finalize (GObject *obj)
71 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (obj);
72 AtkRelationSet *relation_set;
73 AtkRelation *relation;
75 gpointer target_object;
78 if (cell->action_list)
79 g_list_free_full (cell->action_list, destroy_action_info);
81 relation_set = atk_object_ref_relation_set (ATK_OBJECT (obj));
82 if (ATK_IS_RELATION_SET (relation_set))
84 relation = atk_relation_set_get_relation_by_type (relation_set,
85 ATK_RELATION_NODE_CHILD_OF);
88 target = atk_relation_get_target (relation);
89 for (i = 0; i < target->len; i++)
91 target_object = g_ptr_array_index (target, i);
92 if (GTK_IS_CELL_ACCESSIBLE (target_object))
93 g_object_unref (target_object);
96 g_object_unref (relation_set);
98 G_OBJECT_CLASS (_gtk_cell_accessible_parent_class)->finalize (obj);
102 gtk_cell_accessible_get_index_in_parent (AtkObject *obj)
104 GtkCellAccessible *cell;
107 cell = GTK_CELL_ACCESSIBLE (obj);
109 parent = atk_object_get_parent (obj);
110 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
111 return g_list_index (GTK_CONTAINER_CELL_ACCESSIBLE (parent)->children, obj);
113 parent = gtk_widget_get_accessible (cell->widget);
117 return _gtk_cell_accessible_parent_get_child_index (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
121 gtk_cell_accessible_ref_state_set (AtkObject *accessible)
123 GtkCellAccessible *cell_accessible;
124 AtkStateSet *state_set;
125 GtkCellRendererState flags;
128 cell_accessible = GTK_CELL_ACCESSIBLE (accessible);
130 state_set = atk_state_set_new ();
132 if (cell_accessible->widget == NULL)
134 atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
138 flags = _gtk_cell_accessible_get_state (cell_accessible);
140 atk_state_set_add_state (state_set, ATK_STATE_TRANSIENT);
141 atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
142 atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
144 for (i = 0; i < G_N_ELEMENTS (state_map); i++)
146 if (flags & state_map[i].renderer_state)
148 if (!state_map[i].invert)
149 atk_state_set_add_state (state_set, state_map[i].atk_state);
153 if (state_map[i].invert)
154 atk_state_set_add_state (state_set, state_map[i].atk_state);
158 if (gtk_widget_get_mapped (cell_accessible->widget))
159 atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
166 _gtk_cell_accessible_class_init (GtkCellAccessibleClass *klass)
168 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
169 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
171 g_object_class->finalize = gtk_cell_accessible_object_finalize;
173 class->get_index_in_parent = gtk_cell_accessible_get_index_in_parent;
174 class->ref_state_set = gtk_cell_accessible_ref_state_set;
178 _gtk_cell_accessible_init (GtkCellAccessible *cell)
181 cell->action_list = NULL;
185 widget_destroyed (GtkWidget *widget,
186 GtkCellAccessible *cell)
192 _gtk_cell_accessible_initialise (GtkCellAccessible *cell,
196 cell->widget = widget;
197 atk_object_set_parent (ATK_OBJECT (cell), parent);
199 g_signal_connect_object (G_OBJECT (widget), "destroy",
200 G_CALLBACK (widget_destroyed), cell, 0);
204 _gtk_cell_accessible_add_state (GtkCellAccessible *cell,
205 AtkStateType state_type,
206 gboolean emit_signal)
210 /* The signal should only be generated if the value changed,
211 * not when the cell is set up. So states that are set
212 * initially should pass FALSE as the emit_signal argument.
216 atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
217 /* If state_type is ATK_STATE_VISIBLE, additional notification */
218 if (state_type == ATK_STATE_VISIBLE)
219 g_signal_emit_by_name (cell, "visible-data-changed");
222 /* If the parent is a flyweight container cell, propagate the state
225 parent = atk_object_get_parent (ATK_OBJECT (cell));
226 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
227 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
233 _gtk_cell_accessible_remove_state (GtkCellAccessible *cell,
234 AtkStateType state_type,
235 gboolean emit_signal)
239 parent = atk_object_get_parent (ATK_OBJECT (cell));
241 /* The signal should only be generated if the value changed,
242 * not when the cell is set up. So states that are set
243 * initially should pass FALSE as the emit_signal argument.
247 atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
248 /* If state_type is ATK_STATE_VISIBLE, additional notification */
249 if (state_type == ATK_STATE_VISIBLE)
250 g_signal_emit_by_name (cell, "visible-data-changed");
253 /* If the parent is a flyweight container cell, propagate the state
256 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
257 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
263 _gtk_cell_accessible_add_action (GtkCellAccessible *cell,
265 const gchar *description,
266 const gchar *keybinding,
267 void (*func) (GtkCellAccessible *))
271 info = g_new (ActionInfo, 1);
272 info->name = g_strdup (name);
273 info->description = g_strdup (description);
274 info->keybinding = g_strdup (keybinding);
275 info->do_action_func = func;
277 cell->action_list = g_list_append (cell->action_list, info);
283 _gtk_cell_accessible_remove_action (GtkCellAccessible *cell,
288 l = g_list_nth (cell->action_list, index);
292 destroy_action_info (l->data);
293 cell->action_list = g_list_remove_link (cell->action_list, l);
300 _gtk_cell_accessible_remove_action_by_name (GtkCellAccessible *cell,
305 for (l = cell->action_list; l; l = l->next)
307 ActionInfo *info = l->data;
309 if (g_strcmp0 (info->name, name) == 0)
316 destroy_action_info (l->data);
317 cell->action_list = g_list_remove_link (cell->action_list, l);
323 get_action_info (GtkCellAccessible *cell,
328 l = g_list_nth (cell->action_list, index);
332 return (ActionInfo *) (l->data);
336 gtk_cell_accessible_action_get_n_actions (AtkAction *action)
338 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE(action);
339 if (cell->action_list != NULL)
340 return g_list_length (cell->action_list);
346 gtk_cell_accessible_action_get_name (AtkAction *action,
349 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
352 info = get_action_info (cell, index);
360 gtk_cell_accessible_action_get_description (AtkAction *action,
363 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
366 info = get_action_info (cell, index);
370 return info->description;
374 gtk_cell_accessible_action_get_keybinding (AtkAction *action,
377 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
380 info = get_action_info (cell, index);
384 return info->keybinding;
388 gtk_cell_accessible_action_do_action (AtkAction *action,
391 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
394 info = get_action_info (cell, index);
398 if (info->do_action_func == NULL)
401 info->do_action_func (cell);
407 atk_action_interface_init (AtkActionIface *iface)
409 iface->get_n_actions = gtk_cell_accessible_action_get_n_actions;
410 iface->do_action = gtk_cell_accessible_action_do_action;
411 iface->get_name = gtk_cell_accessible_action_get_name;
412 iface->get_description = gtk_cell_accessible_action_get_description;
413 iface->get_keybinding = gtk_cell_accessible_action_get_keybinding;
417 gtk_cell_accessible_get_extents (AtkComponent *component,
422 AtkCoordType coord_type)
424 GtkCellAccessible *cell;
427 cell = GTK_CELL_ACCESSIBLE (component);
428 parent = gtk_widget_get_accessible (cell->widget);
430 _gtk_cell_accessible_parent_get_cell_extents (GTK_CELL_ACCESSIBLE_PARENT (parent),
432 x, y, width, height, coord_type);
436 gtk_cell_accessible_grab_focus (AtkComponent *component)
438 GtkCellAccessible *cell;
441 cell = GTK_CELL_ACCESSIBLE (component);
442 parent = gtk_widget_get_accessible (cell->widget);
444 return _gtk_cell_accessible_parent_grab_focus (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
448 atk_component_interface_init (AtkComponentIface *iface)
450 iface->get_extents = gtk_cell_accessible_get_extents;
451 iface->grab_focus = gtk_cell_accessible_grab_focus;
455 * _gtk_cell_accessible_set_cell_data:
456 * @cell: a #GtkCellAccessible
458 * Sets the cell data to the row used by @cell. This is useful in
459 * particular if you want to work with cell renderers.
461 * Note that this function is potentially slow, so be careful.
464 _gtk_cell_accessible_set_cell_data (GtkCellAccessible *cell)
468 g_return_if_fail (GTK_IS_CELL_ACCESSIBLE (cell));
470 parent = gtk_widget_get_accessible (cell->widget);
474 _gtk_cell_accessible_parent_set_cell_data (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
478 * _gtk_cell_accessible_get_state:
479 * @cell: a #GtkCellAccessible
481 * Gets the state that would be used to render the area referenced by @cell.
483 * Returns: the #GtkCellRendererState for cell
486 _gtk_cell_accessible_get_state (GtkCellAccessible *cell)
490 g_return_val_if_fail (GTK_IS_CELL_ACCESSIBLE (cell), 0);
492 parent = gtk_widget_get_accessible (cell->widget);
496 return _gtk_cell_accessible_parent_get_renderer_state (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
500 * _gtk_cell_accessible_state_changed:
501 * @cell: a #GtkCellAccessible
502 * @added: the flags that were added from @cell
503 * @removed: the flags that were removed from @cell
505 * Notifies @cell of state changes. Multiple states may be added
506 * or removed at the same time. A state that is @added may not be
507 * @removed at the same time.
510 _gtk_cell_accessible_state_changed (GtkCellAccessible *cell,
511 GtkCellRendererState added,
512 GtkCellRendererState removed)
517 g_return_if_fail (GTK_IS_CELL_ACCESSIBLE (cell));
518 g_return_if_fail ((added & removed) == 0);
520 object = ATK_OBJECT (cell);
522 for (i = 0; i < G_N_ELEMENTS (state_map); i++)
524 if (added & state_map[i].renderer_state)
525 atk_object_notify_state_change (object,
526 state_map[i].atk_state,
527 !state_map[i].invert);
528 if (added & state_map[i].renderer_state)
529 atk_object_notify_state_change (object,
530 state_map[i].atk_state,
531 state_map[i].invert);