]> Pileus Git - ~andy/gtk/blob - gtk/a11y/gtktreeviewaccessible.c
a11y: Compute index the easy way
[~andy/gtk] / gtk / a11y / gtktreeviewaccessible.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <gtk/gtk.h>
23 #ifdef GDK_WINDOWING_X11
24 #include <gdk/x11/gdkx.h>
25 #endif
26
27 #include "gtktreeprivate.h"
28 #include "gtkwidgetprivate.h"
29
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"
37
38 typedef struct _GtkTreeViewAccessibleCellInfo  GtkTreeViewAccessibleCellInfo;
39 struct _GtkTreeViewAccessibleCellInfo
40 {
41   GtkCellAccessible *cell;
42   GtkRBTree *tree;
43   GtkRBNode *node;
44   GtkTreeViewColumn *cell_col_ref;
45   GtkTreeViewAccessible *view;
46 };
47
48 /* signal handling */
49
50 static gboolean row_expanded_cb      (GtkTreeView      *tree_view,
51                                       GtkTreeIter      *iter,
52                                       GtkTreePath      *path);
53 static gboolean row_collapsed_cb     (GtkTreeView      *tree_view,
54                                       GtkTreeIter      *iter,
55                                       GtkTreePath      *path);
56 static void     size_allocate_cb     (GtkWidget        *widget,
57                                       GtkAllocation    *allocation);
58 static void     selection_changed_cb (GtkTreeSelection *selection,
59                                       gpointer          data);
60
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);
66
67 static void     column_visibility_changed
68                                      (GObject          *object,
69                                       GParamSpec       *param,
70                                       gpointer          user_data);
71 static void     destroy_count_func   (GtkTreeView      *tree_view,
72                                       GtkTreePath      *path,
73                                       gint              count,
74                                       gpointer          user_data);
75
76 /* Misc */
77
78 static void             set_iter_nth_row                (GtkTreeView            *tree_view,
79                                                          GtkTreeIter            *iter,
80                                                          gint                   row);
81 static gint             get_row_from_tree_path          (GtkTreeView            *tree_view,
82                                                          GtkTreePath            *path);
83 static GtkTreeViewColumn* get_column                    (GtkTreeView            *tree_view,
84                                                          gint                   in_col);
85 static gint             get_visible_column_number       (GtkTreeView            *tree_view,
86                                                          gint                   actual_column);
87 static void             iterate_thru_children           (GtkTreeView            *tree_view,
88                                                          GtkTreeModel           *tree_model,
89                                                          GtkTreePath            *tree_path,
90                                                          GtkTreePath            *orig,
91                                                          gint                   *count,
92                                                          gint                   depth);
93 static int              cell_info_get_index             (GtkTreeView                     *tree_view,
94                                                          GtkTreeViewAccessibleCellInfo   *info);
95 static void             clean_rows                      (GtkTreeViewAccessible           *tree_view);
96 static void             clean_cols                      (GtkTreeViewAccessible           *tree_view,
97                                                          GtkTreeViewColumn      *tv_col);
98 static void             traverse_cells                  (GtkTreeViewAccessible           *tree_view,
99                                                          GtkTreePath            *tree_path,
100                                                          gboolean               inc_row);
101 static gboolean         update_cell_value               (GtkRendererCellAccessible       *renderer_cell,
102                                                          GtkTreeViewAccessible           *accessible,
103                                                          gboolean               emit_change_signal);
104 static void             set_cell_visibility             (GtkTreeView            *tree_view,
105                                                          GtkCellAccessible      *cell,
106                                                          GtkTreeViewColumn      *tv_col,
107                                                          GtkTreePath            *tree_path,
108                                                          gboolean               emit_signal);
109 static gboolean         is_cell_showing                 (GtkTreeView            *tree_view,
110                                                          GdkRectangle           *cell_rect);
111 static void             set_expand_state                (GtkTreeView            *tree_view,
112                                                          GtkTreeModel           *tree_model,
113                                                          GtkTreeViewAccessible           *accessible,
114                                                          GtkTreePath            *tree_path,
115                                                          gboolean               set_on_ancestor);
116 static void             set_cell_expandable             (GtkCellAccessible     *cell);
117 static void             add_cell_actions                (GtkCellAccessible     *cell,
118                                                          gboolean               editable);
119
120 static void             toggle_cell_toggled             (GtkCellAccessible     *cell);
121 static void             edit_cell                       (GtkCellAccessible     *cell);
122 static void             activate_cell                   (GtkCellAccessible     *cell);
123 static void             cell_destroyed                  (gpointer               data);
124 static void             cell_info_new                   (GtkTreeViewAccessible           *accessible,
125                                                          GtkTreeModel           *tree_model,
126                                                          GtkRBTree              *tree,
127                                                          GtkRBNode              *node,
128                                                          GtkTreeViewColumn      *tv_col,
129                                                          GtkCellAccessible      *cell);
130 static GtkCellAccessible *find_cell                       (GtkTreeViewAccessible           *accessible,
131                                                          gint                   index);
132 static void             connect_model_signals           (GtkTreeView            *view,
133                                                          GtkTreeViewAccessible           *accessible);
134 static void             disconnect_model_signals        (GtkTreeViewAccessible           *accessible);
135 static gint             get_column_number               (GtkTreeView            *tree_view,
136                                                          GtkTreeViewColumn      *column,
137                                                          gboolean               visible);
138 static gint             get_focus_index                 (GtkTreeView            *tree_view);
139 static gint             get_index                       (GtkTreeView            *tree_view,
140                                                          GtkTreePath            *path,
141                                                          gint                   actual_column);
142 static void             count_rows                      (GtkTreeModel           *model,
143                                                          GtkTreeIter            *iter,
144                                                          GtkTreePath            *end_path,
145                                                          gint                   *count,
146                                                          gint                   level,
147                                                          gint                   depth);
148
149 static gboolean         get_rbtree_column_from_index    (GtkTreeView            *tree_view,
150                                                          gint                   index,
151                                                          GtkRBTree              **tree,
152                                                          GtkRBNode              **node,
153                                                          GtkTreeViewColumn      **column);
154
155 static GtkTreeViewAccessibleCellInfo* find_cell_info    (GtkTreeViewAccessible           *view,
156                                                          GtkCellAccessible               *cell,
157                                                          gboolean                live_only);
158 static AtkObject *       get_header_from_column         (GtkTreeViewColumn      *tv_col);
159
160
161 static void atk_table_interface_init                  (AtkTableIface                *iface);
162 static void atk_selection_interface_init              (AtkSelectionIface            *iface);
163 static void atk_component_interface_init              (AtkComponentIface            *iface);
164 static void gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface);
165
166 G_DEFINE_TYPE_WITH_CODE (GtkTreeViewAccessible, _gtk_tree_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
167                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE, atk_table_interface_init)
168                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init)
169                          G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
170                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_ACCESSIBLE_PARENT, gtk_cell_accessible_parent_interface_init))
171
172
173 static void
174 adjustment_changed (GtkAdjustment *adjustment,
175                     GtkWidget     *widget)
176 {
177   GtkTreeViewAccessible *accessible;
178
179   accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
180   traverse_cells (accessible, NULL, FALSE);
181 }
182
183 static void
184 hadjustment_set_cb (GObject    *widget,
185                     GParamSpec *pspec,
186                     gpointer    data)
187 {
188   GtkTreeViewAccessible *accessible = data;
189   GtkAdjustment *adj;
190
191   g_object_get (widget, "hadjustment", &adj, NULL);
192   accessible->old_hadj = adj;
193   g_object_add_weak_pointer (G_OBJECT (accessible->old_hadj), (gpointer *)&accessible->old_hadj);
194   g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment_changed), widget);
195 }
196
197 static void
198 vadjustment_set_cb (GObject    *widget,
199                     GParamSpec *pspec,
200                     gpointer    data)
201 {
202   GtkTreeViewAccessible *accessible = data;
203   GtkAdjustment *adj;
204
205   g_object_get (widget, "vadjustment", &adj, NULL);
206   accessible->old_vadj = adj;
207   g_object_add_weak_pointer (G_OBJECT (accessible->old_vadj), (gpointer *)&accessible->old_vadj);
208   g_signal_connect (adj, "value-changed",
209                     G_CALLBACK (adjustment_changed), widget);
210 }
211
212 static GQuark
213 gtk_tree_view_accessible_get_data_quark (void)
214 {
215   static GQuark quark = 0;
216
217   if (G_UNLIKELY (quark == 0))
218     quark = g_quark_from_static_string ("gtk-tree-view-accessible-data");
219
220   return quark;
221 }
222
223 static void
224 cell_info_free (GtkTreeViewAccessibleCellInfo *cell_info)
225 {
226   if (cell_info->cell)
227     {
228       g_object_steal_qdata (G_OBJECT (cell_info->cell),
229                             gtk_tree_view_accessible_get_data_quark ());
230       _gtk_cell_accessible_add_state (cell_info->cell, ATK_STATE_DEFUNCT, FALSE);
231     }
232
233   g_free (cell_info);
234 }
235
236 static GtkTreePath *
237 cell_info_get_path (GtkTreeViewAccessibleCellInfo *cell_info)
238 {
239   return _gtk_tree_view_find_path (NULL,
240                                    cell_info->tree,
241                                    cell_info->node);
242 }
243
244 static void
245 gtk_tree_view_accessible_initialize (AtkObject *obj,
246                                      gpointer   data)
247 {
248   GtkTreeViewAccessible *accessible;
249   GtkTreeView *tree_view;
250   GtkTreeModel *tree_model;
251   GList *tv_cols, *tmp_list;
252   GtkWidget *widget;
253   GtkTreeSelection *selection;
254
255   ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->initialize (obj, data);
256
257   accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
258   accessible->col_data = NULL;
259   accessible->focus_cell = NULL;
260   accessible->old_hadj = NULL;
261   accessible->old_vadj = NULL;
262   accessible->idle_expand_id = 0;
263   accessible->idle_expand_path = NULL;
264   accessible->n_children_deleted = 0;
265
266   accessible->cell_infos = g_hash_table_new_full (g_direct_hash,
267       g_direct_equal, NULL, (GDestroyNotify) cell_info_free);
268
269   widget = GTK_WIDGET (data);
270   tree_view = GTK_TREE_VIEW (widget);
271   tree_model = gtk_tree_view_get_model (tree_view);
272   selection = gtk_tree_view_get_selection (tree_view);
273
274   g_signal_connect_after (widget, "row-collapsed",
275                           G_CALLBACK (row_collapsed_cb), NULL);
276   g_signal_connect (widget, "row-expanded",
277                     G_CALLBACK (row_expanded_cb), NULL);
278   g_signal_connect (widget, "size-allocate",
279                     G_CALLBACK (size_allocate_cb), NULL);
280   g_signal_connect (selection, "changed",
281                     G_CALLBACK (selection_changed_cb), obj);
282
283   g_signal_connect (tree_view, "columns-changed",
284                     G_CALLBACK (columns_changed), NULL);
285   g_signal_connect (tree_view, "cursor-changed",
286                     G_CALLBACK (cursor_changed), accessible);
287   g_signal_connect (tree_view, "focus-in-event",
288                     G_CALLBACK (focus_in), NULL);
289   g_signal_connect (tree_view, "focus-out-event",
290                     G_CALLBACK (focus_out), NULL);
291
292   accessible->tree_model = tree_model;
293   accessible->n_cols = 0;
294   if (tree_model)
295     {
296       g_object_add_weak_pointer (G_OBJECT (accessible->tree_model), (gpointer *)&accessible->tree_model);
297       connect_model_signals (tree_view, accessible);
298
299       if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
300         obj->role = ATK_ROLE_TABLE;
301       else
302         obj->role = ATK_ROLE_TREE_TABLE;
303     }
304
305   hadjustment_set_cb (G_OBJECT (widget), NULL, accessible);
306   vadjustment_set_cb (G_OBJECT (widget), NULL, accessible);
307   g_signal_connect (widget, "notify::hadjustment",
308                     G_CALLBACK (hadjustment_set_cb), accessible);
309   g_signal_connect (widget, "notify::vadjustment",
310                     G_CALLBACK (vadjustment_set_cb), accessible);
311
312   accessible->col_data = g_array_sized_new (FALSE, TRUE,
313                                             sizeof (GtkTreeViewColumn *), 0);
314
315   tv_cols = gtk_tree_view_get_columns (tree_view);
316   for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
317     {
318       accessible->n_cols++;
319       g_signal_connect (tmp_list->data, "notify::visible",
320                         G_CALLBACK (column_visibility_changed), tree_view);
321       g_array_append_val (accessible->col_data, tmp_list->data);
322     }
323   g_list_free (tv_cols);
324
325   gtk_tree_view_set_destroy_count_func (tree_view,
326                                         destroy_count_func,
327                                         NULL, NULL);
328 }
329
330 static void
331 gtk_tree_view_accessible_finalize (GObject *object)
332 {
333   GtkTreeViewAccessible *accessible = GTK_TREE_VIEW_ACCESSIBLE (object);
334
335   /* remove any idle handlers still pending */
336   if (accessible->idle_expand_id)
337     g_source_remove (accessible->idle_expand_id);
338
339   if (accessible->tree_model)
340     disconnect_model_signals (accessible);
341
342   if (accessible->cell_infos)
343     g_hash_table_destroy (accessible->cell_infos);
344
345   if (accessible->col_data)
346     {
347       GArray *array = accessible->col_data;
348
349      /* No need to free the contents of the array since it
350       * just contains pointers to the GtkTreeViewColumn
351       * objects that are in the GtkTreeView.
352       */
353       g_array_free (array, TRUE);
354     }
355
356   G_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->finalize (object);
357 }
358
359 static void
360 gtk_tree_view_accessible_notify_gtk (GObject    *obj,
361                                      GParamSpec *pspec)
362 {
363   GtkWidget *widget;
364   GtkTreeView *tree_view;
365   GtkTreeViewAccessible *accessible;
366   GtkAdjustment *adj;
367
368   widget = GTK_WIDGET (obj);
369   accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
370   tree_view = GTK_TREE_VIEW (widget);
371
372   if (g_strcmp0 (pspec->name, "model") == 0)
373     {
374       GtkTreeModel *tree_model;
375       AtkRole role;
376
377       tree_model = gtk_tree_view_get_model (tree_view);
378       if (accessible->tree_model)
379         disconnect_model_signals (accessible);
380       g_hash_table_remove_all (accessible->cell_infos);
381       accessible->tree_model = tree_model;
382
383       if (tree_model)
384         {
385           g_object_add_weak_pointer (G_OBJECT (accessible->tree_model), (gpointer *)&accessible->tree_model);
386           connect_model_signals (tree_view, accessible);
387
388           if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
389             role = ATK_ROLE_TABLE;
390           else
391             role = ATK_ROLE_TREE_TABLE;
392         }
393       else
394         {
395           role = ATK_ROLE_UNKNOWN;
396         }
397       atk_object_set_role (ATK_OBJECT (accessible), role);
398       g_object_freeze_notify (G_OBJECT (accessible));
399       g_signal_emit_by_name (accessible, "model-changed");
400       g_signal_emit_by_name (accessible, "visible-data-changed");
401       g_object_thaw_notify (G_OBJECT (accessible));
402     }
403   else if (g_strcmp0 (pspec->name, "hadjustment") == 0)
404     {
405       g_object_get (tree_view, "hadjustment", &adj, NULL);
406       g_signal_handlers_disconnect_by_func (accessible->old_hadj,
407                                             (gpointer) adjustment_changed,
408                                             widget);
409       accessible->old_hadj = adj;
410       g_object_add_weak_pointer (G_OBJECT (accessible->old_hadj), (gpointer *)&accessible->old_hadj);
411       g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment_changed), tree_view);
412     }
413   else if (g_strcmp0 (pspec->name, "vadjustment") == 0)
414     {
415       g_object_get (tree_view, "vadjustment", &adj, NULL);
416       g_signal_handlers_disconnect_by_func (accessible->old_vadj,
417                                             (gpointer) adjustment_changed,
418                                             widget);
419       accessible->old_vadj = adj;
420       g_object_add_weak_pointer (G_OBJECT (accessible->old_hadj), (gpointer *)&accessible->old_vadj);
421       g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment_changed), tree_view);
422     }
423   else
424     GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->notify_gtk (obj, pspec);
425 }
426
427 static void
428 gtk_tree_view_accessible_destroyed (GtkWidget     *widget,
429                                     GtkAccessible *gtk_accessible)
430 {
431   GtkAdjustment *adj;
432   GtkTreeViewAccessible *accessible;
433
434   if (!GTK_IS_TREE_VIEW (widget))
435     return;
436
437   accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_accessible);
438   adj = accessible->old_hadj;
439   if (adj)
440     g_signal_handlers_disconnect_by_func (adj,
441                                           (gpointer) adjustment_changed,
442                                           widget);
443   adj = accessible->old_vadj;
444   if (adj)
445     g_signal_handlers_disconnect_by_func (adj,
446                                           (gpointer) adjustment_changed,
447                                           widget);
448   if (accessible->tree_model)
449     {
450       disconnect_model_signals (accessible);
451       accessible->tree_model = NULL;
452     }
453   if (accessible->focus_cell)
454     {
455       g_object_unref (accessible->focus_cell);
456       accessible->focus_cell = NULL;
457     }
458   if (accessible->idle_expand_id)
459     {
460       g_source_remove (accessible->idle_expand_id);
461       accessible->idle_expand_id = 0;
462     }
463 }
464
465 static void
466 gtk_tree_view_accessible_connect_widget_destroyed (GtkAccessible *accessible)
467 {
468   GtkWidget *widget;
469
470   widget = gtk_accessible_get_widget (accessible);
471   if (widget)
472     g_signal_connect_after (widget, "destroy",
473                             G_CALLBACK (gtk_tree_view_accessible_destroyed), accessible);
474
475   GTK_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->connect_widget_destroyed (accessible);
476 }
477
478 static gint
479 get_n_rows (GtkTreeView *tree_view)
480 {
481   GtkRBTree *tree;
482
483   tree = _gtk_tree_view_get_rbtree (tree_view);
484
485   if (tree == NULL)
486     return 0;
487
488   return tree->root->total_count;
489 }
490
491 static gint
492 gtk_tree_view_accessible_get_n_children (AtkObject *obj)
493 {
494   GtkWidget *widget;
495   GtkTreeViewAccessible *accessible;
496   GtkTreeView *tree_view;
497
498   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
499   if (widget == NULL)
500     return 0;
501
502   tree_view = GTK_TREE_VIEW (widget);
503   accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
504   return (get_n_rows (tree_view) + 1) * accessible->n_cols;
505 }
506
507 static AtkObject *
508 gtk_tree_view_accessible_ref_child (AtkObject *obj,
509                                     gint       i)
510 {
511   GtkWidget *widget;
512   GtkTreeViewAccessible *accessible;
513   GtkCellAccessible *cell;
514   GtkTreeView *tree_view;
515   GtkTreeModel *tree_model;
516   GtkCellRenderer *renderer;
517   GtkTreeIter iter;
518   GtkTreeViewColumn *tv_col;
519   GtkTreeSelection *selection;
520   GtkTreePath *path;
521   GtkRBTree *tree;
522   GtkRBNode *node;
523   AtkObject *child;
524   AtkObject *parent;
525   GtkTreeViewColumn *expander_tv;
526   GList *renderer_list;
527   GList *l;
528   GtkContainerCellAccessible *container = NULL;
529   GtkRendererCellAccessible *renderer_cell;
530   gboolean is_expander, is_expanded, retval;
531   gboolean editable = FALSE;
532   gint focus_index;
533
534   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
535   if (widget == NULL)
536     return NULL;
537
538   if (i >= gtk_tree_view_accessible_get_n_children (obj))
539     return NULL;
540
541   accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
542   tree_view = GTK_TREE_VIEW (widget);
543   if (i < accessible->n_cols)
544     {
545       tv_col = gtk_tree_view_get_column (tree_view, i);
546       child = get_header_from_column (tv_col);
547       if (child)
548         g_object_ref (child);
549       return child;
550     }
551
552   /* Check whether the child is cached */
553   cell = find_cell (accessible, i);
554   if (cell)
555     {
556       g_object_ref (cell);
557       return ATK_OBJECT (cell);
558     }
559
560   if (accessible->focus_cell == NULL)
561       focus_index = get_focus_index (tree_view);
562   else
563       focus_index = -1;
564
565   /* Find the RBTree and GtkTreeViewColumn for the index */
566   if (!get_rbtree_column_from_index (tree_view, i, &tree, &node, &tv_col))
567     return NULL;
568
569   path = _gtk_tree_view_find_path (tree_view, tree, node);
570   tree_model = gtk_tree_view_get_model (tree_view);
571   retval = gtk_tree_model_get_iter (tree_model, &iter, path);
572   if (!retval)
573     return NULL;
574
575   expander_tv = gtk_tree_view_get_expander_column (tree_view);
576   is_expander = FALSE;
577   is_expanded = FALSE;
578   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
579     {
580       if (expander_tv == tv_col)
581         {
582           is_expander = TRUE;
583           is_expanded = node->children != NULL;
584         }
585     }
586   gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter,
587                                            is_expander, is_expanded);
588
589   renderer_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
590
591   /* If there are more than one renderer in the list,
592    * make a container
593    */
594   if (renderer_list && renderer_list->next)
595     {
596       GtkCellAccessible *container_cell;
597
598       container = _gtk_container_cell_accessible_new ();
599
600       container_cell = GTK_CELL_ACCESSIBLE (container);
601       _gtk_cell_accessible_initialise (container_cell, widget, ATK_OBJECT (accessible));
602
603       /* The GtkTreeViewAccessibleCellInfo structure for the container will
604        * be before the ones for the cells so that the first one we find for
605        * a position will be for the container
606        */
607       cell_info_new (accessible, tree_model, tree, node, tv_col, container_cell);
608       parent = ATK_OBJECT (container);
609     }
610   else
611     parent = ATK_OBJECT (accessible);
612
613   child = NULL;
614
615   /* Now we make a fake cell_renderer if there is no cell
616    * in renderer_list
617    */
618   if (renderer_list == NULL)
619     {
620       GtkCellRenderer *fake_renderer;
621
622       fake_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
623       child = _gtk_text_cell_accessible_new ();
624       cell = GTK_CELL_ACCESSIBLE (child);
625       renderer_cell = GTK_RENDERER_CELL_ACCESSIBLE (child);
626       renderer_cell->renderer = fake_renderer;
627
628       /* Create the GtkTreeViewAccessibleCellInfo structure for this cell */
629       cell_info_new (accessible, tree_model, tree, node, tv_col, cell);
630
631       _gtk_cell_accessible_initialise (cell, widget, parent);
632
633       /* Set state if it is expandable */
634       if (is_expander)
635         {
636           set_cell_expandable (cell);
637           if (is_expanded)
638             _gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDED, FALSE);
639         }
640     }
641   else
642     {
643       for (l = renderer_list; l; l = l->next)
644         {
645           renderer = GTK_CELL_RENDERER (l->data);
646
647           if (GTK_IS_CELL_RENDERER_TEXT (renderer))
648             {
649               g_object_get (G_OBJECT (renderer), "editable", &editable, NULL);
650               child = _gtk_text_cell_accessible_new ();
651             }
652           else if (GTK_IS_CELL_RENDERER_TOGGLE (renderer))
653             child = _gtk_boolean_cell_accessible_new ();
654           else if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
655             child = _gtk_image_cell_accessible_new ();
656           else
657             child = _gtk_renderer_cell_accessible_new ();
658
659           cell = GTK_CELL_ACCESSIBLE (child);
660           renderer_cell = GTK_RENDERER_CELL_ACCESSIBLE (child);
661
662           /* Create the GtkTreeViewAccessibleCellInfo for this cell */
663           cell_info_new (accessible, tree_model, tree, node, tv_col, cell);
664
665           _gtk_cell_accessible_initialise (cell, widget, parent);
666
667           if (container)
668             _gtk_container_cell_accessible_add_child (container, cell);
669
670           update_cell_value (renderer_cell, accessible, FALSE);
671
672           /* Add the actions appropriate for this cell */
673           add_cell_actions (cell, editable);
674
675           /* Set state if it is expandable */
676           if (is_expander)
677             {
678               set_cell_expandable (cell);
679               if (is_expanded)
680                 _gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDED, FALSE);
681             }
682
683           /* If the column is visible, sets the cell's state */
684           if (gtk_tree_view_column_get_visible (tv_col))
685             set_cell_visibility (tree_view, cell, tv_col, path, FALSE);
686
687           /* If the row is selected, all cells on the row are selected */
688           selection = gtk_tree_view_get_selection (tree_view);
689
690           if (gtk_tree_selection_path_is_selected (selection, path))
691             _gtk_cell_accessible_add_state (cell, ATK_STATE_SELECTED, FALSE);
692
693           _gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
694           if (focus_index == i)
695             {
696               accessible->focus_cell = g_object_ref (cell);
697               _gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSED, FALSE);
698               g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
699             }
700         }
701       g_list_free (renderer_list);
702       if (container)
703         child = ATK_OBJECT (container);
704     }
705
706   if (expander_tv == tv_col)
707     {
708       AtkRelationSet *relation_set;
709       AtkObject *accessible_array[1];
710       AtkRelation* relation;
711       AtkObject *parent_node;
712
713       relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
714
715       gtk_tree_path_up (path);
716       if (gtk_tree_path_get_depth (path) == 0)
717         parent_node = obj;
718       else
719         {
720           gint parent_index;
721
722           parent_index = get_index (tree_view, path, i % accessible->n_cols);
723           parent_node = atk_object_ref_accessible_child (obj, parent_index);
724         }
725       accessible_array[0] = parent_node;
726       relation = atk_relation_new (accessible_array, 1,
727                                    ATK_RELATION_NODE_CHILD_OF);
728       atk_relation_set_add (relation_set, relation);
729       atk_object_add_relationship (parent_node, ATK_RELATION_NODE_PARENT_OF, child);
730       g_object_unref (relation);
731       g_object_unref (relation_set);
732     }
733   gtk_tree_path_free (path);
734
735   /* We do not increase the reference count here; when g_object_unref()
736    * is called for the cell then cell_destroyed() is called and this
737    * removes the cell from the cache.
738    */
739   return child;
740 }
741
742 static AtkStateSet*
743 gtk_tree_view_accessible_ref_state_set (AtkObject *obj)
744 {
745   AtkStateSet *state_set;
746   GtkWidget *widget;
747
748   state_set = ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->ref_state_set (obj);
749   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
750
751   if (widget != NULL)
752     atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
753
754   return state_set;
755 }
756
757 static void
758 _gtk_tree_view_accessible_class_init (GtkTreeViewAccessibleClass *klass)
759 {
760   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
761   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
762   GtkAccessibleClass *accessible_class = (GtkAccessibleClass*)klass;
763   GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
764   GtkContainerAccessibleClass *container_class = (GtkContainerAccessibleClass*)klass;
765
766   class->get_n_children = gtk_tree_view_accessible_get_n_children;
767   class->ref_child = gtk_tree_view_accessible_ref_child;
768   class->ref_state_set = gtk_tree_view_accessible_ref_state_set;
769   class->initialize = gtk_tree_view_accessible_initialize;
770
771   widget_class->notify_gtk = gtk_tree_view_accessible_notify_gtk;
772
773   accessible_class->connect_widget_destroyed = gtk_tree_view_accessible_connect_widget_destroyed;
774
775   /* The children of a GtkTreeView are the buttons at the top of the columns
776    * we do not represent these as children so we do not want to report
777    * children added or deleted when these changed.
778    */
779   container_class->add_gtk = NULL;
780   container_class->remove_gtk = NULL;
781
782   gobject_class->finalize = gtk_tree_view_accessible_finalize;
783 }
784
785 static void
786 _gtk_tree_view_accessible_init (GtkTreeViewAccessible *view)
787 {
788 }
789
790 gint
791 get_focus_index (GtkTreeView *tree_view)
792 {
793   GtkTreePath *focus_path;
794   GtkTreeViewColumn *focus_column;
795   gint index;
796
797   gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
798   if (focus_path && focus_column)
799     index = get_index (tree_view, focus_path,
800                        get_column_number (tree_view, focus_column, FALSE));
801   else
802     index = -1;
803
804   if (focus_path)
805     gtk_tree_path_free (focus_path);
806
807   return index;
808 }
809
810 /* This function returns a reference to the accessible object
811  * for the cell in the treeview which has focus, if any
812  */
813 static AtkObject *
814 gtk_tree_view_accessible_ref_focus_cell (GtkTreeView *tree_view)
815 {
816   AtkObject *focus_cell = NULL;
817   AtkObject *atk_obj;
818   gint focus_index;
819
820   focus_index = get_focus_index (tree_view);
821   if (focus_index >= 0)
822     {
823       atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
824       focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
825     }
826
827   return focus_cell;
828 }
829
830 /* atkcomponent.h */
831
832 static AtkObject *
833 gtk_tree_view_accessible_ref_accessible_at_point (AtkComponent *component,
834                                                   gint          x,
835                                                   gint          y,
836                                                   AtkCoordType  coord_type)
837 {
838   GtkWidget *widget;
839   GtkTreeView *tree_view;
840   GtkTreePath *path;
841   GtkTreeViewColumn *tv_column;
842   gint x_pos, y_pos;
843   gint bx, by;
844   gboolean ret_val;
845
846   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
847   if (widget == NULL)
848     return NULL;
849
850   tree_view = GTK_TREE_VIEW (widget);
851
852   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
853   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &bx, &by);
854   ret_val = gtk_tree_view_get_path_at_pos (tree_view,
855                                            bx - x_pos, by - y_pos,
856                                            &path, &tv_column, NULL, NULL);
857   if (ret_val)
858     {
859       gint index, column;
860
861       column = get_column_number (tree_view, tv_column, FALSE);
862       index = get_index (tree_view, path, column);
863       gtk_tree_path_free (path);
864
865       return gtk_tree_view_accessible_ref_child (ATK_OBJECT (component), index);
866     }
867
868   return NULL;
869 }
870
871 static void
872 atk_component_interface_init (AtkComponentIface *iface)
873 {
874   iface->ref_accessible_at_point = gtk_tree_view_accessible_ref_accessible_at_point;
875 }
876
877 /* atktable.h */
878
879 static gint
880 gtk_tree_view_accessible_get_index_at (AtkTable *table,
881                                        gint      row,
882                                        gint      column)
883 {
884   GtkWidget *widget;
885   gint n_cols, n_rows;
886
887   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
888   if (widget == NULL)
889     return -1;
890
891   n_cols = atk_table_get_n_columns (table);
892   n_rows = atk_table_get_n_rows (table);
893
894   if (row >= n_rows || column >= n_cols)
895     return -1;
896
897   return (row + 1) * n_cols + column;
898 }
899
900 static gint
901 gtk_tree_view_accessible_get_column_at_index (AtkTable *table,
902                                               gint      index)
903 {
904   GtkWidget *widget;
905   GtkTreeView *tree_view;
906   gint n_columns;
907
908   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
909   if (widget == NULL)
910     return -1;
911
912   tree_view = GTK_TREE_VIEW (widget);
913   n_columns = GTK_TREE_VIEW_ACCESSIBLE (table)->n_cols;
914
915   if (n_columns == 0)
916     return 0;
917
918   index = index % n_columns;
919
920   return get_visible_column_number (tree_view, index);
921 }
922
923 static gint
924 gtk_tree_view_accessible_get_row_at_index (AtkTable *table,
925                                            gint      index)
926 {
927   GtkWidget *widget;
928   GtkTreeView *tree_view;
929
930   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
931   if (widget == NULL)
932     return -1;
933
934   tree_view = GTK_TREE_VIEW (widget);
935
936   index /= GTK_TREE_VIEW_ACCESSIBLE (table)->n_cols;
937   index--;
938   if (index >= get_n_rows (tree_view))
939     return -1;
940
941   return index;
942 }
943
944 static AtkObject *
945 gtk_tree_view_accessible_table_ref_at (AtkTable *table,
946                                        gint      row,
947                                        gint      column)
948 {
949   gint index;
950
951   index = gtk_tree_view_accessible_get_index_at (table, row, column);
952   if (index == -1)
953     return NULL;
954
955   return gtk_tree_view_accessible_ref_child (ATK_OBJECT (table), index);
956 }
957
958 static gint
959 gtk_tree_view_accessible_get_n_rows (AtkTable *table)
960 {
961   GtkWidget *widget;
962
963   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
964   if (widget == NULL)
965     return 0;
966
967   return get_n_rows (GTK_TREE_VIEW (widget));
968 }
969
970 static gint
971 gtk_tree_view_accessible_get_n_columns (AtkTable *table)
972 {
973   GtkWidget *widget;
974   GtkTreeView *tree_view;
975   GtkTreeViewColumn *tv_col;
976   gint n_cols = 0;
977   gint i = 0;
978
979   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
980   if (widget == NULL)
981     return 0;
982
983   tree_view = GTK_TREE_VIEW (widget);
984   tv_col = gtk_tree_view_get_column (tree_view, i);
985
986   while (tv_col != NULL)
987     {
988       if (gtk_tree_view_column_get_visible (tv_col))
989         n_cols++;
990
991       i++;
992       tv_col = gtk_tree_view_get_column (tree_view, i);
993     }
994
995   return n_cols;
996 }
997
998 static gboolean
999 gtk_tree_view_accessible_is_row_selected (AtkTable *table,
1000                                           gint      row)
1001 {
1002   GtkWidget *widget;
1003   GtkTreeView *tree_view;
1004   GtkTreeSelection *selection;
1005   GtkTreeIter iter;
1006
1007   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1008   if (widget == NULL)
1009     return FALSE;
1010
1011   if (row < 0)
1012     return FALSE;
1013
1014   tree_view = GTK_TREE_VIEW (widget);
1015   selection = gtk_tree_view_get_selection (tree_view);
1016
1017   set_iter_nth_row (tree_view, &iter, row);
1018   return gtk_tree_selection_iter_is_selected (selection, &iter);
1019 }
1020
1021 static gboolean
1022 gtk_tree_view_accessible_is_selected (AtkTable *table,
1023                                       gint      row,
1024                                       gint      column)
1025 {
1026   return gtk_tree_view_accessible_is_row_selected (table, row);
1027 }
1028
1029 static void
1030 get_selected_rows (GtkTreeModel *model,
1031                    GtkTreePath  *path,
1032                    GtkTreeIter  *iter,
1033                    gpointer      data)
1034 {
1035   GPtrArray *array = (GPtrArray *)data;
1036
1037   g_ptr_array_add (array, gtk_tree_path_copy (path));
1038 }
1039
1040 static gint
1041 gtk_tree_view_accessible_get_selected_rows (AtkTable  *table,
1042                                             gint     **rows_selected)
1043 {
1044   GtkWidget *widget;
1045   GtkTreeView *tree_view;
1046   GtkTreeModel *tree_model;
1047   GtkTreeIter iter;
1048   GtkTreeSelection *selection;
1049   GtkTreePath *tree_path;
1050   gint ret_val = 0;
1051
1052   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1053   if (widget == NULL)
1054     return 0;
1055
1056   tree_view = GTK_TREE_VIEW (widget);
1057   selection = gtk_tree_view_get_selection (tree_view);
1058
1059   switch (gtk_tree_selection_get_mode (selection))
1060     {
1061     case GTK_SELECTION_SINGLE:
1062     case GTK_SELECTION_BROWSE:
1063       if (gtk_tree_selection_get_selected (selection, &tree_model, &iter))
1064         {
1065           gint row;
1066
1067           if (rows_selected)
1068             {
1069               *rows_selected = g_new (gint, 1);
1070               tree_path = gtk_tree_model_get_path (tree_model, &iter);
1071               row = get_row_from_tree_path (tree_view, tree_path);
1072               gtk_tree_path_free (tree_path);
1073
1074               /* shouldn't ever happen */
1075               g_return_val_if_fail (row != -1, 0);
1076
1077               *rows_selected[0] = row;
1078             }
1079           ret_val = 1;
1080         }
1081       break;
1082     case GTK_SELECTION_MULTIPLE:
1083       {
1084         GPtrArray *array = g_ptr_array_new();
1085
1086         gtk_tree_selection_selected_foreach (selection, get_selected_rows, array);
1087         ret_val = array->len;
1088
1089         if (rows_selected && ret_val)
1090           {
1091             gint i;
1092
1093             *rows_selected = g_new (gint, ret_val);
1094             for (i = 0; i < ret_val; i++)
1095               {
1096                 gint row;
1097
1098                 tree_path = (GtkTreePath *) g_ptr_array_index (array, i);
1099                 row = get_row_from_tree_path (tree_view, tree_path);
1100                 gtk_tree_path_free (tree_path);
1101                 (*rows_selected)[i] = row;
1102               }
1103           }
1104         g_ptr_array_free (array, FALSE);
1105       }
1106       break;
1107     case GTK_SELECTION_NONE:
1108       break;
1109     }
1110   return ret_val;
1111 }
1112
1113 static gboolean
1114 gtk_tree_view_accessible_add_row_selection (AtkTable *table,
1115                                             gint      row)
1116 {
1117   GtkWidget *widget;
1118   GtkTreeView *tree_view;
1119   GtkTreeModel *tree_model;
1120   GtkTreeSelection *selection;
1121   GtkTreePath *tree_path;
1122   GtkTreeIter iter_to_row;
1123
1124   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1125   if (widget == NULL)
1126     return FALSE;
1127
1128   if (!gtk_tree_view_accessible_is_row_selected (table, row))
1129     {
1130       tree_view = GTK_TREE_VIEW (widget);
1131       tree_model = gtk_tree_view_get_model (tree_view);
1132       selection = gtk_tree_view_get_selection (tree_view);
1133
1134       if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1135         {
1136           tree_path = gtk_tree_path_new ();
1137           gtk_tree_path_append_index (tree_path, row);
1138           gtk_tree_selection_select_path (selection,tree_path);
1139           gtk_tree_path_free (tree_path);
1140         }
1141       else
1142         {
1143           set_iter_nth_row (tree_view, &iter_to_row, row);
1144           gtk_tree_selection_select_iter (selection, &iter_to_row);
1145         }
1146     }
1147
1148   return gtk_tree_view_accessible_is_row_selected (table, row);
1149 }
1150
1151 static gboolean
1152 gtk_tree_view_accessible_remove_row_selection (AtkTable *table,
1153                                                gint      row)
1154 {
1155   GtkWidget *widget;
1156   GtkTreeView *tree_view;
1157   GtkTreeSelection *selection;
1158
1159   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1160   if (widget == NULL)
1161     return FALSE;
1162
1163   tree_view = GTK_TREE_VIEW (widget);
1164   selection = gtk_tree_view_get_selection (tree_view);
1165
1166   if (gtk_tree_view_accessible_is_row_selected (table, row))
1167     {
1168       gtk_tree_selection_unselect_all (selection);
1169       return TRUE;
1170     }
1171
1172   return FALSE;
1173 }
1174
1175 static AtkObject *
1176 gtk_tree_view_accessible_get_column_header (AtkTable *table,
1177                                             gint      in_col)
1178 {
1179   GtkWidget *widget;
1180   GtkTreeView *tree_view;
1181   GtkTreeViewColumn *tv_col;
1182
1183   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1184   if (widget == NULL)
1185     return NULL;
1186
1187   tree_view = GTK_TREE_VIEW (widget);
1188   tv_col = get_column (tree_view, in_col);
1189   return get_header_from_column (tv_col);
1190 }
1191
1192 static const gchar *
1193 gtk_tree_view_accessible_get_column_description (AtkTable *table,
1194                                                  gint      in_col)
1195 {
1196   GtkWidget *widget;
1197   GtkTreeView *tree_view;
1198   GtkTreeViewColumn *tv_col;
1199
1200   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (table));
1201   if (widget == NULL)
1202     return NULL;
1203
1204   tree_view = GTK_TREE_VIEW (widget);
1205   tv_col = get_column (tree_view, in_col);
1206   if (tv_col == NULL)
1207      return NULL;
1208
1209   return gtk_tree_view_column_get_title (tv_col);
1210 }
1211
1212 static void
1213 atk_table_interface_init (AtkTableIface *iface)
1214 {
1215   iface->ref_at = gtk_tree_view_accessible_table_ref_at;
1216   iface->get_n_rows = gtk_tree_view_accessible_get_n_rows;
1217   iface->get_n_columns = gtk_tree_view_accessible_get_n_columns;
1218   iface->get_index_at = gtk_tree_view_accessible_get_index_at;
1219   iface->get_column_at_index = gtk_tree_view_accessible_get_column_at_index;
1220   iface->get_row_at_index = gtk_tree_view_accessible_get_row_at_index;
1221   iface->is_row_selected = gtk_tree_view_accessible_is_row_selected;
1222   iface->is_selected = gtk_tree_view_accessible_is_selected;
1223   iface->get_selected_rows = gtk_tree_view_accessible_get_selected_rows;
1224   iface->add_row_selection = gtk_tree_view_accessible_add_row_selection;
1225   iface->remove_row_selection = gtk_tree_view_accessible_remove_row_selection;
1226   iface->get_column_extent_at = NULL;
1227   iface->get_row_extent_at = NULL;
1228   iface->get_column_header = gtk_tree_view_accessible_get_column_header;
1229   iface->get_column_description = gtk_tree_view_accessible_get_column_description;
1230 }
1231
1232 /* atkselection.h */
1233
1234 static gboolean
1235 gtk_tree_view_accessible_add_selection (AtkSelection *selection,
1236                                         gint          i)
1237 {
1238   AtkTable *table;
1239   gint n_columns;
1240   gint row;
1241
1242   table = ATK_TABLE (selection);
1243   n_columns = gtk_tree_view_accessible_get_n_columns (table);
1244   if (n_columns != 1)
1245     return FALSE;
1246
1247   row = gtk_tree_view_accessible_get_row_at_index (table, i);
1248   return gtk_tree_view_accessible_add_row_selection (table, row);
1249 }
1250
1251 static gboolean
1252 gtk_tree_view_accessible_clear_selection (AtkSelection *selection)
1253 {
1254   GtkWidget *widget;
1255   GtkTreeView *tree_view;
1256   GtkTreeSelection *tree_selection;
1257
1258   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1259   if (widget == NULL)
1260     return FALSE;
1261
1262   tree_view = GTK_TREE_VIEW (widget);
1263   tree_selection = gtk_tree_view_get_selection (tree_view);
1264
1265   gtk_tree_selection_unselect_all (tree_selection);
1266   return TRUE;
1267 }
1268
1269 static AtkObject *
1270 gtk_tree_view_accessible_ref_selection (AtkSelection *selection,
1271                                         gint          i)
1272 {
1273   AtkTable *table;
1274   gint row;
1275   gint n_selected;
1276   gint n_columns;
1277   gint *selected;
1278
1279   table = ATK_TABLE (selection);
1280   n_columns = gtk_tree_view_accessible_get_n_columns (table);
1281   n_selected = gtk_tree_view_accessible_get_selected_rows (table, &selected);
1282   if (i >= n_columns * n_selected)
1283     return NULL;
1284
1285   row = selected[i / n_columns];
1286   g_free (selected);
1287
1288   return gtk_tree_view_accessible_table_ref_at (table, row, i % n_columns);
1289 }
1290
1291 static gint
1292 gtk_tree_view_accessible_get_selection_count (AtkSelection *selection)
1293 {
1294   AtkTable *table;
1295   gint n_selected;
1296
1297   table = ATK_TABLE (selection);
1298   n_selected = gtk_tree_view_accessible_get_selected_rows (table, NULL);
1299   if (n_selected > 0)
1300     n_selected *= gtk_tree_view_accessible_get_n_columns (table);
1301   return n_selected;
1302 }
1303
1304 static gboolean
1305 gtk_tree_view_accessible_is_child_selected (AtkSelection *selection,
1306                                             gint          i)
1307 {
1308   GtkWidget *widget;
1309   gint row;
1310
1311   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
1312   if (widget == NULL)
1313     return FALSE;
1314
1315   row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
1316
1317   return gtk_tree_view_accessible_is_row_selected (ATK_TABLE (selection), row);
1318 }
1319
1320 static void atk_selection_interface_init (AtkSelectionIface *iface)
1321 {
1322   iface->add_selection = gtk_tree_view_accessible_add_selection;
1323   iface->clear_selection = gtk_tree_view_accessible_clear_selection;
1324   iface->ref_selection = gtk_tree_view_accessible_ref_selection;
1325   iface->get_selection_count = gtk_tree_view_accessible_get_selection_count;
1326   iface->is_child_selected = gtk_tree_view_accessible_is_child_selected;
1327 }
1328
1329 #define EXTRA_EXPANDER_PADDING 4
1330
1331 static void
1332 gtk_tree_view_accessible_get_cell_area (GtkCellAccessibleParent *parent,
1333                                         GtkCellAccessible       *cell,
1334                                         GdkRectangle            *cell_rect)
1335 {
1336   GtkWidget *widget;
1337   GtkTreeView *tree_view;
1338   GtkTreeViewColumn *tv_col;
1339   GtkTreePath *path;
1340   AtkObject *parent_cell;
1341   GtkTreeViewAccessibleCellInfo *cell_info;
1342   GtkCellAccessible *top_cell;
1343
1344   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1345   if (widget == NULL)
1346     return;
1347
1348   tree_view = GTK_TREE_VIEW (widget);
1349   parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
1350   if (parent_cell != ATK_OBJECT (parent))
1351     top_cell = GTK_CELL_ACCESSIBLE (parent_cell);
1352   else
1353     top_cell = cell;
1354   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), top_cell, TRUE);
1355   if (!cell_info)
1356     return;
1357   path = cell_info_get_path (cell_info);
1358   tv_col = cell_info->cell_col_ref;
1359   if (path)
1360     {
1361       GtkTreeViewColumn *expander_column;
1362       gint focus_line_width;
1363
1364       gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
1365       expander_column = gtk_tree_view_get_expander_column (tree_view);
1366       if (expander_column == tv_col)
1367         {
1368           gint expander_size;
1369           gtk_widget_style_get (widget,
1370                                 "expander-size", &expander_size,
1371                                 NULL);
1372           cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
1373           cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
1374         }
1375       gtk_widget_style_get (widget,
1376                             "focus-line-width", &focus_line_width,
1377                             NULL);
1378
1379       cell_rect->x += focus_line_width;
1380       cell_rect->width -= 2 * focus_line_width;
1381
1382       gtk_tree_path_free (path);
1383
1384       /* A column has more than one renderer so we find the position
1385        * and width of each
1386        */
1387       if (top_cell != cell)
1388         {
1389           gint cell_index;
1390           gboolean found;
1391           gint cell_start;
1392           gint cell_width;
1393           GList *renderers;
1394           GtkCellRenderer *renderer;
1395
1396           cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
1397           renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
1398           renderer = g_list_nth_data (renderers, cell_index);
1399
1400           found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
1401           if (found)
1402             {
1403               cell_rect->x += cell_start;
1404               cell_rect->width = cell_width;
1405             }
1406           g_list_free (renderers);
1407         }
1408
1409     }
1410 }
1411
1412 static void
1413 gtk_tree_view_accessible_get_cell_extents (GtkCellAccessibleParent *parent,
1414                                            GtkCellAccessible       *cell,
1415                                            gint                    *x,
1416                                            gint                    *y,
1417                                            gint                    *width,
1418                                            gint                    *height,
1419                                            AtkCoordType             coord_type)
1420 {
1421   GtkWidget *widget;
1422   GtkTreeView *tree_view;
1423   GdkWindow *bin_window;
1424   GdkRectangle cell_rect;
1425   gint w_x, w_y;
1426
1427   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1428   if (widget == NULL)
1429     return;
1430
1431   tree_view = GTK_TREE_VIEW (widget);
1432   gtk_tree_view_accessible_get_cell_area (parent, cell, &cell_rect);
1433   bin_window = gtk_tree_view_get_bin_window (tree_view);
1434   gdk_window_get_origin (bin_window, &w_x, &w_y);
1435
1436   if (coord_type == ATK_XY_WINDOW)
1437     {
1438       GdkWindow *window;
1439       gint x_toplevel, y_toplevel;
1440
1441       window = gdk_window_get_toplevel (bin_window);
1442       gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
1443
1444       w_x -= x_toplevel;
1445       w_y -= y_toplevel;
1446     }
1447
1448   *width = cell_rect.width;
1449   *height = cell_rect.height;
1450   if (is_cell_showing (tree_view, &cell_rect))
1451     {
1452       *x = cell_rect.x + w_x;
1453       *y = cell_rect.y + w_y;
1454     }
1455   else
1456     {
1457       *x = G_MININT;
1458       *y = G_MININT;
1459     }
1460 }
1461
1462 static gboolean
1463 gtk_tree_view_accessible_grab_cell_focus (GtkCellAccessibleParent *parent,
1464                                           GtkCellAccessible       *cell)
1465 {
1466   GtkWidget *widget;
1467   GtkTreeView *tree_view;
1468   GtkTreeViewColumn *tv_col;
1469   GtkTreePath *path;
1470   AtkObject *parent_cell;
1471   AtkObject *cell_object;
1472   GtkTreeViewAccessibleCellInfo *cell_info;
1473   GtkCellRenderer *renderer = NULL;
1474   GtkWidget *toplevel;
1475   gint index;
1476
1477   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
1478   if (widget == NULL)
1479     return FALSE;
1480
1481   tree_view = GTK_TREE_VIEW (widget);
1482
1483   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
1484   if (!cell_info)
1485     return FALSE;
1486   cell_object = ATK_OBJECT (cell);
1487   parent_cell = atk_object_get_parent (cell_object);
1488   tv_col = cell_info->cell_col_ref;
1489   if (parent_cell != ATK_OBJECT (parent))
1490     {
1491       /* GtkCellAccessible is in a GtkContainerCellAccessible.
1492        * The GtkTreeViewColumn has multiple renderers;
1493        * find the corresponding one.
1494        */
1495       GList *renderers;
1496
1497       renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
1498       index = atk_object_get_index_in_parent (cell_object);
1499       renderer = g_list_nth_data (renderers, index);
1500       g_list_free (renderers);
1501     }
1502   path = cell_info_get_path (cell_info);
1503   if (path)
1504     {
1505       if (renderer)
1506         gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
1507       else
1508         gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
1509
1510       gtk_tree_path_free (path);
1511       gtk_widget_grab_focus (widget);
1512       toplevel = gtk_widget_get_toplevel (widget);
1513       if (gtk_widget_is_toplevel (toplevel))
1514         {
1515 #ifdef GDK_WINDOWING_X11
1516           gtk_window_present_with_time (GTK_WINDOW (toplevel),
1517                                         gdk_x11_get_server_time (gtk_widget_get_window (widget)));
1518 #else
1519           gtk_window_present (GTK_WINDOW (toplevel));
1520 #endif
1521         }
1522
1523       return TRUE;
1524     }
1525   else
1526       return FALSE;
1527 }
1528
1529 static int
1530 gtk_tree_view_accessible_get_child_index (GtkCellAccessibleParent *parent,
1531                                           GtkCellAccessible       *cell)
1532 {
1533   GtkTreeViewAccessibleCellInfo *cell_info;
1534   GtkTreeView *tree_view;
1535
1536   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
1537   if (!cell_info)
1538     return -1;
1539
1540   tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
1541
1542   return cell_info_get_index (tree_view, cell_info);
1543 }
1544
1545 static void
1546 gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface)
1547 {
1548   iface->get_cell_extents = gtk_tree_view_accessible_get_cell_extents;
1549   iface->get_cell_area = gtk_tree_view_accessible_get_cell_area;
1550   iface->grab_focus = gtk_tree_view_accessible_grab_cell_focus;
1551   iface->get_child_index = gtk_tree_view_accessible_get_child_index;
1552 }
1553
1554 /* signal handling */
1555
1556 static gboolean
1557 idle_expand_row (gpointer data)
1558 {
1559   GtkTreeViewAccessible *accessible = data;
1560   GtkTreePath *path;
1561   GtkTreeView *tree_view;
1562   GtkTreeIter iter;
1563   GtkTreeModel *tree_model;
1564   gint n_inserted, row;
1565
1566   accessible->idle_expand_id = 0;
1567
1568   path = accessible->idle_expand_path;
1569   tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
1570
1571   tree_model = gtk_tree_view_get_model (tree_view);
1572   if (!tree_model)
1573     return FALSE;
1574
1575   if (!path || !gtk_tree_model_get_iter (tree_model, &iter, path))
1576     return FALSE;
1577
1578   /* Update visibility of cells below expansion row */
1579   traverse_cells (accessible, path, FALSE);
1580
1581   /* Figure out number of visible children, the following test
1582    * should not fail
1583    */
1584   if (gtk_tree_model_iter_has_child (tree_model, &iter))
1585     {
1586       GtkTreePath *path_copy;
1587
1588       /* By passing path into this function, we find the number of
1589        * visible children of path.
1590        */
1591       path_copy = gtk_tree_path_copy (path);
1592       gtk_tree_path_append_index (path_copy, 0);
1593
1594       n_inserted = 0;
1595       iterate_thru_children (tree_view, tree_model,
1596                              path_copy, NULL, &n_inserted, 0);
1597       gtk_tree_path_free (path_copy);
1598     }
1599   else
1600     {
1601       /* We can get here if the row expanded callback deleted the row */
1602       return FALSE;
1603     }
1604
1605   /* Set expand state */
1606   set_expand_state (tree_view, tree_model, accessible, path, TRUE);
1607
1608   row = get_row_from_tree_path (tree_view, path);
1609
1610   /* shouldn't ever happen */
1611   if (row == -1)
1612     g_assert_not_reached ();
1613
1614   /* Must add 1 because the "added rows" are below the row being expanded */
1615   row += 1;
1616
1617   g_signal_emit_by_name (accessible, "row-inserted", row, n_inserted);
1618
1619   accessible->idle_expand_path = NULL;
1620
1621   gtk_tree_path_free (path);
1622
1623   return FALSE;
1624 }
1625
1626 static gboolean
1627 row_expanded_cb (GtkTreeView *tree_view,
1628                  GtkTreeIter *iter,
1629                  GtkTreePath *path)
1630 {
1631   AtkObject *atk_obj;
1632   GtkTreeViewAccessible *accessible;
1633
1634   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
1635   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1636
1637   /*
1638    * The visible rectangle has not been updated when this signal is emitted
1639    * so we process the signal when the GTK processing is completed
1640    */
1641   /* this seems wrong since it overwrites any other pending expand handlers... */
1642   accessible->idle_expand_path = gtk_tree_path_copy (path);
1643   if (accessible->idle_expand_id)
1644     g_source_remove (accessible->idle_expand_id);
1645   accessible->idle_expand_id = gdk_threads_add_idle (idle_expand_row, accessible);
1646
1647   return FALSE;
1648 }
1649
1650 static gboolean
1651 row_collapsed_cb (GtkTreeView *tree_view,
1652                   GtkTreeIter *iter,
1653                   GtkTreePath *path)
1654 {
1655   GtkTreeModel *tree_model;
1656   AtkObject *atk_obj;
1657   GtkTreeViewAccessible *accessible;
1658   gint row;
1659
1660   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
1661   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1662   tree_model = gtk_tree_view_get_model (tree_view);
1663
1664   clean_rows (accessible);
1665
1666   /* Update visibility of cells below collapsed row */
1667   traverse_cells (accessible, path, FALSE);
1668
1669   /* Set collapse state */
1670   set_expand_state (tree_view, tree_model, accessible, path, FALSE);
1671   if (accessible->n_children_deleted == 0)
1672     return FALSE;
1673   row = get_row_from_tree_path (tree_view, path);
1674   if (row == -1)
1675     return FALSE;
1676   g_signal_emit_by_name (atk_obj, "row-deleted", row,
1677                          accessible->n_children_deleted);
1678   accessible->n_children_deleted = 0;
1679   return FALSE;
1680 }
1681
1682 static void
1683 size_allocate_cb (GtkWidget     *widget,
1684                   GtkAllocation *allocation)
1685 {
1686   AtkObject *atk_obj;
1687   GtkTreeViewAccessible *accessible;
1688
1689   atk_obj = gtk_widget_get_accessible (widget);
1690   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1691
1692   /* If the size allocation changes, the visibility of cells
1693    * may change so update the cells visibility.
1694    */
1695   traverse_cells (accessible, NULL, FALSE);
1696 }
1697
1698 static void
1699 selection_changed_cb (GtkTreeSelection *selection,
1700                       gpointer          data)
1701 {
1702   GtkTreeViewAccessible *accessible;
1703   GtkTreeView *tree_view;
1704   GtkWidget *widget;
1705   GtkTreeViewAccessibleCellInfo *info;
1706   GtkTreeSelection *tree_selection;
1707   GtkTreePath *path;
1708   GHashTableIter iter;
1709
1710   accessible = GTK_TREE_VIEW_ACCESSIBLE (data);
1711   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
1712   if (widget == NULL)
1713     return;
1714
1715   tree_view = GTK_TREE_VIEW (widget);
1716   tree_selection = gtk_tree_view_get_selection (tree_view);
1717
1718   clean_rows (accessible);
1719
1720   /* FIXME: clean rows iterates through all cells too */
1721   g_hash_table_iter_init (&iter, accessible->cell_infos);
1722   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&info))
1723     {
1724       _gtk_cell_accessible_remove_state (info->cell, ATK_STATE_SELECTED, TRUE);
1725
1726       path = cell_info_get_path (info);
1727       if (path && gtk_tree_selection_path_is_selected (tree_selection, path))
1728         _gtk_cell_accessible_add_state (info->cell, ATK_STATE_SELECTED, TRUE);
1729       gtk_tree_path_free (path);
1730     }
1731   if (gtk_widget_get_realized (widget))
1732     g_signal_emit_by_name (accessible, "selection-changed");
1733 }
1734
1735 static void
1736 columns_changed (GtkTreeView *tree_view)
1737 {
1738   AtkObject *atk_obj;
1739   GtkTreeViewAccessible *accessible;
1740   GList *tv_cols, *tmp_list;
1741   gboolean column_found;
1742   gboolean move_found = FALSE;
1743   gint column_count = 0;
1744   gint i;
1745
1746   atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
1747   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
1748
1749   /* This function must determine if the change is an add, delete
1750    * or a move based upon its cache of TreeViewColumns in
1751    * accessible->col_data
1752    */
1753   tv_cols = gtk_tree_view_get_columns (tree_view);
1754   accessible->n_cols = g_list_length (tv_cols);
1755
1756   /* check for adds or moves */
1757   for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
1758     {
1759       column_found = FALSE;
1760
1761       for (i = 0; i < accessible->col_data->len; i++)
1762         {
1763
1764           if ((GtkTreeViewColumn *)tmp_list->data ==
1765               (GtkTreeViewColumn *)g_array_index (accessible->col_data,
1766                GtkTreeViewColumn *, i))
1767             {
1768               column_found = TRUE;
1769
1770               /* If the column isn't in the same position, a move happened */
1771               if (!move_found && i != column_count)
1772                 {
1773                   /* Just emit one column reordered signal when a move happens */
1774                   g_signal_emit_by_name (atk_obj, "column-reordered");
1775                   move_found = TRUE;
1776                 }
1777
1778               break;
1779             }
1780         }
1781
1782      /* If column_found is FALSE, then an insert happened for column
1783       * number column_count
1784       */
1785       if (!column_found)
1786         {
1787           gint row;
1788
1789           /* Generate column-inserted signal */
1790           g_signal_emit_by_name (atk_obj, "column-inserted", column_count, 1);
1791
1792           /* Generate children-changed signals */
1793           for (row = 0; row < get_n_rows (tree_view); row++)
1794             {
1795              /* Pass NULL as the child object, i.e. 4th argument */
1796               g_signal_emit_by_name (atk_obj, "children-changed::add",
1797                                     ((row * accessible->n_cols) + column_count), NULL, NULL);
1798             }
1799         }
1800
1801       column_count++;
1802     }
1803
1804   /* check for deletes */
1805   for (i = 0; i < accessible->col_data->len; i++)
1806     {
1807       column_found = FALSE;
1808
1809       for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
1810         {
1811             if ((GtkTreeViewColumn *)tmp_list->data ==
1812                 (GtkTreeViewColumn *)g_array_index (accessible->col_data,
1813                  GtkTreeViewColumn *, i))
1814               {
1815                 column_found = TRUE;
1816                 break;
1817               }
1818         }
1819
1820        /* If column_found is FALSE, then a delete happened for column
1821         * number i
1822         */
1823       if (!column_found)
1824         {
1825           gint row;
1826
1827           clean_cols (accessible,
1828                       (GtkTreeViewColumn *)g_array_index (accessible->col_data,
1829                       GtkTreeViewColumn *, i));
1830
1831           /* Generate column-deleted signal */
1832           g_signal_emit_by_name (atk_obj, "column-deleted", i, 1);
1833
1834           /* Generate children-changed signals */
1835           for (row = 0; row < get_n_rows (tree_view); row++)
1836             {
1837               /* Pass NULL as the child object, 4th argument */
1838               g_signal_emit_by_name (atk_obj, "children-changed::remove",
1839                                      ((row * accessible->n_cols) + column_count), NULL, NULL);
1840             }
1841         }
1842     }
1843
1844   traverse_cells (accessible, NULL, FALSE);
1845
1846   /* rebuild the array */
1847   g_array_free (accessible->col_data, TRUE);
1848   accessible->col_data = g_array_sized_new (FALSE, TRUE, sizeof (GtkTreeViewColumn *), 0);
1849
1850   for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
1851     g_array_append_val (accessible->col_data, tmp_list->data);
1852   g_list_free (tv_cols);
1853 }
1854
1855 static void
1856 cursor_changed (GtkTreeView           *tree_view,
1857                 GtkTreeViewAccessible *accessible)
1858 {
1859   AtkObject *cell;
1860
1861   cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
1862   if (cell)
1863     {
1864       if (cell != accessible->focus_cell)
1865         {
1866           if (accessible->focus_cell)
1867             {
1868               _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
1869               _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
1870               g_object_unref (accessible->focus_cell);
1871               accessible->focus_cell = cell;
1872             }
1873
1874           if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
1875             {
1876               _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
1877               _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
1878             }
1879
1880           g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
1881         }
1882       else
1883         g_object_unref (cell);
1884     }
1885 }
1886
1887 static gboolean
1888 focus_in (GtkWidget *widget)
1889 {
1890   GtkTreeView *tree_view;
1891   GtkTreeViewAccessible *accessible;
1892   AtkStateSet *state_set;
1893   AtkObject *cell;
1894
1895   tree_view = GTK_TREE_VIEW (widget);
1896   accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
1897
1898   if (accessible->focus_cell == NULL)
1899     {
1900       cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
1901       if (cell)
1902         {
1903           state_set = atk_object_ref_state_set (cell);
1904           if (state_set)
1905             {
1906               if (!atk_state_set_contains_state (state_set, ATK_STATE_FOCUSED))
1907                 {
1908                   _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
1909                   accessible->focus_cell = cell;
1910                   _gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
1911                   g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
1912                 }
1913               g_object_unref (state_set);
1914             }
1915         }
1916     }
1917   return FALSE;
1918 }
1919
1920 static gboolean
1921 focus_out (GtkWidget *widget)
1922 {
1923   GtkTreeViewAccessible *accessible;
1924
1925   accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
1926   if (accessible->focus_cell)
1927     {
1928       _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
1929       _gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
1930       g_object_unref (accessible->focus_cell);
1931       accessible->focus_cell = NULL;
1932     }
1933   return FALSE;
1934 }
1935
1936 static void
1937 model_row_changed (GtkTreeModel *tree_model,
1938                    GtkTreePath  *path,
1939                    GtkTreeIter  *iter,
1940                    gpointer      user_data)
1941 {
1942   GtkTreeView *tree_view = GTK_TREE_VIEW (user_data);
1943   GtkTreeViewAccessible *accessible;
1944   GtkTreePath *cell_path;
1945   GtkTreeViewAccessibleCellInfo *cell_info;
1946   GHashTableIter hash_iter;
1947
1948   accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
1949
1950   /* Loop through our cached cells */
1951   /* Must loop through them all */
1952   g_hash_table_iter_init (&hash_iter, accessible->cell_infos);
1953   while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer *)&cell_info))
1954     {
1955       cell_path = cell_info_get_path (cell_info);
1956
1957       if (cell_path != NULL)
1958         {
1959           if (path && gtk_tree_path_compare (cell_path, path) == 0)
1960             {
1961               if (GTK_IS_RENDERER_CELL_ACCESSIBLE (cell_info->cell))
1962                 update_cell_value (GTK_RENDERER_CELL_ACCESSIBLE (cell_info->cell),
1963                                    accessible, TRUE);
1964             }
1965           gtk_tree_path_free (cell_path);
1966         }
1967     }
1968   g_signal_emit_by_name (accessible, "visible-data-changed");
1969 }
1970
1971 static void
1972 column_visibility_changed (GObject    *object,
1973                            GParamSpec *pspec,
1974                            gpointer    user_data)
1975 {
1976   if (g_strcmp0 (pspec->name, "visible") == 0)
1977     {
1978       /* A column has been made visible or invisible
1979        * We update our cache of cells and emit model_changed signal
1980        */
1981       GtkTreeView *tree_view = (GtkTreeView *)user_data;
1982       GtkTreeViewAccessible *accessible;
1983       GtkTreeViewAccessibleCellInfo *cell_info;
1984       GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
1985       GtkTreeViewColumn *tv_col;
1986       GHashTableIter iter;
1987
1988       accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
1989 );
1990       g_signal_emit_by_name (accessible, "model-changed");
1991
1992       g_hash_table_iter_init (&iter, accessible->cell_infos);
1993       while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
1994         {
1995           tv_col = cell_info->cell_col_ref;
1996           if (tv_col == this_col)
1997             {
1998               GtkTreePath *row_path;
1999               row_path = cell_info_get_path (cell_info);
2000               if (GTK_IS_RENDERER_CELL_ACCESSIBLE (cell_info->cell))
2001                 {
2002                   if (gtk_tree_view_column_get_visible (tv_col))
2003                       set_cell_visibility (tree_view,
2004                                            cell_info->cell,
2005                                            tv_col, row_path, FALSE);
2006                   else
2007                     {
2008                       _gtk_cell_accessible_remove_state (cell_info->cell, ATK_STATE_VISIBLE, TRUE);
2009                       _gtk_cell_accessible_remove_state (cell_info->cell, ATK_STATE_SHOWING, TRUE);
2010                     }
2011                 }
2012               gtk_tree_path_free (row_path);
2013             }
2014         }
2015     }
2016 }
2017
2018 static void
2019 model_row_inserted (GtkTreeModel *tree_model,
2020                     GtkTreePath  *path,
2021                     GtkTreeIter  *iter,
2022                     gpointer      user_data)
2023 {
2024   GtkTreeView *tree_view = (GtkTreeView *)user_data;
2025   AtkObject *atk_obj;
2026   GtkTreeViewAccessible *accessible;
2027   GtkTreePath *path_copy;
2028   gint row, n_inserted, child_row;
2029
2030   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2031   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2032
2033   if (accessible->idle_expand_id)
2034     {
2035       g_source_remove (accessible->idle_expand_id);
2036       accessible->idle_expand_id = 0;
2037
2038       /* don't do this if the insertion precedes the idle path,
2039        * since it will now be invalid
2040        */
2041       if (path && accessible->idle_expand_path &&
2042           (gtk_tree_path_compare (path, accessible->idle_expand_path) > 0))
2043           set_expand_state (tree_view, tree_model, accessible, accessible->idle_expand_path, FALSE);
2044       if (accessible->idle_expand_path)
2045           gtk_tree_path_free (accessible->idle_expand_path);
2046     }
2047   /* Check to see if row is visible */
2048   row = get_row_from_tree_path (tree_view, path);
2049
2050  /* A row insert is not necessarily visible.  For example,
2051   * a row can be draged & dropped into another row, which
2052   * causes an insert on the model that isn't visible in the
2053   * view.  Only generate a signal if the inserted row is
2054   * visible.
2055   */
2056   if (row != -1)
2057     {
2058       GtkTreeIter tmp_iter;
2059       gint n_cols, col;
2060
2061       gtk_tree_model_get_iter (tree_model, &tmp_iter, path);
2062
2063       /* Figure out number of visible children. */
2064       if (gtk_tree_model_iter_has_child (tree_model, &tmp_iter))
2065         {
2066           GtkTreePath *path2;
2067          /*
2068           * By passing path into this function, we find the number of
2069           * visible children of path.
2070           */
2071           n_inserted = 0;
2072           /* iterate_thru_children modifies path, we don't want that, so give
2073            * it a copy */
2074           path2 = gtk_tree_path_copy (path);
2075           iterate_thru_children (tree_view, tree_model,
2076                                  path2, NULL, &n_inserted, 0);
2077           gtk_tree_path_free (path2);
2078
2079           /* Must add one to include the row that is being added */
2080           n_inserted++;
2081         }
2082       else
2083         n_inserted = 1;
2084
2085       traverse_cells (accessible, path, TRUE);
2086
2087       /* Generate row-inserted signal */
2088       g_signal_emit_by_name (atk_obj, "row-inserted", row, n_inserted);
2089
2090       /* Generate children-changed signals */
2091       n_cols = gtk_tree_view_accessible_get_n_columns (ATK_TABLE (atk_obj));
2092       for (child_row = row; child_row < (row + n_inserted); child_row++)
2093         {
2094           for (col = 0; col < n_cols; col++)
2095             {
2096              /* Pass NULL as the child object, i.e. 4th argument */
2097               g_signal_emit_by_name (atk_obj, "children-changed::add",
2098                                     ((row * n_cols) + col), NULL, NULL);
2099             }
2100         }
2101     }
2102   else
2103     {
2104      /* The row has been inserted inside another row.  This can
2105       * cause a row that previously couldn't be expanded to now
2106       * be expandable.
2107       */
2108       path_copy = gtk_tree_path_copy (path);
2109       gtk_tree_path_up (path_copy);
2110       set_expand_state (tree_view, tree_model, accessible, path_copy, TRUE);
2111       gtk_tree_path_free (path_copy);
2112     }
2113 }
2114
2115 static void
2116 model_row_deleted (GtkTreeModel *tree_model,
2117                    GtkTreePath  *path,
2118                    gpointer      user_data)
2119 {
2120   GtkTreeView *tree_view = (GtkTreeView *)user_data;
2121   GtkTreePath *path_copy;
2122   AtkObject *atk_obj;
2123   GtkTreeViewAccessible *accessible;
2124   gint row, col;
2125
2126   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2127   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2128
2129   if (accessible->idle_expand_id)
2130     {
2131       g_source_remove (accessible->idle_expand_id);
2132       gtk_tree_path_free (accessible->idle_expand_path);
2133       accessible->idle_expand_id = 0;
2134     }
2135
2136   /* Check to see if row is visible */
2137   clean_rows (accessible);
2138
2139   traverse_cells (accessible, path, TRUE);
2140
2141   /* If deleting a row with a depth > 1, then this may affect the
2142    * expansion/contraction of its parent(s). Make sure this is
2143    * handled.
2144    */
2145   if (gtk_tree_path_get_depth (path) > 1)
2146     {
2147       path_copy = gtk_tree_path_copy (path);
2148       gtk_tree_path_up (path_copy);
2149       set_expand_state (tree_view, tree_model, accessible, path_copy, TRUE);
2150       gtk_tree_path_free (path_copy);
2151     }
2152   row = get_row_from_tree_path (tree_view, path);
2153
2154   /* If the row which is deleted is not visible because it is a child of
2155    * a collapsed row then row will be -1
2156    */
2157   if (row > 0)
2158     g_signal_emit_by_name (atk_obj, "row-deleted", row,
2159                            accessible->n_children_deleted + 1);
2160   accessible->n_children_deleted = 0;
2161
2162   /* Generate children-changed signals */
2163   for (col = 0; col < accessible->n_cols; col++)
2164     {
2165       /* Pass NULL as the child object, 4th argument */
2166       g_signal_emit_by_name (atk_obj, "children-changed::remove",
2167                              ((row * accessible->n_cols) + col), NULL, NULL);
2168     }
2169 }
2170
2171 /* This function gets called when a row is deleted or when rows are
2172  * removed from the view due to a collapse event. Note that the
2173  * count is the number of visible *children* of the deleted row,
2174  * so it does not include the row being deleted.
2175  *
2176  * As this function is called before the rows are removed we just note
2177  * the number of rows and then deal with it when we get a notification
2178  * that rows were deleted or collapsed.
2179  */
2180 static void
2181 destroy_count_func (GtkTreeView *tree_view,
2182                     GtkTreePath *path,
2183                     gint         count,
2184                     gpointer     user_data)
2185 {
2186   AtkObject *atk_obj;
2187   GtkTreeViewAccessible *accessible;
2188
2189   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2190   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2191
2192   if (accessible->n_children_deleted != 0)
2193     return;
2194
2195   accessible->n_children_deleted = count;
2196 }
2197
2198 static void
2199 model_rows_reordered (GtkTreeModel *tree_model,
2200                       GtkTreePath  *path,
2201                       GtkTreeIter  *iter,
2202                       gint         *new_order,
2203                       gpointer      user_data)
2204 {
2205   GtkTreeView *tree_view = (GtkTreeView *)user_data;
2206   AtkObject *atk_obj;
2207   GtkTreeViewAccessible *accessible;
2208
2209   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2210   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
2211
2212   if (accessible->idle_expand_id)
2213     {
2214       g_source_remove (accessible->idle_expand_id);
2215       gtk_tree_path_free (accessible->idle_expand_path);
2216       accessible->idle_expand_id = 0;
2217     }
2218   traverse_cells (accessible, NULL, FALSE);
2219
2220   g_signal_emit_by_name (atk_obj, "row-reordered");
2221 }
2222
2223 static void
2224 set_cell_visibility (GtkTreeView       *tree_view,
2225                      GtkCellAccessible *cell,
2226                      GtkTreeViewColumn *tv_col,
2227                      GtkTreePath       *tree_path,
2228                      gboolean           emit_signal)
2229 {
2230   GdkRectangle cell_rect;
2231
2232   /* Get these three values in tree coords */
2233   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
2234     gtk_tree_view_get_cell_area (tree_view, tree_path, tv_col, &cell_rect);
2235   else
2236     cell_rect.height = 0;
2237
2238   if (cell_rect.height > 0)
2239     {
2240       /* The height will be zero for a cell for which an antecedent
2241        * is not expanded
2242        */
2243       _gtk_cell_accessible_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
2244       if (is_cell_showing (tree_view, &cell_rect))
2245         _gtk_cell_accessible_add_state (cell, ATK_STATE_SHOWING, emit_signal);
2246       else
2247         _gtk_cell_accessible_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
2248     }
2249   else
2250     {
2251       _gtk_cell_accessible_remove_state (cell, ATK_STATE_VISIBLE, emit_signal);
2252       _gtk_cell_accessible_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
2253     }
2254 }
2255
2256 static gboolean
2257 is_cell_showing (GtkTreeView  *tree_view,
2258                  GdkRectangle *cell_rect)
2259 {
2260   GdkRectangle rect, *visible_rect;
2261   GdkRectangle rect1, *tree_cell_rect;
2262   gint bx, by;
2263   gboolean is_showing;
2264
2265  /* A cell is considered "SHOWING" if any part of the cell is
2266   * in the visible area. Other ways we could do this is by a
2267   * cell's midpoint or if the cell is fully in the visible range.
2268   * Since we have the cell_rect x, y, width, height of the cell,
2269   * any of these is easy to compute.
2270   *
2271   * It is assumed that cell's rectangle is in widget coordinates
2272   * so we must transform to tree cordinates.
2273   */
2274   visible_rect = &rect;
2275   tree_cell_rect = &rect1;
2276   tree_cell_rect->x = cell_rect->x;
2277   tree_cell_rect->y = cell_rect->y;
2278   tree_cell_rect->width = cell_rect->width;
2279   tree_cell_rect->height = cell_rect->height;
2280
2281   gtk_tree_view_get_visible_rect (tree_view, visible_rect);
2282   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view, visible_rect->x,
2283                                                    visible_rect->y, &bx, &by);
2284
2285   if (((tree_cell_rect->x + tree_cell_rect->width) < bx) ||
2286      ((tree_cell_rect->y + tree_cell_rect->height) < by) ||
2287      (tree_cell_rect->x > (bx + visible_rect->width)) ||
2288      (tree_cell_rect->y > (by + visible_rect->height)))
2289     is_showing =  FALSE;
2290   else
2291     is_showing = TRUE;
2292
2293   return is_showing;
2294 }
2295
2296 /* Misc Public */
2297
2298 /* This function is called when a cell's flyweight is created in
2299  * gtk_tree_view_accessible_table_ref_at with emit_change_signal
2300  * set to FALSE and in model_row_changed() on receipt of "row-changed"
2301  * signal when emit_change_signal is set to TRUE
2302  */
2303 static gboolean
2304 update_cell_value (GtkRendererCellAccessible      *renderer_cell,
2305                    GtkTreeViewAccessible *accessible,
2306                    gboolean               emit_change_signal)
2307 {
2308   GtkTreeViewAccessibleCellInfo *cell_info;
2309   GtkTreeView *tree_view;
2310   GtkTreeModel *tree_model;
2311   GtkTreePath *path;
2312   GtkTreeIter iter;
2313   GList *renderers, *cur_renderer;
2314   GParamSpec *spec;
2315   GtkRendererCellAccessibleClass *renderer_cell_class;
2316   GtkCellRendererClass *gtk_cell_renderer_class;
2317   GtkCellAccessible *cell;
2318   gchar **prop_list;
2319   AtkObject *parent;
2320   gboolean is_expander, is_expanded;
2321
2322   renderer_cell_class = GTK_RENDERER_CELL_ACCESSIBLE_GET_CLASS (renderer_cell);
2323   if (renderer_cell->renderer)
2324     gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
2325   else
2326     gtk_cell_renderer_class = NULL;
2327
2328   prop_list = renderer_cell_class->property_list;
2329
2330   cell = GTK_CELL_ACCESSIBLE (renderer_cell);
2331   cell_info = find_cell_info (accessible, cell, TRUE);
2332   if (!cell_info)
2333     return FALSE;
2334
2335   if (emit_change_signal)
2336     {
2337       tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
2338       tree_model = gtk_tree_view_get_model (tree_view);
2339       path = cell_info_get_path (cell_info);
2340       if (path == NULL)
2341         return FALSE;
2342
2343       gtk_tree_model_get_iter (tree_model, &iter, path);
2344       is_expander = FALSE;
2345       is_expanded = FALSE;
2346       if (gtk_tree_model_iter_has_child (tree_model, &iter))
2347         {
2348           GtkTreeViewColumn *expander_tv;
2349
2350           expander_tv = gtk_tree_view_get_expander_column (tree_view);
2351           if (expander_tv == cell_info->cell_col_ref)
2352             {
2353               is_expander = TRUE;
2354               is_expanded = gtk_tree_view_row_expanded (tree_view, path);
2355             }
2356         }
2357       gtk_tree_path_free (path);
2358       gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
2359                                                tree_model, &iter,
2360                                                is_expander, is_expanded);
2361     }
2362   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_info->cell_col_ref));
2363   if (!renderers)
2364     return FALSE;
2365
2366   /* If the cell is in a container, its index is used to find the renderer
2367    * in the list. Otherwise, we assume that the cell is represented
2368    * by the first renderer in the list
2369    */
2370   parent = atk_object_get_parent (ATK_OBJECT (cell));
2371
2372   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2373     cur_renderer = g_list_nth (renderers, atk_object_get_index_in_parent (ATK_OBJECT (cell)));
2374   else
2375     cur_renderer = renderers;
2376
2377   if (cur_renderer == NULL)
2378     return FALSE;
2379
2380   if (gtk_cell_renderer_class)
2381     {
2382       while (*prop_list)
2383         {
2384           spec = g_object_class_find_property
2385                            (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
2386
2387           if (spec != NULL)
2388             {
2389               GValue value = G_VALUE_INIT;
2390
2391               g_value_init (&value, spec->value_type);
2392               g_object_get_property (cur_renderer->data, *prop_list, &value);
2393               g_object_set_property (G_OBJECT (renderer_cell->renderer),
2394                                      *prop_list, &value);
2395               g_value_unset (&value);
2396             }
2397           else
2398             g_warning ("Invalid property: %s\n", *prop_list);
2399           prop_list++;
2400         }
2401     }
2402   g_list_free (renderers);
2403
2404   return _gtk_renderer_cell_accessible_update_cache (renderer_cell, emit_change_signal);
2405 }
2406
2407 static gint
2408 get_row_from_tree_path (GtkTreeView *tree_view,
2409                         GtkTreePath *path)
2410 {
2411   GtkTreeModel *tree_model;
2412   GtkTreePath *root_tree;
2413   gint row;
2414
2415   tree_model = gtk_tree_view_get_model (tree_view);
2416
2417   if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
2418     row = gtk_tree_path_get_indices (path)[0];
2419   else
2420     {
2421       root_tree = gtk_tree_path_new_first ();
2422       row = 0;
2423       iterate_thru_children (tree_view, tree_model, root_tree, path, &row, 0);
2424       gtk_tree_path_free (root_tree);
2425     }
2426
2427   return row;
2428 }
2429
2430 /* Misc Private */
2431
2432 /*
2433  * Get the specified GtkTreeViewColumn in the GtkTreeView.
2434  * Only visible columns are considered.
2435  */
2436 static GtkTreeViewColumn *
2437 get_column (GtkTreeView *tree_view,
2438             gint         in_col)
2439 {
2440   GtkTreeViewColumn *tv_col;
2441   gint n_cols = -1;
2442   gint i = 0;
2443
2444   if (in_col < 0)
2445     {
2446        g_warning ("Request for invalid column %d\n", in_col);
2447        return NULL;
2448     }
2449
2450   tv_col = gtk_tree_view_get_column (tree_view, i);
2451   while (tv_col != NULL)
2452     {
2453       if (gtk_tree_view_column_get_visible (tv_col))
2454         n_cols++;
2455       if (in_col == n_cols)
2456         break;
2457       tv_col = gtk_tree_view_get_column (tree_view, ++i);
2458     }
2459
2460   if (in_col != n_cols)
2461     {
2462        g_warning ("Request for invalid column %d\n", in_col);
2463        return NULL;
2464     }
2465   return tv_col;
2466 }
2467
2468 static gint
2469 get_visible_column_number (GtkTreeView *tree_view,
2470                            gint         actual_column)
2471 {
2472   GtkTreeViewColumn *tv_col;
2473   gint column = 0;
2474   gint visible_columns = -1;
2475
2476   /* This function calculates the visible column number
2477    * which corresponds to the specified actual column number
2478    */
2479   tv_col = gtk_tree_view_get_column (tree_view, column);
2480
2481   while (tv_col != NULL)
2482     {
2483       if (gtk_tree_view_column_get_visible (tv_col))
2484         {
2485           visible_columns++;
2486           if (actual_column == column)
2487             return visible_columns;
2488         }
2489       else
2490         if (actual_column == column)
2491           return -1;
2492       tv_col = gtk_tree_view_get_column (tree_view, ++column);
2493     }
2494   g_warning ("get_visible_column_number failed for %d\n", actual_column);
2495   return -1;
2496 }
2497
2498 /* Helper recursive function that returns an iter to nth row
2499  */
2500 static GtkTreeIter *
2501 return_iter_nth_row (GtkTreeView  *tree_view,
2502                      GtkTreeModel *tree_model,
2503                      GtkTreeIter  *iter,
2504                      gint          increment,
2505                      gint          row)
2506 {
2507   GtkTreePath *current_path;
2508   GtkTreeIter new_iter;
2509   gboolean row_expanded;
2510
2511   current_path = gtk_tree_model_get_path (tree_model, iter);
2512   if (increment == row)
2513     {
2514       gtk_tree_path_free (current_path);
2515       return iter;
2516     }
2517
2518   row_expanded = gtk_tree_view_row_expanded (tree_view, current_path);
2519   gtk_tree_path_free (current_path);
2520
2521   new_iter = *iter;
2522   if ((row_expanded && gtk_tree_model_iter_children (tree_model, iter, &new_iter)) ||
2523       (gtk_tree_model_iter_next (tree_model, iter)) ||
2524       (gtk_tree_model_iter_parent (tree_model, iter, &new_iter) &&
2525           (gtk_tree_model_iter_next (tree_model, iter))))
2526     return return_iter_nth_row (tree_view, tree_model, iter,
2527       ++increment, row);
2528
2529   return NULL;
2530 }
2531
2532 static void
2533 set_iter_nth_row (GtkTreeView *tree_view,
2534                   GtkTreeIter *iter,
2535                   gint         row)
2536 {
2537   GtkTreeModel *tree_model;
2538
2539   tree_model = gtk_tree_view_get_model (tree_view);
2540   gtk_tree_model_get_iter_first (tree_model, iter);
2541   iter = return_iter_nth_row (tree_view, tree_model, iter, 0, row);
2542 }
2543
2544 /* Recursively called until the row specified by orig is found.
2545  *
2546  * *count will be set to the visible row number of the child
2547  * relative to the row that was initially passed in as tree_path.
2548  * tree_path could be modified by this function.
2549  *
2550  * *count will be -1 if orig is not found as a child (a row that is
2551  * not visible will not be found, e.g. if the row is inside a
2552  * collapsed row).  If NULL is passed in as orig, *count will
2553  * be a count of the visible children.
2554  *
2555  * NOTE: the value for depth must be 0 when this recursive function
2556  * is initially called, or it may not function as expected.
2557  */
2558 static void
2559 iterate_thru_children (GtkTreeView  *tree_view,
2560                        GtkTreeModel *tree_model,
2561                        GtkTreePath  *tree_path,
2562                        GtkTreePath  *orig,
2563                        gint         *count,
2564                        gint          depth)
2565 {
2566   GtkTreeIter iter;
2567
2568   if (!gtk_tree_model_get_iter (tree_model, &iter, tree_path))
2569     return;
2570
2571   if (tree_path && orig && !gtk_tree_path_compare (tree_path, orig))
2572     /* Found it! */
2573     return;
2574
2575   if (tree_path && orig && gtk_tree_path_compare (tree_path, orig) > 0)
2576     {
2577       /* Past it, so return -1 */
2578       *count = -1;
2579       return;
2580     }
2581   else if (gtk_tree_view_row_expanded (tree_view, tree_path) &&
2582     gtk_tree_model_iter_has_child (tree_model, &iter))
2583     {
2584       (*count)++;
2585       gtk_tree_path_append_index (tree_path, 0);
2586       iterate_thru_children (tree_view, tree_model, tree_path,
2587                              orig, count, (depth + 1));
2588       return;
2589     }
2590   else if (gtk_tree_model_iter_next (tree_model, &iter))
2591     {
2592       (*count)++;
2593       tree_path = gtk_tree_model_get_path (tree_model, &iter);
2594        if (tree_path)
2595          {
2596            iterate_thru_children (tree_view, tree_model, tree_path,
2597                                  orig, count, depth);
2598            gtk_tree_path_free (tree_path);
2599          }
2600       return;
2601   }
2602   else if (gtk_tree_path_up (tree_path))
2603     {
2604       GtkTreeIter temp_iter;
2605       gboolean exit_loop = FALSE;
2606       gint new_depth = depth - 1;
2607
2608       (*count)++;
2609
2610      /* Make sure that we back up until we find a row
2611       * where gtk_tree_path_next does not return NULL.
2612       */
2613       while (!exit_loop)
2614         {
2615           if (gtk_tree_path_get_depth (tree_path) == 0)
2616               /* depth is now zero so */
2617             return;
2618           gtk_tree_path_next (tree_path);
2619
2620           /* Verify that the next row is a valid row! */
2621           exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
2622
2623           if (!exit_loop)
2624             {
2625               /* Keep going up until we find a row that has a valid next */
2626               if (gtk_tree_path_get_depth(tree_path) > 1)
2627                 {
2628                   new_depth--;
2629                   gtk_tree_path_up (tree_path);
2630                 }
2631               else
2632                 {
2633                  /* If depth is 1 and gtk_tree_model_get_iter returns FALSE,
2634                   * then we are at the last row, so just return.
2635                   */
2636                   if (orig != NULL)
2637                     *count = -1;
2638
2639                   return;
2640                 }
2641             }
2642         }
2643
2644      /* This guarantees that we will stop when we hit the end of the
2645       * children.
2646       */
2647       if (new_depth < 0)
2648         return;
2649
2650       iterate_thru_children (tree_view, tree_model, tree_path,
2651                              orig, count, new_depth);
2652       return;
2653     }
2654
2655  /* If it gets here, then the path wasn't found.  Situations
2656   * that would cause this would be if the path passed in is
2657   * invalid or contained within the last row, but not visible
2658   * because the last row is not expanded.  If NULL was passed
2659   * in then a row count is desired, so only set count to -1
2660   * if orig is not NULL.
2661   */
2662   if (orig != NULL)
2663     *count = -1;
2664
2665   return;
2666 }
2667
2668 static void
2669 clean_rows (GtkTreeViewAccessible *accessible)
2670 {
2671   GtkTreeViewAccessibleCellInfo *cell_info;
2672   GHashTableIter iter;
2673
2674   /* Clean GtkTreeViewAccessibleCellInfo data */
2675   g_hash_table_iter_init (&iter, accessible->cell_infos);
2676   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
2677     {
2678       GtkTreePath *row_path;
2679
2680       row_path = cell_info_get_path (cell_info);
2681
2682       /* If the cell has become invalid because the row has been removed,
2683        * then set the cell's state to ATK_STATE_DEFUNCT and schedule
2684        * its removal.  If row_path is NULL then the row has
2685        * been removed.
2686        */
2687       if (row_path == NULL)
2688         g_hash_table_iter_remove (&iter);
2689       else
2690         gtk_tree_path_free (row_path);
2691     }
2692 }
2693
2694 static void
2695 clean_cols (GtkTreeViewAccessible *accessible,
2696             GtkTreeViewColumn     *tv_col)
2697 {
2698   GtkTreeViewAccessibleCellInfo *cell_info;
2699   GHashTableIter iter;
2700
2701   /* Clean GtkTreeViewAccessibleCellInfo data */
2702   g_hash_table_iter_init (&iter, accessible->cell_infos);
2703   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cell_info))
2704     {
2705       /* If the cell has become invalid because the column tv_col
2706        * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
2707        * and remove the cell from accessible->cell_data.
2708        */
2709       if (cell_info->cell_col_ref == tv_col)
2710         g_hash_table_iter_remove (&iter);
2711     }
2712 }
2713
2714 /* If tree_path is passed in as NULL, then all cells are acted on.
2715  * Otherwise, just act on those cells that are on a row greater than
2716  * the specified tree_path. If inc_row is passed in as TRUE, then rows
2717  * greater and equal to the specified tree_path are acted on.
2718  *
2719  * The function set_cell_visibility() is called on all cells to be
2720  * acted on to update the visibility of the cell.
2721  */
2722 static void
2723 traverse_cells (GtkTreeViewAccessible *accessible,
2724                 GtkTreePath           *tree_path,
2725                 gboolean               inc_row)
2726 {
2727   GtkTreeViewAccessibleCellInfo *cell_info;
2728   GtkWidget *widget;
2729   GHashTableIter iter;
2730
2731   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
2732   if (!widget)
2733     return;
2734
2735   /* Must loop through them all */
2736   g_hash_table_iter_init (&iter, accessible->cell_infos);
2737   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
2738     {
2739       GtkTreePath *row_path;
2740       gboolean act_on_cell;
2741
2742       row_path = cell_info_get_path (cell_info);
2743       g_return_if_fail (row_path != NULL);
2744       if (tree_path == NULL)
2745         act_on_cell = TRUE;
2746       else
2747         {
2748           gint comparison;
2749
2750           comparison =  gtk_tree_path_compare (row_path, tree_path);
2751           if ((comparison > 0) ||
2752               (comparison == 0 && inc_row))
2753             act_on_cell = TRUE;
2754           else
2755             act_on_cell = FALSE;
2756         }
2757
2758       if (act_on_cell)
2759         {
2760           set_cell_visibility (GTK_TREE_VIEW (widget),
2761                                cell_info->cell,
2762                                cell_info->cell_col_ref,
2763                                row_path, TRUE);
2764         }
2765       gtk_tree_path_free (row_path);
2766     }
2767
2768   g_signal_emit_by_name (accessible, "visible-data-changed");
2769 }
2770
2771 /* If the tree_path passed in has children, then
2772  * ATK_STATE_EXPANDABLE is set.  If the row is expanded
2773  * ATK_STATE_EXPANDED is turned on.  If the row is
2774  * collapsed, then ATK_STATE_EXPANDED is removed.
2775  *
2776  * If the tree_path passed in has no children, then
2777  * ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED are removed.
2778  *
2779  * If set_on_ancestor is TRUE, then this function will also
2780  * update all cells that are ancestors of the tree_path.
2781  */
2782 static void
2783 set_expand_state (GtkTreeView           *tree_view,
2784                   GtkTreeModel          *tree_model,
2785                   GtkTreeViewAccessible *accessible,
2786                   GtkTreePath           *tree_path,
2787                   gboolean               set_on_ancestor)
2788 {
2789   GtkTreeViewColumn *expander_tv;
2790   GtkTreeViewAccessibleCellInfo *cell_info;
2791   GtkTreePath *cell_path;
2792   GtkTreeIter iter;
2793   gboolean found;
2794   GHashTableIter hash_iter;
2795
2796   g_hash_table_iter_init (&hash_iter, accessible->cell_infos);
2797   while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer *) &cell_info))
2798     {
2799       cell_path = cell_info_get_path (cell_info);
2800       found = FALSE;
2801
2802       if (cell_path != NULL)
2803         {
2804           GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (cell_info->cell);
2805
2806           expander_tv = gtk_tree_view_get_expander_column (tree_view);
2807
2808           /* Only set state for the cell that is in the column with the
2809            * expander toggle
2810            */
2811           if (expander_tv == cell_info->cell_col_ref)
2812             {
2813               if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
2814                 found = TRUE;
2815               else if (set_on_ancestor &&
2816                        gtk_tree_path_get_depth (cell_path) <
2817                        gtk_tree_path_get_depth (tree_path) &&
2818                        gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
2819                 /* Only set if set_on_ancestor was passed in as TRUE */
2820                 found = TRUE;
2821             }
2822
2823           /* Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
2824            * for ancestors and found cells.
2825            */
2826           if (found)
2827             {
2828               /* Must check against cell_path since cell_path
2829                * can be equal to or an ancestor of tree_path.
2830                */
2831               gtk_tree_model_get_iter (tree_model, &iter, cell_path);
2832
2833               /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
2834               if (gtk_tree_model_iter_has_child (tree_model, &iter))
2835                 {
2836                   set_cell_expandable (cell);
2837
2838                   if (gtk_tree_view_row_expanded (tree_view, cell_path))
2839                     _gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDED, TRUE);
2840                   else
2841                     _gtk_cell_accessible_remove_state (cell, ATK_STATE_EXPANDED, TRUE);
2842                 }
2843               else
2844                 {
2845                   _gtk_cell_accessible_remove_state (cell, ATK_STATE_EXPANDED, TRUE);
2846                   if (_gtk_cell_accessible_remove_state (cell, ATK_STATE_EXPANDABLE, TRUE))
2847                   /* The state may have been propagated to the container cell */
2848                   if (!GTK_IS_CONTAINER_CELL_ACCESSIBLE (cell))
2849                     _gtk_cell_accessible_remove_action_by_name (cell,
2850                                                                 "expand or contract");
2851                 }
2852
2853               /* We assume that each cell in the cache once and
2854                * a container cell is before its child cells so we are
2855                * finished if set_on_ancestor is not set to TRUE.
2856                */
2857               if (!set_on_ancestor)
2858                 break;
2859             }
2860         }
2861       gtk_tree_path_free (cell_path);
2862     }
2863 }
2864
2865 static void
2866 add_cell_actions (GtkCellAccessible *cell,
2867                   gboolean           editable)
2868 {
2869   if (GTK_IS_BOOLEAN_CELL_ACCESSIBLE (cell))
2870     _gtk_cell_accessible_add_action (cell,
2871                                      "toggle", "toggles the cell",
2872                                      NULL, toggle_cell_toggled);
2873   if (editable)
2874     _gtk_cell_accessible_add_action (cell,
2875                                      "edit", "creates a widget in which the contents of the cell can be edited",
2876                                      NULL, edit_cell);
2877   _gtk_cell_accessible_add_action (cell,
2878                                    "activate", "activate the cell",
2879                                    NULL, activate_cell);
2880 }
2881
2882 static void
2883 toggle_cell_expanded (GtkCellAccessible *cell)
2884 {
2885   GtkTreeViewAccessibleCellInfo *cell_info;
2886   GtkTreeView *tree_view;
2887   GtkTreePath *path;
2888   AtkObject *parent;
2889   AtkStateSet *stateset;
2890
2891   parent = atk_object_get_parent (ATK_OBJECT (cell));
2892   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2893     parent = atk_object_get_parent (parent);
2894
2895   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
2896   if (!cell_info)
2897     return;
2898
2899   tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
2900   path = cell_info_get_path (cell_info);
2901   if (!path)
2902     return;
2903
2904   stateset = atk_object_ref_state_set (ATK_OBJECT (cell));
2905   if (atk_state_set_contains_state (stateset, ATK_STATE_EXPANDED))
2906     gtk_tree_view_collapse_row (tree_view, path);
2907   else
2908     gtk_tree_view_expand_row (tree_view, path, TRUE);
2909   g_object_unref (stateset);
2910   gtk_tree_path_free (path);
2911 }
2912
2913 static void
2914 toggle_cell_toggled (GtkCellAccessible *cell)
2915 {
2916   GtkTreeViewAccessibleCellInfo *cell_info;
2917   GtkTreePath *path;
2918   gchar *pathstring;
2919   GList *renderers, *cur_renderer;
2920   AtkObject *parent;
2921   gboolean is_container_cell = FALSE;
2922
2923   parent = atk_object_get_parent (ATK_OBJECT (cell));
2924   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2925     {
2926       is_container_cell = TRUE;
2927       parent = atk_object_get_parent (parent);
2928     }
2929
2930   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
2931   if (!cell_info)
2932     return;
2933
2934   path = cell_info_get_path (cell_info);
2935   if (!path)
2936     return;
2937
2938   /* If the cell is in a container, its index is used to find the
2939    * renderer in the list. Otherwise, we assume that the cell is
2940    * represented by the first renderer in the list
2941    */
2942   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_info->cell_col_ref));
2943   if (is_container_cell)
2944     cur_renderer = g_list_nth (renderers, atk_object_get_index_in_parent (ATK_OBJECT (cell)));
2945   else
2946     cur_renderer = renderers;
2947
2948   if (cur_renderer)
2949     {
2950       pathstring = gtk_tree_path_to_string (path);
2951       g_signal_emit_by_name (cur_renderer->data, "toggled", pathstring);
2952       g_free (pathstring);
2953     }
2954
2955   g_list_free (renderers);
2956   gtk_tree_path_free (path);
2957 }
2958
2959 static void
2960 edit_cell (GtkCellAccessible *cell)
2961 {
2962   GtkTreeViewAccessibleCellInfo *cell_info;
2963   GtkTreeView *tree_view;
2964   GtkTreePath *path;
2965   AtkObject *parent;
2966
2967   parent = atk_object_get_parent (ATK_OBJECT (cell));
2968   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2969     parent = atk_object_get_parent (parent);
2970
2971   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
2972   if (!cell_info)
2973     return;
2974
2975   tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
2976   path = cell_info_get_path (cell_info);
2977   if (!path)
2978     return;
2979   gtk_tree_view_set_cursor (tree_view, path, cell_info->cell_col_ref, TRUE);
2980   gtk_tree_path_free (path);
2981 }
2982
2983 static void
2984 activate_cell (GtkCellAccessible *cell)
2985 {
2986   GtkTreeViewAccessibleCellInfo *cell_info;
2987   GtkTreeView *tree_view;
2988   GtkTreePath *path;
2989   AtkObject *parent;
2990
2991   parent = atk_object_get_parent (ATK_OBJECT (cell));
2992   if (GTK_IS_CONTAINER_CELL_ACCESSIBLE (parent))
2993     parent = atk_object_get_parent (parent);
2994
2995   cell_info = find_cell_info (GTK_TREE_VIEW_ACCESSIBLE (parent), cell, TRUE);
2996   if (!cell_info)
2997     return;
2998
2999   tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
3000   path = cell_info_get_path (cell_info);
3001   if (!path)
3002     return;
3003   gtk_tree_view_row_activated (tree_view, path, cell_info->cell_col_ref);
3004   gtk_tree_path_free (path);
3005 }
3006
3007 static void
3008 cell_destroyed (gpointer data)
3009 {
3010   GtkTreeViewAccessibleCellInfo *cell_info = data;
3011
3012   cell_info->cell = NULL;
3013
3014   g_hash_table_remove (cell_info->view->cell_infos, cell_info);
3015 }
3016
3017 static int
3018 cell_info_get_index (GtkTreeView                     *tree_view,
3019                      GtkTreeViewAccessibleCellInfo   *info)
3020 {
3021   GtkTreePath *path;
3022   gint column_number;
3023   int index;
3024
3025   path = cell_info_get_path (info);
3026   if (!path)
3027     return -1;
3028
3029   column_number = get_column_number (tree_view, info->cell_col_ref, FALSE);
3030   index = get_index (tree_view, path, column_number);
3031   gtk_tree_path_free (path);
3032
3033   return index;
3034 }
3035
3036 static void
3037 cell_info_new (GtkTreeViewAccessible *accessible,
3038                GtkTreeModel          *tree_model,
3039                GtkRBTree             *tree,
3040                GtkRBNode             *node,
3041                GtkTreeViewColumn     *tv_col,
3042                GtkCellAccessible     *cell)
3043 {
3044   GtkTreeViewAccessibleCellInfo *cell_info;
3045
3046   cell_info = g_new (GtkTreeViewAccessibleCellInfo, 1);
3047
3048   cell_info->tree = tree;
3049   cell_info->node = node;
3050   cell_info->cell_col_ref = tv_col;
3051   cell_info->cell = cell;
3052   cell_info->view = accessible;
3053
3054   g_object_set_qdata_full (G_OBJECT (cell), 
3055                            gtk_tree_view_accessible_get_data_quark (),
3056                            cell_info,
3057                            cell_destroyed);
3058
3059   g_hash_table_replace (accessible->cell_infos, cell_info, cell_info);
3060 }
3061
3062 static GtkCellAccessible *
3063 find_cell (GtkTreeViewAccessible *accessible,
3064            gint                   index)
3065 {
3066   GtkTreeViewAccessibleCellInfo *info;
3067   GHashTableIter iter;
3068   GtkTreeView *tree_view;
3069
3070   tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
3071
3072   g_hash_table_iter_init (&iter, accessible->cell_infos);
3073   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
3074     {
3075       if (index == cell_info_get_index (tree_view, info))
3076         return info->cell;
3077     }
3078
3079   return NULL;
3080 }
3081
3082 static void
3083 connect_model_signals (GtkTreeView           *view,
3084                        GtkTreeViewAccessible *accessible)
3085 {
3086   GObject *obj;
3087
3088   obj = G_OBJECT (accessible->tree_model);
3089   g_signal_connect_data (obj, "row-changed",
3090                          G_CALLBACK (model_row_changed), view, NULL, 0);
3091   g_signal_connect_data (obj, "row-inserted",
3092                          G_CALLBACK (model_row_inserted), view, NULL,
3093                          G_CONNECT_AFTER);
3094   g_signal_connect_data (obj, "row-deleted",
3095                          G_CALLBACK (model_row_deleted), view, NULL,
3096                          G_CONNECT_AFTER);
3097   g_signal_connect_data (obj, "rows-reordered",
3098                          G_CALLBACK (model_rows_reordered), view, NULL,
3099                          G_CONNECT_AFTER);
3100 }
3101
3102 static void
3103 disconnect_model_signals (GtkTreeViewAccessible *accessible)
3104 {
3105   GObject *obj;
3106   GtkWidget *widget;
3107
3108   obj = G_OBJECT (accessible->tree_model);
3109   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
3110   g_signal_handlers_disconnect_by_func (obj, model_row_changed, widget);
3111   g_signal_handlers_disconnect_by_func (obj, model_row_inserted, widget);
3112   g_signal_handlers_disconnect_by_func (obj, model_row_deleted, widget);
3113   g_signal_handlers_disconnect_by_func (obj, model_rows_reordered, widget);
3114 }
3115
3116 /* Returns the column number of the specified GtkTreeViewColumn
3117  *
3118  * If visible is set, the value returned will be the visible column number,
3119  * i.e. suitable for use in AtkTable function. If visible is not set, the
3120  * value returned is the actual column number, which is suitable for use in
3121  * getting an index value.
3122  */
3123 static gint
3124 get_column_number (GtkTreeView       *tree_view,
3125                    GtkTreeViewColumn *column,
3126                    gboolean           visible)
3127 {
3128   GtkTreeViewColumn *tv_column;
3129   gint ret_val;
3130   gint i;
3131   AtkObject *atk_obj;
3132   GtkTreeViewAccessible *accessible;
3133
3134   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3135   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
3136
3137   ret_val = 0;
3138   for (i = 0; i < accessible->col_data->len; i++)
3139     {
3140       tv_column = g_array_index (accessible->col_data, GtkTreeViewColumn *, i);
3141       if (tv_column == column)
3142         break;
3143       if (!visible || gtk_tree_view_column_get_visible (tv_column))
3144         ret_val++;
3145     }
3146   if (i == accessible->col_data->len)
3147     ret_val = -1;
3148
3149   return ret_val;
3150 }
3151
3152 static gint
3153 get_index (GtkTreeView *tree_view,
3154            GtkTreePath *path,
3155            gint         actual_column)
3156 {
3157   AtkObject *atk_obj;
3158   GtkTreeViewAccessible *accessible;
3159   gint depth = 0;
3160   gint index = 1;
3161   gint *indices = NULL;
3162
3163   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3164   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
3165
3166   if (path)
3167     {
3168       depth = gtk_tree_path_get_depth (path);
3169       indices = gtk_tree_path_get_indices (path);
3170     }
3171
3172   if (depth > 1)
3173     {
3174       GtkTreePath *copy_path;
3175       GtkTreeModel *model;
3176
3177       model = gtk_tree_view_get_model (tree_view);
3178       copy_path = gtk_tree_path_copy (path);
3179       gtk_tree_path_up (copy_path);
3180       count_rows (model, NULL, copy_path, &index, 0, depth);
3181       gtk_tree_path_free (copy_path);
3182     }
3183
3184   if (path)
3185     index += indices[depth - 1];
3186   index *= accessible->n_cols;
3187   index +=  actual_column;
3188   return index;
3189 }
3190
3191 /* The function count_rows counts the number of rows starting at iter
3192  * and ending at end_path. The value of level is the depth of iter and
3193  * the value of depth is the depth of end_path. Rows at depth before
3194  * end_path are counted. This functions counts rows which are not visible
3195  * because an ancestor is collapsed.
3196  */
3197 static void
3198 count_rows (GtkTreeModel *model,
3199             GtkTreeIter  *iter,
3200             GtkTreePath  *end_path,
3201             gint         *count,
3202             gint          level,
3203             gint          depth)
3204 {
3205   GtkTreeIter child_iter;
3206
3207   if (!model)
3208     return;
3209
3210   level++;
3211   *count += gtk_tree_model_iter_n_children (model, iter);
3212
3213   if (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY)
3214     return;
3215
3216   if (level >= depth)
3217     return;
3218
3219   if (gtk_tree_model_iter_children (model, &child_iter, iter))
3220     {
3221       gboolean ret_val = TRUE;
3222
3223       while (ret_val)
3224         {
3225           if (level == depth - 1)
3226             {
3227               GtkTreePath *iter_path;
3228               gboolean finished = FALSE;
3229
3230               iter_path = gtk_tree_model_get_path (model, &child_iter);
3231               if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
3232                 finished = TRUE;
3233               gtk_tree_path_free (iter_path);
3234               if (finished)
3235                 break;
3236             }
3237           if (gtk_tree_model_iter_has_child (model, &child_iter))
3238             count_rows (model, &child_iter, end_path, count, level, depth);
3239           ret_val = gtk_tree_model_iter_next (model, &child_iter);
3240         }
3241     }
3242 }
3243
3244 static gboolean
3245 get_rbtree_column_from_index (GtkTreeView        *tree_view,
3246                               gint                index,
3247                               GtkRBTree         **tree,
3248                               GtkRBNode         **node,
3249                               GtkTreeViewColumn **column)
3250 {
3251   AtkObject *atk_obj;
3252   GtkTreeViewAccessible *accessible;
3253
3254   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3255   accessible = GTK_TREE_VIEW_ACCESSIBLE (atk_obj);
3256
3257   if (accessible->n_cols == 0)
3258     return FALSE;
3259   /* First row is the column headers */
3260   index -= accessible->n_cols;
3261   if (index < 0)
3262     return FALSE;
3263
3264   if (tree)
3265     {
3266       g_return_val_if_fail (node != NULL, FALSE);
3267
3268       if (!_gtk_rbtree_find_index (_gtk_tree_view_get_rbtree (tree_view),
3269                                    index / accessible->n_cols,
3270                                    tree,
3271                                    node))
3272         return FALSE;
3273     }
3274
3275   if (column)
3276     {
3277       *column = gtk_tree_view_get_column (tree_view, index % accessible->n_cols);
3278       if (*column == NULL)
3279         return FALSE;
3280   }
3281   return TRUE;
3282 }
3283
3284 static void
3285 set_cell_expandable (GtkCellAccessible *cell)
3286 {
3287   if (_gtk_cell_accessible_add_state (cell, ATK_STATE_EXPANDABLE, FALSE))
3288     _gtk_cell_accessible_add_action (cell,
3289                                      "expand or contract",
3290                                      "expands or contracts the row in the tree view containing this cell",
3291                                      NULL, toggle_cell_expanded);
3292 }
3293
3294 static GtkTreeViewAccessibleCellInfo *
3295 find_cell_info (GtkTreeViewAccessible *accessible,
3296                 GtkCellAccessible     *cell,
3297                 gboolean               live_only)
3298 {
3299   return g_object_get_qdata (G_OBJECT (cell),
3300                                   gtk_tree_view_accessible_get_data_quark ());
3301 }
3302
3303 static AtkObject *
3304 get_header_from_column (GtkTreeViewColumn *tv_col)
3305 {
3306   AtkObject *rc;
3307   GtkWidget *header_widget;
3308
3309   if (tv_col == NULL)
3310     return NULL;
3311
3312   header_widget = gtk_tree_view_column_get_button (tv_col);
3313
3314   if (header_widget)
3315     rc = gtk_widget_get_accessible (header_widget);
3316   else
3317     rc = NULL;
3318
3319   return rc;
3320 }
3321
3322 /**
3323  * _gtk_rbtree_get_ancestor_node:
3324  * @ancestor: the ancestor tree
3325  * @child_tree: the potential child's tree
3326  * @child_node: the potential child's node
3327  *
3328  * Finds the node that is the ancestor of @child_tree and @child_node
3329  * and belongs to @ancestor. If @ancestor is not an ancestor tree
3330  * of @child_node, %NULL is returned.
3331  *
3332  * Returns: the ancestor node or %NULL if @ancestor is not an ancestor.
3333  **/
3334 static GtkRBNode *
3335 _gtk_rbtree_get_ancestor_node (GtkRBTree *ancestor,
3336                                GtkRBTree *child_tree,
3337                                GtkRBNode *child_node)
3338 {
3339   while (child_tree != NULL)
3340     {
3341       if (child_tree == ancestor)
3342         return child_node;
3343
3344       child_node = child_tree->parent_node;
3345       child_tree = child_tree->parent_tree;
3346     }
3347
3348   return NULL;
3349 }
3350
3351 void
3352 _gtk_tree_view_accessible_remove (GtkTreeView *treeview,
3353                                   GtkRBTree   *tree,
3354                                   GtkRBNode   *node)
3355 {
3356   GtkTreeViewAccessibleCellInfo *cell_info;
3357   GHashTableIter iter;
3358   GtkTreeViewAccessible *accessible;
3359
3360   accessible = GTK_TREE_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (treeview)));
3361   if (accessible == NULL)
3362     return;
3363
3364   /* if this shows up in profiles, special-case node->children == NULL */
3365
3366   g_hash_table_iter_init (&iter, accessible->cell_infos);
3367   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
3368     {
3369       GtkRBNode *child_node = _gtk_rbtree_get_ancestor_node (tree,
3370                                                              cell_info->tree,
3371                                                              cell_info->node);
3372
3373       if (child_node == NULL)
3374         continue;
3375
3376       if (node == NULL || node == child_node)
3377         g_hash_table_iter_remove (&iter);
3378     }
3379 }
3380