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);
36 static void atk_action_interface_init (AtkActionIface *iface);
37 static void atk_component_interface_init (AtkComponentIface *iface);
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))
44 destroy_action_info (gpointer action_info)
46 ActionInfo *info = (ActionInfo *)action_info;
49 g_free (info->description);
50 g_free (info->keybinding);
55 gtk_cell_accessible_object_finalize (GObject *obj)
57 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (obj);
58 AtkRelationSet *relation_set;
59 AtkRelation *relation;
61 gpointer target_object;
64 if (cell->action_list)
65 g_list_free_full (cell->action_list, destroy_action_info);
67 relation_set = atk_object_ref_relation_set (ATK_OBJECT (obj));
68 if (ATK_IS_RELATION_SET (relation_set))
70 relation = atk_relation_set_get_relation_by_type (relation_set,
71 ATK_RELATION_NODE_CHILD_OF);
74 target = atk_relation_get_target (relation);
75 for (i = 0; i < target->len; i++)
77 target_object = g_ptr_array_index (target, i);
78 if (GTK_IS_CELL_ACCESSIBLE (target_object))
79 g_object_unref (target_object);
82 g_object_unref (relation_set);
84 G_OBJECT_CLASS (_gtk_cell_accessible_parent_class)->finalize (obj);
88 gtk_cell_accessible_get_index_in_parent (AtkObject *obj)
90 GtkCellAccessible *cell;
93 cell = GTK_CELL_ACCESSIBLE (obj);
95 parent = atk_object_get_parent (obj);
96 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
97 return g_list_index (GTK_CONTAINER_CELL_ACCESSIBLE (parent)->children, obj);
99 parent = gtk_widget_get_accessible (cell->widget);
103 return _gtk_cell_accessible_parent_get_child_index (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
107 gtk_cell_accessible_ref_state_set (AtkObject *accessible)
109 GtkCellAccessible *cell_accessible;
110 AtkStateSet *state_set;
111 GtkCellRendererState flags;
112 gboolean expandable, expanded;
114 cell_accessible = GTK_CELL_ACCESSIBLE (accessible);
116 state_set = atk_state_set_new ();
118 if (cell_accessible->widget == NULL)
120 atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
124 flags = _gtk_cell_accessible_get_state (cell_accessible, &expandable, &expanded);
126 atk_state_set_add_state (state_set, ATK_STATE_TRANSIENT);
128 if (!(flags & GTK_CELL_RENDERER_INSENSITIVE))
130 atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
131 atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
134 atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
135 if (flags & GTK_CELL_RENDERER_SELECTED)
136 atk_state_set_add_state (state_set, ATK_STATE_SELECTED);
138 atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
139 if (gtk_widget_get_mapped (cell_accessible->widget))
140 atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
142 /* This is not completely right. We should be tracking the
143 * focussed cell renderer, but that involves diving into
146 atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
147 if (flags & GTK_CELL_RENDERER_FOCUSED)
149 /* XXX: Why do we set ACTIVE here? */
150 atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
151 atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
155 atk_state_set_add_state (state_set, ATK_STATE_EXPANDABLE);
157 atk_state_set_add_state (state_set, ATK_STATE_EXPANDED);
164 _gtk_cell_accessible_class_init (GtkCellAccessibleClass *klass)
166 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
167 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
169 g_object_class->finalize = gtk_cell_accessible_object_finalize;
171 class->get_index_in_parent = gtk_cell_accessible_get_index_in_parent;
172 class->ref_state_set = gtk_cell_accessible_ref_state_set;
176 _gtk_cell_accessible_init (GtkCellAccessible *cell)
179 cell->action_list = NULL;
183 widget_destroyed (GtkWidget *widget,
184 GtkCellAccessible *cell)
190 _gtk_cell_accessible_initialise (GtkCellAccessible *cell,
194 cell->widget = widget;
195 atk_object_set_parent (ATK_OBJECT (cell), parent);
197 g_signal_connect_object (G_OBJECT (widget), "destroy",
198 G_CALLBACK (widget_destroyed), cell, 0);
202 _gtk_cell_accessible_add_state (GtkCellAccessible *cell,
203 AtkStateType state_type,
204 gboolean emit_signal)
208 /* The signal should only be generated if the value changed,
209 * not when the cell is set up. So states that are set
210 * initially should pass FALSE as the emit_signal argument.
214 atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
215 /* If state_type is ATK_STATE_VISIBLE, additional notification */
216 if (state_type == ATK_STATE_VISIBLE)
217 g_signal_emit_by_name (cell, "visible-data-changed");
220 /* If the parent is a flyweight container cell, propagate the state
223 parent = atk_object_get_parent (ATK_OBJECT (cell));
224 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
225 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
231 _gtk_cell_accessible_remove_state (GtkCellAccessible *cell,
232 AtkStateType state_type,
233 gboolean emit_signal)
237 parent = atk_object_get_parent (ATK_OBJECT (cell));
239 /* The signal should only be generated if the value changed,
240 * not when the cell is set up. So states that are set
241 * initially should pass FALSE as the emit_signal argument.
245 atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
246 /* If state_type is ATK_STATE_VISIBLE, additional notification */
247 if (state_type == ATK_STATE_VISIBLE)
248 g_signal_emit_by_name (cell, "visible-data-changed");
251 /* If the parent is a flyweight container cell, propagate the state
254 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
255 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (parent), state_type, emit_signal);
261 _gtk_cell_accessible_add_action (GtkCellAccessible *cell,
263 const gchar *description,
264 const gchar *keybinding,
265 void (*func) (GtkCellAccessible *))
269 info = g_new (ActionInfo, 1);
270 info->name = g_strdup (name);
271 info->description = g_strdup (description);
272 info->keybinding = g_strdup (keybinding);
273 info->do_action_func = func;
275 cell->action_list = g_list_append (cell->action_list, info);
281 _gtk_cell_accessible_remove_action (GtkCellAccessible *cell,
286 l = g_list_nth (cell->action_list, index);
290 destroy_action_info (l->data);
291 cell->action_list = g_list_remove_link (cell->action_list, l);
298 _gtk_cell_accessible_remove_action_by_name (GtkCellAccessible *cell,
303 for (l = cell->action_list; l; l = l->next)
305 ActionInfo *info = l->data;
307 if (g_strcmp0 (info->name, name) == 0)
314 destroy_action_info (l->data);
315 cell->action_list = g_list_remove_link (cell->action_list, l);
321 get_action_info (GtkCellAccessible *cell,
326 l = g_list_nth (cell->action_list, index);
330 return (ActionInfo *) (l->data);
334 gtk_cell_accessible_action_get_n_actions (AtkAction *action)
336 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE(action);
337 if (cell->action_list != NULL)
338 return g_list_length (cell->action_list);
344 gtk_cell_accessible_action_get_name (AtkAction *action,
347 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
350 info = get_action_info (cell, index);
358 gtk_cell_accessible_action_get_description (AtkAction *action,
361 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
364 info = get_action_info (cell, index);
368 return info->description;
372 gtk_cell_accessible_action_get_keybinding (AtkAction *action,
375 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
378 info = get_action_info (cell, index);
382 return info->keybinding;
386 gtk_cell_accessible_action_do_action (AtkAction *action,
389 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
392 info = get_action_info (cell, index);
396 if (info->do_action_func == NULL)
399 info->do_action_func (cell);
405 atk_action_interface_init (AtkActionIface *iface)
407 iface->get_n_actions = gtk_cell_accessible_action_get_n_actions;
408 iface->do_action = gtk_cell_accessible_action_do_action;
409 iface->get_name = gtk_cell_accessible_action_get_name;
410 iface->get_description = gtk_cell_accessible_action_get_description;
411 iface->get_keybinding = gtk_cell_accessible_action_get_keybinding;
415 gtk_cell_accessible_get_extents (AtkComponent *component,
420 AtkCoordType coord_type)
422 GtkCellAccessible *cell;
425 cell = GTK_CELL_ACCESSIBLE (component);
426 parent = gtk_widget_get_accessible (cell->widget);
428 _gtk_cell_accessible_parent_get_cell_extents (GTK_CELL_ACCESSIBLE_PARENT (parent),
430 x, y, width, height, coord_type);
434 gtk_cell_accessible_grab_focus (AtkComponent *component)
436 GtkCellAccessible *cell;
439 cell = GTK_CELL_ACCESSIBLE (component);
440 parent = gtk_widget_get_accessible (cell->widget);
442 return _gtk_cell_accessible_parent_grab_focus (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
446 atk_component_interface_init (AtkComponentIface *iface)
448 iface->get_extents = gtk_cell_accessible_get_extents;
449 iface->grab_focus = gtk_cell_accessible_grab_focus;
453 * _gtk_cell_accessible_set_cell_data:
454 * @cell: a #GtkCellAccessible
456 * Sets the cell data to the row used by @cell. This is useful in
457 * particular if you want to work with cell renderers.
459 * Note that this function is potentially slow, so be careful.
462 _gtk_cell_accessible_set_cell_data (GtkCellAccessible *cell)
466 g_return_if_fail (GTK_IS_CELL_ACCESSIBLE (cell));
468 parent = gtk_widget_get_accessible (cell->widget);
472 _gtk_cell_accessible_parent_set_cell_data (GTK_CELL_ACCESSIBLE_PARENT (parent), cell);
476 * _gtk_cell_accessible_get_state:
477 * @cell: a #GtkCellAccessible
478 * @expandable: (out): %NULL or pointer to boolean that gets set to
479 * whether the cell can be expanded
480 * @expanded: (out): %NULL or pointer to boolean that gets set to
481 * whether the cell is expanded
483 * Gets the state that would be used to render the area referenced by @cell.
485 * Returns: the #GtkCellRendererState for cell
488 _gtk_cell_accessible_get_state (GtkCellAccessible *cell,
489 gboolean *expandable,
494 g_return_val_if_fail (GTK_IS_CELL_ACCESSIBLE (cell), 0);
501 parent = gtk_widget_get_accessible (cell->widget);
505 return _gtk_cell_accessible_parent_get_renderer_state (GTK_CELL_ACCESSIBLE_PARENT (parent),