1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2001, 2002, 2003 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 #ifdef GDK_WINDOWING_X11
24 #include <gdk/x11/gdkx.h>
27 #include "gtktreeprivate.h"
28 #include "gtkwidgetprivate.h"
30 #include "gtktreeviewaccessible.h"
31 #include "gtkrenderercellaccessible.h"
32 #include "gtkbooleancellaccessible.h"
33 #include "gtkimagecellaccessible.h"
34 #include "gtkcontainercellaccessible.h"
35 #include "gtktextcellaccessible.h"
36 #include "gtkcellaccessibleparent.h"
38 typedef struct _GtkTreeViewAccessibleCellInfo GtkTreeViewAccessibleCellInfo;
39 struct _GtkTreeViewAccessibleCellInfo
41 GtkCellAccessible *cell;
44 GtkTreeViewColumn *cell_col_ref;
45 GtkTreeViewAccessible *view;
50 static void cursor_changed (GtkTreeView *tree_view,
51 GtkTreeViewAccessible *accessible);
52 static gboolean focus_in (GtkWidget *widget);
53 static gboolean focus_out (GtkWidget *widget);
57 static int cell_info_get_index (GtkTreeView *tree_view,
58 GtkTreeViewAccessibleCellInfo *info);
59 static gboolean update_cell_value (GtkRendererCellAccessible *renderer_cell,
60 GtkTreeViewAccessible *accessible,
61 gboolean emit_change_signal);
62 static gboolean is_cell_showing (GtkTreeView *tree_view,
63 GdkRectangle *cell_rect);
65 static void cell_destroyed (gpointer data);
66 static void cell_info_new (GtkTreeViewAccessible *accessible,
67 GtkTreeModel *tree_model,
70 GtkTreeViewColumn *tv_col,
71 GtkCellAccessible *cell);
72 static GtkCellAccessible *find_cell (GtkTreeViewAccessible *accessible,
74 static gint get_column_number (GtkTreeView *tree_view,
75 GtkTreeViewColumn *column);
76 static gint get_focus_index (GtkTreeView *tree_view);
77 static gint get_index (GtkTreeView *tree_view,
80 static void count_rows (GtkTreeModel *model,
82 GtkTreePath *end_path,
87 static gboolean get_rbtree_column_from_index (GtkTreeView *tree_view,
91 GtkTreeViewColumn **column);
93 static GtkTreeViewAccessibleCellInfo* find_cell_info (GtkTreeViewAccessible *view,
94 GtkCellAccessible *cell);
95 static AtkObject * get_header_from_column (GtkTreeViewColumn *tv_col);
98 static void atk_table_interface_init (AtkTableIface *iface);
99 static void atk_selection_interface_init (AtkSelectionIface *iface);
100 static void atk_component_interface_init (AtkComponentIface *iface);
101 static void gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface);
103 G_DEFINE_TYPE_WITH_CODE (GtkTreeViewAccessible, _gtk_tree_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
104 G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE, atk_table_interface_init)
105 G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init)
106 G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
107 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_ACCESSIBLE_PARENT, gtk_cell_accessible_parent_interface_init))
111 gtk_tree_view_accessible_get_data_quark (void)
113 static GQuark quark = 0;
115 if (G_UNLIKELY (quark == 0))
116 quark = g_quark_from_static_string ("gtk-tree-view-accessible-data");
122 cell_info_free (GtkTreeViewAccessibleCellInfo *cell_info)
126 g_object_steal_qdata (G_OBJECT (cell_info->cell),
127 gtk_tree_view_accessible_get_data_quark ());
128 _gtk_cell_accessible_add_state (cell_info->cell, ATK_STATE_DEFUNCT, FALSE);
135 cell_info_get_path (GtkTreeViewAccessibleCellInfo *cell_info)
137 return _gtk_tree_path_new_from_rbtree (cell_info->tree, cell_info->node);
141 cell_info_hash (gconstpointer info)
143 const GtkTreeViewAccessibleCellInfo *cell_info = info;
146 node = GPOINTER_TO_UINT (cell_info->node);
147 col = GPOINTER_TO_UINT (cell_info->cell_col_ref);
149 return ((node << sizeof (guint) / 2) | (node >> sizeof (guint) / 2)) ^ col;
153 cell_info_equal (gconstpointer a, gconstpointer b)
155 const GtkTreeViewAccessibleCellInfo *cell_info_a = a;
156 const GtkTreeViewAccessibleCellInfo *cell_info_b = b;
158 return cell_info_a->node == cell_info_b->node &&
159 cell_info_a->cell_col_ref == cell_info_b->cell_col_ref;
163 gtk_tree_view_accessible_initialize (AtkObject *obj,
166 GtkTreeViewAccessible *accessible;
167 GtkTreeView *tree_view;
168 GtkTreeModel *tree_model;
171 ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->initialize (obj, data);
173 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
174 accessible->focus_cell = NULL;
176 accessible->cell_infos = g_hash_table_new_full (cell_info_hash,
177 cell_info_equal, NULL, (GDestroyNotify) cell_info_free);
179 widget = GTK_WIDGET (data);
180 tree_view = GTK_TREE_VIEW (widget);
181 tree_model = gtk_tree_view_get_model (tree_view);
183 g_signal_connect (tree_view, "cursor-changed",
184 G_CALLBACK (cursor_changed), accessible);
185 g_signal_connect (tree_view, "focus-in-event",
186 G_CALLBACK (focus_in), NULL);
187 g_signal_connect (tree_view, "focus-out-event",
188 G_CALLBACK (focus_out), NULL);
192 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
193 obj->role = ATK_ROLE_TABLE;
195 obj->role = ATK_ROLE_TREE_TABLE;
200 gtk_tree_view_accessible_finalize (GObject *object)
202 GtkTreeViewAccessible *accessible = GTK_TREE_VIEW_ACCESSIBLE (object);
204 if (accessible->cell_infos)
205 g_hash_table_destroy (accessible->cell_infos);
207 G_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->finalize (object);
211 gtk_tree_view_accessible_notify_gtk (GObject *obj,
215 GtkTreeView *tree_view;
216 GtkTreeViewAccessible *accessible;
218 widget = GTK_WIDGET (obj);
219 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
220 tree_view = GTK_TREE_VIEW (widget);
222 if (g_strcmp0 (pspec->name, "model") == 0)
224 GtkTreeModel *tree_model;
227 tree_model = gtk_tree_view_get_model (tree_view);
228 g_hash_table_remove_all (accessible->cell_infos);
232 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
233 role = ATK_ROLE_TABLE;
235 role = ATK_ROLE_TREE_TABLE;
239 role = ATK_ROLE_UNKNOWN;
241 atk_object_set_role (ATK_OBJECT (accessible), role);
242 g_object_freeze_notify (G_OBJECT (accessible));
243 g_signal_emit_by_name (accessible, "model-changed");
244 g_signal_emit_by_name (accessible, "visible-data-changed");
245 g_object_thaw_notify (G_OBJECT (accessible));
248 GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->notify_gtk (obj, pspec);
252 gtk_tree_view_accessible_destroyed (GtkWidget *widget,
253 GtkAccessible *gtk_accessible)
255 GtkTreeViewAccessible *accessible;
257 if (!GTK_IS_TREE_VIEW (widget))
260 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_accessible);
262 if (accessible->focus_cell)
264 g_object_unref (accessible->focus_cell);
265 accessible->focus_cell = NULL;
270 gtk_tree_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
274 widget = gtk_accessible_get_widget (accessible);
276 g_signal_connect_after (widget, "destroy",
277 G_CALLBACK (gtk_tree_view_accessible_destroyed), accessible);
279 GTK_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->connect_widget_destroyed (accessible);
283 get_n_rows (GtkTreeView *tree_view)
287 tree = _gtk_tree_view_get_rbtree (tree_view);
292 return tree->root->total_count;
296 get_n_columns (GtkTreeView *tree_view)
298 guint i, visible_columns;
302 for (i = 0; i < gtk_tree_view_get_n_columns (tree_view); i++)
304 GtkTreeViewColumn *column = gtk_tree_view_get_column (tree_view, i);
306 if (gtk_tree_view_column_get_visible (column))
310 return visible_columns;
313 gtk_tree_view_accessible_get_n_children (AtkObject *obj)
316 GtkTreeView *tree_view;
318 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
322 tree_view = GTK_TREE_VIEW (widget);
323 return (get_n_rows (tree_view) + 1) * get_n_columns (tree_view);
326 static GtkTreeViewColumn *
327 get_visible_column (GtkTreeView *tree_view,
332 for (i = 0; i < gtk_tree_view_get_n_columns (tree_view); i++)
334 GtkTreeViewColumn *column = gtk_tree_view_get_column (tree_view, i);
336 if (!gtk_tree_view_column_get_visible (column))
345 g_return_val_if_reached (NULL);
349 gtk_tree_view_accessible_ref_child (AtkObject *obj,
353 GtkTreeViewAccessible *accessible;
354 GtkCellAccessible *cell;
355 GtkTreeView *tree_view;
356 GtkTreeModel *tree_model;
357 GtkCellRenderer *renderer;
359 GtkTreeViewColumn *tv_col;
365 GtkTreeViewColumn *expander_tv;
366 GList *renderer_list;
368 GtkContainerCellAccessible *container = NULL;
369 GtkRendererCellAccessible *renderer_cell;
370 gboolean is_expander, is_expanded, retval;
373 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
377 if (i >= gtk_tree_view_accessible_get_n_children (obj))
380 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
381 tree_view = GTK_TREE_VIEW (widget);
382 if (i < get_n_columns (tree_view))
384 tv_col = get_visible_column (tree_view, i);
385 child = get_header_from_column (tv_col);
387 g_object_ref (child);
391 /* Check whether the child is cached */
392 cell = find_cell (accessible, i);
396 return ATK_OBJECT (cell);
399 if (accessible->focus_cell == NULL)
400 focus_index = get_focus_index (tree_view);
404 /* Find the RBTree and GtkTreeViewColumn for the index */
405 if (!get_rbtree_column_from_index (tree_view, i, &tree, &node, &tv_col))
408 path = _gtk_tree_path_new_from_rbtree (tree, node);
409 tree_model = gtk_tree_view_get_model (tree_view);
410 retval = gtk_tree_model_get_iter (tree_model, &iter, path);
414 expander_tv = gtk_tree_view_get_expander_column (tree_view);
417 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
419 if (expander_tv == tv_col)
422 is_expanded = node->children != NULL;
425 gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter,
426 is_expander, is_expanded);
428 renderer_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
430 /* If there is not exactly one renderer in the list,
433 if (renderer_list == NULL || renderer_list->next)
435 GtkCellAccessible *container_cell;
437 container = _gtk_container_cell_accessible_new ();
439 container_cell = GTK_CELL_ACCESSIBLE (container);
440 _gtk_cell_accessible_initialise (container_cell, widget, ATK_OBJECT (accessible));
442 /* The GtkTreeViewAccessibleCellInfo structure for the container will
443 * be before the ones for the cells so that the first one we find for
444 * a position will be for the container
446 cell_info_new (accessible, tree_model, tree, node, tv_col, container_cell);
447 parent = ATK_OBJECT (container);
450 parent = ATK_OBJECT (accessible);
454 for (l = renderer_list; l; l = l->next)
456 renderer = GTK_CELL_RENDERER (l->data);
458 if (GTK_IS_CELL_RENDERER_TEXT (renderer))
459 child = _gtk_text_cell_accessible_new ();
460 else if (GTK_IS_CELL_RENDERER_TOGGLE (renderer))
461 child = _gtk_boolean_cell_accessible_new ();
462 else if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
463 child = _gtk_image_cell_accessible_new ();
465 child = _gtk_renderer_cell_accessible_new (renderer);
467 cell = GTK_CELL_ACCESSIBLE (child);
468 renderer_cell = GTK_RENDERER_CELL_ACCESSIBLE (child);
470 /* Create the GtkTreeViewAccessibleCellInfo for this cell */
471 if (parent == ATK_OBJECT (accessible))
472 cell_info_new (accessible, tree_model, tree, node, tv_col, cell);
474 _gtk_cell_accessible_initialise (cell, widget, parent);
477 _gtk_container_cell_accessible_add_child (container, cell);
479 update_cell_value (renderer_cell, accessible, FALSE);
481 _gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
482 if (focus_index == i)
484 accessible->focus_cell = g_object_ref (cell);
485 _gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSED, FALSE);
486 g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
489 g_list_free (renderer_list);
491 child = ATK_OBJECT (container);
493 if (expander_tv == tv_col)
495 AtkRelationSet *relation_set;
496 AtkObject *accessible_array[1];
497 AtkRelation* relation;
498 AtkObject *parent_node;
500 relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
502 gtk_tree_path_up (path);
503 if (gtk_tree_path_get_depth (path) == 0)
509 parent_index = get_index (tree_view, path, i % get_n_columns (tree_view));
510 parent_node = atk_object_ref_accessible_child (obj, parent_index);
512 accessible_array[0] = parent_node;
513 relation = atk_relation_new (accessible_array, 1,
514 ATK_RELATION_NODE_CHILD_OF);
515 atk_relation_set_add (relation_set, relation);
516 atk_object_add_relationship (parent_node, ATK_RELATION_NODE_PARENT_OF, child);
517 g_object_unref (relation);
518 g_object_unref (relation_set);
520 gtk_tree_path_free (path);
522 /* We do not increase the reference count here; when g_object_unref()
523 * is called for the cell then cell_destroyed() is called and this
524 * removes the cell from the cache.
530 gtk_tree_view_accessible_ref_state_set (AtkObject *obj)
532 AtkStateSet *state_set;
535 state_set = ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->ref_state_set (obj);
536 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
539 atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
545 _gtk_tree_view_accessible_class_init (GtkTreeViewAccessibleClass *klass)
547 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
548 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
549 GtkAccessibleClass *accessible_class = (GtkAccessibleClass*)klass;
550 GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
551 GtkContainerAccessibleClass *container_class = (GtkContainerAccessibleClass*)klass;
553 class->get_n_children = gtk_tree_view_accessible_get_n_children;
554 class->ref_child = gtk_tree_view_accessible_ref_child;
555 class->ref_state_set = gtk_tree_view_accessible_ref_state_set;
556 class->initialize = gtk_tree_view_accessible_initialize;
558 widget_class->notify_gtk = gtk_tree_view_accessible_notify_gtk;
560 accessible_class->connect_widget_destroyed = gtk_tree_view_accessible_connect_widget_destroyed;
562 /* The children of a GtkTreeView are the buttons at the top of the columns
563 * we do not represent these as children so we do not want to report
564 * children added or deleted when these changed.
566 container_class->add_gtk = NULL;
567 container_class->remove_gtk = NULL;
569 gobject_class->finalize = gtk_tree_view_accessible_finalize;
573 _gtk_tree_view_accessible_init (GtkTreeViewAccessible *view)
578 get_focus_index (GtkTreeView *tree_view)
580 GtkTreePath *focus_path;
581 GtkTreeViewColumn *focus_column;
584 gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
585 if (focus_path && focus_column)
586 index = get_index (tree_view, focus_path,
587 get_column_number (tree_view, focus_column));
592 gtk_tree_path_free (focus_path);
597 /* This function returns a reference to the accessible object
598 * for the cell in the treeview which has focus, if any
601 gtk_tree_view_accessible_ref_focus_cell (GtkTreeView *tree_view)
603 AtkObject *focus_cell = NULL;
607 focus_index = get_focus_index (tree_view);
608 if (focus_index >= 0)
610 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
611 focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
620 gtk_tree_view_accessible_ref_accessible_at_point (AtkComponent *component,
623 AtkCoordType coord_type)
626 GtkTreeView *tree_view;
628 GtkTreeViewColumn *tv_column;
633 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
637 tree_view = GTK_TREE_VIEW (widget);
639 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
640 gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &bx, &by);
641 ret_val = gtk_tree_view_get_path_at_pos (tree_view,
642 bx - x_pos, by - y_pos,
643 &path, &tv_column, NULL, NULL);
648 column = get_column_number (tree_view, tv_column);
649 index = get_index (tree_view, path, column);
650 gtk_tree_path_free (path);
652 return gtk_tree_view_accessible_ref_child (ATK_OBJECT (component), index);
659 atk_component_interface_init (AtkComponentIface *iface)
661 iface->ref_accessible_at_point = gtk_tree_view_accessible_ref_accessible_at_point;
667 gtk_tree_view_accessible_get_index_at (AtkTable *table,
674 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
678 n_cols = atk_table_get_n_columns (table);
679 n_rows = atk_table_get_n_rows (table);
681 if (row >= n_rows || column >= n_cols)
684 return (row + 1) * n_cols + column;
688 gtk_tree_view_accessible_get_column_at_index (AtkTable *table,
694 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
698 if (index >= gtk_tree_view_accessible_get_n_children (ATK_OBJECT (table)))
701 n_columns = get_n_columns (GTK_TREE_VIEW (widget));
703 /* checked by the n_children() check above */
704 g_assert (n_columns > 0);
706 return index % n_columns;
710 gtk_tree_view_accessible_get_row_at_index (AtkTable *table,
714 GtkTreeView *tree_view;
716 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
720 tree_view = GTK_TREE_VIEW (widget);
722 index /= get_n_columns (tree_view);
724 if (index >= get_n_rows (tree_view))
731 gtk_tree_view_accessible_table_ref_at (AtkTable *table,
737 index = gtk_tree_view_accessible_get_index_at (table, row, column);
741 return gtk_tree_view_accessible_ref_child (ATK_OBJECT (table), index);
745 gtk_tree_view_accessible_get_n_rows (AtkTable *table)
749 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
753 return get_n_rows (GTK_TREE_VIEW (widget));
757 gtk_tree_view_accessible_get_n_columns (AtkTable *table)
761 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
765 return get_n_columns (GTK_TREE_VIEW (widget));
769 gtk_tree_view_accessible_is_row_selected (AtkTable *table,
779 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
783 if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (GTK_TREE_VIEW (widget)),
789 return GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
793 gtk_tree_view_accessible_is_selected (AtkTable *table,
797 return gtk_tree_view_accessible_is_row_selected (table, row);
802 GtkTreeView *treeview;
806 get_selected_rows (GtkTreeModel *model,
811 SelectedRowsData *data = datap;
816 if (_gtk_tree_view_find_node (data->treeview,
820 g_assert_not_reached ();
823 id = _gtk_rbtree_node_get_index (tree, node);
825 g_array_append_val (data->array, id);
829 gtk_tree_view_accessible_get_selected_rows (AtkTable *table,
830 gint **rows_selected)
832 SelectedRowsData data;
836 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
840 data.treeview = GTK_TREE_VIEW (widget);
841 data.array = g_array_new (FALSE, FALSE, sizeof (gint));
843 gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (data.treeview),
847 n_rows = data.array->len;
849 *rows_selected = (gint *) g_array_free (data.array, FALSE);
851 g_array_free (data.array, TRUE);
857 gtk_tree_view_accessible_add_row_selection (AtkTable *table,
860 GtkTreeView *treeview;
868 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (table)));
869 if (treeview == NULL)
872 if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (treeview),
878 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
881 path = _gtk_tree_path_new_from_rbtree (tree, node);
882 gtk_tree_selection_select_path (gtk_tree_view_get_selection (treeview), path);
883 gtk_tree_path_free (path);
889 gtk_tree_view_accessible_remove_row_selection (AtkTable *table,
892 GtkTreeView *treeview;
900 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (table)));
901 if (treeview == NULL)
904 if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (treeview),
910 if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
913 path = _gtk_tree_path_new_from_rbtree (tree, node);
914 gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (treeview), path);
915 gtk_tree_path_free (path);
921 gtk_tree_view_accessible_get_column_header (AtkTable *table,
925 GtkTreeView *tree_view;
926 GtkTreeViewColumn *tv_col;
928 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
932 tree_view = GTK_TREE_VIEW (widget);
933 if (in_col < 0 || in_col >= get_n_columns (tree_view))
936 tv_col = get_visible_column (tree_view, in_col);
937 return get_header_from_column (tv_col);
941 gtk_tree_view_accessible_get_column_description (AtkTable *table,
945 GtkTreeView *tree_view;
946 GtkTreeViewColumn *tv_col;
948 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
952 tree_view = GTK_TREE_VIEW (widget);
953 if (in_col < 0 || in_col >= get_n_columns (tree_view))
956 tv_col = get_visible_column (tree_view, in_col);
957 return gtk_tree_view_column_get_title (tv_col);
961 atk_table_interface_init (AtkTableIface *iface)
963 iface->ref_at = gtk_tree_view_accessible_table_ref_at;
964 iface->get_n_rows = gtk_tree_view_accessible_get_n_rows;
965 iface->get_n_columns = gtk_tree_view_accessible_get_n_columns;
966 iface->get_index_at = gtk_tree_view_accessible_get_index_at;
967 iface->get_column_at_index = gtk_tree_view_accessible_get_column_at_index;
968 iface->get_row_at_index = gtk_tree_view_accessible_get_row_at_index;
969 iface->is_row_selected = gtk_tree_view_accessible_is_row_selected;
970 iface->is_selected = gtk_tree_view_accessible_is_selected;
971 iface->get_selected_rows = gtk_tree_view_accessible_get_selected_rows;
972 iface->add_row_selection = gtk_tree_view_accessible_add_row_selection;
973 iface->remove_row_selection = gtk_tree_view_accessible_remove_row_selection;
974 iface->get_column_extent_at = NULL;
975 iface->get_row_extent_at = NULL;
976 iface->get_column_header = gtk_tree_view_accessible_get_column_header;
977 iface->get_column_description = gtk_tree_view_accessible_get_column_description;
983 gtk_tree_view_accessible_add_selection (AtkSelection *selection,
990 table = ATK_TABLE (selection);
991 n_columns = gtk_tree_view_accessible_get_n_columns (table);
995 row = gtk_tree_view_accessible_get_row_at_index (table, i);
996 return gtk_tree_view_accessible_add_row_selection (table, row);
1000 gtk_tree_view_accessible_clear_selection (AtkSelection *selection)
1003 GtkTreeView *tree_view;
1004 GtkTreeSelection *tree_selection;
1006 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1010 tree_view = GTK_TREE_VIEW (widget);
1011 tree_selection = gtk_tree_view_get_selection (tree_view);
1013 gtk_tree_selection_unselect_all (tree_selection);
1018 gtk_tree_view_accessible_ref_selection (AtkSelection *selection,
1027 table = ATK_TABLE (selection);
1028 n_columns = gtk_tree_view_accessible_get_n_columns (table);
1029 n_selected = gtk_tree_view_accessible_get_selected_rows (table, &selected);
1030 if (i >= n_columns * n_selected)
1033 row = selected[i / n_columns];
1036 return gtk_tree_view_accessible_table_ref_at (table, row, i % n_columns);
1040 gtk_tree_view_accessible_get_selection_count (AtkSelection *selection)
1045 table = ATK_TABLE (selection);
1046 n_selected = gtk_tree_view_accessible_get_selected_rows (table, NULL);
1048 n_selected *= gtk_tree_view_accessible_get_n_columns (table);
1053 gtk_tree_view_accessible_is_child_selected (AtkSelection *selection,
1059 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1063 row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
1065 return gtk_tree_view_accessible_is_row_selected (ATK_TABLE (selection), row);
1068 static void atk_selection_interface_init (AtkSelectionIface *iface)
1070 iface->add_selection = gtk_tree_view_accessible_add_selection;
1071 iface->clear_selection = gtk_tree_view_accessible_clear_selection;
1072 iface->ref_selection = gtk_tree_view_accessible_ref_selection;
1073 iface->get_selection_count = gtk_tree_view_accessible_get_selection_count;
1074 iface->is_child_selected = gtk_tree_view_accessible_is_child_selected;
1077 #define EXTRA_EXPANDER_PADDING 4
1080 gtk_tree_view_accessible_get_cell_area (GtkCellAccessibleParent *parent,
1081 GtkCellAccessible *cell,
1082 GdkRectangle *cell_rect)
1085 GtkTreeView *tree_view;
1086 GtkTreeViewColumn *tv_col;
1088 AtkObject *parent_cell;
1089 GtkTreeViewAccessibleCellInfo *cell_info;
1090 GtkCellAccessible *top_cell;
1092 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1096 tree_view = GTK_TREE_VIEW (widget);
1097 parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
1098 if (parent_cell != ATK_OBJECT (parent))
1099 top_cell = GTK_CELL_ACCESSIBLE (parent_cell);
1102 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), top_cell);
1105 path = cell_info_get_path (cell_info);
1106 tv_col = cell_info->cell_col_ref;
1109 GtkTreeViewColumn *expander_column;
1110 gint focus_line_width;
1112 gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
1113 expander_column = gtk_tree_view_get_expander_column (tree_view);
1114 if (expander_column == tv_col)
1117 gtk_widget_style_get (widget,
1118 "expander-size", &expander_size,
1120 cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
1121 cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
1123 gtk_widget_style_get (widget,
1124 "focus-line-width", &focus_line_width,
1127 cell_rect->x += focus_line_width;
1128 cell_rect->width -= 2 * focus_line_width;
1130 gtk_tree_path_free (path);
1132 /* A column has more than one renderer so we find the position
1135 if (top_cell != cell)
1142 GtkCellRenderer *renderer;
1144 cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
1145 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
1146 renderer = g_list_nth_data (renderers, cell_index);
1148 found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
1151 cell_rect->x += cell_start;
1152 cell_rect->width = cell_width;
1154 g_list_free (renderers);
1161 gtk_tree_view_accessible_get_cell_extents (GtkCellAccessibleParent *parent,
1162 GtkCellAccessible *cell,
1167 AtkCoordType coord_type)
1170 GtkTreeView *tree_view;
1171 GdkWindow *bin_window;
1172 GdkRectangle cell_rect;
1175 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1179 tree_view = GTK_TREE_VIEW (widget);
1180 gtk_tree_view_accessible_get_cell_area (parent, cell, &cell_rect);
1181 bin_window = gtk_tree_view_get_bin_window (tree_view);
1182 gdk_window_get_origin (bin_window, &w_x, &w_y);
1184 if (coord_type == ATK_XY_WINDOW)
1187 gint x_toplevel, y_toplevel;
1189 window = gdk_window_get_toplevel (bin_window);
1190 gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
1196 *width = cell_rect.width;
1197 *height = cell_rect.height;
1198 if (is_cell_showing (tree_view, &cell_rect))
1200 *x = cell_rect.x + w_x;
1201 *y = cell_rect.y + w_y;
1211 gtk_tree_view_accessible_grab_cell_focus (GtkCellAccessibleParent *parent,
1212 GtkCellAccessible *cell)
1215 GtkTreeView *tree_view;
1216 GtkTreeViewColumn *tv_col;
1218 AtkObject *parent_cell;
1219 AtkObject *cell_object;
1220 GtkTreeViewAccessibleCellInfo *cell_info;
1221 GtkCellRenderer *renderer = NULL;
1222 GtkWidget *toplevel;
1225 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1229 tree_view = GTK_TREE_VIEW (widget);
1231 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell);
1234 cell_object = ATK_OBJECT (cell);
1235 parent_cell = atk_object_get_parent (cell_object);
1236 tv_col = cell_info->cell_col_ref;
1237 if (parent_cell != ATK_OBJECT (parent))
1239 /* GtkCellAccessible is in a GtkContainerCellAccessible.
1240 * The GtkTreeViewColumn has multiple renderers;
1241 * find the corresponding one.
1245 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
1246 index = atk_object_get_index_in_parent (cell_object);
1247 renderer = g_list_nth_data (renderers, index);
1248 g_list_free (renderers);
1250 path = cell_info_get_path (cell_info);
1254 gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
1256 gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
1258 gtk_tree_path_free (path);
1259 gtk_widget_grab_focus (widget);
1260 toplevel = gtk_widget_get_toplevel (widget);
1261 if (gtk_widget_is_toplevel (toplevel))
1263 #ifdef GDK_WINDOWING_X11
1264 gtk_window_present_with_time (GTK_WINDOW (toplevel),
1265 gdk_x11_get_server_time (gtk_widget_get_window (widget)));
1267 gtk_window_present (GTK_WINDOW (toplevel));
1278 gtk_tree_view_accessible_get_child_index (GtkCellAccessibleParent *parent,
1279 GtkCellAccessible *cell)
1281 GtkTreeViewAccessibleCellInfo *cell_info;
1282 GtkTreeView *tree_view;
1284 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell);
1288 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1290 return cell_info_get_index (tree_view, cell_info);
1293 static GtkCellRendererState
1294 gtk_tree_view_accessible_get_renderer_state (GtkCellAccessibleParent *parent,
1295 GtkCellAccessible *cell)
1297 GtkTreeViewAccessibleCellInfo *cell_info;
1298 GtkTreeView *treeview;
1299 GtkCellRendererState flags;
1301 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell);
1307 if (GTK_RBNODE_FLAG_SET (cell_info->node, GTK_RBNODE_IS_SELECTED))
1308 flags |= GTK_CELL_RENDERER_SELECTED;
1310 if (GTK_RBNODE_FLAG_SET (cell_info->node, GTK_RBNODE_IS_PRELIT))
1311 flags |= GTK_CELL_RENDERER_PRELIT;
1313 if (gtk_tree_view_column_get_sort_indicator (cell_info->cell_col_ref))
1314 flags |= GTK_CELL_RENDERER_SORTED;
1316 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1318 if (cell_info->cell_col_ref == gtk_tree_view_get_expander_column (treeview))
1320 if (GTK_RBNODE_FLAG_SET (cell_info->node, GTK_RBNODE_IS_PARENT))
1321 flags |= GTK_CELL_RENDERER_EXPANDABLE;
1323 if (cell_info->node->children)
1324 flags |= GTK_CELL_RENDERER_EXPANDED;
1327 if (gtk_widget_has_focus (GTK_WIDGET (treeview)))
1329 GtkTreeViewColumn *column;
1334 gtk_tree_view_get_cursor (treeview, &path, &column);
1337 _gtk_tree_view_find_node (treeview, path, &tree, &node);
1338 gtk_tree_path_free (path);
1343 if (cell_info->cell_col_ref == column
1344 && cell_info->tree == tree
1345 && cell_info->node == node)
1346 flags |= GTK_CELL_RENDERER_FOCUSED;
1353 gtk_tree_view_accessible_set_cell_data (GtkCellAccessibleParent *parent,
1354 GtkCellAccessible *cell)
1356 GtkTreeViewAccessibleCellInfo *cell_info;
1357 GtkTreeView *treeview;
1358 gboolean is_expander, is_expanded;
1359 GtkTreeModel *model;
1363 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell);
1367 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1368 model = gtk_tree_view_get_model (treeview);
1370 if (GTK_RBNODE_FLAG_SET (cell_info->node, GTK_RBNODE_IS_PARENT) &&
1371 cell_info->cell_col_ref == gtk_tree_view_get_expander_column (treeview))
1374 is_expanded = cell_info->node->children != NULL;
1378 is_expander = FALSE;
1379 is_expanded = FALSE;
1382 path = cell_info_get_path (cell_info);
1384 !gtk_tree_model_get_iter (model, &iter, path))
1386 /* We only track valid cells, this should never happen */
1387 g_return_if_reached ();
1390 gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
1398 gtk_tree_view_accessible_expand_collapse (GtkCellAccessibleParent *parent,
1399 GtkCellAccessible *cell)
1401 GtkTreeViewAccessibleCellInfo *cell_info;
1402 GtkTreeView *treeview;
1405 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1407 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell);
1409 cell_info->cell_col_ref != gtk_tree_view_get_expander_column (treeview))
1412 path = cell_info_get_path (cell_info);
1414 if (cell_info->node->children)
1415 gtk_tree_view_collapse_row (treeview, path);
1417 gtk_tree_view_expand_row (treeview, path, FALSE);
1419 gtk_tree_path_free (path);
1423 gtk_tree_view_accessible_activate (GtkCellAccessibleParent *parent,
1424 GtkCellAccessible *cell)
1426 GtkTreeViewAccessibleCellInfo *cell_info;
1427 GtkTreeView *treeview;
1430 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1432 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell);
1436 path = cell_info_get_path (cell_info);
1438 gtk_tree_view_row_activated (treeview, path, cell_info->cell_col_ref);
1440 gtk_tree_path_free (path);
1444 gtk_tree_view_accessible_edit (GtkCellAccessibleParent *parent,
1445 GtkCellAccessible *cell)
1447 GtkTreeView *treeview;
1449 if (!gtk_tree_view_accessible_grab_cell_focus (parent, cell))
1452 treeview = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1454 g_signal_emit_by_name (treeview,
1455 "real-select-cursor-row",
1460 gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface)
1462 iface->get_cell_extents = gtk_tree_view_accessible_get_cell_extents;
1463 iface->get_cell_area = gtk_tree_view_accessible_get_cell_area;
1464 iface->grab_focus = gtk_tree_view_accessible_grab_cell_focus;
1465 iface->get_child_index = gtk_tree_view_accessible_get_child_index;
1466 iface->get_renderer_state = gtk_tree_view_accessible_get_renderer_state;
1467 iface->set_cell_data = gtk_tree_view_accessible_set_cell_data;
1468 iface->expand_collapse = gtk_tree_view_accessible_expand_collapse;
1469 iface->activate = gtk_tree_view_accessible_activate;
1470 iface->edit = gtk_tree_view_accessible_edit;
1473 /* signal handling */
1476 cursor_changed (GtkTreeView *tree_view,
1477 GtkTreeViewAccessible *accessible)
1481 cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
1484 if (cell != accessible->focus_cell)
1486 if (accessible->focus_cell)
1488 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
1489 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
1490 g_object_unref (accessible->focus_cell);
1491 accessible->focus_cell = cell;
1494 if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
1496 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
1497 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
1500 g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
1503 g_object_unref (cell);
1508 focus_in (GtkWidget *widget)
1510 GtkTreeView *tree_view;
1511 GtkTreeViewAccessible *accessible;
1512 AtkStateSet *state_set;
1515 tree_view = GTK_TREE_VIEW (widget);
1516 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
1518 if (accessible->focus_cell == NULL)
1520 cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
1523 state_set = atk_object_ref_state_set (cell);
1526 if (!atk_state_set_contains_state (state_set, ATK_STATE_FOCUSED))
1528 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
1529 accessible->focus_cell = cell;
1530 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
1531 g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
1533 g_object_unref (state_set);
1541 focus_out (GtkWidget *widget)
1543 GtkTreeViewAccessible *accessible;
1545 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
1546 if (accessible->focus_cell)
1548 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
1549 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
1550 g_object_unref (accessible->focus_cell);
1551 accessible->focus_cell = NULL;
1557 _gtk_tree_view_accessible_reorder (GtkTreeView *treeview)
1559 GtkTreeViewAccessible *accessible;
1561 accessible = GTK_TREE_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (treeview)));
1562 if (accessible == NULL)
1565 g_signal_emit_by_name (accessible, "row-reordered");
1569 is_cell_showing (GtkTreeView *tree_view,
1570 GdkRectangle *cell_rect)
1572 GdkRectangle rect, *visible_rect;
1573 GdkRectangle rect1, *tree_cell_rect;
1575 gboolean is_showing;
1577 /* A cell is considered "SHOWING" if any part of the cell is
1578 * in the visible area. Other ways we could do this is by a
1579 * cell's midpoint or if the cell is fully in the visible range.
1580 * Since we have the cell_rect x, y, width, height of the cell,
1581 * any of these is easy to compute.
1583 * It is assumed that cell's rectangle is in widget coordinates
1584 * so we must transform to tree cordinates.
1586 visible_rect = ▭
1587 tree_cell_rect = &rect1;
1588 tree_cell_rect->x = cell_rect->x;
1589 tree_cell_rect->y = cell_rect->y;
1590 tree_cell_rect->width = cell_rect->width;
1591 tree_cell_rect->height = cell_rect->height;
1593 gtk_tree_view_get_visible_rect (tree_view, visible_rect);
1594 gtk_tree_view_convert_tree_to_bin_window_coords (tree_view, visible_rect->x,
1595 visible_rect->y, &bx, &by);
1597 if (((tree_cell_rect->x + tree_cell_rect->width) < bx) ||
1598 ((tree_cell_rect->y + tree_cell_rect->height) < by) ||
1599 (tree_cell_rect->x > (bx + visible_rect->width)) ||
1600 (tree_cell_rect->y > (by + visible_rect->height)))
1610 /* This function is called when a cell's flyweight is created in
1611 * gtk_tree_view_accessible_table_ref_at with emit_change_signal
1612 * set to FALSE and in model_row_changed() on receipt of "row-changed"
1613 * signal when emit_change_signal is set to TRUE
1616 update_cell_value (GtkRendererCellAccessible *renderer_cell,
1617 GtkTreeViewAccessible *accessible,
1618 gboolean emit_change_signal)
1620 GtkTreeViewAccessibleCellInfo *cell_info;
1621 GtkTreeView *tree_view;
1622 GtkTreeModel *tree_model;
1625 GList *renderers, *cur_renderer;
1627 GtkRendererCellAccessibleClass *renderer_cell_class;
1628 GtkCellRendererClass *gtk_cell_renderer_class;
1629 GtkCellAccessible *cell;
1632 gboolean is_expander, is_expanded;
1634 renderer_cell_class = GTK_RENDERER_CELL_ACCESSIBLE_GET_CLASS (renderer_cell);
1635 if (renderer_cell->renderer)
1636 gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
1638 gtk_cell_renderer_class = NULL;
1640 prop_list = renderer_cell_class->property_list;
1642 cell = GTK_CELL_ACCESSIBLE (renderer_cell);
1643 cell_info = find_cell_info (accessible, cell);
1647 if (emit_change_signal)
1649 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
1650 tree_model = gtk_tree_view_get_model (tree_view);
1651 path = cell_info_get_path (cell_info);
1655 gtk_tree_model_get_iter (tree_model, &iter, path);
1656 is_expander = FALSE;
1657 is_expanded = FALSE;
1658 if (gtk_tree_model_iter_has_child (tree_model, &iter))
1660 GtkTreeViewColumn *expander_tv;
1662 expander_tv = gtk_tree_view_get_expander_column (tree_view);
1663 if (expander_tv == cell_info->cell_col_ref)
1666 is_expanded = gtk_tree_view_row_expanded (tree_view, path);
1669 gtk_tree_path_free (path);
1670 gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
1672 is_expander, is_expanded);
1674 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_info->cell_col_ref));
1678 /* If the cell is in a container, its index is used to find the renderer
1679 * in the list. Otherwise, we assume that the cell is represented
1680 * by the first renderer in the list
1682 parent = atk_object_get_parent (ATK_OBJECT (cell));
1684 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
1685 cur_renderer = g_list_nth (renderers, atk_object_get_index_in_parent (ATK_OBJECT (cell)));
1687 cur_renderer = renderers;
1689 if (cur_renderer == NULL)
1692 if (gtk_cell_renderer_class)
1696 spec = g_object_class_find_property
1697 (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
1701 GValue value = G_VALUE_INIT;
1703 g_value_init (&value, spec->value_type);
1704 g_object_get_property (cur_renderer->data, *prop_list, &value);
1705 g_object_set_property (G_OBJECT (renderer_cell->renderer),
1706 *prop_list, &value);
1707 g_value_unset (&value);
1710 g_warning ("Invalid property: %s\n", *prop_list);
1714 g_list_free (renderers);
1716 return _gtk_renderer_cell_accessible_update_cache (renderer_cell, emit_change_signal);
1722 cell_destroyed (gpointer data)
1724 GtkTreeViewAccessibleCellInfo *cell_info = data;
1726 cell_info->cell = NULL;
1728 g_hash_table_remove (cell_info->view->cell_infos, cell_info);
1732 cell_info_get_index (GtkTreeView *tree_view,
1733 GtkTreeViewAccessibleCellInfo *info)
1737 index = _gtk_rbtree_node_get_index (info->tree, info->node) + 1;
1738 index *= get_n_columns (tree_view);
1739 index += get_column_number (tree_view, info->cell_col_ref);
1745 cell_info_new (GtkTreeViewAccessible *accessible,
1746 GtkTreeModel *tree_model,
1749 GtkTreeViewColumn *tv_col,
1750 GtkCellAccessible *cell)
1752 GtkTreeViewAccessibleCellInfo *cell_info;
1754 cell_info = g_new (GtkTreeViewAccessibleCellInfo, 1);
1756 cell_info->tree = tree;
1757 cell_info->node = node;
1758 cell_info->cell_col_ref = tv_col;
1759 cell_info->cell = cell;
1760 cell_info->view = accessible;
1762 g_object_set_qdata_full (G_OBJECT (cell),
1763 gtk_tree_view_accessible_get_data_quark (),
1767 g_hash_table_replace (accessible->cell_infos, cell_info, cell_info);
1770 static GtkCellAccessible *
1771 peek_cell (GtkTreeViewAccessible *accessible,
1774 GtkTreeViewColumn *column)
1776 GtkTreeViewAccessibleCellInfo lookup, *cell_info;
1780 lookup.cell_col_ref = column;
1782 cell_info = g_hash_table_lookup (accessible->cell_infos, &lookup);
1783 if (cell_info == NULL)
1786 return cell_info->cell;
1789 static GtkCellAccessible *
1790 find_cell (GtkTreeViewAccessible *accessible,
1793 GtkTreeView *tree_view;
1797 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
1799 if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (tree_view),
1800 index / get_n_columns (tree_view) - 1,
1804 g_assert_not_reached ();
1807 return peek_cell (accessible,
1809 get_visible_column (tree_view, index % get_n_columns (tree_view)));
1812 /* Returns the column number of the specified GtkTreeViewColumn
1813 * The column must be visible.
1816 get_column_number (GtkTreeView *treeview,
1817 GtkTreeViewColumn *column)
1819 GtkTreeViewColumn *cur;
1824 for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
1826 cur = gtk_tree_view_get_column (treeview, i);
1828 if (!gtk_tree_view_column_get_visible (cur))
1837 g_return_val_if_fail (i < gtk_tree_view_get_n_columns (treeview), 0);
1843 get_index (GtkTreeView *tree_view,
1849 gint *indices = NULL;
1853 depth = gtk_tree_path_get_depth (path);
1854 indices = gtk_tree_path_get_indices (path);
1859 GtkTreePath *copy_path;
1860 GtkTreeModel *model;
1862 model = gtk_tree_view_get_model (tree_view);
1863 copy_path = gtk_tree_path_copy (path);
1864 gtk_tree_path_up (copy_path);
1865 count_rows (model, NULL, copy_path, &index, 0, depth);
1866 gtk_tree_path_free (copy_path);
1870 index += indices[depth - 1];
1871 index *= get_n_columns (tree_view);
1872 index += actual_column;
1876 /* The function count_rows counts the number of rows starting at iter
1877 * and ending at end_path. The value of level is the depth of iter and
1878 * the value of depth is the depth of end_path. Rows at depth before
1879 * end_path are counted. This functions counts rows which are not visible
1880 * because an ancestor is collapsed.
1883 count_rows (GtkTreeModel *model,
1885 GtkTreePath *end_path,
1890 GtkTreeIter child_iter;
1896 *count += gtk_tree_model_iter_n_children (model, iter);
1898 if (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY)
1904 if (gtk_tree_model_iter_children (model, &child_iter, iter))
1906 gboolean ret_val = TRUE;
1910 if (level == depth - 1)
1912 GtkTreePath *iter_path;
1913 gboolean finished = FALSE;
1915 iter_path = gtk_tree_model_get_path (model, &child_iter);
1916 if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
1918 gtk_tree_path_free (iter_path);
1922 if (gtk_tree_model_iter_has_child (model, &child_iter))
1923 count_rows (model, &child_iter, end_path, count, level, depth);
1924 ret_val = gtk_tree_model_iter_next (model, &child_iter);
1930 get_rbtree_column_from_index (GtkTreeView *tree_view,
1934 GtkTreeViewColumn **column)
1936 guint n_columns = get_n_columns (tree_view);
1940 /* First row is the column headers */
1947 g_return_val_if_fail (node != NULL, FALSE);
1949 if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (tree_view),
1958 *column = get_visible_column (tree_view, index % n_columns);
1959 if (*column == NULL)
1965 static GtkTreeViewAccessibleCellInfo *
1966 find_cell_info (GtkTreeViewAccessible *accessible,
1967 GtkCellAccessible *cell)
1971 parent = atk_object_get_parent (ATK_OBJECT (cell));
1972 while (parent != ATK_OBJECT (accessible))
1974 cell = GTK_CELL_ACCESSIBLE (parent);
1975 parent = atk_object_get_parent (ATK_OBJECT (cell));
1978 return g_object_get_qdata (G_OBJECT (cell),
1979 gtk_tree_view_accessible_get_data_quark ());
1983 get_header_from_column (GtkTreeViewColumn *tv_col)
1986 GtkWidget *header_widget;
1991 header_widget = gtk_tree_view_column_get_button (tv_col);
1994 rc = gtk_widget_get_accessible (header_widget);
2002 _gtk_tree_view_accessible_add (GtkTreeView *treeview,
2006 GtkTreeViewAccessible *accessible;
2007 guint row, n_rows, n_cols, i;
2009 accessible = GTK_TREE_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (treeview)));
2010 if (accessible == NULL)
2015 row = tree->parent_tree ? _gtk_rbtree_node_get_index (tree->parent_tree, tree->parent_node) : 0;
2016 n_rows = tree->root->total_count;
2020 row = _gtk_rbtree_node_get_index (tree, node);
2021 n_rows = 1 + (node->children ? node->children->root->total_count : 0);
2024 g_signal_emit_by_name (accessible, "row-inserted", row, n_rows);
2026 n_cols = get_n_columns (treeview);
2027 for (i = (row + 1) * n_cols; i < (row + n_rows + 1) * n_cols; i++)
2029 /* Pass NULL as the child object, i.e. 4th argument */
2030 g_signal_emit_by_name (accessible, "children-changed::add", i, NULL, NULL);
2035 _gtk_tree_view_accessible_remove (GtkTreeView *treeview,
2039 GtkTreeViewAccessibleCellInfo *cell_info;
2040 GHashTableIter iter;
2041 GtkTreeViewAccessible *accessible;
2042 guint row, n_rows, n_cols, i;
2044 accessible = GTK_TREE_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (treeview)));
2045 if (accessible == NULL)
2048 /* if this shows up in profiles, special-case node->children == NULL */
2052 row = tree->parent_tree ? _gtk_rbtree_node_get_index (tree->parent_tree, tree->parent_node) : 0;
2053 n_rows = tree->root->total_count + 1;
2057 row = _gtk_rbtree_node_get_index (tree, node);
2058 n_rows = 1 + (node->children ? node->children->root->total_count : 0);
2060 tree = node->children;
2063 g_signal_emit_by_name (accessible, "row-deleted", row, n_rows);
2065 n_cols = get_n_columns (treeview);
2066 for (i = (n_rows + row + 1) * n_cols - 1; i >= (row + 1) * n_cols; i--)
2068 /* Pass NULL as the child object, i.e. 4th argument */
2069 g_signal_emit_by_name (accessible, "children-changed::remove", i, NULL, NULL);
2072 g_hash_table_iter_init (&iter, accessible->cell_infos);
2073 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
2075 if (node == cell_info->node ||
2076 tree == cell_info->tree ||
2077 (tree && _gtk_rbtree_contains (tree, cell_info->tree)))
2078 g_hash_table_iter_remove (&iter);
2083 _gtk_tree_view_accessible_changed (GtkTreeView *treeview,
2087 GtkTreeViewAccessible *accessible;
2090 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (treeview)));
2092 for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
2094 GtkCellAccessible *cell = peek_cell (accessible,
2096 gtk_tree_view_get_column (treeview, i));
2098 if (!GTK_IS_RENDERER_CELL_ACCESSIBLE (cell))
2101 update_cell_value (GTK_RENDERER_CELL_ACCESSIBLE (cell),
2105 g_signal_emit_by_name (accessible, "visible-data-changed");
2108 /* NB: id is not checked, only columns < id are.
2109 * This is important so the function works for notification of removal of a column */
2111 to_visible_column_id (GtkTreeView *treeview,
2119 for (i = 0; i < id; i++)
2121 GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
2123 if (!gtk_tree_view_column_get_visible (column))
2127 return id - invisible;
2131 _gtk_tree_view_accessible_do_add_column (GtkTreeViewAccessible *accessible,
2132 GtkTreeView *treeview,
2133 GtkTreeViewColumn *column,
2136 guint row, n_rows, n_cols;
2138 /* Generate column-inserted signal */
2139 g_signal_emit_by_name (accessible, "column-inserted", id, 1);
2141 n_rows = get_n_rows (treeview);
2142 n_cols = get_n_columns (treeview);
2144 /* Generate children-changed signals */
2145 for (row = 0; row <= n_rows; row++)
2147 /* Pass NULL as the child object, i.e. 4th argument */
2148 g_signal_emit_by_name (accessible, "children-changed::add",
2149 (row * n_cols) + id, NULL, NULL);
2154 _gtk_tree_view_accessible_add_column (GtkTreeView *treeview,
2155 GtkTreeViewColumn *column,
2160 if (!gtk_tree_view_column_get_visible (column))
2163 obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
2167 _gtk_tree_view_accessible_do_add_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
2170 to_visible_column_id (treeview, id));
2174 _gtk_tree_view_accessible_do_remove_column (GtkTreeViewAccessible *accessible,
2175 GtkTreeView *treeview,
2176 GtkTreeViewColumn *column,
2179 GtkTreeViewAccessibleCellInfo *cell_info;
2180 GHashTableIter iter;
2182 guint row, n_rows, n_cols;
2184 /* Clean column from cache */
2185 g_hash_table_iter_init (&iter, accessible->cell_infos);
2186 while (g_hash_table_iter_next (&iter, NULL, &value))
2189 if (cell_info->cell_col_ref == column)
2190 g_hash_table_iter_remove (&iter);
2193 /* Generate column-deleted signal */
2194 g_signal_emit_by_name (accessible, "column-deleted", id, 1);
2196 n_rows = get_n_rows (treeview);
2197 n_cols = get_n_columns (treeview);
2199 /* Generate children-changed signals */
2200 for (row = 0; row <= n_rows; row++)
2202 /* Pass NULL as the child object, 4th argument */
2203 g_signal_emit_by_name (accessible, "children-changed::remove",
2204 (row * n_cols) + id, NULL, NULL);
2209 _gtk_tree_view_accessible_remove_column (GtkTreeView *treeview,
2210 GtkTreeViewColumn *column,
2215 if (!gtk_tree_view_column_get_visible (column))
2218 obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
2222 _gtk_tree_view_accessible_do_remove_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
2225 to_visible_column_id (treeview, id));
2229 _gtk_tree_view_accessible_reorder_column (GtkTreeView *treeview,
2230 GtkTreeViewColumn *column)
2234 obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
2238 g_signal_emit_by_name (obj, "column-reordered");
2242 _gtk_tree_view_accessible_toggle_visibility (GtkTreeView *treeview,
2243 GtkTreeViewColumn *column)
2248 obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
2252 id = get_column_number (treeview, column);
2254 if (gtk_tree_view_column_get_visible (column))
2255 _gtk_tree_view_accessible_do_add_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
2260 _gtk_tree_view_accessible_do_remove_column (GTK_TREE_VIEW_ACCESSIBLE (obj),
2267 _gtk_tree_view_accessible_add_state (GtkTreeView *treeview,
2270 GtkCellRendererState state)
2272 GtkTreeViewAccessible *accessible;
2276 obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
2280 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
2282 for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
2284 GtkCellAccessible *cell = peek_cell (accessible,
2286 gtk_tree_view_get_column (treeview, i));
2291 _gtk_cell_accessible_state_changed (cell, state, 0);
2294 if (state == GTK_CELL_RENDERER_SELECTED)
2295 g_signal_emit_by_name (accessible, "selection-changed");
2299 _gtk_tree_view_accessible_remove_state (GtkTreeView *treeview,
2302 GtkCellRendererState state)
2304 GtkTreeViewAccessible *accessible;
2308 obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
2312 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
2314 for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
2316 GtkCellAccessible *cell = peek_cell (accessible,
2318 gtk_tree_view_get_column (treeview, i));
2323 _gtk_cell_accessible_state_changed (cell, 0, state);
2326 if (state == GTK_CELL_RENDERER_SELECTED)
2327 g_signal_emit_by_name (accessible, "selection-changed");