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