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 gboolean row_expanded_cb (GtkTreeView *tree_view,
53 static gboolean row_collapsed_cb (GtkTreeView *tree_view,
56 static void size_allocate_cb (GtkWidget *widget,
57 GtkAllocation *allocation);
58 static void selection_changed_cb (GtkTreeSelection *selection,
61 static void columns_changed (GtkTreeView *tree_view);
62 static void cursor_changed (GtkTreeView *tree_view,
63 GtkTreeViewAccessible *accessible);
64 static gboolean focus_in (GtkWidget *widget);
65 static gboolean focus_out (GtkWidget *widget);
67 static void column_visibility_changed
71 static void destroy_count_func (GtkTreeView *tree_view,
78 static void set_iter_nth_row (GtkTreeView *tree_view,
81 static gint get_row_from_tree_path (GtkTreeView *tree_view,
83 static GtkTreeViewColumn* get_column (GtkTreeView *tree_view,
85 static gint get_actual_column_number (GtkTreeView *tree_view,
87 static gint get_visible_column_number (GtkTreeView *tree_view,
89 static void iterate_thru_children (GtkTreeView *tree_view,
90 GtkTreeModel *tree_model,
91 GtkTreePath *tree_path,
95 static int cell_info_get_index (GtkTreeView *tree_view,
96 GtkTreeViewAccessibleCellInfo *info);
97 static void clean_rows (GtkTreeViewAccessible *tree_view);
98 static void clean_cols (GtkTreeViewAccessible *tree_view,
99 GtkTreeViewColumn *tv_col);
100 static void traverse_cells (GtkTreeViewAccessible *tree_view,
101 GtkTreePath *tree_path,
103 static gboolean update_cell_value (GtkRendererCellAccessible *renderer_cell,
104 GtkTreeViewAccessible *accessible,
105 gboolean emit_change_signal);
106 static void set_cell_visibility (GtkTreeView *tree_view,
107 GtkCellAccessible *cell,
108 GtkTreeViewColumn *tv_col,
109 GtkTreePath *tree_path,
110 gboolean emit_signal);
111 static gboolean is_cell_showing (GtkTreeView *tree_view,
112 GdkRectangle *cell_rect);
113 static void set_expand_state (GtkTreeView *tree_view,
114 GtkTreeModel *tree_model,
115 GtkTreeViewAccessible *accessible,
116 GtkTreePath *tree_path,
117 gboolean set_on_ancestor);
118 static void set_cell_expandable (GtkCellAccessible *cell);
119 static void add_cell_actions (GtkCellAccessible *cell,
122 static void toggle_cell_toggled (GtkCellAccessible *cell);
123 static void edit_cell (GtkCellAccessible *cell);
124 static void activate_cell (GtkCellAccessible *cell);
125 static void cell_destroyed (gpointer data);
126 static void cell_info_new (GtkTreeViewAccessible *accessible,
127 GtkTreeModel *tree_model,
130 GtkTreeViewColumn *tv_col,
131 GtkCellAccessible *cell);
132 static GtkCellAccessible *find_cell (GtkTreeViewAccessible *accessible,
134 static void connect_model_signals (GtkTreeView *view,
135 GtkTreeViewAccessible *accessible);
136 static void disconnect_model_signals (GtkTreeViewAccessible *accessible);
137 static gint get_column_number (GtkTreeView *tree_view,
138 GtkTreeViewColumn *column,
140 static gint get_focus_index (GtkTreeView *tree_view);
141 static gint get_index (GtkTreeView *tree_view,
144 static void count_rows (GtkTreeModel *model,
146 GtkTreePath *end_path,
151 static gboolean get_rbtree_column_from_index (GtkTreeView *tree_view,
155 GtkTreeViewColumn **column);
157 static GtkTreeViewAccessibleCellInfo* find_cell_info (GtkTreeViewAccessible *view,
158 GtkCellAccessible *cell,
160 static AtkObject * get_header_from_column (GtkTreeViewColumn *tv_col);
163 static void atk_table_interface_init (AtkTableIface *iface);
164 static void atk_selection_interface_init (AtkSelectionIface *iface);
165 static void atk_component_interface_init (AtkComponentIface *iface);
166 static void gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface);
168 G_DEFINE_TYPE_WITH_CODE (GtkTreeViewAccessible, _gtk_tree_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
169 G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE, atk_table_interface_init)
170 G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init)
171 G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
172 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_ACCESSIBLE_PARENT, gtk_cell_accessible_parent_interface_init))
176 adjustment_changed (GtkAdjustment *adjustment,
179 GtkTreeViewAccessible *accessible;
181 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
182 traverse_cells (accessible, NULL, FALSE);
186 hadjustment_set_cb (GObject *widget,
190 GtkTreeViewAccessible *accessible = data;
193 g_object_get (widget, "hadjustment", &adj, NULL);
194 accessible->old_hadj = adj;
195 g_object_add_weak_pointer (G_OBJECT (accessible->old_hadj), (gpointer *)&accessible->old_hadj);
196 g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment_changed), widget);
200 vadjustment_set_cb (GObject *widget,
204 GtkTreeViewAccessible *accessible = data;
207 g_object_get (widget, "vadjustment", &adj, NULL);
208 accessible->old_vadj = adj;
209 g_object_add_weak_pointer (G_OBJECT (accessible->old_vadj), (gpointer *)&accessible->old_vadj);
210 g_signal_connect (adj, "value-changed",
211 G_CALLBACK (adjustment_changed), widget);
215 gtk_tree_view_accessible_get_data_quark (void)
217 static GQuark quark = 0;
219 if (G_UNLIKELY (quark == 0))
220 quark = g_quark_from_static_string ("gtk-tree-view-accessible-data");
226 cell_info_free (GtkTreeViewAccessibleCellInfo *cell_info)
230 g_object_steal_qdata (G_OBJECT (cell_info->cell),
231 gtk_tree_view_accessible_get_data_quark ());
232 _gtk_cell_accessible_add_state (cell_info->cell, ATK_STATE_DEFUNCT, FALSE);
239 cell_info_get_path (GtkTreeViewAccessibleCellInfo *cell_info)
241 return _gtk_tree_view_find_path (NULL,
247 gtk_tree_view_accessible_initialize (AtkObject *obj,
250 GtkTreeViewAccessible *accessible;
251 GtkTreeView *tree_view;
252 GtkTreeModel *tree_model;
253 GList *tv_cols, *tmp_list;
255 GtkTreeSelection *selection;
257 ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->initialize (obj, data);
259 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
260 accessible->col_data = NULL;
261 accessible->focus_cell = NULL;
262 accessible->old_hadj = NULL;
263 accessible->old_vadj = NULL;
264 accessible->idle_expand_id = 0;
265 accessible->idle_expand_path = NULL;
266 accessible->n_children_deleted = 0;
268 accessible->cell_infos = g_hash_table_new_full (g_direct_hash,
269 g_direct_equal, NULL, (GDestroyNotify) cell_info_free);
271 widget = GTK_WIDGET (data);
272 tree_view = GTK_TREE_VIEW (widget);
273 tree_model = gtk_tree_view_get_model (tree_view);
274 selection = gtk_tree_view_get_selection (tree_view);
276 g_signal_connect_after (widget, "row-collapsed",
277 G_CALLBACK (row_collapsed_cb), NULL);
278 g_signal_connect (widget, "row-expanded",
279 G_CALLBACK (row_expanded_cb), NULL);
280 g_signal_connect (widget, "size-allocate",
281 G_CALLBACK (size_allocate_cb), NULL);
282 g_signal_connect (selection, "changed",
283 G_CALLBACK (selection_changed_cb), obj);
285 g_signal_connect (tree_view, "columns-changed",
286 G_CALLBACK (columns_changed), NULL);
287 g_signal_connect (tree_view, "cursor-changed",
288 G_CALLBACK (cursor_changed), accessible);
289 g_signal_connect (tree_view, "focus-in-event",
290 G_CALLBACK (focus_in), NULL);
291 g_signal_connect (tree_view, "focus-out-event",
292 G_CALLBACK (focus_out), NULL);
294 accessible->tree_model = tree_model;
295 accessible->n_cols = 0;
298 g_object_add_weak_pointer (G_OBJECT (accessible->tree_model), (gpointer *)&accessible->tree_model);
299 connect_model_signals (tree_view, accessible);
301 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
302 obj->role = ATK_ROLE_TABLE;
304 obj->role = ATK_ROLE_TREE_TABLE;
307 hadjustment_set_cb (G_OBJECT (widget), NULL, accessible);
308 vadjustment_set_cb (G_OBJECT (widget), NULL, accessible);
309 g_signal_connect (widget, "notify::hadjustment",
310 G_CALLBACK (hadjustment_set_cb), accessible);
311 g_signal_connect (widget, "notify::vadjustment",
312 G_CALLBACK (vadjustment_set_cb), accessible);
314 accessible->col_data = g_array_sized_new (FALSE, TRUE,
315 sizeof (GtkTreeViewColumn *), 0);
317 tv_cols = gtk_tree_view_get_columns (tree_view);
318 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
320 accessible->n_cols++;
321 g_signal_connect (tmp_list->data, "notify::visible",
322 G_CALLBACK (column_visibility_changed), tree_view);
323 g_array_append_val (accessible->col_data, tmp_list->data);
325 g_list_free (tv_cols);
327 gtk_tree_view_set_destroy_count_func (tree_view,
333 gtk_tree_view_accessible_finalize (GObject *object)
335 GtkTreeViewAccessible *accessible = GTK_TREE_VIEW_ACCESSIBLE (object);
337 /* remove any idle handlers still pending */
338 if (accessible->idle_expand_id)
339 g_source_remove (accessible->idle_expand_id);
341 if (accessible->tree_model)
342 disconnect_model_signals (accessible);
344 if (accessible->cell_infos)
345 g_hash_table_destroy (accessible->cell_infos);
347 if (accessible->col_data)
349 GArray *array = accessible->col_data;
351 /* No need to free the contents of the array since it
352 * just contains pointers to the GtkTreeViewColumn
353 * objects that are in the GtkTreeView.
355 g_array_free (array, TRUE);
358 G_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->finalize (object);
362 gtk_tree_view_accessible_notify_gtk (GObject *obj,
366 GtkTreeView *tree_view;
367 GtkTreeViewAccessible *accessible;
370 widget = GTK_WIDGET (obj);
371 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
372 tree_view = GTK_TREE_VIEW (widget);
374 if (g_strcmp0 (pspec->name, "model") == 0)
376 GtkTreeModel *tree_model;
379 tree_model = gtk_tree_view_get_model (tree_view);
380 if (accessible->tree_model)
381 disconnect_model_signals (accessible);
382 g_hash_table_remove_all (accessible->cell_infos);
383 accessible->tree_model = tree_model;
387 g_object_add_weak_pointer (G_OBJECT (accessible->tree_model), (gpointer *)&accessible->tree_model);
388 connect_model_signals (tree_view, accessible);
390 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
391 role = ATK_ROLE_TABLE;
393 role = ATK_ROLE_TREE_TABLE;
397 role = ATK_ROLE_UNKNOWN;
399 atk_object_set_role (ATK_OBJECT (accessible), role);
400 g_object_freeze_notify (G_OBJECT (accessible));
401 g_signal_emit_by_name (accessible, "model-changed");
402 g_signal_emit_by_name (accessible, "visible-data-changed");
403 g_object_thaw_notify (G_OBJECT (accessible));
405 else if (g_strcmp0 (pspec->name, "hadjustment") == 0)
407 g_object_get (tree_view, "hadjustment", &adj, NULL);
408 g_signal_handlers_disconnect_by_func (accessible->old_hadj,
409 (gpointer) adjustment_changed,
411 accessible->old_hadj = adj;
412 g_object_add_weak_pointer (G_OBJECT (accessible->old_hadj), (gpointer *)&accessible->old_hadj);
413 g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment_changed), tree_view);
415 else if (g_strcmp0 (pspec->name, "vadjustment") == 0)
417 g_object_get (tree_view, "vadjustment", &adj, NULL);
418 g_signal_handlers_disconnect_by_func (accessible->old_vadj,
419 (gpointer) adjustment_changed,
421 accessible->old_vadj = adj;
422 g_object_add_weak_pointer (G_OBJECT (accessible->old_hadj), (gpointer *)&accessible->old_vadj);
423 g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment_changed), tree_view);
426 GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->notify_gtk (obj, pspec);
430 gtk_tree_view_accessible_destroyed (GtkWidget *widget,
431 GtkAccessible *gtk_accessible)
434 GtkTreeViewAccessible *accessible;
436 if (!GTK_IS_TREE_VIEW (widget))
439 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_accessible);
440 adj = accessible->old_hadj;
442 g_signal_handlers_disconnect_by_func (adj,
443 (gpointer) adjustment_changed,
445 adj = accessible->old_vadj;
447 g_signal_handlers_disconnect_by_func (adj,
448 (gpointer) adjustment_changed,
450 if (accessible->tree_model)
452 disconnect_model_signals (accessible);
453 accessible->tree_model = NULL;
455 if (accessible->focus_cell)
457 g_object_unref (accessible->focus_cell);
458 accessible->focus_cell = NULL;
460 if (accessible->idle_expand_id)
462 g_source_remove (accessible->idle_expand_id);
463 accessible->idle_expand_id = 0;
468 gtk_tree_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
472 widget = gtk_accessible_get_widget (accessible);
474 g_signal_connect_after (widget, "destroy",
475 G_CALLBACK (gtk_tree_view_accessible_destroyed), accessible);
477 GTK_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->connect_widget_destroyed (accessible);
481 get_n_rows (GtkTreeView *tree_view)
485 tree = _gtk_tree_view_get_rbtree (tree_view);
490 return tree->root->total_count;
494 gtk_tree_view_accessible_get_n_children (AtkObject *obj)
497 GtkTreeViewAccessible *accessible;
498 GtkTreeView *tree_view;
500 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
504 tree_view = GTK_TREE_VIEW (widget);
505 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
506 return (get_n_rows (tree_view) + 1) * accessible->n_cols;
510 gtk_tree_view_accessible_ref_child (AtkObject *obj,
514 GtkTreeViewAccessible *accessible;
515 GtkCellAccessible *cell;
516 GtkTreeView *tree_view;
517 GtkTreeModel *tree_model;
518 GtkCellRenderer *renderer;
520 GtkTreeViewColumn *tv_col;
521 GtkTreeSelection *selection;
527 GtkTreeViewColumn *expander_tv;
528 GList *renderer_list;
530 GtkContainerCellAccessible *container = NULL;
531 GtkRendererCellAccessible *renderer_cell;
532 gboolean is_expander, is_expanded, retval;
533 gboolean editable = FALSE;
536 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
540 if (i >= gtk_tree_view_accessible_get_n_children (obj))
543 accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
544 tree_view = GTK_TREE_VIEW (widget);
545 if (i < accessible->n_cols)
547 tv_col = gtk_tree_view_get_column (tree_view, i);
548 child = get_header_from_column (tv_col);
550 g_object_ref (child);
554 /* Check whether the child is cached */
555 cell = find_cell (accessible, i);
559 return ATK_OBJECT (cell);
562 if (accessible->focus_cell == NULL)
563 focus_index = get_focus_index (tree_view);
567 /* Find the RBTree and GtkTreeViewColumn for the index */
568 if (!get_rbtree_column_from_index (tree_view, i, &tree, &node, &tv_col))
571 path = _gtk_tree_view_find_path (tree_view, tree, node);
572 tree_model = gtk_tree_view_get_model (tree_view);
573 retval = gtk_tree_model_get_iter (tree_model, &iter, path);
577 expander_tv = gtk_tree_view_get_expander_column (tree_view);
580 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
582 if (expander_tv == tv_col)
585 is_expanded = node->children != NULL;
588 gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter,
589 is_expander, is_expanded);
591 renderer_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
593 /* If there are more than one renderer in the list,
596 if (renderer_list && renderer_list->next)
598 GtkCellAccessible *container_cell;
600 container = _gtk_container_cell_accessible_new ();
602 container_cell = GTK_CELL_ACCESSIBLE (container);
603 _gtk_cell_accessible_initialise (container_cell, widget, ATK_OBJECT (accessible));
605 /* The GtkTreeViewAccessibleCellInfo structure for the container will
606 * be before the ones for the cells so that the first one we find for
607 * a position will be for the container
609 cell_info_new (accessible, tree_model, tree, node, tv_col, container_cell);
610 parent = ATK_OBJECT (container);
613 parent = ATK_OBJECT (accessible);
617 /* Now we make a fake cell_renderer if there is no cell
620 if (renderer_list == NULL)
622 GtkCellRenderer *fake_renderer;
624 fake_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
625 child = _gtk_text_cell_accessible_new ();
626 cell = GTK_CELL_ACCESSIBLE (child);
627 renderer_cell = GTK_RENDERER_CELL_ACCESSIBLE (child);
628 renderer_cell->renderer = fake_renderer;
630 /* Create the GtkTreeViewAccessibleCellInfo structure for this cell */
631 cell_info_new (accessible, tree_model, tree, node, tv_col, cell);
633 _gtk_cell_accessible_initialise (cell, widget, parent);
635 /* Set state if it is expandable */
638 set_cell_expandable (cell);
640 _gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDED, FALSE);
645 for (l = renderer_list; l; l = l->next)
647 renderer = GTK_CELL_RENDERER (l->data);
649 if (GTK_IS_CELL_RENDERER_TEXT (renderer))
651 g_object_get (G_OBJECT (renderer), "editable", &editable, NULL);
652 child = _gtk_text_cell_accessible_new ();
654 else if (GTK_IS_CELL_RENDERER_TOGGLE (renderer))
655 child = _gtk_boolean_cell_accessible_new ();
656 else if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
657 child = _gtk_image_cell_accessible_new ();
659 child = _gtk_renderer_cell_accessible_new ();
661 cell = GTK_CELL_ACCESSIBLE (child);
662 renderer_cell = GTK_RENDERER_CELL_ACCESSIBLE (child);
664 /* Create the GtkTreeViewAccessibleCellInfo for this cell */
665 cell_info_new (accessible, tree_model, tree, node, tv_col, cell);
667 _gtk_cell_accessible_initialise (cell, widget, parent);
670 _gtk_container_cell_accessible_add_child (container, cell);
672 update_cell_value (renderer_cell, accessible, FALSE);
674 /* Add the actions appropriate for this cell */
675 add_cell_actions (cell, editable);
677 /* Set state if it is expandable */
680 set_cell_expandable (cell);
682 _gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDED, FALSE);
685 /* If the column is visible, sets the cell's state */
686 if (gtk_tree_view_column_get_visible (tv_col))
687 set_cell_visibility (tree_view, cell, tv_col, path, FALSE);
689 /* If the row is selected, all cells on the row are selected */
690 selection = gtk_tree_view_get_selection (tree_view);
692 if (gtk_tree_selection_path_is_selected (selection, path))
693 _gtk_cell_accessible_add_state (cell, ATK_STATE_SELECTED, FALSE);
695 _gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
696 if (focus_index == i)
698 accessible->focus_cell = g_object_ref (cell);
699 _gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSED, FALSE);
700 g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
703 g_list_free (renderer_list);
705 child = ATK_OBJECT (container);
708 if (expander_tv == tv_col)
710 AtkRelationSet *relation_set;
711 AtkObject *accessible_array[1];
712 AtkRelation* relation;
713 AtkObject *parent_node;
715 relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
717 gtk_tree_path_up (path);
718 if (gtk_tree_path_get_depth (path) == 0)
724 parent_index = get_index (tree_view, path, i % accessible->n_cols);
725 parent_node = atk_object_ref_accessible_child (obj, parent_index);
727 accessible_array[0] = parent_node;
728 relation = atk_relation_new (accessible_array, 1,
729 ATK_RELATION_NODE_CHILD_OF);
730 atk_relation_set_add (relation_set, relation);
731 atk_object_add_relationship (parent_node, ATK_RELATION_NODE_PARENT_OF, child);
732 g_object_unref (relation);
733 g_object_unref (relation_set);
735 gtk_tree_path_free (path);
737 /* We do not increase the reference count here; when g_object_unref()
738 * is called for the cell then cell_destroyed() is called and this
739 * removes the cell from the cache.
745 gtk_tree_view_accessible_ref_state_set (AtkObject *obj)
747 AtkStateSet *state_set;
750 state_set = ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->ref_state_set (obj);
751 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
754 atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
760 _gtk_tree_view_accessible_class_init (GtkTreeViewAccessibleClass *klass)
762 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
763 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
764 GtkAccessibleClass *accessible_class = (GtkAccessibleClass*)klass;
765 GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
766 GtkContainerAccessibleClass *container_class = (GtkContainerAccessibleClass*)klass;
768 class->get_n_children = gtk_tree_view_accessible_get_n_children;
769 class->ref_child = gtk_tree_view_accessible_ref_child;
770 class->ref_state_set = gtk_tree_view_accessible_ref_state_set;
771 class->initialize = gtk_tree_view_accessible_initialize;
773 widget_class->notify_gtk = gtk_tree_view_accessible_notify_gtk;
775 accessible_class->connect_widget_destroyed = gtk_tree_view_accessible_connect_widget_destroyed;
777 /* The children of a GtkTreeView are the buttons at the top of the columns
778 * we do not represent these as children so we do not want to report
779 * children added or deleted when these changed.
781 container_class->add_gtk = NULL;
782 container_class->remove_gtk = NULL;
784 gobject_class->finalize = gtk_tree_view_accessible_finalize;
788 _gtk_tree_view_accessible_init (GtkTreeViewAccessible *view)
793 get_focus_index (GtkTreeView *tree_view)
795 GtkTreePath *focus_path;
796 GtkTreeViewColumn *focus_column;
799 gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
800 if (focus_path && focus_column)
801 index = get_index (tree_view, focus_path,
802 get_column_number (tree_view, focus_column, FALSE));
807 gtk_tree_path_free (focus_path);
812 /* This function returns a reference to the accessible object
813 * for the cell in the treeview which has focus, if any
816 gtk_tree_view_accessible_ref_focus_cell (GtkTreeView *tree_view)
818 AtkObject *focus_cell = NULL;
822 focus_index = get_focus_index (tree_view);
823 if (focus_index >= 0)
825 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
826 focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
835 gtk_tree_view_accessible_ref_accessible_at_point (AtkComponent *component,
838 AtkCoordType coord_type)
841 GtkTreeView *tree_view;
843 GtkTreeViewColumn *tv_column;
848 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
852 tree_view = GTK_TREE_VIEW (widget);
854 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
855 gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &bx, &by);
856 ret_val = gtk_tree_view_get_path_at_pos (tree_view,
857 bx - x_pos, by - y_pos,
858 &path, &tv_column, NULL, NULL);
863 column = get_column_number (tree_view, tv_column, FALSE);
864 index = get_index (tree_view, path, column);
865 gtk_tree_path_free (path);
867 return gtk_tree_view_accessible_ref_child (ATK_OBJECT (component), index);
874 atk_component_interface_init (AtkComponentIface *iface)
876 iface->ref_accessible_at_point = gtk_tree_view_accessible_ref_accessible_at_point;
882 gtk_tree_view_accessible_get_index_at (AtkTable *table,
887 GtkTreeView *tree_view;
894 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
898 n_cols = atk_table_get_n_columns (table);
899 n_rows = atk_table_get_n_rows (table);
901 if (row >= n_rows || column >= n_cols)
904 tree_view = GTK_TREE_VIEW (widget);
905 actual_column = get_actual_column_number (tree_view, column);
907 set_iter_nth_row (tree_view, &iter, row);
908 path = gtk_tree_model_get_path (gtk_tree_view_get_model (tree_view), &iter);
910 index = get_index (tree_view, path, actual_column);
911 gtk_tree_path_free (path);
917 gtk_tree_view_accessible_get_column_at_index (AtkTable *table,
921 GtkTreeView *tree_view;
924 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
928 tree_view = GTK_TREE_VIEW (widget);
929 n_columns = GTK_TREE_VIEW_ACCESSIBLE (table)->n_cols;
934 index = index % n_columns;
936 return get_visible_column_number (tree_view, index);
940 gtk_tree_view_accessible_get_row_at_index (AtkTable *table,
944 GtkTreeView *tree_view;
946 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
950 tree_view = GTK_TREE_VIEW (widget);
952 index /= GTK_TREE_VIEW_ACCESSIBLE (table)->n_cols;
954 if (index >= get_n_rows (tree_view))
961 gtk_tree_view_accessible_table_ref_at (AtkTable *table,
967 index = gtk_tree_view_accessible_get_index_at (table, row, column);
971 return gtk_tree_view_accessible_ref_child (ATK_OBJECT (table), index);
975 gtk_tree_view_accessible_get_n_rows (AtkTable *table)
979 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
983 return get_n_rows (GTK_TREE_VIEW (widget));
987 gtk_tree_view_accessible_get_n_columns (AtkTable *table)
990 GtkTreeView *tree_view;
991 GtkTreeViewColumn *tv_col;
995 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
999 tree_view = GTK_TREE_VIEW (widget);
1000 tv_col = gtk_tree_view_get_column (tree_view, i);
1002 while (tv_col != NULL)
1004 if (gtk_tree_view_column_get_visible (tv_col))
1008 tv_col = gtk_tree_view_get_column (tree_view, i);
1015 gtk_tree_view_accessible_is_row_selected (AtkTable *table,
1019 GtkTreeView *tree_view;
1020 GtkTreeSelection *selection;
1023 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1030 tree_view = GTK_TREE_VIEW (widget);
1031 selection = gtk_tree_view_get_selection (tree_view);
1033 set_iter_nth_row (tree_view, &iter, row);
1034 return gtk_tree_selection_iter_is_selected (selection, &iter);
1038 gtk_tree_view_accessible_is_selected (AtkTable *table,
1042 return gtk_tree_view_accessible_is_row_selected (table, row);
1046 get_selected_rows (GtkTreeModel *model,
1051 GPtrArray *array = (GPtrArray *)data;
1053 g_ptr_array_add (array, gtk_tree_path_copy (path));
1057 gtk_tree_view_accessible_get_selected_rows (AtkTable *table,
1058 gint **rows_selected)
1061 GtkTreeView *tree_view;
1062 GtkTreeModel *tree_model;
1064 GtkTreeSelection *selection;
1065 GtkTreePath *tree_path;
1068 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1072 tree_view = GTK_TREE_VIEW (widget);
1073 selection = gtk_tree_view_get_selection (tree_view);
1075 switch (gtk_tree_selection_get_mode (selection))
1077 case GTK_SELECTION_SINGLE:
1078 case GTK_SELECTION_BROWSE:
1079 if (gtk_tree_selection_get_selected (selection, &tree_model, &iter))
1085 *rows_selected = g_new (gint, 1);
1086 tree_path = gtk_tree_model_get_path (tree_model, &iter);
1087 row = get_row_from_tree_path (tree_view, tree_path);
1088 gtk_tree_path_free (tree_path);
1090 /* shouldn't ever happen */
1091 g_return_val_if_fail (row != -1, 0);
1093 *rows_selected[0] = row;
1098 case GTK_SELECTION_MULTIPLE:
1100 GPtrArray *array = g_ptr_array_new();
1102 gtk_tree_selection_selected_foreach (selection, get_selected_rows, array);
1103 ret_val = array->len;
1105 if (rows_selected && ret_val)
1109 *rows_selected = g_new (gint, ret_val);
1110 for (i = 0; i < ret_val; i++)
1114 tree_path = (GtkTreePath *) g_ptr_array_index (array, i);
1115 row = get_row_from_tree_path (tree_view, tree_path);
1116 gtk_tree_path_free (tree_path);
1117 (*rows_selected)[i] = row;
1120 g_ptr_array_free (array, FALSE);
1123 case GTK_SELECTION_NONE:
1130 gtk_tree_view_accessible_add_row_selection (AtkTable *table,
1134 GtkTreeView *tree_view;
1135 GtkTreeModel *tree_model;
1136 GtkTreeSelection *selection;
1137 GtkTreePath *tree_path;
1138 GtkTreeIter iter_to_row;
1140 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1144 if (!gtk_tree_view_accessible_is_row_selected (table, row))
1146 tree_view = GTK_TREE_VIEW (widget);
1147 tree_model = gtk_tree_view_get_model (tree_view);
1148 selection = gtk_tree_view_get_selection (tree_view);
1150 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1152 tree_path = gtk_tree_path_new ();
1153 gtk_tree_path_append_index (tree_path, row);
1154 gtk_tree_selection_select_path (selection,tree_path);
1155 gtk_tree_path_free (tree_path);
1159 set_iter_nth_row (tree_view, &iter_to_row, row);
1160 gtk_tree_selection_select_iter (selection, &iter_to_row);
1164 return gtk_tree_view_accessible_is_row_selected (table, row);
1168 gtk_tree_view_accessible_remove_row_selection (AtkTable *table,
1172 GtkTreeView *tree_view;
1173 GtkTreeSelection *selection;
1175 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1179 tree_view = GTK_TREE_VIEW (widget);
1180 selection = gtk_tree_view_get_selection (tree_view);
1182 if (gtk_tree_view_accessible_is_row_selected (table, row))
1184 gtk_tree_selection_unselect_all (selection);
1192 gtk_tree_view_accessible_get_column_header (AtkTable *table,
1196 GtkTreeView *tree_view;
1197 GtkTreeViewColumn *tv_col;
1199 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1203 tree_view = GTK_TREE_VIEW (widget);
1204 tv_col = get_column (tree_view, in_col);
1205 return get_header_from_column (tv_col);
1208 static const gchar *
1209 gtk_tree_view_accessible_get_column_description (AtkTable *table,
1213 GtkTreeView *tree_view;
1214 GtkTreeViewColumn *tv_col;
1216 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1220 tree_view = GTK_TREE_VIEW (widget);
1221 tv_col = get_column (tree_view, in_col);
1225 return gtk_tree_view_column_get_title (tv_col);
1229 atk_table_interface_init (AtkTableIface *iface)
1231 iface->ref_at = gtk_tree_view_accessible_table_ref_at;
1232 iface->get_n_rows = gtk_tree_view_accessible_get_n_rows;
1233 iface->get_n_columns = gtk_tree_view_accessible_get_n_columns;
1234 iface->get_index_at = gtk_tree_view_accessible_get_index_at;
1235 iface->get_column_at_index = gtk_tree_view_accessible_get_column_at_index;
1236 iface->get_row_at_index = gtk_tree_view_accessible_get_row_at_index;
1237 iface->is_row_selected = gtk_tree_view_accessible_is_row_selected;
1238 iface->is_selected = gtk_tree_view_accessible_is_selected;
1239 iface->get_selected_rows = gtk_tree_view_accessible_get_selected_rows;
1240 iface->add_row_selection = gtk_tree_view_accessible_add_row_selection;
1241 iface->remove_row_selection = gtk_tree_view_accessible_remove_row_selection;
1242 iface->get_column_extent_at = NULL;
1243 iface->get_row_extent_at = NULL;
1244 iface->get_column_header = gtk_tree_view_accessible_get_column_header;
1245 iface->get_column_description = gtk_tree_view_accessible_get_column_description;
1248 /* atkselection.h */
1251 gtk_tree_view_accessible_add_selection (AtkSelection *selection,
1258 table = ATK_TABLE (selection);
1259 n_columns = gtk_tree_view_accessible_get_n_columns (table);
1263 row = gtk_tree_view_accessible_get_row_at_index (table, i);
1264 return gtk_tree_view_accessible_add_row_selection (table, row);
1268 gtk_tree_view_accessible_clear_selection (AtkSelection *selection)
1271 GtkTreeView *tree_view;
1272 GtkTreeSelection *tree_selection;
1274 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1278 tree_view = GTK_TREE_VIEW (widget);
1279 tree_selection = gtk_tree_view_get_selection (tree_view);
1281 gtk_tree_selection_unselect_all (tree_selection);
1286 gtk_tree_view_accessible_ref_selection (AtkSelection *selection,
1295 table = ATK_TABLE (selection);
1296 n_columns = gtk_tree_view_accessible_get_n_columns (table);
1297 n_selected = gtk_tree_view_accessible_get_selected_rows (table, &selected);
1298 if (i >= n_columns * n_selected)
1301 row = selected[i / n_columns];
1304 return gtk_tree_view_accessible_table_ref_at (table, row, i % n_columns);
1308 gtk_tree_view_accessible_get_selection_count (AtkSelection *selection)
1313 table = ATK_TABLE (selection);
1314 n_selected = gtk_tree_view_accessible_get_selected_rows (table, NULL);
1316 n_selected *= gtk_tree_view_accessible_get_n_columns (table);
1321 gtk_tree_view_accessible_is_child_selected (AtkSelection *selection,
1327 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1331 row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
1333 return gtk_tree_view_accessible_is_row_selected (ATK_TABLE (selection), row);
1336 static void atk_selection_interface_init (AtkSelectionIface *iface)
1338 iface->add_selection = gtk_tree_view_accessible_add_selection;
1339 iface->clear_selection = gtk_tree_view_accessible_clear_selection;
1340 iface->ref_selection = gtk_tree_view_accessible_ref_selection;
1341 iface->get_selection_count = gtk_tree_view_accessible_get_selection_count;
1342 iface->is_child_selected = gtk_tree_view_accessible_is_child_selected;
1345 #define EXTRA_EXPANDER_PADDING 4
1348 gtk_tree_view_accessible_get_cell_area (GtkCellAccessibleParent *parent,
1349 GtkCellAccessible *cell,
1350 GdkRectangle *cell_rect)
1353 GtkTreeView *tree_view;
1354 GtkTreeViewColumn *tv_col;
1356 AtkObject *parent_cell;
1357 GtkTreeViewAccessibleCellInfo *cell_info;
1358 GtkCellAccessible *top_cell;
1360 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1364 tree_view = GTK_TREE_VIEW (widget);
1365 parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
1366 if (parent_cell != ATK_OBJECT (parent))
1367 top_cell = GTK_CELL_ACCESSIBLE (parent_cell);
1370 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), top_cell, TRUE);
1373 path = cell_info_get_path (cell_info);
1374 tv_col = cell_info->cell_col_ref;
1377 GtkTreeViewColumn *expander_column;
1378 gint focus_line_width;
1380 gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
1381 expander_column = gtk_tree_view_get_expander_column (tree_view);
1382 if (expander_column == tv_col)
1385 gtk_widget_style_get (widget,
1386 "expander-size", &expander_size,
1388 cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
1389 cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
1391 gtk_widget_style_get (widget,
1392 "focus-line-width", &focus_line_width,
1395 cell_rect->x += focus_line_width;
1396 cell_rect->width -= 2 * focus_line_width;
1398 gtk_tree_path_free (path);
1400 /* A column has more than one renderer so we find the position
1403 if (top_cell != cell)
1410 GtkCellRenderer *renderer;
1412 cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
1413 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
1414 renderer = g_list_nth_data (renderers, cell_index);
1416 found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
1419 cell_rect->x += cell_start;
1420 cell_rect->width = cell_width;
1422 g_list_free (renderers);
1429 gtk_tree_view_accessible_get_cell_extents (GtkCellAccessibleParent *parent,
1430 GtkCellAccessible *cell,
1435 AtkCoordType coord_type)
1438 GtkTreeView *tree_view;
1439 GdkWindow *bin_window;
1440 GdkRectangle cell_rect;
1443 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1447 tree_view = GTK_TREE_VIEW (widget);
1448 gtk_tree_view_accessible_get_cell_area (parent, cell, &cell_rect);
1449 bin_window = gtk_tree_view_get_bin_window (tree_view);
1450 gdk_window_get_origin (bin_window, &w_x, &w_y);
1452 if (coord_type == ATK_XY_WINDOW)
1455 gint x_toplevel, y_toplevel;
1457 window = gdk_window_get_toplevel (bin_window);
1458 gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
1464 *width = cell_rect.width;
1465 *height = cell_rect.height;
1466 if (is_cell_showing (tree_view, &cell_rect))
1468 *x = cell_rect.x + w_x;
1469 *y = cell_rect.y + w_y;
1479 gtk_tree_view_accessible_grab_cell_focus (GtkCellAccessibleParent *parent,
1480 GtkCellAccessible *cell)
1483 GtkTreeView *tree_view;
1484 GtkTreeViewColumn *tv_col;
1486 AtkObject *parent_cell;
1487 AtkObject *cell_object;
1488 GtkTreeViewAccessibleCellInfo *cell_info;
1489 GtkCellRenderer *renderer = NULL;
1490 GtkWidget *toplevel;
1493 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1497 tree_view = GTK_TREE_VIEW (widget);
1499 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
1502 cell_object = ATK_OBJECT (cell);
1503 parent_cell = atk_object_get_parent (cell_object);
1504 tv_col = cell_info->cell_col_ref;
1505 if (parent_cell != ATK_OBJECT (parent))
1507 /* GtkCellAccessible is in a GtkContainerCellAccessible.
1508 * The GtkTreeViewColumn has multiple renderers;
1509 * find the corresponding one.
1513 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
1514 index = atk_object_get_index_in_parent (cell_object);
1515 renderer = g_list_nth_data (renderers, index);
1516 g_list_free (renderers);
1518 path = cell_info_get_path (cell_info);
1522 gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
1524 gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
1526 gtk_tree_path_free (path);
1527 gtk_widget_grab_focus (widget);
1528 toplevel = gtk_widget_get_toplevel (widget);
1529 if (gtk_widget_is_toplevel (toplevel))
1531 #ifdef GDK_WINDOWING_X11
1532 gtk_window_present_with_time (GTK_WINDOW (toplevel),
1533 gdk_x11_get_server_time (gtk_widget_get_window (widget)));
1535 gtk_window_present (GTK_WINDOW (toplevel));
1546 gtk_tree_view_accessible_get_child_index (GtkCellAccessibleParent *parent,
1547 GtkCellAccessible *cell)
1549 GtkTreeViewAccessibleCellInfo *cell_info;
1550 GtkTreeView *tree_view;
1552 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
1556 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1558 return cell_info_get_index (tree_view, cell_info);
1562 gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface)
1564 iface->get_cell_extents = gtk_tree_view_accessible_get_cell_extents;
1565 iface->get_cell_area = gtk_tree_view_accessible_get_cell_area;
1566 iface->grab_focus = gtk_tree_view_accessible_grab_cell_focus;
1567 iface->get_child_index = gtk_tree_view_accessible_get_child_index;
1570 /* signal handling */
1573 idle_expand_row (gpointer data)
1575 GtkTreeViewAccessible *accessible = data;
1577 GtkTreeView *tree_view;
1579 GtkTreeModel *tree_model;
1580 gint n_inserted, row;
1582 accessible->idle_expand_id = 0;
1584 path = accessible->idle_expand_path;
1585 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
1587 tree_model = gtk_tree_view_get_model (tree_view);
1591 if (!path || !gtk_tree_model_get_iter (tree_model, &iter, path))
1594 /* Update visibility of cells below expansion row */
1595 traverse_cells (accessible, path, FALSE);
1597 /* Figure out number of visible children, the following test
1600 if (gtk_tree_model_iter_has_child (tree_model, &iter))
1602 GtkTreePath *path_copy;
1604 /* By passing path into this function, we find the number of
1605 * visible children of path.
1607 path_copy = gtk_tree_path_copy (path);
1608 gtk_tree_path_append_index (path_copy, 0);
1611 iterate_thru_children (tree_view, tree_model,
1612 path_copy, NULL, &n_inserted, 0);
1613 gtk_tree_path_free (path_copy);
1617 /* We can get here if the row expanded callback deleted the row */
1621 /* Set expand state */
1622 set_expand_state (tree_view, tree_model, accessible, path, TRUE);
1624 row = get_row_from_tree_path (tree_view, path);
1626 /* shouldn't ever happen */
1628 g_assert_not_reached ();
1630 /* Must add 1 because the "added rows" are below the row being expanded */
1633 g_signal_emit_by_name (accessible, "row-inserted", row, n_inserted);
1635 accessible->idle_expand_path = NULL;
1637 gtk_tree_path_free (path);
1643 row_expanded_cb (GtkTreeView *tree_view,
1648 GtkTreeViewAccessible *accessible;
1650 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
1651 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1654 * The visible rectangle has not been updated when this signal is emitted
1655 * so we process the signal when the GTK processing is completed
1657 /* this seems wrong since it overwrites any other pending expand handlers... */
1658 accessible->idle_expand_path = gtk_tree_path_copy (path);
1659 if (accessible->idle_expand_id)
1660 g_source_remove (accessible->idle_expand_id);
1661 accessible->idle_expand_id = gdk_threads_add_idle (idle_expand_row, accessible);
1667 row_collapsed_cb (GtkTreeView *tree_view,
1671 GtkTreeModel *tree_model;
1673 GtkTreeViewAccessible *accessible;
1676 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
1677 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1678 tree_model = gtk_tree_view_get_model (tree_view);
1680 clean_rows (accessible);
1682 /* Update visibility of cells below collapsed row */
1683 traverse_cells (accessible, path, FALSE);
1685 /* Set collapse state */
1686 set_expand_state (tree_view, tree_model, accessible, path, FALSE);
1687 if (accessible->n_children_deleted == 0)
1689 row = get_row_from_tree_path (tree_view, path);
1692 g_signal_emit_by_name (atk_obj, "row-deleted", row,
1693 accessible->n_children_deleted);
1694 accessible->n_children_deleted = 0;
1699 size_allocate_cb (GtkWidget *widget,
1700 GtkAllocation *allocation)
1703 GtkTreeViewAccessible *accessible;
1705 atk_obj = gtk_widget_get_accessible (widget);
1706 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1708 /* If the size allocation changes, the visibility of cells
1709 * may change so update the cells visibility.
1711 traverse_cells (accessible, NULL, FALSE);
1715 selection_changed_cb (GtkTreeSelection *selection,
1718 GtkTreeViewAccessible *accessible;
1719 GtkTreeView *tree_view;
1721 GtkTreeViewAccessibleCellInfo *info;
1722 GtkTreeSelection *tree_selection;
1724 GHashTableIter iter;
1726 accessible = GTK_TREE_VIEW_ACCESSIBLE (data);
1727 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
1731 tree_view = GTK_TREE_VIEW (widget);
1732 tree_selection = gtk_tree_view_get_selection (tree_view);
1734 clean_rows (accessible);
1736 /* FIXME: clean rows iterates through all cells too */
1737 g_hash_table_iter_init (&iter, accessible->cell_infos);
1738 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&info))
1740 _gtk_cell_accessible_remove_state (info->cell, ATK_STATE_SELECTED, TRUE);
1742 path = cell_info_get_path (info);
1743 if (path && gtk_tree_selection_path_is_selected (tree_selection, path))
1744 _gtk_cell_accessible_add_state (info->cell, ATK_STATE_SELECTED, TRUE);
1745 gtk_tree_path_free (path);
1747 if (gtk_widget_get_realized (widget))
1748 g_signal_emit_by_name (accessible, "selection-changed");
1752 columns_changed (GtkTreeView *tree_view)
1755 GtkTreeViewAccessible *accessible;
1756 GList *tv_cols, *tmp_list;
1757 gboolean column_found;
1758 gboolean move_found = FALSE;
1759 gint column_count = 0;
1762 atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
1763 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1765 /* This function must determine if the change is an add, delete
1766 * or a move based upon its cache of TreeViewColumns in
1767 * accessible->col_data
1769 tv_cols = gtk_tree_view_get_columns (tree_view);
1770 accessible->n_cols = g_list_length (tv_cols);
1772 /* check for adds or moves */
1773 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
1775 column_found = FALSE;
1777 for (i = 0; i < accessible->col_data->len; i++)
1780 if ((GtkTreeViewColumn *)tmp_list->data ==
1781 (GtkTreeViewColumn *)g_array_index (accessible->col_data,
1782 GtkTreeViewColumn *, i))
1784 column_found = TRUE;
1786 /* If the column isn't in the same position, a move happened */
1787 if (!move_found && i != column_count)
1789 /* Just emit one column reordered signal when a move happens */
1790 g_signal_emit_by_name (atk_obj, "column-reordered");
1798 /* If column_found is FALSE, then an insert happened for column
1799 * number column_count
1805 /* Generate column-inserted signal */
1806 g_signal_emit_by_name (atk_obj, "column-inserted", column_count, 1);
1808 /* Generate children-changed signals */
1809 for (row = 0; row < get_n_rows (tree_view); row++)
1811 /* Pass NULL as the child object, i.e. 4th argument */
1812 g_signal_emit_by_name (atk_obj, "children-changed::add",
1813 ((row * accessible->n_cols) + column_count), NULL, NULL);
1820 /* check for deletes */
1821 for (i = 0; i < accessible->col_data->len; i++)
1823 column_found = FALSE;
1825 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
1827 if ((GtkTreeViewColumn *)tmp_list->data ==
1828 (GtkTreeViewColumn *)g_array_index (accessible->col_data,
1829 GtkTreeViewColumn *, i))
1831 column_found = TRUE;
1836 /* If column_found is FALSE, then a delete happened for column
1843 clean_cols (accessible,
1844 (GtkTreeViewColumn *)g_array_index (accessible->col_data,
1845 GtkTreeViewColumn *, i));
1847 /* Generate column-deleted signal */
1848 g_signal_emit_by_name (atk_obj, "column-deleted", i, 1);
1850 /* Generate children-changed signals */
1851 for (row = 0; row < get_n_rows (tree_view); row++)
1853 /* Pass NULL as the child object, 4th argument */
1854 g_signal_emit_by_name (atk_obj, "children-changed::remove",
1855 ((row * accessible->n_cols) + column_count), NULL, NULL);
1860 traverse_cells (accessible, NULL, FALSE);
1862 /* rebuild the array */
1863 g_array_free (accessible->col_data, TRUE);
1864 accessible->col_data = g_array_sized_new (FALSE, TRUE, sizeof (GtkTreeViewColumn *), 0);
1866 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
1867 g_array_append_val (accessible->col_data, tmp_list->data);
1868 g_list_free (tv_cols);
1872 cursor_changed (GtkTreeView *tree_view,
1873 GtkTreeViewAccessible *accessible)
1877 cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
1880 if (cell != accessible->focus_cell)
1882 if (accessible->focus_cell)
1884 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
1885 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
1886 g_object_unref (accessible->focus_cell);
1887 accessible->focus_cell = cell;
1890 if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
1892 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
1893 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
1896 g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
1899 g_object_unref (cell);
1904 focus_in (GtkWidget *widget)
1906 GtkTreeView *tree_view;
1907 GtkTreeViewAccessible *accessible;
1908 AtkStateSet *state_set;
1911 tree_view = GTK_TREE_VIEW (widget);
1912 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
1914 if (accessible->focus_cell == NULL)
1916 cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
1919 state_set = atk_object_ref_state_set (cell);
1922 if (!atk_state_set_contains_state (state_set, ATK_STATE_FOCUSED))
1924 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
1925 accessible->focus_cell = cell;
1926 _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
1927 g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
1929 g_object_unref (state_set);
1937 focus_out (GtkWidget *widget)
1939 GtkTreeViewAccessible *accessible;
1941 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
1942 if (accessible->focus_cell)
1944 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
1945 _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
1946 g_object_unref (accessible->focus_cell);
1947 accessible->focus_cell = NULL;
1953 model_row_changed (GtkTreeModel *tree_model,
1958 GtkTreeView *tree_view = GTK_TREE_VIEW (user_data);
1959 GtkTreeViewAccessible *accessible;
1960 GtkTreePath *cell_path;
1961 GtkTreeViewAccessibleCellInfo *cell_info;
1962 GHashTableIter hash_iter;
1964 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
1966 /* Loop through our cached cells */
1967 /* Must loop through them all */
1968 g_hash_table_iter_init (&hash_iter, accessible->cell_infos);
1969 while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer *)&cell_info))
1971 cell_path = cell_info_get_path (cell_info);
1973 if (cell_path != NULL)
1975 if (path && gtk_tree_path_compare (cell_path, path) == 0)
1977 if (GTK_IS_RENDERER_CELL_ACCESSIBLE (cell_info->cell))
1978 update_cell_value (GTK_RENDERER_CELL_ACCESSIBLE (cell_info->cell),
1981 gtk_tree_path_free (cell_path);
1984 g_signal_emit_by_name (accessible, "visible-data-changed");
1988 column_visibility_changed (GObject *object,
1992 if (g_strcmp0 (pspec->name, "visible") == 0)
1994 /* A column has been made visible or invisible
1995 * We update our cache of cells and emit model_changed signal
1997 GtkTreeView *tree_view = (GtkTreeView *)user_data;
1998 GtkTreeViewAccessible *accessible;
1999 GtkTreeViewAccessibleCellInfo *cell_info;
2000 GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
2001 GtkTreeViewColumn *tv_col;
2002 GHashTableIter iter;
2004 accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
2006 g_signal_emit_by_name (accessible, "model-changed");
2008 g_hash_table_iter_init (&iter, accessible->cell_infos);
2009 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
2011 tv_col = cell_info->cell_col_ref;
2012 if (tv_col == this_col)
2014 GtkTreePath *row_path;
2015 row_path = cell_info_get_path (cell_info);
2016 if (GTK_IS_RENDERER_CELL_ACCESSIBLE (cell_info->cell))
2018 if (gtk_tree_view_column_get_visible (tv_col))
2019 set_cell_visibility (tree_view,
2021 tv_col, row_path, FALSE);
2024 _gtk_cell_accessible_remove_state (cell_info->cell, ATK_STATE_VISIBLE, TRUE);
2025 _gtk_cell_accessible_remove_state (cell_info->cell, ATK_STATE_SHOWING, TRUE);
2028 gtk_tree_path_free (row_path);
2035 model_row_inserted (GtkTreeModel *tree_model,
2040 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2042 GtkTreeViewAccessible *accessible;
2043 GtkTreePath *path_copy;
2044 gint row, n_inserted, child_row;
2046 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2047 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2049 if (accessible->idle_expand_id)
2051 g_source_remove (accessible->idle_expand_id);
2052 accessible->idle_expand_id = 0;
2054 /* don't do this if the insertion precedes the idle path,
2055 * since it will now be invalid
2057 if (path && accessible->idle_expand_path &&
2058 (gtk_tree_path_compare (path, accessible->idle_expand_path) > 0))
2059 set_expand_state (tree_view, tree_model, accessible, accessible->idle_expand_path, FALSE);
2060 if (accessible->idle_expand_path)
2061 gtk_tree_path_free (accessible->idle_expand_path);
2063 /* Check to see if row is visible */
2064 row = get_row_from_tree_path (tree_view, path);
2066 /* A row insert is not necessarily visible. For example,
2067 * a row can be draged & dropped into another row, which
2068 * causes an insert on the model that isn't visible in the
2069 * view. Only generate a signal if the inserted row is
2074 GtkTreeIter tmp_iter;
2077 gtk_tree_model_get_iter (tree_model, &tmp_iter, path);
2079 /* Figure out number of visible children. */
2080 if (gtk_tree_model_iter_has_child (tree_model, &tmp_iter))
2084 * By passing path into this function, we find the number of
2085 * visible children of path.
2088 /* iterate_thru_children modifies path, we don't want that, so give
2090 path2 = gtk_tree_path_copy (path);
2091 iterate_thru_children (tree_view, tree_model,
2092 path2, NULL, &n_inserted, 0);
2093 gtk_tree_path_free (path2);
2095 /* Must add one to include the row that is being added */
2101 traverse_cells (accessible, path, TRUE);
2103 /* Generate row-inserted signal */
2104 g_signal_emit_by_name (atk_obj, "row-inserted", row, n_inserted);
2106 /* Generate children-changed signals */
2107 n_cols = gtk_tree_view_accessible_get_n_columns (ATK_TABLE (atk_obj));
2108 for (child_row = row; child_row < (row + n_inserted); child_row++)
2110 for (col = 0; col < n_cols; col++)
2112 /* Pass NULL as the child object, i.e. 4th argument */
2113 g_signal_emit_by_name (atk_obj, "children-changed::add",
2114 ((row * n_cols) + col), NULL, NULL);
2120 /* The row has been inserted inside another row. This can
2121 * cause a row that previously couldn't be expanded to now
2124 path_copy = gtk_tree_path_copy (path);
2125 gtk_tree_path_up (path_copy);
2126 set_expand_state (tree_view, tree_model, accessible, path_copy, TRUE);
2127 gtk_tree_path_free (path_copy);
2132 model_row_deleted (GtkTreeModel *tree_model,
2136 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2137 GtkTreePath *path_copy;
2139 GtkTreeViewAccessible *accessible;
2142 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2143 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2145 if (accessible->idle_expand_id)
2147 g_source_remove (accessible->idle_expand_id);
2148 gtk_tree_path_free (accessible->idle_expand_path);
2149 accessible->idle_expand_id = 0;
2152 /* Check to see if row is visible */
2153 clean_rows (accessible);
2155 traverse_cells (accessible, path, TRUE);
2157 /* If deleting a row with a depth > 1, then this may affect the
2158 * expansion/contraction of its parent(s). Make sure this is
2161 if (gtk_tree_path_get_depth (path) > 1)
2163 path_copy = gtk_tree_path_copy (path);
2164 gtk_tree_path_up (path_copy);
2165 set_expand_state (tree_view, tree_model, accessible, path_copy, TRUE);
2166 gtk_tree_path_free (path_copy);
2168 row = get_row_from_tree_path (tree_view, path);
2170 /* If the row which is deleted is not visible because it is a child of
2171 * a collapsed row then row will be -1
2174 g_signal_emit_by_name (atk_obj, "row-deleted", row,
2175 accessible->n_children_deleted + 1);
2176 accessible->n_children_deleted = 0;
2178 /* Generate children-changed signals */
2179 for (col = 0; col < accessible->n_cols; col++)
2181 /* Pass NULL as the child object, 4th argument */
2182 g_signal_emit_by_name (atk_obj, "children-changed::remove",
2183 ((row * accessible->n_cols) + col), NULL, NULL);
2187 /* This function gets called when a row is deleted or when rows are
2188 * removed from the view due to a collapse event. Note that the
2189 * count is the number of visible *children* of the deleted row,
2190 * so it does not include the row being deleted.
2192 * As this function is called before the rows are removed we just note
2193 * the number of rows and then deal with it when we get a notification
2194 * that rows were deleted or collapsed.
2197 destroy_count_func (GtkTreeView *tree_view,
2203 GtkTreeViewAccessible *accessible;
2205 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2206 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2208 if (accessible->n_children_deleted != 0)
2211 accessible->n_children_deleted = count;
2215 model_rows_reordered (GtkTreeModel *tree_model,
2221 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2223 GtkTreeViewAccessible *accessible;
2225 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2226 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2228 if (accessible->idle_expand_id)
2230 g_source_remove (accessible->idle_expand_id);
2231 gtk_tree_path_free (accessible->idle_expand_path);
2232 accessible->idle_expand_id = 0;
2234 traverse_cells (accessible, NULL, FALSE);
2236 g_signal_emit_by_name (atk_obj, "row-reordered");
2240 set_cell_visibility (GtkTreeView *tree_view,
2241 GtkCellAccessible *cell,
2242 GtkTreeViewColumn *tv_col,
2243 GtkTreePath *tree_path,
2244 gboolean emit_signal)
2246 GdkRectangle cell_rect;
2248 /* Get these three values in tree coords */
2249 if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
2250 gtk_tree_view_get_cell_area (tree_view, tree_path, tv_col, &cell_rect);
2252 cell_rect.height = 0;
2254 if (cell_rect.height > 0)
2256 /* The height will be zero for a cell for which an antecedent
2259 _gtk_cell_accessible_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
2260 if (is_cell_showing (tree_view, &cell_rect))
2261 _gtk_cell_accessible_add_state (cell, ATK_STATE_SHOWING, emit_signal);
2263 _gtk_cell_accessible_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
2267 _gtk_cell_accessible_remove_state (cell, ATK_STATE_VISIBLE, emit_signal);
2268 _gtk_cell_accessible_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
2273 is_cell_showing (GtkTreeView *tree_view,
2274 GdkRectangle *cell_rect)
2276 GdkRectangle rect, *visible_rect;
2277 GdkRectangle rect1, *tree_cell_rect;
2279 gboolean is_showing;
2281 /* A cell is considered "SHOWING" if any part of the cell is
2282 * in the visible area. Other ways we could do this is by a
2283 * cell's midpoint or if the cell is fully in the visible range.
2284 * Since we have the cell_rect x, y, width, height of the cell,
2285 * any of these is easy to compute.
2287 * It is assumed that cell's rectangle is in widget coordinates
2288 * so we must transform to tree cordinates.
2290 visible_rect = ▭
2291 tree_cell_rect = &rect1;
2292 tree_cell_rect->x = cell_rect->x;
2293 tree_cell_rect->y = cell_rect->y;
2294 tree_cell_rect->width = cell_rect->width;
2295 tree_cell_rect->height = cell_rect->height;
2297 gtk_tree_view_get_visible_rect (tree_view, visible_rect);
2298 gtk_tree_view_convert_tree_to_bin_window_coords (tree_view, visible_rect->x,
2299 visible_rect->y, &bx, &by);
2301 if (((tree_cell_rect->x + tree_cell_rect->width) < bx) ||
2302 ((tree_cell_rect->y + tree_cell_rect->height) < by) ||
2303 (tree_cell_rect->x > (bx + visible_rect->width)) ||
2304 (tree_cell_rect->y > (by + visible_rect->height)))
2314 /* This function is called when a cell's flyweight is created in
2315 * gtk_tree_view_accessible_table_ref_at with emit_change_signal
2316 * set to FALSE and in model_row_changed() on receipt of "row-changed"
2317 * signal when emit_change_signal is set to TRUE
2320 update_cell_value (GtkRendererCellAccessible *renderer_cell,
2321 GtkTreeViewAccessible *accessible,
2322 gboolean emit_change_signal)
2324 GtkTreeViewAccessibleCellInfo *cell_info;
2325 GtkTreeView *tree_view;
2326 GtkTreeModel *tree_model;
2329 GList *renderers, *cur_renderer;
2331 GtkRendererCellAccessibleClass *renderer_cell_class;
2332 GtkCellRendererClass *gtk_cell_renderer_class;
2333 GtkCellAccessible *cell;
2336 gboolean is_expander, is_expanded;
2338 renderer_cell_class = GTK_RENDERER_CELL_ACCESSIBLE_GET_CLASS (renderer_cell);
2339 if (renderer_cell->renderer)
2340 gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
2342 gtk_cell_renderer_class = NULL;
2344 prop_list = renderer_cell_class->property_list;
2346 cell = GTK_CELL_ACCESSIBLE (renderer_cell);
2347 cell_info = find_cell_info (accessible, cell, TRUE);
2351 if (emit_change_signal)
2353 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
2354 tree_model = gtk_tree_view_get_model (tree_view);
2355 path = cell_info_get_path (cell_info);
2359 gtk_tree_model_get_iter (tree_model, &iter, path);
2360 is_expander = FALSE;
2361 is_expanded = FALSE;
2362 if (gtk_tree_model_iter_has_child (tree_model, &iter))
2364 GtkTreeViewColumn *expander_tv;
2366 expander_tv = gtk_tree_view_get_expander_column (tree_view);
2367 if (expander_tv == cell_info->cell_col_ref)
2370 is_expanded = gtk_tree_view_row_expanded (tree_view, path);
2373 gtk_tree_path_free (path);
2374 gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
2376 is_expander, is_expanded);
2378 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_info->cell_col_ref));
2382 /* If the cell is in a container, its index is used to find the renderer
2383 * in the list. Otherwise, we assume that the cell is represented
2384 * by the first renderer in the list
2386 parent = atk_object_get_parent (ATK_OBJECT (cell));
2388 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2389 cur_renderer = g_list_nth (renderers, atk_object_get_index_in_parent (ATK_OBJECT (cell)));
2391 cur_renderer = renderers;
2393 if (cur_renderer == NULL)
2396 if (gtk_cell_renderer_class)
2400 spec = g_object_class_find_property
2401 (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
2405 GValue value = G_VALUE_INIT;
2407 g_value_init (&value, spec->value_type);
2408 g_object_get_property (cur_renderer->data, *prop_list, &value);
2409 g_object_set_property (G_OBJECT (renderer_cell->renderer),
2410 *prop_list, &value);
2411 g_value_unset (&value);
2414 g_warning ("Invalid property: %s\n", *prop_list);
2418 g_list_free (renderers);
2420 return _gtk_renderer_cell_accessible_update_cache (renderer_cell, emit_change_signal);
2424 get_row_from_tree_path (GtkTreeView *tree_view,
2427 GtkTreeModel *tree_model;
2428 GtkTreePath *root_tree;
2431 tree_model = gtk_tree_view_get_model (tree_view);
2433 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
2434 row = gtk_tree_path_get_indices (path)[0];
2437 root_tree = gtk_tree_path_new_first ();
2439 iterate_thru_children (tree_view, tree_model, root_tree, path, &row, 0);
2440 gtk_tree_path_free (root_tree);
2449 * Get the specified GtkTreeViewColumn in the GtkTreeView.
2450 * Only visible columns are considered.
2452 static GtkTreeViewColumn *
2453 get_column (GtkTreeView *tree_view,
2456 GtkTreeViewColumn *tv_col;
2462 g_warning ("Request for invalid column %d\n", in_col);
2466 tv_col = gtk_tree_view_get_column (tree_view, i);
2467 while (tv_col != NULL)
2469 if (gtk_tree_view_column_get_visible (tv_col))
2471 if (in_col == n_cols)
2473 tv_col = gtk_tree_view_get_column (tree_view, ++i);
2476 if (in_col != n_cols)
2478 g_warning ("Request for invalid column %d\n", in_col);
2485 get_actual_column_number (GtkTreeView *tree_view,
2486 gint visible_column)
2488 GtkTreeViewColumn *tv_col;
2489 gint actual_column = 0;
2490 gint visible_columns = -1;
2492 /* This function calculates the column number which corresponds
2493 * to the specified visible column number
2495 tv_col = gtk_tree_view_get_column (tree_view, actual_column);
2496 while (tv_col != NULL)
2498 if (gtk_tree_view_column_get_visible (tv_col))
2500 if (visible_columns == visible_column)
2501 return actual_column;
2502 tv_col = gtk_tree_view_get_column (tree_view, ++actual_column);
2504 g_warning ("get_actual_column_number failed for %d\n", visible_column);
2509 get_visible_column_number (GtkTreeView *tree_view,
2512 GtkTreeViewColumn *tv_col;
2514 gint visible_columns = -1;
2516 /* This function calculates the visible column number
2517 * which corresponds to the specified actual column number
2519 tv_col = gtk_tree_view_get_column (tree_view, column);
2521 while (tv_col != NULL)
2523 if (gtk_tree_view_column_get_visible (tv_col))
2526 if (actual_column == column)
2527 return visible_columns;
2530 if (actual_column == column)
2532 tv_col = gtk_tree_view_get_column (tree_view, ++column);
2534 g_warning ("get_visible_column_number failed for %d\n", actual_column);
2538 /* Helper recursive function that returns an iter to nth row
2540 static GtkTreeIter *
2541 return_iter_nth_row (GtkTreeView *tree_view,
2542 GtkTreeModel *tree_model,
2547 GtkTreePath *current_path;
2548 GtkTreeIter new_iter;
2549 gboolean row_expanded;
2551 current_path = gtk_tree_model_get_path (tree_model, iter);
2552 if (increment == row)
2554 gtk_tree_path_free (current_path);
2558 row_expanded = gtk_tree_view_row_expanded (tree_view, current_path);
2559 gtk_tree_path_free (current_path);
2562 if ((row_expanded && gtk_tree_model_iter_children (tree_model, iter, &new_iter)) ||
2563 (gtk_tree_model_iter_next (tree_model, iter)) ||
2564 (gtk_tree_model_iter_parent (tree_model, iter, &new_iter) &&
2565 (gtk_tree_model_iter_next (tree_model, iter))))
2566 return return_iter_nth_row (tree_view, tree_model, iter,
2573 set_iter_nth_row (GtkTreeView *tree_view,
2577 GtkTreeModel *tree_model;
2579 tree_model = gtk_tree_view_get_model (tree_view);
2580 gtk_tree_model_get_iter_first (tree_model, iter);
2581 iter = return_iter_nth_row (tree_view, tree_model, iter, 0, row);
2584 /* Recursively called until the row specified by orig is found.
2586 * *count will be set to the visible row number of the child
2587 * relative to the row that was initially passed in as tree_path.
2588 * tree_path could be modified by this function.
2590 * *count will be -1 if orig is not found as a child (a row that is
2591 * not visible will not be found, e.g. if the row is inside a
2592 * collapsed row). If NULL is passed in as orig, *count will
2593 * be a count of the visible children.
2595 * NOTE: the value for depth must be 0 when this recursive function
2596 * is initially called, or it may not function as expected.
2599 iterate_thru_children (GtkTreeView *tree_view,
2600 GtkTreeModel *tree_model,
2601 GtkTreePath *tree_path,
2608 if (!gtk_tree_model_get_iter (tree_model, &iter, tree_path))
2611 if (tree_path && orig && !gtk_tree_path_compare (tree_path, orig))
2615 if (tree_path && orig && gtk_tree_path_compare (tree_path, orig) > 0)
2617 /* Past it, so return -1 */
2621 else if (gtk_tree_view_row_expanded (tree_view, tree_path) &&
2622 gtk_tree_model_iter_has_child (tree_model, &iter))
2625 gtk_tree_path_append_index (tree_path, 0);
2626 iterate_thru_children (tree_view, tree_model, tree_path,
2627 orig, count, (depth + 1));
2630 else if (gtk_tree_model_iter_next (tree_model, &iter))
2633 tree_path = gtk_tree_model_get_path (tree_model, &iter);
2636 iterate_thru_children (tree_view, tree_model, tree_path,
2637 orig, count, depth);
2638 gtk_tree_path_free (tree_path);
2642 else if (gtk_tree_path_up (tree_path))
2644 GtkTreeIter temp_iter;
2645 gboolean exit_loop = FALSE;
2646 gint new_depth = depth - 1;
2650 /* Make sure that we back up until we find a row
2651 * where gtk_tree_path_next does not return NULL.
2655 if (gtk_tree_path_get_depth (tree_path) == 0)
2656 /* depth is now zero so */
2658 gtk_tree_path_next (tree_path);
2660 /* Verify that the next row is a valid row! */
2661 exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
2665 /* Keep going up until we find a row that has a valid next */
2666 if (gtk_tree_path_get_depth(tree_path) > 1)
2669 gtk_tree_path_up (tree_path);
2673 /* If depth is 1 and gtk_tree_model_get_iter returns FALSE,
2674 * then we are at the last row, so just return.
2684 /* This guarantees that we will stop when we hit the end of the
2690 iterate_thru_children (tree_view, tree_model, tree_path,
2691 orig, count, new_depth);
2695 /* If it gets here, then the path wasn't found. Situations
2696 * that would cause this would be if the path passed in is
2697 * invalid or contained within the last row, but not visible
2698 * because the last row is not expanded. If NULL was passed
2699 * in then a row count is desired, so only set count to -1
2700 * if orig is not NULL.
2709 clean_rows (GtkTreeViewAccessible *accessible)
2711 GtkTreeViewAccessibleCellInfo *cell_info;
2712 GHashTableIter iter;
2714 /* Clean GtkTreeViewAccessibleCellInfo data */
2715 g_hash_table_iter_init (&iter, accessible->cell_infos);
2716 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
2718 GtkTreePath *row_path;
2720 row_path = cell_info_get_path (cell_info);
2722 /* If the cell has become invalid because the row has been removed,
2723 * then set the cell's state to ATK_STATE_DEFUNCT and schedule
2724 * its removal. If row_path is NULL then the row has
2727 if (row_path == NULL)
2728 g_hash_table_iter_remove (&iter);
2730 gtk_tree_path_free (row_path);
2735 clean_cols (GtkTreeViewAccessible *accessible,
2736 GtkTreeViewColumn *tv_col)
2738 GtkTreeViewAccessibleCellInfo *cell_info;
2739 GHashTableIter iter;
2741 /* Clean GtkTreeViewAccessibleCellInfo data */
2742 g_hash_table_iter_init (&iter, accessible->cell_infos);
2743 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cell_info))
2745 /* If the cell has become invalid because the column tv_col
2746 * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
2747 * and remove the cell from accessible->cell_data.
2749 if (cell_info->cell_col_ref == tv_col)
2750 g_hash_table_iter_remove (&iter);
2754 /* If tree_path is passed in as NULL, then all cells are acted on.
2755 * Otherwise, just act on those cells that are on a row greater than
2756 * the specified tree_path. If inc_row is passed in as TRUE, then rows
2757 * greater and equal to the specified tree_path are acted on.
2759 * The function set_cell_visibility() is called on all cells to be
2760 * acted on to update the visibility of the cell.
2763 traverse_cells (GtkTreeViewAccessible *accessible,
2764 GtkTreePath *tree_path,
2767 GtkTreeViewAccessibleCellInfo *cell_info;
2769 GHashTableIter iter;
2771 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
2775 /* Must loop through them all */
2776 g_hash_table_iter_init (&iter, accessible->cell_infos);
2777 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
2779 GtkTreePath *row_path;
2780 gboolean act_on_cell;
2782 row_path = cell_info_get_path (cell_info);
2783 g_return_if_fail (row_path != NULL);
2784 if (tree_path == NULL)
2790 comparison = gtk_tree_path_compare (row_path, tree_path);
2791 if ((comparison > 0) ||
2792 (comparison == 0 && inc_row))
2795 act_on_cell = FALSE;
2800 set_cell_visibility (GTK_TREE_VIEW (widget),
2802 cell_info->cell_col_ref,
2805 gtk_tree_path_free (row_path);
2808 g_signal_emit_by_name (accessible, "visible-data-changed");
2811 /* If the tree_path passed in has children, then
2812 * ATK_STATE_EXPANDABLE is set. If the row is expanded
2813 * ATK_STATE_EXPANDED is turned on. If the row is
2814 * collapsed, then ATK_STATE_EXPANDED is removed.
2816 * If the tree_path passed in has no children, then
2817 * ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED are removed.
2819 * If set_on_ancestor is TRUE, then this function will also
2820 * update all cells that are ancestors of the tree_path.
2823 set_expand_state (GtkTreeView *tree_view,
2824 GtkTreeModel *tree_model,
2825 GtkTreeViewAccessible *accessible,
2826 GtkTreePath *tree_path,
2827 gboolean set_on_ancestor)
2829 GtkTreeViewColumn *expander_tv;
2830 GtkTreeViewAccessibleCellInfo *cell_info;
2831 GtkTreePath *cell_path;
2834 GHashTableIter hash_iter;
2836 g_hash_table_iter_init (&hash_iter, accessible->cell_infos);
2837 while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer *) &cell_info))
2839 cell_path = cell_info_get_path (cell_info);
2842 if (cell_path != NULL)
2844 GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (cell_info->cell);
2846 expander_tv = gtk_tree_view_get_expander_column (tree_view);
2848 /* Only set state for the cell that is in the column with the
2851 if (expander_tv == cell_info->cell_col_ref)
2853 if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
2855 else if (set_on_ancestor &&
2856 gtk_tree_path_get_depth (cell_path) <
2857 gtk_tree_path_get_depth (tree_path) &&
2858 gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
2859 /* Only set if set_on_ancestor was passed in as TRUE */
2863 /* Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
2864 * for ancestors and found cells.
2868 /* Must check against cell_path since cell_path
2869 * can be equal to or an ancestor of tree_path.
2871 gtk_tree_model_get_iter (tree_model, &iter, cell_path);
2873 /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
2874 if (gtk_tree_model_iter_has_child (tree_model, &iter))
2876 set_cell_expandable (cell);
2878 if (gtk_tree_view_row_expanded (tree_view, cell_path))
2879 _gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDED, TRUE);
2881 _gtk_cell_accessible_remove_state (cell, ATK_STATE_EXPANDED, TRUE);
2885 _gtk_cell_accessible_remove_state (cell, ATK_STATE_EXPANDED, TRUE);
2886 if (_gtk_cell_accessible_remove_state (cell, ATK_STATE_EXPANDABLE, TRUE))
2887 /* The state may have been propagated to the container cell */
2888 if (!GTK_IS_CONTAINER_CELL_ACCESSIBLE (cell))
2889 _gtk_cell_accessible_remove_action_by_name (cell,
2890 "expand or contract");
2893 /* We assume that each cell in the cache once and
2894 * a container cell is before its child cells so we are
2895 * finished if set_on_ancestor is not set to TRUE.
2897 if (!set_on_ancestor)
2901 gtk_tree_path_free (cell_path);
2906 add_cell_actions (GtkCellAccessible *cell,
2909 if (GTK_IS_BOOLEAN_CELL_ACCESSIBLE (cell))
2910 _gtk_cell_accessible_add_action (cell,
2911 "toggle", "toggles the cell",
2912 NULL, toggle_cell_toggled);
2914 _gtk_cell_accessible_add_action (cell,
2915 "edit", "creates a widget in which the contents of the cell can be edited",
2917 _gtk_cell_accessible_add_action (cell,
2918 "activate", "activate the cell",
2919 NULL, activate_cell);
2923 toggle_cell_expanded (GtkCellAccessible *cell)
2925 GtkTreeViewAccessibleCellInfo *cell_info;
2926 GtkTreeView *tree_view;
2929 AtkStateSet *stateset;
2931 parent = atk_object_get_parent (ATK_OBJECT (cell));
2932 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2933 parent = atk_object_get_parent (parent);
2935 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
2939 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
2940 path = cell_info_get_path (cell_info);
2944 stateset = atk_object_ref_state_set (ATK_OBJECT (cell));
2945 if (atk_state_set_contains_state (stateset, ATK_STATE_EXPANDED))
2946 gtk_tree_view_collapse_row (tree_view, path);
2948 gtk_tree_view_expand_row (tree_view, path, TRUE);
2949 g_object_unref (stateset);
2950 gtk_tree_path_free (path);
2954 toggle_cell_toggled (GtkCellAccessible *cell)
2956 GtkTreeViewAccessibleCellInfo *cell_info;
2959 GList *renderers, *cur_renderer;
2961 gboolean is_container_cell = FALSE;
2963 parent = atk_object_get_parent (ATK_OBJECT (cell));
2964 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2966 is_container_cell = TRUE;
2967 parent = atk_object_get_parent (parent);
2970 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
2974 path = cell_info_get_path (cell_info);
2978 /* If the cell is in a container, its index is used to find the
2979 * renderer in the list. Otherwise, we assume that the cell is
2980 * represented by the first renderer in the list
2982 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_info->cell_col_ref));
2983 if (is_container_cell)
2984 cur_renderer = g_list_nth (renderers, atk_object_get_index_in_parent (ATK_OBJECT (cell)));
2986 cur_renderer = renderers;
2990 pathstring = gtk_tree_path_to_string (path);
2991 g_signal_emit_by_name (cur_renderer->data, "toggled", pathstring);
2992 g_free (pathstring);
2995 g_list_free (renderers);
2996 gtk_tree_path_free (path);
3000 edit_cell (GtkCellAccessible *cell)
3002 GtkTreeViewAccessibleCellInfo *cell_info;
3003 GtkTreeView *tree_view;
3007 parent = atk_object_get_parent (ATK_OBJECT (cell));
3008 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
3009 parent = atk_object_get_parent (parent);
3011 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
3015 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
3016 path = cell_info_get_path (cell_info);
3019 gtk_tree_view_set_cursor (tree_view, path, cell_info->cell_col_ref, TRUE);
3020 gtk_tree_path_free (path);
3024 activate_cell (GtkCellAccessible *cell)
3026 GtkTreeViewAccessibleCellInfo *cell_info;
3027 GtkTreeView *tree_view;
3031 parent = atk_object_get_parent (ATK_OBJECT (cell));
3032 if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
3033 parent = atk_object_get_parent (parent);
3035 cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
3039 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
3040 path = cell_info_get_path (cell_info);
3043 gtk_tree_view_row_activated (tree_view, path, cell_info->cell_col_ref);
3044 gtk_tree_path_free (path);
3048 cell_destroyed (gpointer data)
3050 GtkTreeViewAccessibleCellInfo *cell_info = data;
3052 cell_info->cell = NULL;
3054 g_hash_table_remove (cell_info->view->cell_infos, cell_info);
3058 cell_info_get_index (GtkTreeView *tree_view,
3059 GtkTreeViewAccessibleCellInfo *info)
3065 path = cell_info_get_path (info);
3069 column_number = get_column_number (tree_view, info->cell_col_ref, FALSE);
3070 index = get_index (tree_view, path, column_number);
3071 gtk_tree_path_free (path);
3077 cell_info_new (GtkTreeViewAccessible *accessible,
3078 GtkTreeModel *tree_model,
3081 GtkTreeViewColumn *tv_col,
3082 GtkCellAccessible *cell)
3084 GtkTreeViewAccessibleCellInfo *cell_info;
3086 cell_info = g_new (GtkTreeViewAccessibleCellInfo, 1);
3088 cell_info->tree = tree;
3089 cell_info->node = node;
3090 cell_info->cell_col_ref = tv_col;
3091 cell_info->cell = cell;
3092 cell_info->view = accessible;
3094 g_object_set_qdata_full (G_OBJECT (cell),
3095 gtk_tree_view_accessible_get_data_quark (),
3099 g_hash_table_replace (accessible->cell_infos, cell_info, cell_info);
3102 static GtkCellAccessible *
3103 find_cell (GtkTreeViewAccessible *accessible,
3106 GtkTreeViewAccessibleCellInfo *info;
3107 GHashTableIter iter;
3108 GtkTreeView *tree_view;
3110 tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
3112 g_hash_table_iter_init (&iter, accessible->cell_infos);
3113 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
3115 if (index == cell_info_get_index (tree_view, info))
3123 connect_model_signals (GtkTreeView *view,
3124 GtkTreeViewAccessible *accessible)
3128 obj = G_OBJECT (accessible->tree_model);
3129 g_signal_connect_data (obj, "row-changed",
3130 G_CALLBACK (model_row_changed), view, NULL, 0);
3131 g_signal_connect_data (obj, "row-inserted",
3132 G_CALLBACK (model_row_inserted), view, NULL,
3134 g_signal_connect_data (obj, "row-deleted",
3135 G_CALLBACK (model_row_deleted), view, NULL,
3137 g_signal_connect_data (obj, "rows-reordered",
3138 G_CALLBACK (model_rows_reordered), view, NULL,
3143 disconnect_model_signals (GtkTreeViewAccessible *accessible)
3148 obj = G_OBJECT (accessible->tree_model);
3149 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
3150 g_signal_handlers_disconnect_by_func (obj, model_row_changed, widget);
3151 g_signal_handlers_disconnect_by_func (obj, model_row_inserted, widget);
3152 g_signal_handlers_disconnect_by_func (obj, model_row_deleted, widget);
3153 g_signal_handlers_disconnect_by_func (obj, model_rows_reordered, widget);
3156 /* Returns the column number of the specified GtkTreeViewColumn
3158 * If visible is set, the value returned will be the visible column number,
3159 * i.e. suitable for use in AtkTable function. If visible is not set, the
3160 * value returned is the actual column number, which is suitable for use in
3161 * getting an index value.
3164 get_column_number (GtkTreeView *tree_view,
3165 GtkTreeViewColumn *column,
3168 GtkTreeViewColumn *tv_column;
3172 GtkTreeViewAccessible *accessible;
3174 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3175 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
3178 for (i = 0; i < accessible->col_data->len; i++)
3180 tv_column = g_array_index (accessible->col_data, GtkTreeViewColumn *, i);
3181 if (tv_column == column)
3183 if (!visible || gtk_tree_view_column_get_visible (tv_column))
3186 if (i == accessible->col_data->len)
3193 get_index (GtkTreeView *tree_view,
3198 GtkTreeViewAccessible *accessible;
3201 gint *indices = NULL;
3203 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3204 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
3208 depth = gtk_tree_path_get_depth (path);
3209 indices = gtk_tree_path_get_indices (path);
3214 GtkTreePath *copy_path;
3215 GtkTreeModel *model;
3217 model = gtk_tree_view_get_model (tree_view);
3218 copy_path = gtk_tree_path_copy (path);
3219 gtk_tree_path_up (copy_path);
3220 count_rows (model, NULL, copy_path, &index, 0, depth);
3221 gtk_tree_path_free (copy_path);
3225 index += indices[depth - 1];
3226 index *= accessible->n_cols;
3227 index += actual_column;
3231 /* The function count_rows counts the number of rows starting at iter
3232 * and ending at end_path. The value of level is the depth of iter and
3233 * the value of depth is the depth of end_path. Rows at depth before
3234 * end_path are counted. This functions counts rows which are not visible
3235 * because an ancestor is collapsed.
3238 count_rows (GtkTreeModel *model,
3240 GtkTreePath *end_path,
3245 GtkTreeIter child_iter;
3251 *count += gtk_tree_model_iter_n_children (model, iter);
3253 if (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY)
3259 if (gtk_tree_model_iter_children (model, &child_iter, iter))
3261 gboolean ret_val = TRUE;
3265 if (level == depth - 1)
3267 GtkTreePath *iter_path;
3268 gboolean finished = FALSE;
3270 iter_path = gtk_tree_model_get_path (model, &child_iter);
3271 if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
3273 gtk_tree_path_free (iter_path);
3277 if (gtk_tree_model_iter_has_child (model, &child_iter))
3278 count_rows (model, &child_iter, end_path, count, level, depth);
3279 ret_val = gtk_tree_model_iter_next (model, &child_iter);
3285 get_rbtree_column_from_index (GtkTreeView *tree_view,
3289 GtkTreeViewColumn **column)
3292 GtkTreeViewAccessible *accessible;
3294 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3295 accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
3297 if (accessible->n_cols == 0)
3299 /* First row is the column headers */
3300 index -= accessible->n_cols;
3306 g_return_val_if_fail (node != NULL, FALSE);
3308 if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (tree_view),
3309 index / accessible->n_cols,
3317 *column = gtk_tree_view_get_column (tree_view, index % accessible->n_cols);
3318 if (*column == NULL)
3325 set_cell_expandable (GtkCellAccessible *cell)
3327 if (_gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDABLE, FALSE))
3328 _gtk_cell_accessible_add_action (cell,
3329 "expand or contract",
3330 "expands or contracts the row in the tree view containing this cell",
3331 NULL, toggle_cell_expanded);
3334 static GtkTreeViewAccessibleCellInfo *
3335 find_cell_info (GtkTreeViewAccessible *accessible,
3336 GtkCellAccessible *cell,
3339 return g_object_get_qdata (G_OBJECT (cell),
3340 gtk_tree_view_accessible_get_data_quark ());
3344 get_header_from_column (GtkTreeViewColumn *tv_col)
3347 GtkWidget *header_widget;
3352 header_widget = gtk_tree_view_column_get_button (tv_col);
3355 rc = gtk_widget_get_accessible (header_widget);
3363 * _gtk_rbtree_get_ancestor_node:
3364 * @ancestor: the ancestor tree
3365 * @child_tree: the potential child's tree
3366 * @child_node: the potential child's node
3368 * Finds the node that is the ancestor of @child_tree and @child_node
3369 * and belongs to @ancestor. If @ancestor is not an ancestor tree
3370 * of @child_node, %NULL is returned.
3372 * Returns: the ancestor node or %NULL if @ancestor is not an ancestor.
3375 _gtk_rbtree_get_ancestor_node (GtkRBTree *ancestor,
3376 GtkRBTree *child_tree,
3377 GtkRBNode *child_node)
3379 while (child_tree != NULL)
3381 if (child_tree == ancestor)
3384 child_node = child_tree->parent_node;
3385 child_tree = child_tree->parent_tree;
3392 _gtk_tree_view_accessible_remove (GtkTreeView *treeview,
3396 GtkTreeViewAccessibleCellInfo *cell_info;
3397 GHashTableIter iter;
3398 GtkTreeViewAccessible *accessible;
3400 accessible = GTK_TREE_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (treeview)));
3401 if (accessible == NULL)
3404 /* if this shows up in profiles, special-case node->children == NULL */
3406 g_hash_table_iter_init (&iter, accessible->cell_infos);
3407 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
3409 GtkRBNode *child_node = _gtk_rbtree_get_ancestor_node (tree,
3413 if (child_node == NULL)
3416 if (node == NULL || node == child_node)
3417 g_hash_table_iter_remove (&iter);