]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailtreeview.c
Use gdk_threads_add_idle. Bug #504571.
[~andy/gtk] / modules / other / gail / gailtreeview.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 <string.h>
21 #include <gtk/gtk.h>
22 #ifdef GDK_WINDOWING_X11
23 #include <gdk/x11/gdkx.h>
24 #endif
25 #include <gtk/gtktreeviewcolumn.h>
26 #include "gailtreeview.h"
27 #include "gailrenderercell.h"
28 #include "gailbooleancell.h"
29 #include "gailcontainercell.h"
30 #include "gailtextcell.h"
31 #include "gailcellparent.h"
32 #include "gail-private-macros.h"
33
34 typedef struct _GailTreeViewRowInfo    GailTreeViewRowInfo;
35 typedef struct _GailTreeViewCellInfo   GailTreeViewCellInfo;
36
37 static void             gail_tree_view_class_init       (GailTreeViewClass      *klass);
38 static void             gail_tree_view_real_initialize  (AtkObject              *obj,
39                                                          gpointer               data);
40 static void             gail_tree_view_real_notify_gtk  (GObject                *obj,
41                                                          GParamSpec             *pspec);
42 static void             gail_tree_view_finalize         (GObject                *object);
43
44 static void             gail_tree_view_connect_widget_destroyed 
45                                                         (GtkAccessible          *accessible);
46 static void             gail_tree_view_destroyed        (GtkWidget              *widget,
47                                                          GtkAccessible          *accessible); 
48 /* atkobject.h */
49
50 static gint             gail_tree_view_get_n_children   (AtkObject              *obj);
51 static AtkObject*       gail_tree_view_ref_child        (AtkObject              *obj,
52                                                          gint                   i);
53 static AtkStateSet*     gail_tree_view_ref_state_set    (AtkObject              *obj);
54
55 /* atkcomponent.h */
56
57 static void             atk_component_interface_init    (AtkComponentIface      *iface);
58
59 static AtkObject*       gail_tree_view_ref_accessible_at_point
60                                                         (AtkComponent           *component,
61                                                          gint                   x,
62                                                          gint                   y,
63                                                          AtkCoordType           coord_type);
64            
65 /* atktable.h */
66
67 static void             atk_table_interface_init        (AtkTableIface          *iface);
68
69 static gint             gail_tree_view_get_index_at     (AtkTable               *table,
70                                                          gint                   row,
71                                                          gint                   column);
72 static gint             gail_tree_view_get_column_at_index
73                                                         (AtkTable               *table,
74                                                          gint                   index);
75 static gint             gail_tree_view_get_row_at_index (AtkTable               *table,
76                                                          gint                   index);
77
78 static AtkObject*       gail_tree_view_table_ref_at     (AtkTable               *table,
79                                                          gint                   row,
80                                                          gint                   column);
81 static gint             gail_tree_view_get_n_rows       (AtkTable               *table);
82 static gint             gail_tree_view_get_n_columns    (AtkTable               *table);
83 static gint             get_n_actual_columns            (GtkTreeView            *tree_view);
84 static gboolean         gail_tree_view_is_row_selected  (AtkTable               *table,
85                                                          gint                   row);
86 static gboolean         gail_tree_view_is_selected      (AtkTable               *table,
87                                                          gint                   row,
88                                                          gint                   column);
89 static gint             gail_tree_view_get_selected_rows 
90                                                         (AtkTable               *table, 
91                                                          gint                   **selected);
92 static gboolean         gail_tree_view_add_row_selection 
93                                                         (AtkTable               *table, 
94                                                          gint                   row);
95 static gboolean         gail_tree_view_remove_row_selection 
96                                                         (AtkTable               *table, 
97                                                          gint                   row);
98 static AtkObject*       gail_tree_view_get_row_header   (AtkTable               *table,
99                                                          gint                   row);
100 static AtkObject*       gail_tree_view_get_column_header 
101                                                         (AtkTable               *table,
102                                                          gint                   column);
103 static void             gail_tree_view_set_row_header   (AtkTable               *table,
104                                                          gint                   row,
105                                                          AtkObject              *header);
106 static void             gail_tree_view_set_column_header 
107                                                         (AtkTable               *table,
108                                                          gint                   column,
109                                                          AtkObject              *header);
110 static AtkObject*
111                         gail_tree_view_get_caption      (AtkTable               *table);
112 static void             gail_tree_view_set_caption      (AtkTable               *table,
113                                                          AtkObject              *caption);
114 static AtkObject*       gail_tree_view_get_summary      (AtkTable               *table);
115 static void             gail_tree_view_set_summary      (AtkTable               *table,
116                                                          AtkObject              *accessible);
117 static G_CONST_RETURN gchar*
118                         gail_tree_view_get_row_description 
119                                                         (AtkTable               *table,
120                                                          gint                   row);
121 static void             gail_tree_view_set_row_description 
122                                                         (AtkTable               *table,
123                                                          gint                   row,
124                                                          const gchar            *description);
125 static G_CONST_RETURN gchar*
126                         gail_tree_view_get_column_description
127                                                         (AtkTable               *table,
128                                                          gint                   column);
129 static void             gail_tree_view_set_column_description
130                                                         (AtkTable               *table,
131                                                          gint                   column,
132                                                          const gchar            *description);
133
134 static void             set_row_data                    (AtkTable               *table,
135                                                          gint                   row,
136                                                          AtkObject              *header,
137                                                          const gchar            *description,
138                                                          gboolean               is_header);
139 static GailTreeViewRowInfo* 
140                         get_row_info                    (AtkTable               *table,
141                                                          gint                   row);
142
143 /* atkselection.h */
144
145 static void             atk_selection_interface_init    (AtkSelectionIface      *iface);
146 static gboolean         gail_tree_view_add_selection    (AtkSelection           *selection,
147                                                          gint                   i);
148 static gboolean         gail_tree_view_clear_selection  (AtkSelection           *selection);
149 static AtkObject*       gail_tree_view_ref_selection    (AtkSelection           *selection,
150                                                          gint                   i);
151 static gint             gail_tree_view_get_selection_count 
152                                                         (AtkSelection           *selection);
153 static gboolean         gail_tree_view_is_child_selected 
154                                                         (AtkSelection           *selection,
155                                                          gint                   i);
156
157 /* gailcellparent.h */
158
159 static void             gail_cell_parent_interface_init (GailCellParentIface    *iface);
160 static void             gail_tree_view_get_cell_extents (GailCellParent         *parent,
161                                                          GailCell               *cell,
162                                                          gint                   *x,
163                                                          gint                   *y,
164                                                          gint                   *width,
165                                                          gint                   *height,
166                                                          AtkCoordType           coord_type);
167 static void             gail_tree_view_get_cell_area    (GailCellParent         *parent,
168                                                          GailCell               *cell,
169                                                          GdkRectangle           *cell_rect);
170 static gboolean         gail_tree_view_grab_cell_focus  (GailCellParent         *parent,
171                                                          GailCell               *cell);
172
173 /* signal handling */
174
175 static gboolean         gail_tree_view_expand_row_gtk   (GtkTreeView            *tree_view,
176                                                          GtkTreeIter            *iter,
177                                                          GtkTreePath            *path);
178 static gint             idle_expand_row                 (gpointer               data);
179 static gboolean         gail_tree_view_collapse_row_gtk (GtkTreeView            *tree_view,
180                                                          GtkTreeIter            *iter,
181                                                          GtkTreePath            *path);
182 static void             gail_tree_view_size_allocate_gtk (GtkWidget             *widget,
183                                                          GtkAllocation          *allocation);
184 static void             gail_tree_view_set_scroll_adjustments
185                                                         (GtkWidget              *widget,
186                                                          GtkAdjustment          *hadj,
187                                                          GtkAdjustment          *vadj);
188 static void             gail_tree_view_changed_gtk      (GtkTreeSelection       *selection,
189                                                          gpointer               data);
190
191 static void             columns_changed                 (GtkTreeView            *tree_view);
192 static void             cursor_changed                  (GtkTreeView            *tree_view);
193 static gint             idle_cursor_changed             (gpointer               data);
194
195 static void             model_row_changed               (GtkTreeModel           *tree_model,
196                                                          GtkTreePath            *path,
197                                                          GtkTreeIter            *iter,
198                                                          gpointer               user_data);
199 static void             column_visibility_changed       (GObject                *object,
200                                                          GParamSpec             *param,
201                                                          gpointer               user_data);
202 static void             column_destroy                  (GtkObject              *obj); 
203 static void             model_row_inserted              (GtkTreeModel           *tree_model,
204                                                          GtkTreePath            *path,
205                                                          GtkTreeIter            *iter,
206                                                          gpointer               user_data);
207 static void             model_row_deleted               (GtkTreeModel           *tree_model,
208                                                          GtkTreePath            *path,
209                                                          gpointer               user_data);
210 static void             destroy_count_func              (GtkTreeView            *tree_view,
211                                                          GtkTreePath            *path,
212                                                          gint                   count,
213                                                          gpointer               user_data);
214 static void             model_rows_reordered            (GtkTreeModel           *tree_model,
215                                                          GtkTreePath            *path,
216                                                          GtkTreeIter            *iter,
217                                                          gint                   *new_order,
218                                                          gpointer               user_data);
219 static void             adjustment_changed              (GtkAdjustment          *adjustment,
220                                                          GtkTreeView            *tree_view);
221
222 /* Misc */
223
224 static void             set_iter_nth_row                (GtkTreeView            *tree_view,
225                                                          GtkTreeIter            *iter,
226                                                          gint                   row);
227 static gint             get_row_from_tree_path          (GtkTreeView            *tree_view,
228                                                          GtkTreePath            *path);
229 static GtkTreeViewColumn* get_column                    (GtkTreeView            *tree_view,
230                                                          gint                   in_col);
231 static gint             get_actual_column_number        (GtkTreeView            *tree_view,
232                                                          gint                   visible_column);
233 static gint             get_visible_column_number       (GtkTreeView            *tree_view,
234                                                          gint                   actual_column);
235 static void             iterate_thru_children           (GtkTreeView            *tree_view,
236                                                          GtkTreeModel           *tree_model,
237                                                          GtkTreePath            *tree_path,
238                                                          GtkTreePath            *orig,
239                                                          gint                   *count,
240                                                          gint                   depth);
241 static GtkTreeIter*     return_iter_nth_row             (GtkTreeView            *tree_view,
242                                                          GtkTreeModel           *tree_model,
243                                                          GtkTreeIter            *iter,
244                                                          gint                   increment,
245                                                          gint                   row);
246 static void             free_row_info                   (GArray                 *array,
247                                                          gint                   array_idx,
248                                                          gboolean               shift);
249 static void             clean_cell_info                 (GailTreeView           *tree_view,
250                                                          GList                  *list); 
251 static void             clean_rows                      (GailTreeView           *tree_view);
252 static void             clean_cols                      (GailTreeView           *tree_view,
253                                                          GtkTreeViewColumn      *tv_col);
254 static void             traverse_cells                  (GailTreeView           *tree_view,
255                                                          GtkTreePath            *tree_path,
256                                                          gboolean               set_stale,
257                                                          gboolean               inc_row);
258 static gboolean         update_cell_value               (GailRendererCell       *renderer_cell,
259                                                          GailTreeView           *gailview,
260                                                          gboolean               emit_change_signal);
261 static void             set_cell_visibility             (GtkTreeView            *tree_view,
262                                                          GailCell               *cell,
263                                                          GtkTreeViewColumn      *tv_col,
264                                                          GtkTreePath            *tree_path,
265                                                          gboolean               emit_signal);
266 static gboolean         is_cell_showing                 (GtkTreeView            *tree_view,
267                                                          GdkRectangle           *cell_rect);
268 static void             set_expand_state                (GtkTreeView            *tree_view,
269                                                          GtkTreeModel           *tree_model,
270                                                          GailTreeView           *gailview,
271                                                          GtkTreePath            *tree_path,
272                                                          gboolean               set_on_ancestor);
273 static void             add_cell_actions                (GailCell               *cell,
274                                                          gboolean               editable);
275
276 static void             toggle_cell_expanded            (GailCell               *cell);
277 static void             toggle_cell_toggled             (GailCell               *cell);
278 static void             edit_cell                       (GailCell               *cell);
279 static void             activate_cell                   (GailCell               *cell);
280 static void             cell_destroyed                  (gpointer               data);
281 #if 0
282 static void             cell_info_remove                (GailTreeView           *tree_view, 
283                                                          GailCell               *cell);
284 #endif
285 static void             cell_info_get_index             (GtkTreeView            *tree_view, 
286                                                          GailTreeViewCellInfo   *info,
287                                                          gint                   *index);
288 static void             cell_info_new                   (GailTreeView           *gailview, 
289                                                          GtkTreeModel           *tree_model,
290                                                          GtkTreePath            *path,
291                                                          GtkTreeViewColumn      *tv_col,
292                                                          GailCell               *cell);
293 static GailCell*        find_cell                       (GailTreeView           *gailview, 
294                                                          gint                   index);
295 static void             refresh_cell_index              (GailCell               *cell);
296 static void             get_selected_rows               (GtkTreeModel           *model,
297                                                          GtkTreePath            *path,
298                                                          GtkTreeIter            *iter,
299                                                          gpointer               data);
300 static void             connect_model_signals           (GtkTreeView            *view,
301                                                          GailTreeView           *gailview); 
302 static void             disconnect_model_signals        (GailTreeView           *gailview); 
303 static void             clear_cached_data               (GailTreeView           *view);
304 static gint             get_column_number               (GtkTreeView            *tree_view,
305                                                          GtkTreeViewColumn      *column,
306                                                          gboolean               visible); 
307 static gint             get_focus_index                 (GtkTreeView            *tree_view);
308 static gint             get_index                       (GtkTreeView            *tree_view,
309                                                          GtkTreePath            *path,
310                                                          gint                   actual_column);
311 static void             count_rows                      (GtkTreeModel           *model,
312                                                          GtkTreeIter            *iter,
313                                                          GtkTreePath            *end_path,
314                                                          gint                   *count,
315                                                          gint                   level,
316                                                          gint                   depth);
317
318 static gboolean         get_next_node_with_child_at_depth 
319                                                         (GtkTreeModel           *model,
320                                                          GtkTreeIter            *iter,
321                                                          GtkTreePath            **path,
322                                                          gint                   level,
323                                                          gint                   depth);
324 static gboolean         get_next_node_with_child        (GtkTreeModel           *model,
325                                                          GtkTreePath            *path,
326                                                          GtkTreePath            **return_path);
327 static gboolean         get_tree_path_from_row_index    (GtkTreeModel           *model,
328                                                          gint                   row_index,
329                                                          GtkTreePath            **tree_path);
330 static gint             get_row_count                   (GtkTreeModel           *model);
331 static gboolean         get_path_column_from_index      (GtkTreeView            *tree_view,
332                                                          gint                   index,
333                                                          GtkTreePath            **path,
334                                                          GtkTreeViewColumn      **column);
335 static void             set_cell_expandable             (GailCell               *cell);
336
337 static GailTreeViewCellInfo* find_cell_info             (GailTreeView           *view,
338                                                          GailCell               *cell,
339                                                           GList**                list,
340                                                          gboolean                live_only);
341 static AtkObject *       get_header_from_column         (GtkTreeViewColumn      *tv_col);
342 static gboolean          idle_garbage_collect_cell_data (gpointer data);
343 static gboolean          garbage_collect_cell_data      (gpointer data);
344
345 static GailWidgetClass *parent_class = NULL;
346 static GQuark quark_column_desc_object = 0;
347 static GQuark quark_column_header_object = 0;
348 static gboolean editing = FALSE;
349 static const gchar* hadjustment = "hadjustment";
350 static const gchar* vadjustment = "vadjustment";
351
352 struct _GailTreeViewRowInfo
353 {
354   GtkTreeRowReference *row_ref;
355   gchar *description;
356   AtkObject *header;
357 };
358
359 struct _GailTreeViewCellInfo
360 {
361   GailCell *cell;
362   GtkTreeRowReference *cell_row_ref;
363   GtkTreeViewColumn *cell_col_ref;
364   GailTreeView *view;
365   gboolean in_use;
366 };
367
368 GType
369 gail_tree_view_get_type (void)
370 {
371   static GType type = 0;
372
373   if (!type)
374     {
375       static const GTypeInfo tinfo =
376       {
377         sizeof (GailTreeViewClass),
378         (GBaseInitFunc) NULL, /* base init */
379         (GBaseFinalizeFunc) NULL, /* base finalize */
380         (GClassInitFunc) gail_tree_view_class_init, /* class init */
381         (GClassFinalizeFunc) NULL, /* class finalize */
382         NULL, /* class data */
383         sizeof (GailTreeView), /* instance size */
384         0, /* nb preallocs */
385         (GInstanceInitFunc) NULL, /* instance init */
386         NULL /* value table */
387       };
388
389       static const GInterfaceInfo atk_table_info =
390       {
391         (GInterfaceInitFunc) atk_table_interface_init,
392         (GInterfaceFinalizeFunc) NULL,
393         NULL
394       };
395
396       static const GInterfaceInfo atk_selection_info =
397       {
398         (GInterfaceInitFunc) atk_selection_interface_init,
399         (GInterfaceFinalizeFunc) NULL,
400         NULL
401       };
402
403       static const GInterfaceInfo atk_component_info =
404       {
405         (GInterfaceInitFunc) atk_component_interface_init,
406         (GInterfaceFinalizeFunc) NULL,
407         NULL
408       };
409
410       static const GInterfaceInfo gail_cell_parent_info =
411       {
412         (GInterfaceInitFunc) gail_cell_parent_interface_init,
413         (GInterfaceFinalizeFunc) NULL,
414         NULL
415       };
416
417       type = g_type_register_static (GAIL_TYPE_CONTAINER,
418                                      "GailTreeView", &tinfo, 0);
419
420       g_type_add_interface_static (type, ATK_TYPE_TABLE,
421                                    &atk_table_info);
422       g_type_add_interface_static (type, ATK_TYPE_SELECTION,
423                                    &atk_selection_info);
424       g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
425                                    &atk_component_info);
426       g_type_add_interface_static (type, GAIL_TYPE_CELL_PARENT,
427                                    &gail_cell_parent_info);
428     }
429
430   return type;
431 }
432
433 static void
434 gail_tree_view_class_init (GailTreeViewClass *klass)
435 {
436   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
437   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
438   GtkAccessibleClass *accessible_class;
439   GailWidgetClass *widget_class;
440   GailContainerClass *container_class;
441
442   accessible_class = (GtkAccessibleClass*)klass;
443   widget_class = (GailWidgetClass*)klass;
444   container_class = (GailContainerClass*)klass;
445
446   parent_class = g_type_class_peek_parent (klass);
447
448   class->get_n_children = gail_tree_view_get_n_children;
449   class->ref_child = gail_tree_view_ref_child;
450   class->ref_state_set = gail_tree_view_ref_state_set;
451   class->initialize = gail_tree_view_real_initialize;
452
453   widget_class->notify_gtk = gail_tree_view_real_notify_gtk;
454
455   accessible_class->connect_widget_destroyed = gail_tree_view_connect_widget_destroyed;
456
457   /*
458    * The children of a GtkTreeView are the buttons at the top of the columns
459    * we do not represent these as children so we do not want to report
460    * children added or deleted when these changed.
461    */
462   container_class->add_gtk = NULL;
463   container_class->remove_gtk = NULL;
464
465   gobject_class->finalize = gail_tree_view_finalize;
466
467   quark_column_desc_object = g_quark_from_static_string ("gtk-column-object");
468   quark_column_header_object = g_quark_from_static_string ("gtk-header-object");
469 }
470
471 static void
472 gail_tree_view_real_initialize (AtkObject *obj,
473                                 gpointer  data)
474 {
475   GailTreeView *view;
476   GtkTreeView *tree_view;
477   GtkTreeModel *tree_model; 
478   GtkAdjustment *adj;
479   GList *tv_cols, *tmp_list;
480   GtkWidget *widget;
481
482   ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
483
484   view = GAIL_TREE_VIEW (obj);
485   view->caption = NULL;
486   view->summary = NULL;
487   view->row_data = NULL;
488   view->col_data = NULL;
489   view->cell_data = NULL;
490   view->focus_cell = NULL;
491   view->old_hadj = NULL;
492   view->old_vadj = NULL;
493   view->idle_expand_id = 0;
494   view->idle_expand_path = NULL;
495
496   view->n_children_deleted = 0;
497
498   widget = GTK_WIDGET (data);
499   g_signal_connect_after (widget,
500                           "row-collapsed",
501                           G_CALLBACK (gail_tree_view_collapse_row_gtk),
502                           NULL);
503   g_signal_connect (widget,
504                     "row-expanded",
505                     G_CALLBACK (gail_tree_view_expand_row_gtk),
506                     NULL);
507   g_signal_connect (widget,
508                     "size-allocate",
509                     G_CALLBACK (gail_tree_view_size_allocate_gtk),
510                     NULL);
511
512   tree_view = GTK_TREE_VIEW (widget);
513   tree_model = gtk_tree_view_get_model (tree_view);
514
515   /* Set up signal handling */
516
517   g_signal_connect_data (gtk_tree_view_get_selection (tree_view),
518                          "changed",
519                          (GCallback) gail_tree_view_changed_gtk,
520                          obj, NULL, 0);
521
522   g_signal_connect_data (tree_view, "columns-changed",
523     (GCallback) columns_changed, NULL, NULL, 0);
524   g_signal_connect_data (tree_view, "cursor-changed",
525     (GCallback) cursor_changed, NULL, NULL, 0);
526
527   view->tree_model = tree_model;
528   if (tree_model)
529     {
530       g_object_add_weak_pointer (G_OBJECT (view->tree_model), (gpointer *)&view->tree_model);
531       connect_model_signals (tree_view, view);
532
533       if (GTK_IS_TREE_STORE (tree_model))
534         obj->role = ATK_ROLE_TREE_TABLE;
535       else
536         obj->role = ATK_ROLE_TABLE;
537     }
538   else
539     {
540       obj->role = ATK_ROLE_UNKNOWN;
541     }
542
543   /* adjustment callbacks */
544
545   g_object_get (tree_view, hadjustment, &adj, NULL);
546   view->old_hadj = adj;
547   g_object_add_weak_pointer (G_OBJECT (view->old_hadj), (gpointer *)&view->old_hadj);
548   g_signal_connect (adj, 
549                     "value_changed",
550                     G_CALLBACK (adjustment_changed),
551                     tree_view);
552
553   g_object_get (tree_view, vadjustment, &adj, NULL);
554   view->old_vadj = adj;
555   g_object_add_weak_pointer (G_OBJECT (view->old_vadj), (gpointer *)&view->old_vadj);
556   g_signal_connect (adj, 
557                     "value_changed",
558                     G_CALLBACK (adjustment_changed),
559                     tree_view);
560   g_signal_connect_after (widget,
561                           "set_scroll_adjustments",
562                           G_CALLBACK (gail_tree_view_set_scroll_adjustments),
563                           NULL);
564
565   view->col_data = g_array_sized_new (FALSE, TRUE, 
566                                       sizeof(GtkTreeViewColumn *), 0);
567
568   tv_cols = gtk_tree_view_get_columns (tree_view);
569
570   for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
571     {
572       g_signal_connect_data (tmp_list->data, "notify::visible",
573        (GCallback)column_visibility_changed, 
574         tree_view, NULL, FALSE);
575       g_signal_connect_data (tmp_list->data, "destroy",
576        (GCallback)column_destroy, 
577         NULL, NULL, FALSE);
578       g_array_append_val (view->col_data, tmp_list->data);
579     }
580
581   gtk_tree_view_set_destroy_count_func (tree_view, 
582                                         destroy_count_func,
583                                         NULL, NULL);
584   g_list_free (tv_cols);
585 }
586
587 static void
588 gail_tree_view_real_notify_gtk (GObject             *obj,
589                                 GParamSpec          *pspec)
590 {
591   GtkWidget *widget;
592   AtkObject* atk_obj;
593   GtkTreeView *tree_view;
594   GailTreeView *gailview;
595   GtkAdjustment *adj;
596
597   widget = GTK_WIDGET (obj);
598   atk_obj = gtk_widget_get_accessible (widget);
599   tree_view = GTK_TREE_VIEW (widget);
600   gailview = GAIL_TREE_VIEW (atk_obj);
601
602   if (strcmp (pspec->name, "model") == 0)
603     {
604       GtkTreeModel *tree_model;
605       AtkRole role;
606
607       tree_model = gtk_tree_view_get_model (tree_view);
608       if (gailview->tree_model)
609         disconnect_model_signals (gailview);
610       clear_cached_data (gailview);
611       gailview->tree_model = tree_model;
612       /*
613        * if there is no model the GtkTreeView is probably being destroyed
614        */
615       if (tree_model)
616         {
617           g_object_add_weak_pointer (G_OBJECT (gailview->tree_model), (gpointer *)&gailview->tree_model);
618           connect_model_signals (tree_view, gailview);
619
620           if (GTK_IS_TREE_STORE (tree_model))
621             role = ATK_ROLE_TREE_TABLE;
622           else
623             role = ATK_ROLE_TABLE;
624         }
625       else
626         {
627           role = ATK_ROLE_UNKNOWN;
628         }
629       atk_object_set_role (atk_obj, role);
630       g_object_freeze_notify (G_OBJECT (atk_obj));
631       g_signal_emit_by_name (atk_obj, "model_changed");
632       g_signal_emit_by_name (atk_obj, "visible_data_changed");
633       g_object_thaw_notify (G_OBJECT (atk_obj));
634     }
635   else if (strcmp (pspec->name, hadjustment) == 0)
636     {
637       g_object_get (tree_view, hadjustment, &adj, NULL);
638       g_signal_handlers_disconnect_by_func (gailview->old_hadj, 
639                                            (gpointer) adjustment_changed,
640                                            widget);
641       gailview->old_hadj = adj;
642       g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
643       g_signal_connect (adj, 
644                         "value_changed",
645                         G_CALLBACK (adjustment_changed),
646                         tree_view);
647     }
648   else if (strcmp (pspec->name, vadjustment) == 0)
649     {
650       g_object_get (tree_view, vadjustment, &adj, NULL);
651       g_signal_handlers_disconnect_by_func (gailview->old_vadj, 
652                                            (gpointer) adjustment_changed,
653                                            widget);
654       gailview->old_vadj = adj;
655       g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_vadj);
656       g_signal_connect (adj, 
657                         "value_changed",
658                         G_CALLBACK (adjustment_changed),
659                         tree_view);
660     }
661   else
662     parent_class->notify_gtk (obj, pspec);
663 }
664
665 AtkObject*
666 gail_tree_view_new (GtkWidget *widget)
667 {
668   GObject *object;
669   AtkObject *accessible;
670
671   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), NULL);
672
673   object = g_object_new (GAIL_TYPE_TREE_VIEW, NULL);
674
675   accessible = ATK_OBJECT (object);
676   atk_object_initialize (accessible, widget);
677
678   return accessible;
679 }
680
681 static void
682 gail_tree_view_finalize (GObject            *object)
683 {
684   GailTreeView *view = GAIL_TREE_VIEW (object);
685
686   clear_cached_data (view);
687
688   /* remove any idle handlers still pending */
689   if (view->idle_garbage_collect_id)
690     g_source_remove (view->idle_garbage_collect_id);
691   if (view->idle_cursor_changed_id)
692     g_source_remove (view->idle_cursor_changed_id);
693   if (view->idle_expand_id)
694     g_source_remove (view->idle_expand_id);
695
696   if (view->caption)
697     g_object_unref (view->caption);
698   if (view->summary)
699     g_object_unref (view->summary);
700
701   if (view->tree_model)
702     disconnect_model_signals (view);
703
704   if (view->col_data)
705     {
706       GArray *array = view->col_data;
707
708      /*
709       * No need to free the contents of the array since it
710       * just contains pointers to the GtkTreeViewColumn
711       * objects that are in the GtkTreeView.
712       */
713       g_array_free (array, TRUE);
714     }
715
716   G_OBJECT_CLASS (parent_class)->finalize (object);
717 }
718
719 static void
720 gail_tree_view_connect_widget_destroyed (GtkAccessible *accessible)
721 {
722   if (accessible->widget)
723     {
724       g_signal_connect_after (accessible->widget,
725                               "destroy",
726                               G_CALLBACK (gail_tree_view_destroyed),
727                               accessible);
728     }
729   GTK_ACCESSIBLE_CLASS (parent_class)->connect_widget_destroyed (accessible);
730 }
731
732 static void
733 gail_tree_view_destroyed (GtkWidget *widget,
734                           GtkAccessible *accessible)
735 {
736   GtkAdjustment *adj;
737   GailTreeView *gailview;
738
739   gail_return_if_fail (GTK_IS_TREE_VIEW (widget));
740
741   gailview = GAIL_TREE_VIEW (accessible);
742   adj = gailview->old_hadj;
743   if (adj)
744     g_signal_handlers_disconnect_by_func (adj, 
745                                           (gpointer) adjustment_changed,
746                                           widget);
747   adj = gailview->old_vadj;
748   if (adj)
749     g_signal_handlers_disconnect_by_func (adj, 
750                                           (gpointer) adjustment_changed,
751                                           widget);
752   if (gailview->tree_model)
753     {
754       disconnect_model_signals (gailview);
755       gailview->tree_model = NULL;
756     }
757   if (gailview->focus_cell)
758     {
759       g_object_unref (gailview->focus_cell);
760       gailview->focus_cell = NULL;
761     }
762   if (gailview->idle_expand_id) 
763     {
764       g_source_remove (gailview->idle_expand_id);
765       gailview->idle_expand_id = 0;
766     }
767 }
768
769 gint 
770 get_focus_index (GtkTreeView *tree_view)
771 {
772   GtkTreePath *focus_path;
773   GtkTreeViewColumn *focus_column;
774   gint index;
775
776   gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
777   if (focus_path && focus_column)
778     {
779
780       index = get_index (tree_view, focus_path,
781                          get_column_number (tree_view, focus_column, FALSE));
782     }
783   else
784     index = -1;
785
786   if (focus_path)
787     gtk_tree_path_free (focus_path);
788
789   return index;
790 }
791
792 AtkObject *
793 gail_tree_view_ref_focus_cell (GtkTreeView *tree_view)
794 {
795   /*
796    * This function returns a reference to the accessible object for the cell
797    * in the treeview which has focus, if a cell has focus.
798    */
799   AtkObject *focus_cell = NULL;
800   AtkObject *atk_obj;
801   gint focus_index;
802
803   focus_index = get_focus_index (tree_view);
804   if (focus_index >= 0)
805     {
806       atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
807       focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
808     }
809
810   return focus_cell;
811 }
812
813 /* atkobject.h */
814
815 static gint
816 gail_tree_view_get_n_children (AtkObject *obj)
817 {
818   GtkWidget *widget;
819   GtkTreeView *tree_view;
820   GtkTreeModel *tree_model;
821   gint n_rows, n_cols;
822
823   gail_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), 0);
824
825   widget = GTK_ACCESSIBLE (obj)->widget;
826   if (widget == NULL)
827     /*
828      * State is defunct
829      */
830     return 0;
831
832   tree_view = GTK_TREE_VIEW (widget);
833   tree_model = gtk_tree_view_get_model (tree_view);
834
835   /*
836    * We get the total number of rows including those which are collapsed
837    */
838   n_rows = get_row_count (tree_model);
839   /*
840    * We get the total number of columns including those which are not visible
841    */
842   n_cols = get_n_actual_columns (tree_view);
843   return (n_rows * n_cols);
844 }
845
846 static AtkObject*
847 gail_tree_view_ref_child (AtkObject *obj, 
848                           gint      i)
849 {
850   GtkWidget *widget;
851   GailTreeView *gailview;
852   GailCell *cell;
853   GtkTreeView *tree_view;
854   GtkTreeModel *tree_model; 
855   GtkCellRenderer *renderer;
856   GtkTreeIter iter;
857   GtkTreeViewColumn *tv_col;
858   GtkTreeSelection *selection;
859   GtkTreePath *path;
860   AtkRegistry *default_registry;
861   AtkObjectFactory *factory;
862   AtkObject *child;
863   AtkObject *parent;
864   GtkTreeViewColumn *expander_tv;
865   GList *renderer_list;
866   GList *l;
867   GailContainerCell *container = NULL;
868   GailRendererCell *renderer_cell;
869   gboolean is_expander, is_expanded, retval;
870   gboolean editable = FALSE;
871   gint focus_index;
872
873   g_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), NULL);
874   g_return_val_if_fail (i >= 0, NULL);
875
876   widget = GTK_ACCESSIBLE (obj)->widget;
877   if (widget == NULL)
878     /*
879      * State is defunct
880      */
881     return NULL;
882
883   if (i >= gail_tree_view_get_n_children (obj))
884     return NULL;
885
886   tree_view = GTK_TREE_VIEW (widget);
887   if (i < get_n_actual_columns (tree_view))
888     {
889       tv_col = gtk_tree_view_get_column (tree_view, i);
890       child = get_header_from_column (tv_col);
891       if (child)
892         g_object_ref (child);
893       return child;
894     }
895
896   gailview = GAIL_TREE_VIEW (obj);
897   /*
898    * Check whether the child is cached
899    */
900   cell = find_cell (gailview, i);
901   if (cell)
902     {
903       g_object_ref (cell);
904       return ATK_OBJECT (cell);
905     }
906
907   if (gailview->focus_cell == NULL)
908       focus_index = get_focus_index (tree_view);
909   else
910       focus_index = -1;
911   /*
912    * Find the TreePath and GtkTreeViewColumn for the index
913    */
914   if (!get_path_column_from_index (tree_view, i, &path, &tv_col))
915     return NULL;
916  
917   tree_model = gtk_tree_view_get_model (tree_view);
918   retval = gtk_tree_model_get_iter (tree_model, &iter, path);
919   gail_return_val_if_fail (retval, NULL);
920
921   expander_tv = gtk_tree_view_get_expander_column (tree_view);
922   is_expander = FALSE;
923   is_expanded = FALSE;
924   if (gtk_tree_model_iter_has_child (tree_model, &iter))
925     {
926       if (expander_tv == tv_col)
927         {
928           is_expander = TRUE;
929           is_expanded = gtk_tree_view_row_expanded (tree_view, path);
930         }
931     } 
932   gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter, 
933                                            is_expander, is_expanded);
934
935   renderer_list = gtk_tree_view_column_get_cell_renderers (tv_col);
936
937   /* If there are more than one renderer in the list, make a container */
938
939   if (renderer_list && renderer_list->next)
940     {
941       GailCell *container_cell;
942
943       container = gail_container_cell_new ();
944       gail_return_val_if_fail (container, NULL);
945
946       container_cell = GAIL_CELL (container);
947       gail_cell_init (container_cell,
948                       widget, ATK_OBJECT (gailview), 
949                       i);
950       /*
951        * The GailTreeViewCellInfo structure for the container will be before
952        * the ones for the cells so that the first one we find for a position
953        * will be for the container
954        */
955       cell_info_new (gailview, tree_model, path, tv_col, container_cell);
956       container_cell->refresh_index = refresh_cell_index;
957       parent = ATK_OBJECT (container);
958     }
959   else
960     parent = ATK_OBJECT (gailview);
961
962   child = NULL;
963
964   /*
965    * Now we make a fake cell_renderer if there is no cell in renderer_list
966    */
967
968   if (renderer_list == NULL)
969   {
970     GtkCellRenderer *fake_renderer;
971     fake_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
972     default_registry = atk_get_default_registry ();
973     factory = atk_registry_get_factory (default_registry,
974                                         GTK_OBJECT_TYPE (fake_renderer));
975     child = atk_object_factory_create_accessible (factory,
976                                                   G_OBJECT (fake_renderer));
977     gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
978     cell = GAIL_CELL (child);
979     renderer_cell = GAIL_RENDERER_CELL (child);
980     renderer_cell->renderer = fake_renderer;
981
982     /* Create the GailTreeViewCellInfo structure for this cell */
983     cell_info_new (gailview, tree_model, path, tv_col, cell);
984
985     gail_cell_init (cell,
986                     widget, parent, 
987                     i);
988
989     cell->refresh_index = refresh_cell_index;
990
991     /* set state if it is expandable */
992     if (is_expander)
993     {
994       set_cell_expandable (cell);
995       if (is_expanded)
996         gail_cell_add_state (cell, 
997                              ATK_STATE_EXPANDED,
998                              FALSE);
999     }
1000   } else {
1001     for (l = renderer_list; l; l = l->next)
1002       {
1003         renderer = GTK_CELL_RENDERER (l->data);
1004
1005         if (GTK_IS_CELL_RENDERER_TEXT (renderer))
1006           g_object_get (G_OBJECT (renderer), "editable", &editable, NULL);
1007
1008         default_registry = atk_get_default_registry ();
1009         factory = atk_registry_get_factory (default_registry,
1010                                             GTK_OBJECT_TYPE (renderer));
1011         child = atk_object_factory_create_accessible (factory,
1012                                                       G_OBJECT (renderer));
1013         gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
1014         cell = GAIL_CELL (child);
1015         renderer_cell = GAIL_RENDERER_CELL (child);
1016
1017         /* Create the GailTreeViewCellInfo structure for this cell */
1018         cell_info_new (gailview, tree_model, path, tv_col, cell);
1019
1020         gail_cell_init (cell,
1021                         widget, parent, 
1022                         i);
1023
1024         if (container)
1025           gail_container_cell_add_child (container, cell);
1026         else
1027           cell->refresh_index = refresh_cell_index;
1028
1029         update_cell_value (renderer_cell, gailview, FALSE);
1030         /* Add the actions appropriate for this cell */
1031         add_cell_actions (cell, editable);
1032
1033         /* set state if it is expandable */
1034         if (is_expander)
1035           {
1036             set_cell_expandable (cell);
1037             if (is_expanded)
1038               gail_cell_add_state (cell, 
1039                                    ATK_STATE_EXPANDED,
1040                                    FALSE);
1041           }
1042         /*
1043          * If the column is visible, sets the cell's state
1044          */
1045         if (gtk_tree_view_column_get_visible (tv_col))
1046           set_cell_visibility (tree_view, cell, tv_col, path, FALSE);
1047         /*
1048          * If the row is selected, all cells on the row are selected
1049          */
1050         selection = gtk_tree_view_get_selection (tree_view);
1051
1052         if (gtk_tree_selection_path_is_selected (selection, path))
1053           gail_cell_add_state (cell, ATK_STATE_SELECTED, FALSE);
1054
1055         gail_cell_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
1056         if (focus_index == i)
1057           {
1058             gailview->focus_cell = g_object_ref (cell);
1059             gail_cell_add_state (cell, ATK_STATE_FOCUSED, FALSE);
1060           }
1061       }
1062     g_list_free (renderer_list); 
1063     if (container)
1064       child =  ATK_OBJECT (container);
1065   } 
1066
1067   if (expander_tv == tv_col)
1068     {
1069       AtkRelationSet *relation_set;
1070       AtkObject *accessible_array[1];
1071       AtkRelation* relation;
1072       AtkObject *parent_node;
1073
1074       relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
1075
1076       gtk_tree_path_up (path);
1077       if (gtk_tree_path_get_depth (path) == 0)
1078         parent_node = obj;
1079       else
1080         {
1081           gint parent_index;
1082           gint n_columns;
1083
1084           n_columns = get_n_actual_columns (tree_view);
1085           parent_index = get_index (tree_view, path, i % n_columns);
1086           parent_node = atk_object_ref_accessible_child (obj, parent_index);
1087         }
1088       accessible_array[0] = parent_node;
1089       relation = atk_relation_new (accessible_array, 1,
1090                                    ATK_RELATION_NODE_CHILD_OF);
1091       atk_relation_set_add (relation_set, relation);
1092       g_object_unref (relation);
1093       g_object_unref (relation_set);
1094     }
1095   gtk_tree_path_free (path);
1096
1097   /*
1098    * We do not increase the reference count here; when g_object_unref() is 
1099    * called for the cell then cell_destroyed() is called and
1100    * this removes the cell from the cache.
1101    */
1102   return child;
1103 }
1104
1105 static AtkStateSet*
1106 gail_tree_view_ref_state_set (AtkObject *obj)
1107 {
1108   AtkStateSet *state_set;
1109   GtkWidget *widget;
1110
1111   state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
1112   widget = GTK_ACCESSIBLE (obj)->widget;
1113
1114   if (widget != NULL)
1115     atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
1116
1117   return state_set;
1118 }
1119
1120 /* atkcomponent.h */
1121
1122 static void
1123 atk_component_interface_init (AtkComponentIface *iface)
1124 {
1125   g_return_if_fail (iface != NULL);
1126
1127   iface->ref_accessible_at_point = gail_tree_view_ref_accessible_at_point;
1128 }
1129
1130 static AtkObject*
1131 gail_tree_view_ref_accessible_at_point (AtkComponent           *component,
1132                                         gint                   x,
1133                                         gint                   y,
1134                                         AtkCoordType           coord_type)
1135 {
1136   GtkWidget *widget;
1137   GtkTreeView *tree_view;
1138   GtkTreePath *path;
1139   GtkTreeViewColumn *tv_column;
1140   gint x_pos, y_pos;
1141   gboolean ret_val;
1142
1143   widget = GTK_ACCESSIBLE (component)->widget;
1144   if (widget == NULL)
1145     /* State is defunct */
1146     return NULL;
1147
1148   tree_view = GTK_TREE_VIEW (widget);
1149
1150   atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
1151   ret_val = gtk_tree_view_get_path_at_pos (tree_view, 
1152                                            x - x_pos, y - y_pos, 
1153                                            &path, &tv_column, NULL, NULL);
1154   if (ret_val)
1155     {
1156       gint index, column;
1157
1158       column = get_column_number (tree_view, tv_column, FALSE);
1159       index = get_index (tree_view, path, column);
1160       gtk_tree_path_free (path);
1161
1162       return gail_tree_view_ref_child (ATK_OBJECT (component), index);
1163     } 
1164   else
1165     {
1166       g_warning ("gail_tree_view_ref_accessible_at_point: gtk_tree_view_get_path_at_pos () failed\n");
1167     }
1168   return NULL;
1169 }
1170            
1171 /* atktable.h */
1172
1173 static void 
1174 atk_table_interface_init (AtkTableIface *iface)
1175 {
1176   g_return_if_fail (iface != NULL);
1177   iface->ref_at = gail_tree_view_table_ref_at;
1178   iface->get_n_rows = gail_tree_view_get_n_rows;        
1179   iface->get_n_columns = gail_tree_view_get_n_columns;  
1180   iface->get_index_at = gail_tree_view_get_index_at;    
1181   iface->get_column_at_index = gail_tree_view_get_column_at_index;      
1182   iface->get_row_at_index = gail_tree_view_get_row_at_index;    
1183   iface->is_row_selected = gail_tree_view_is_row_selected;
1184   iface->is_selected = gail_tree_view_is_selected;
1185   iface->get_selected_rows = gail_tree_view_get_selected_rows;
1186   iface->add_row_selection = gail_tree_view_add_row_selection;
1187   iface->remove_row_selection = gail_tree_view_remove_row_selection;
1188   iface->get_column_extent_at = NULL;
1189   iface->get_row_extent_at = NULL;
1190   iface->get_row_header = gail_tree_view_get_row_header;
1191   iface->set_row_header = gail_tree_view_set_row_header;
1192   iface->get_column_header = gail_tree_view_get_column_header;
1193   iface->set_column_header = gail_tree_view_set_column_header;
1194   iface->get_caption = gail_tree_view_get_caption;
1195   iface->set_caption = gail_tree_view_set_caption;
1196   iface->get_summary = gail_tree_view_get_summary;
1197   iface->set_summary = gail_tree_view_set_summary;
1198   iface->get_row_description = gail_tree_view_get_row_description;
1199   iface->set_row_description = gail_tree_view_set_row_description;
1200   iface->get_column_description = gail_tree_view_get_column_description;
1201   iface->set_column_description = gail_tree_view_set_column_description;
1202 }
1203
1204 static gint
1205 gail_tree_view_get_index_at (AtkTable *table,
1206                              gint     row,
1207                              gint     column)
1208 {
1209   GtkWidget *widget;
1210   GtkTreeView *tree_view;
1211   gint actual_column;
1212   gint n_cols, n_rows;
1213   GtkTreeIter iter;
1214   GtkTreePath *path;
1215   gint index;
1216
1217   n_cols = atk_table_get_n_columns (table);
1218   n_rows = atk_table_get_n_rows (table);
1219
1220   if (row >= n_rows ||
1221       column >= n_cols)
1222     return -1;
1223
1224   widget = GTK_ACCESSIBLE (table)->widget;
1225   if (widget == NULL)
1226     /* State is defunct */
1227     return -1;
1228
1229   tree_view = GTK_TREE_VIEW (widget);
1230   actual_column = get_actual_column_number (tree_view, column);
1231
1232   set_iter_nth_row (tree_view, &iter, row);
1233   path = gtk_tree_model_get_path (gtk_tree_view_get_model (tree_view), &iter);
1234
1235   index = get_index (tree_view, path, actual_column);
1236   gtk_tree_path_free (path);
1237
1238   return index;
1239 }
1240
1241 static gint
1242 gail_tree_view_get_column_at_index (AtkTable *table,
1243                                     gint     index)
1244 {
1245   GtkWidget *widget;
1246   GtkTreeView *tree_view;
1247   gint n_columns;
1248
1249   widget = GTK_ACCESSIBLE (table)->widget;
1250   if (widget == NULL)
1251     /* State is defunct */
1252     return -1;
1253
1254   tree_view = GTK_TREE_VIEW (widget);
1255   n_columns = get_n_actual_columns (tree_view);
1256
1257   if (n_columns == 0)
1258     return 0;
1259   index = index % n_columns;
1260
1261   return get_visible_column_number (tree_view, index);
1262 }
1263
1264 static gint
1265 gail_tree_view_get_row_at_index (AtkTable *table,
1266                                  gint     index)
1267 {
1268   GtkWidget *widget;
1269   GtkTreeView *tree_view;
1270   GtkTreePath *path;
1271
1272   widget = GTK_ACCESSIBLE (table)->widget;
1273   if (widget == NULL)
1274     /* State is defunct */
1275     return -1;
1276
1277   tree_view = GTK_TREE_VIEW (widget);
1278   if (get_path_column_from_index (tree_view, index, &path, NULL))
1279     {
1280       gint row = get_row_from_tree_path (tree_view, path);
1281       gtk_tree_path_free (path);
1282       return row;
1283     }
1284   else
1285     return -1;
1286 }
1287
1288 static AtkObject* 
1289 gail_tree_view_table_ref_at (AtkTable *table,
1290                              gint     row, 
1291                              gint     column)
1292 {
1293   gint index;
1294
1295   index = gail_tree_view_get_index_at (table, row, column);
1296   if (index == -1)
1297     return NULL;
1298   
1299   return gail_tree_view_ref_child (ATK_OBJECT (table), index);
1300 }
1301
1302 static gint 
1303 gail_tree_view_get_n_rows (AtkTable *table)
1304 {
1305   GtkWidget *widget;
1306   GtkTreeView *tree_view;
1307   GtkTreeModel *tree_model;
1308   gint n_rows;
1309
1310   widget = GTK_ACCESSIBLE (table)->widget;
1311   if (widget == NULL)
1312     /* State is defunct */
1313     return 0;
1314
1315   tree_view = GTK_TREE_VIEW (widget);
1316   tree_model = gtk_tree_view_get_model (tree_view);
1317
1318   if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1319    /* 
1320     * If working with a LIST store, then this is a faster way
1321     * to get the number of rows.
1322     */
1323     n_rows = gtk_tree_model_iter_n_children (tree_model, NULL);
1324   else
1325     {
1326       GtkTreePath *root_tree;
1327
1328       n_rows = 0;
1329       root_tree = gtk_tree_path_new_root ();
1330       iterate_thru_children (tree_view, tree_model,
1331                              root_tree, NULL, &n_rows, 0);
1332       g_free (root_tree);
1333     }
1334
1335   return n_rows;
1336 }
1337
1338 /*
1339  * The function get_n_actual_columns returns the number of columns in the 
1340  * GtkTreeView. i.e. it include both visible and non-visible columns.
1341  */
1342 static gint 
1343 get_n_actual_columns (GtkTreeView *tree_view)
1344 {
1345   GList *columns;
1346   gint n_cols;
1347
1348   columns = gtk_tree_view_get_columns (tree_view);
1349   n_cols = g_list_length (columns);
1350   g_list_free (columns);
1351   return n_cols;
1352 }
1353
1354 static gint 
1355 gail_tree_view_get_n_columns (AtkTable *table)
1356 {
1357   GtkWidget *widget;
1358   GtkTreeView *tree_view;
1359   GtkTreeViewColumn *tv_col;
1360   gint n_cols = 0;
1361   gint i = 0;
1362
1363   widget = GTK_ACCESSIBLE (table)->widget;
1364   if (widget == NULL)
1365     /* State is defunct */
1366     return 0;
1367
1368   tree_view = GTK_TREE_VIEW (widget);
1369   tv_col = gtk_tree_view_get_column (tree_view, i);
1370
1371   while (tv_col != NULL) 
1372     {
1373       if (gtk_tree_view_column_get_visible (tv_col)) 
1374         n_cols++;
1375
1376       i++;
1377       tv_col = gtk_tree_view_get_column (tree_view, i);
1378     }
1379
1380   return n_cols;
1381 }
1382
1383 static gboolean 
1384 gail_tree_view_is_row_selected (AtkTable *table,
1385                                 gint     row)
1386 {
1387   GtkWidget *widget;
1388   GtkTreeView *tree_view;
1389   GtkTreeSelection *selection;
1390   GtkTreeIter iter;
1391
1392   widget = GTK_ACCESSIBLE (table)->widget;
1393   if (widget == NULL)
1394     /* State is defunct */
1395     return FALSE;
1396
1397   if (row < 0)
1398     return FALSE;
1399
1400   tree_view = GTK_TREE_VIEW (widget);
1401
1402   selection = gtk_tree_view_get_selection (tree_view);
1403
1404   set_iter_nth_row (tree_view, &iter, row);
1405
1406   return gtk_tree_selection_iter_is_selected (selection, &iter);
1407 }
1408
1409 static gboolean 
1410 gail_tree_view_is_selected (AtkTable *table, 
1411                             gint     row, 
1412                             gint     column)
1413 {
1414   return gail_tree_view_is_row_selected (table, row);
1415 }
1416
1417 static gint 
1418 gail_tree_view_get_selected_rows (AtkTable *table,
1419                                   gint     **rows_selected)
1420 {
1421   GtkWidget *widget;
1422   GtkTreeView *tree_view;
1423   GtkTreeModel *tree_model;
1424   GtkTreeIter iter;
1425   GtkTreeSelection *selection;
1426   GtkTreePath *tree_path;
1427   gint ret_val = 0;
1428
1429   widget = GTK_ACCESSIBLE (table)->widget;
1430   if (widget == NULL)
1431     /* State is defunct */
1432     return 0;
1433
1434   tree_view = GTK_TREE_VIEW (widget);
1435
1436   selection = gtk_tree_view_get_selection (tree_view);
1437
1438   switch (selection->type)
1439     {
1440     case GTK_SELECTION_SINGLE:
1441     case GTK_SELECTION_BROWSE:
1442       if (gtk_tree_selection_get_selected (selection, &tree_model, &iter))
1443         {
1444           gint row;
1445
1446           if (rows_selected)
1447             {
1448               *rows_selected = (gint *)g_malloc (sizeof(gint));
1449               tree_path = gtk_tree_model_get_path (tree_model, &iter);
1450               row = get_row_from_tree_path (tree_view, tree_path);
1451               gtk_tree_path_free (tree_path);
1452
1453               /* shouldn't ever happen */
1454               g_return_val_if_fail (row != -1, 0);
1455
1456               *rows_selected[0] = row;
1457             }
1458           ret_val = 1;
1459         }
1460       break;
1461     case GTK_SELECTION_MULTIPLE:
1462       {
1463         GPtrArray *array = g_ptr_array_new();
1464
1465         gtk_tree_selection_selected_foreach (selection,
1466                                              get_selected_rows,
1467                                              array);
1468         ret_val = array->len;
1469
1470         if (rows_selected && ret_val)
1471           {
1472             gint i;
1473             *rows_selected = (gint *) g_malloc (ret_val * sizeof (gint));
1474
1475             for (i = 0; i < ret_val; i++)
1476               {
1477                 gint row;
1478
1479                 tree_path = (GtkTreePath *) g_ptr_array_index (array, i);
1480                 row = get_row_from_tree_path (tree_view, tree_path);
1481                 gtk_tree_path_free (tree_path);
1482                 (*rows_selected)[i] = row;
1483               }
1484           }
1485         g_ptr_array_free (array, FALSE);
1486       }
1487       break;
1488     case GTK_SELECTION_NONE:
1489       break; 
1490     }
1491   return ret_val;
1492 }
1493
1494 static gboolean 
1495 gail_tree_view_add_row_selection (AtkTable *table, 
1496                                   gint     row)
1497 {
1498   GtkWidget *widget;
1499   GtkTreeView *tree_view;
1500   GtkTreeModel *tree_model;
1501   GtkTreeSelection *selection;
1502   GtkTreePath *tree_path;
1503   GtkTreeIter iter_to_row;
1504
1505   widget = GTK_ACCESSIBLE (table)->widget;
1506   if (widget == NULL)
1507     /* State is defunct */
1508     return FALSE;
1509   
1510   if (!gail_tree_view_is_row_selected (table, row))
1511     {
1512       tree_view = GTK_TREE_VIEW (widget);
1513       tree_model = gtk_tree_view_get_model (tree_view);
1514       selection = gtk_tree_view_get_selection (tree_view);
1515
1516       if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1517         {
1518           tree_path = gtk_tree_path_new ();
1519           gtk_tree_path_append_index (tree_path, row);
1520           gtk_tree_selection_select_path (selection,tree_path);
1521           gtk_tree_path_free (tree_path);
1522         }
1523       else
1524         { 
1525           set_iter_nth_row (tree_view, &iter_to_row, row);
1526           if (&iter_to_row != NULL)
1527             gtk_tree_selection_select_iter (selection, &iter_to_row);
1528           else
1529             return FALSE;
1530         }
1531     }
1532
1533   return gail_tree_view_is_row_selected (table, row);
1534 }
1535
1536 static gboolean 
1537 gail_tree_view_remove_row_selection (AtkTable *table, 
1538                                      gint     row)
1539 {
1540   GtkWidget *widget;
1541   GtkTreeView *tree_view;
1542   GtkTreeSelection *selection;
1543
1544   widget = GTK_ACCESSIBLE (table)->widget;
1545   if (widget == NULL)
1546     /* State is defunct */
1547     return FALSE;
1548
1549   tree_view = GTK_TREE_VIEW (widget);
1550
1551   selection = gtk_tree_view_get_selection (tree_view);
1552
1553   if (gail_tree_view_is_row_selected (table, row)) 
1554     {
1555       gtk_tree_selection_unselect_all (selection);
1556       return TRUE;
1557     }
1558   else return FALSE;
1559 }
1560
1561 static AtkObject* 
1562 gail_tree_view_get_row_header (AtkTable *table, 
1563                                gint     row)
1564 {
1565   GailTreeViewRowInfo *row_info;
1566
1567   row_info = get_row_info (table, row);
1568   if (row_info)
1569     return row_info->header;
1570   else
1571     return NULL;
1572 }
1573
1574 static void
1575 gail_tree_view_set_row_header (AtkTable  *table, 
1576                                gint      row, 
1577                                AtkObject *header)
1578 {
1579   set_row_data (table, row, header, NULL, TRUE);
1580 }
1581
1582 static AtkObject* 
1583 gail_tree_view_get_column_header (AtkTable *table, 
1584                                   gint     in_col)
1585 {
1586   GtkWidget *widget;
1587   GtkTreeView *tree_view;
1588   GtkTreeViewColumn *tv_col;
1589
1590   widget = GTK_ACCESSIBLE (table)->widget;
1591   if (widget == NULL)
1592     /* State is defunct */
1593     return NULL;
1594
1595   tree_view = GTK_TREE_VIEW (widget);
1596   tv_col = get_column (tree_view, in_col);
1597   return get_header_from_column (tv_col);
1598 }
1599
1600 static void
1601 gail_tree_view_set_column_header (AtkTable  *table, 
1602                                   gint      in_col,
1603                                   AtkObject *header)
1604 {
1605   GtkWidget *widget;
1606   GtkTreeView *tree_view;
1607   GtkTreeViewColumn *tv_col;
1608   AtkObject *rc;
1609   AtkPropertyValues values = { NULL };
1610
1611   widget = GTK_ACCESSIBLE (table)->widget;
1612   if (widget == NULL)
1613     /* State is defunct */
1614     return;
1615
1616   tree_view = GTK_TREE_VIEW (widget);
1617   tv_col = get_column (tree_view, in_col);
1618   if (tv_col == NULL)
1619      return;
1620
1621   rc = g_object_get_qdata (G_OBJECT (tv_col),
1622                           quark_column_header_object);
1623   if (rc)
1624     g_object_unref (rc);
1625
1626   g_object_set_qdata (G_OBJECT (tv_col),
1627                         quark_column_header_object,
1628                         header);
1629   if (header)
1630     g_object_ref (header);
1631   g_value_init (&values.new_value, G_TYPE_INT);
1632   g_value_set_int (&values.new_value, in_col);
1633
1634   values.property_name = "accessible-table-column-header";
1635   g_signal_emit_by_name (table, 
1636                          "property_change::accessible-table-column-header",
1637                          &values, NULL);
1638 }
1639
1640 static AtkObject*
1641 gail_tree_view_get_caption (AtkTable    *table)
1642 {
1643   GailTreeView* obj = GAIL_TREE_VIEW (table);
1644
1645   return obj->caption;
1646 }
1647
1648 static void
1649 gail_tree_view_set_caption (AtkTable    *table,
1650                             AtkObject   *caption)
1651 {
1652   GailTreeView* obj = GAIL_TREE_VIEW (table);
1653   AtkPropertyValues values = { NULL };
1654   AtkObject *old_caption;
1655
1656   old_caption = obj->caption;
1657   obj->caption = caption;
1658   if (obj->caption)
1659     g_object_ref (obj->caption);
1660   g_value_init (&values.old_value, G_TYPE_POINTER);
1661   g_value_set_pointer (&values.old_value, old_caption);
1662   g_value_init (&values.new_value, G_TYPE_POINTER);
1663   g_value_set_pointer (&values.new_value, obj->caption);
1664
1665   values.property_name = "accessible-table-caption-object";
1666   g_signal_emit_by_name (table, 
1667                          "property_change::accessible-table-caption-object", 
1668                          &values, NULL);
1669   if (old_caption)
1670     g_object_unref (old_caption);
1671 }
1672
1673 static G_CONST_RETURN gchar*
1674 gail_tree_view_get_column_description (AtkTable   *table,
1675                                        gint       in_col)
1676 {
1677   GtkWidget *widget;
1678   GtkTreeView *tree_view;
1679   GtkTreeViewColumn *tv_col;
1680   gchar *rc;
1681
1682   widget = GTK_ACCESSIBLE (table)->widget;
1683   if (widget == NULL)
1684     /* State is defunct */
1685     return NULL;
1686
1687   tree_view = GTK_TREE_VIEW (widget);
1688   tv_col = get_column (tree_view, in_col);
1689   if (tv_col == NULL)
1690      return NULL;
1691
1692   rc = g_object_get_qdata (G_OBJECT (tv_col),
1693                            quark_column_desc_object);
1694
1695   if (rc != NULL)
1696     return rc;
1697   else
1698     {
1699       gchar *title_text;
1700
1701       g_object_get (tv_col, "title", &title_text, NULL);
1702       return title_text;
1703     }
1704 }
1705
1706 static void
1707 gail_tree_view_set_column_description (AtkTable    *table,
1708                                        gint        in_col,
1709                                        const gchar *description)
1710 {
1711   GtkWidget *widget;
1712   GtkTreeView *tree_view;
1713   GtkTreeViewColumn *tv_col;
1714   AtkPropertyValues values = { NULL };
1715
1716   widget = GTK_ACCESSIBLE (table)->widget;
1717   if (widget == NULL)
1718     /* State is defunct */
1719     return;
1720
1721   tree_view = GTK_TREE_VIEW (widget);
1722   tv_col = get_column (tree_view, in_col);
1723   if (tv_col == NULL)
1724      return;
1725
1726   g_object_set_qdata (G_OBJECT (tv_col),
1727                       quark_column_desc_object,
1728                       g_strdup (description));
1729   g_value_init (&values.new_value, G_TYPE_INT);
1730   g_value_set_int (&values.new_value, in_col);
1731
1732   values.property_name = "accessible-table-column-description";
1733   g_signal_emit_by_name (table, 
1734                          "property_change::accessible-table-column-description",
1735                          &values, NULL);
1736 }
1737
1738 static G_CONST_RETURN gchar*
1739 gail_tree_view_get_row_description (AtkTable    *table,
1740                                     gint        row)
1741 {
1742   GailTreeViewRowInfo *row_info;
1743
1744   row_info = get_row_info (table, row);
1745   if (row_info)
1746     return row_info->description;
1747   else
1748     return NULL;
1749 }
1750
1751 static void
1752 gail_tree_view_set_row_description (AtkTable    *table,
1753                                     gint        row,
1754                                     const gchar *description)
1755 {
1756   set_row_data (table, row, NULL, description, FALSE);
1757 }
1758
1759 static AtkObject*
1760 gail_tree_view_get_summary (AtkTable    *table)
1761 {
1762   GailTreeView* obj = GAIL_TREE_VIEW (table);
1763
1764   return obj->summary;
1765 }
1766
1767 static void
1768 gail_tree_view_set_summary (AtkTable    *table,
1769                             AtkObject   *accessible)
1770 {
1771   GailTreeView* obj = GAIL_TREE_VIEW (table);
1772   AtkPropertyValues values = { NULL };
1773   AtkObject *old_summary;
1774
1775   old_summary = obj->summary;
1776   obj->summary = accessible;
1777   if (obj->summary)
1778     g_object_ref (obj->summary);
1779   g_value_init (&values.old_value, G_TYPE_POINTER);
1780   g_value_set_pointer (&values.old_value, old_summary);
1781   g_value_init (&values.new_value, G_TYPE_POINTER);
1782   g_value_set_pointer (&values.new_value, obj->summary);
1783
1784   values.property_name = "accessible-table-summary";
1785   g_signal_emit_by_name (table, 
1786                          "property_change::accessible-table-ummary",
1787                          &values, NULL);
1788   if (old_summary)
1789     g_object_unref (old_summary);
1790 }
1791
1792 static void
1793 set_row_data (AtkTable    *table, 
1794               gint        row, 
1795               AtkObject   *header,
1796               const gchar *description,
1797               gboolean    is_header)
1798 {
1799   GtkWidget *widget;
1800   GtkTreeView *tree_view;
1801   GtkTreeModel *tree_model;
1802   GailTreeView* obj = GAIL_TREE_VIEW (table);
1803   GailTreeViewRowInfo* row_info;
1804   GtkTreePath *path;
1805   GtkTreeIter iter;
1806   GArray *array;
1807   gboolean found = FALSE;
1808   gint i;
1809   AtkPropertyValues values = { NULL };
1810   gchar *signal_name;
1811
1812   widget = GTK_ACCESSIBLE (table)->widget;
1813   if (widget == NULL)
1814     /* State is defunct */
1815     return;
1816
1817   tree_view = GTK_TREE_VIEW (widget);
1818   tree_model = gtk_tree_view_get_model (tree_view);
1819
1820   set_iter_nth_row (tree_view, &iter, row);
1821   path = gtk_tree_model_get_path (tree_model, &iter);
1822
1823   if (obj->row_data == NULL)
1824     obj->row_data = g_array_sized_new (FALSE, TRUE,
1825                                        sizeof(GailTreeViewRowInfo *), 0);
1826
1827   array = obj->row_data;
1828
1829   for (i = 0; i < array->len; i++)
1830     {
1831       GtkTreePath *row_path;
1832
1833       row_info = g_array_index (array, GailTreeViewRowInfo*, i);
1834       row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
1835
1836       if (row_path != NULL)
1837         {
1838           if (path && gtk_tree_path_compare (row_path, path) == 0)
1839             found = TRUE;
1840
1841           gtk_tree_path_free (row_path);
1842
1843           if (found)
1844             {
1845               if (is_header)
1846                 {
1847                   if (row_info->header)
1848                     g_object_unref (row_info->header);
1849                   row_info->header = header;
1850                   if (row_info->header)
1851                     g_object_ref (row_info->header);
1852                 }
1853               else
1854                 {
1855                   g_free (row_info->description);
1856                   row_info->description = g_strdup (description);
1857                 }
1858               break;
1859             }
1860         }
1861     }
1862
1863   if (!found)
1864     {
1865       /* if not found */
1866       row_info = g_malloc (sizeof(GailTreeViewRowInfo));
1867       row_info->row_ref = gtk_tree_row_reference_new (tree_model, path);
1868       if (is_header)
1869         {
1870           row_info->header = header;
1871           if (row_info->header)
1872             g_object_ref (row_info->header);
1873           row_info->description = NULL;
1874         }
1875       else
1876         {
1877           row_info->header = NULL;
1878           row_info->description = g_strdup (description);
1879         }
1880       g_array_append_val (array, row_info);
1881     }
1882   g_value_init (&values.new_value, G_TYPE_INT);
1883   g_value_set_int (&values.new_value, row);
1884
1885   if (is_header)
1886     {
1887       values.property_name = "accessible-table-row-header";
1888       signal_name = "property_change::accessible-table-row-header";
1889     }
1890   else
1891     {
1892       values.property_name = "accessible-table-row-description";
1893       signal_name = "property-change::accessible-table-row-description";
1894     }
1895   g_signal_emit_by_name (table, 
1896                          signal_name,
1897                          &values, NULL);
1898
1899   gtk_tree_path_free (path);
1900 }
1901
1902
1903 static GailTreeViewRowInfo*
1904 get_row_info (AtkTable    *table,
1905               gint        row)
1906 {
1907   GtkWidget *widget;
1908   GtkTreeView *tree_view;
1909   GtkTreeModel *tree_model;
1910   GailTreeView* obj = GAIL_TREE_VIEW (table);
1911   GtkTreePath *path;
1912   GtkTreeIter iter;
1913   GArray *array;
1914   GailTreeViewRowInfo *rc = NULL;
1915
1916   widget = GTK_ACCESSIBLE (table)->widget;
1917   if (widget == NULL)
1918     /* State is defunct */
1919     return NULL;
1920
1921   tree_view = GTK_TREE_VIEW (widget);
1922   tree_model = gtk_tree_view_get_model (tree_view);
1923
1924   set_iter_nth_row (tree_view, &iter, row);
1925   path = gtk_tree_model_get_path (tree_model, &iter);
1926   array = obj->row_data;
1927
1928   if (array != NULL)
1929     {
1930       GailTreeViewRowInfo *row_info;
1931       GtkTreePath *row_path;
1932       gint i;
1933
1934       for (i = 0; i < array->len; i++)
1935         {
1936           row_info = g_array_index (array, GailTreeViewRowInfo*, i);
1937           row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
1938           if (row_path != NULL)
1939             {
1940               if (path && gtk_tree_path_compare (row_path, path) == 0)
1941                 rc = row_info;
1942
1943               gtk_tree_path_free (row_path);
1944
1945               if (rc != NULL)
1946                 break;
1947             }
1948         }
1949     }
1950
1951   gtk_tree_path_free (path);
1952   return rc;
1953 }
1954 /* atkselection.h */
1955
1956 static void atk_selection_interface_init (AtkSelectionIface *iface)
1957 {
1958   g_return_if_fail (iface != NULL);
1959   iface->add_selection = gail_tree_view_add_selection;
1960   iface->clear_selection = gail_tree_view_clear_selection;
1961   iface->ref_selection = gail_tree_view_ref_selection;
1962   iface->get_selection_count = gail_tree_view_get_selection_count;
1963   iface->is_child_selected = gail_tree_view_is_child_selected;
1964 }
1965
1966 static gboolean
1967 gail_tree_view_add_selection (AtkSelection *selection,
1968                               gint         i)
1969 {
1970   AtkTable *table;
1971   gint n_columns;
1972   gint row;
1973
1974   table = ATK_TABLE (selection);
1975   n_columns = gail_tree_view_get_n_columns (table);
1976   if (n_columns != 1)
1977     return FALSE;
1978
1979   row = gail_tree_view_get_row_at_index (table, i);
1980   return gail_tree_view_add_row_selection (table, row);
1981 }
1982
1983 static gboolean
1984 gail_tree_view_clear_selection (AtkSelection *selection)
1985 {
1986   GtkWidget *widget;
1987   GtkTreeView *tree_view;
1988   GtkTreeSelection *tree_selection;
1989
1990   widget = GTK_ACCESSIBLE (selection)->widget;
1991   if (widget == NULL)
1992     /* State is defunct */
1993     return FALSE;
1994  
1995   tree_view = GTK_TREE_VIEW (widget);
1996
1997   tree_selection = gtk_tree_view_get_selection (tree_view);
1998   gtk_tree_selection_unselect_all (tree_selection);  
1999
2000   return TRUE;
2001 }
2002
2003 static AtkObject*  
2004 gail_tree_view_ref_selection (AtkSelection *selection, 
2005                               gint         i)
2006 {
2007   AtkTable *table;
2008   gint row;
2009   gint n_selected;
2010   gint n_columns;
2011   gint *selected;
2012
2013   table = ATK_TABLE (selection);
2014   n_columns = gail_tree_view_get_n_columns (table);
2015   n_selected = gail_tree_view_get_selected_rows (table, &selected);
2016   if (i >= n_columns * n_selected)
2017     return NULL;
2018
2019   row = selected[i / n_columns];
2020   g_free (selected);
2021
2022   return gail_tree_view_table_ref_at (table, row, i % n_columns);
2023 }
2024
2025 static gint
2026 gail_tree_view_get_selection_count (AtkSelection *selection)
2027 {
2028   AtkTable *table;
2029   gint n_selected;
2030
2031   table = ATK_TABLE (selection);
2032   n_selected = gail_tree_view_get_selected_rows (table, NULL);
2033   if (n_selected > 0)
2034     n_selected *= gail_tree_view_get_n_columns (table);
2035   return n_selected;
2036 }
2037
2038 static gboolean
2039 gail_tree_view_is_child_selected (AtkSelection *selection, 
2040                                   gint         i)
2041 {
2042   GtkWidget *widget;
2043   gint row;
2044
2045   widget = GTK_ACCESSIBLE (selection)->widget;
2046   if (widget == NULL)
2047     /* State is defunct */
2048     return FALSE;
2049
2050   row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
2051
2052   return gail_tree_view_is_row_selected (ATK_TABLE (selection), row);
2053 }
2054
2055
2056 static void gail_cell_parent_interface_init (GailCellParentIface *iface)
2057 {
2058   g_return_if_fail (iface);
2059
2060   iface->get_cell_extents = gail_tree_view_get_cell_extents;
2061   iface->get_cell_area = gail_tree_view_get_cell_area;
2062   iface->grab_focus = gail_tree_view_grab_cell_focus;
2063 }
2064
2065 static void
2066 gail_tree_view_get_cell_extents (GailCellParent *parent,
2067                                  GailCell       *cell,
2068                                  gint           *x,
2069                                  gint           *y,
2070                                  gint           *width,
2071                                  gint           *height,
2072                                  AtkCoordType   coord_type)
2073 {
2074   GtkWidget *widget;
2075   GtkTreeView *tree_view;
2076   GdkWindow *bin_window;
2077   GdkRectangle cell_rect;
2078   gint w_x, w_y;
2079
2080   widget = GTK_ACCESSIBLE (parent)->widget;
2081   if (widget == NULL)
2082     /* State is defunct */
2083     return;
2084
2085   tree_view = GTK_TREE_VIEW (widget);
2086   gail_tree_view_get_cell_area (parent, cell, &cell_rect);
2087   bin_window = gtk_tree_view_get_bin_window (tree_view);
2088   gdk_window_get_origin (bin_window, &w_x, &w_y);
2089
2090   if (coord_type == ATK_XY_WINDOW)
2091     {
2092       GdkWindow *window;
2093       gint x_toplevel, y_toplevel;
2094
2095       window = gdk_window_get_toplevel (bin_window);
2096       gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
2097
2098       w_x -= x_toplevel;
2099       w_y -= y_toplevel;
2100     }
2101
2102   *width = cell_rect.width;
2103   *height = cell_rect.height;
2104   if (is_cell_showing (tree_view, &cell_rect))
2105     {
2106       *x = cell_rect.x + w_x;
2107       *y = cell_rect.y + w_y;
2108     }
2109   else
2110     {
2111       *x = G_MININT;
2112       *y = G_MININT;
2113     }
2114 }
2115
2116 #define EXTRA_EXPANDER_PADDING 4
2117
2118 static void
2119 gail_tree_view_get_cell_area (GailCellParent *parent,
2120                               GailCell       *cell,
2121                               GdkRectangle   *cell_rect)
2122 {
2123   GtkWidget *widget;
2124   GtkTreeView *tree_view;
2125   GtkTreeViewColumn *tv_col;
2126   GtkTreePath *path;
2127   AtkObject *parent_cell;
2128   GailTreeViewCellInfo *cell_info;
2129   GailCell *top_cell;
2130
2131   widget = GTK_ACCESSIBLE (parent)->widget;
2132   if (widget == NULL)
2133     /* State is defunct */
2134     return;
2135
2136   tree_view = GTK_TREE_VIEW (widget);
2137   parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
2138   if (parent_cell != ATK_OBJECT (parent))
2139     {
2140       /*
2141        * GailCell is in a GailContainerCell
2142        */
2143       top_cell = GAIL_CELL (parent_cell);
2144     }
2145   else
2146     {
2147       top_cell = cell;
2148     }
2149   cell_info = find_cell_info (GAIL_TREE_VIEW (parent), top_cell, NULL, TRUE);
2150   gail_return_if_fail (cell_info);
2151   gail_return_if_fail (cell_info->cell_col_ref);
2152   gail_return_if_fail (cell_info->cell_row_ref);
2153   path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2154   tv_col = cell_info->cell_col_ref;
2155   if (path && cell_info->in_use)
2156     {
2157       GtkTreeViewColumn *expander_column;
2158       gint focus_line_width;
2159
2160       gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
2161       expander_column = gtk_tree_view_get_expander_column (tree_view);
2162       if (expander_column == tv_col)
2163         {
2164           gint expander_size;
2165
2166           gtk_widget_style_get (widget,
2167                                 "expander_size", &expander_size,
2168                                 NULL);
2169
2170           cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
2171           cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
2172         }
2173       gtk_widget_style_get (widget,
2174                             "focus-line-width", &focus_line_width,
2175                             NULL);
2176
2177       cell_rect->x += focus_line_width;
2178       cell_rect->width -= 2 * focus_line_width; 
2179
2180       gtk_tree_path_free (path);
2181
2182       /*
2183        * A column has more than one renderer so we find the position and width
2184        * of each.
2185        */
2186       if (top_cell != cell)
2187         {
2188           gint cell_index;
2189           gboolean found;
2190           gint cell_start;
2191           gint cell_width;
2192           GList *renderers;
2193           GtkCellRenderer *renderer;
2194
2195           cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
2196           renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
2197           renderer = g_list_nth_data (renderers, cell_index);
2198
2199           found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
2200           if (found)
2201             {
2202               cell_rect->x += cell_start;
2203               cell_rect->width = cell_width;
2204             }
2205           g_list_free (renderers);
2206         }
2207
2208     }
2209 }
2210
2211 static gboolean
2212 gail_tree_view_grab_cell_focus  (GailCellParent *parent,
2213                                  GailCell       *cell)
2214 {
2215   GtkWidget *widget;
2216   GtkTreeView *tree_view;
2217   GtkTreeViewColumn *tv_col;
2218   GtkTreePath *path;
2219   AtkObject *parent_cell;
2220   AtkObject *cell_object;
2221   GailTreeViewCellInfo *cell_info;
2222   GtkCellRenderer *renderer = NULL;
2223   GtkWidget *toplevel;
2224   gint index;
2225
2226   widget = GTK_ACCESSIBLE (parent)->widget;
2227   if (widget == NULL)
2228     /* State is defunct */
2229     return FALSE;
2230
2231   tree_view = GTK_TREE_VIEW (widget);
2232
2233   cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
2234   gail_return_val_if_fail (cell_info, FALSE);
2235   gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
2236   gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
2237   cell_object = ATK_OBJECT (cell);
2238   parent_cell = atk_object_get_parent (cell_object);
2239   tv_col = cell_info->cell_col_ref;
2240   if (parent_cell != ATK_OBJECT (parent))
2241     {
2242       /*
2243        * GailCell is in a GailContainerCell.
2244        * The GtkTreeViewColumn has multiple renderers; 
2245        * find the corresponding one.
2246        */
2247       GList *renderers;
2248
2249       renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
2250       if (cell_info->in_use) {
2251           index = atk_object_get_index_in_parent (cell_object);
2252           renderer = g_list_nth_data (renderers, index);
2253       }
2254       g_list_free (renderers);
2255     }
2256   path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2257   if (path && cell_info->in_use)
2258     {
2259       if (renderer)
2260         gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
2261       else
2262         gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
2263
2264       gtk_tree_path_free (path);
2265       gtk_widget_grab_focus (widget);
2266       toplevel = gtk_widget_get_toplevel (widget);
2267       if (GTK_WIDGET_TOPLEVEL (toplevel))
2268         {
2269 #ifdef GDK_WINDOWING_X11
2270           gtk_window_present_with_time (GTK_WINDOW (toplevel), gdk_x11_get_server_time (widget->window));
2271 #else
2272           gtk_window_present (GTK_WINDOW (toplevel));
2273 #endif
2274         }
2275
2276       return TRUE;
2277     }
2278   else
2279       return FALSE; 
2280 }
2281
2282 /* signal handling */
2283
2284 static gboolean
2285 gail_tree_view_expand_row_gtk (GtkTreeView       *tree_view,
2286                                GtkTreeIter        *iter,
2287                                GtkTreePath        *path)
2288 {
2289   AtkObject *atk_obj;
2290   GailTreeView *gailview;
2291
2292   g_assert (GTK_IS_TREE_VIEW (tree_view));
2293
2294   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2295
2296   g_assert (GAIL_IS_TREE_VIEW (atk_obj));
2297
2298   gailview = GAIL_TREE_VIEW (atk_obj);
2299
2300   /*
2301    * The visible rectangle has not been updated when this signal is emitted
2302    * so we process the signal when the GTK processing is completed
2303    */
2304   /* this seems wrong since it overwrites any other pending expand handlers... */
2305   gailview->idle_expand_path = gtk_tree_path_copy (path);
2306   if (gailview->idle_expand_id)
2307     g_source_remove (gailview->idle_expand_id);
2308   gailview->idle_expand_id = gdk_threads_add_idle (idle_expand_row, gailview);
2309   return FALSE;
2310 }
2311
2312 static gint
2313 idle_expand_row (gpointer data)
2314 {
2315   GailTreeView *gailview = data;
2316   GtkTreePath *path;
2317   GtkTreeView *tree_view;
2318   GtkTreeIter iter;
2319   GtkTreeModel *tree_model;
2320   gint n_inserted, row;
2321
2322   gailview->idle_expand_id = 0;
2323
2324   path = gailview->idle_expand_path;
2325   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
2326
2327   g_assert (GTK_IS_TREE_VIEW (tree_view));
2328
2329   tree_model = gtk_tree_view_get_model(tree_view);
2330   if (!tree_model)
2331     return FALSE;
2332
2333   if (!path || !gtk_tree_model_get_iter (tree_model, &iter, path))
2334     return FALSE;
2335
2336   /*
2337    * Update visibility of cells below expansion row
2338    */
2339   traverse_cells (gailview, path, FALSE, FALSE);
2340   /*
2341    * Figure out number of visible children, the following test
2342    * should not fail
2343    */
2344   if (gtk_tree_model_iter_has_child (tree_model, &iter))
2345     {
2346       GtkTreePath *path_copy;
2347
2348      /*
2349       * By passing path into this function, we find the number of
2350       * visible children of path.
2351       */
2352       path_copy = gtk_tree_path_copy (path);
2353       gtk_tree_path_append_index(path_copy, 0);
2354
2355       n_inserted = 0;
2356       iterate_thru_children (tree_view, tree_model,
2357                              path_copy, NULL, &n_inserted, 0);
2358       gtk_tree_path_free (path_copy);
2359     }
2360   else
2361     {
2362       /* We can get here if the row expanded callback deleted the row */
2363       return FALSE;
2364     }
2365
2366   /* Set expand state */
2367   set_expand_state (tree_view, tree_model, gailview, path, TRUE);
2368
2369   row = get_row_from_tree_path (tree_view, path);
2370
2371   /* shouldn't ever happen */
2372   if (row == -1)
2373     g_assert_not_reached ();
2374
2375   /* Must add 1 because the "added rows" are below the row being expanded */
2376   row += 1;
2377   
2378   g_signal_emit_by_name (gailview, "row_inserted", row, n_inserted);
2379
2380   gailview->idle_expand_path = NULL;
2381
2382   gtk_tree_path_free (path);
2383
2384   return FALSE;
2385 }
2386
2387 static gboolean
2388 gail_tree_view_collapse_row_gtk (GtkTreeView       *tree_view,
2389                                  GtkTreeIter        *iter,
2390                                  GtkTreePath        *path)
2391 {
2392   GtkTreeModel *tree_model;
2393   AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2394   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2395   gint row;
2396
2397   tree_model = gtk_tree_view_get_model (tree_view);
2398
2399   clean_rows (gailview);
2400
2401   /*
2402    * Update visibility of cells below collapsed row
2403    */
2404   traverse_cells (gailview, path, FALSE, FALSE);
2405   /* Set collapse state */
2406   set_expand_state (tree_view, tree_model, gailview, path, FALSE);
2407
2408   gail_return_val_if_fail (gailview->n_children_deleted, FALSE);
2409   row = get_row_from_tree_path (tree_view, path);
2410   gail_return_val_if_fail (row != -1, FALSE);
2411   g_signal_emit_by_name (atk_obj, "row_deleted", row, 
2412                          gailview->n_children_deleted);
2413   gailview->n_children_deleted = 0;
2414   return FALSE;
2415 }
2416
2417 static void
2418 gail_tree_view_size_allocate_gtk (GtkWidget     *widget,
2419                                   GtkAllocation *allocation)
2420 {
2421   AtkObject *atk_obj = gtk_widget_get_accessible (widget);
2422   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2423
2424   /*
2425    * If the size allocation changes, the visibility of cells may change so
2426    * update the cells visibility.
2427    */
2428   traverse_cells (gailview, NULL, FALSE, FALSE);
2429 }
2430
2431 static void
2432 gail_tree_view_set_scroll_adjustments (GtkWidget     *widget,
2433                                        GtkAdjustment *hadj,
2434                                        GtkAdjustment *vadj)
2435 {
2436   AtkObject *atk_obj = gtk_widget_get_accessible (widget);
2437   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2438   GtkAdjustment *adj;
2439
2440   g_object_get (widget, hadjustment, &adj, NULL);
2441   if (gailview->old_hadj != adj)
2442      {
2443         g_signal_handlers_disconnect_by_func (gailview->old_hadj, 
2444                                               (gpointer) adjustment_changed,
2445                                               widget);
2446         gailview->old_hadj = adj;
2447         g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
2448         g_signal_connect (adj, 
2449                           "value_changed",
2450                           G_CALLBACK (adjustment_changed),
2451                           widget);
2452      } 
2453   g_object_get (widget, vadjustment, &adj, NULL);
2454   if (gailview->old_vadj != adj)
2455      {
2456         g_signal_handlers_disconnect_by_func (gailview->old_vadj, 
2457                                               (gpointer) adjustment_changed,
2458                                               widget);
2459         gailview->old_vadj = adj;
2460         g_object_add_weak_pointer (G_OBJECT (gailview->old_vadj), (gpointer *)&gailview->old_vadj);
2461         g_signal_connect (adj, 
2462                           "value_changed",
2463                           G_CALLBACK (adjustment_changed),
2464                           widget);
2465      } 
2466 }
2467
2468 static void
2469 gail_tree_view_changed_gtk (GtkTreeSelection *selection,
2470                             gpointer         data)
2471 {
2472   GailTreeView *gailview;
2473   GtkTreeView *tree_view;
2474   GtkWidget *widget;
2475   GList *cell_list;
2476   GList *l;
2477   GailTreeViewCellInfo *info;
2478   GtkTreeSelection *tree_selection;
2479   GtkTreePath *path;
2480
2481   gailview = GAIL_TREE_VIEW (data);
2482   cell_list = gailview->cell_data;
2483   widget = GTK_ACCESSIBLE (gailview)->widget;
2484   if (widget == NULL)
2485     /*
2486      * destroy signal emitted for widget
2487      */
2488     return;
2489   tree_view = GTK_TREE_VIEW (widget);
2490
2491   tree_selection = gtk_tree_view_get_selection (tree_view);
2492
2493   for (l = cell_list; l; l = l->next)
2494     {
2495       info = (GailTreeViewCellInfo *) (l->data);
2496
2497       if (info->in_use)
2498       {
2499           gail_cell_remove_state (info->cell, ATK_STATE_SELECTED, TRUE); 
2500           
2501           path = gtk_tree_row_reference_get_path (info->cell_row_ref);
2502           if (path && gtk_tree_selection_path_is_selected (tree_selection, path))
2503               gail_cell_add_state (info->cell, ATK_STATE_SELECTED, TRUE); 
2504           gtk_tree_path_free (path);
2505       }
2506     }
2507   if (GTK_WIDGET_REALIZED (widget))
2508     g_signal_emit_by_name (gailview, "selection_changed");
2509 }
2510
2511 static void
2512 columns_changed (GtkTreeView *tree_view)
2513 {
2514   AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
2515   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2516   GList *tv_cols, *tmp_list;
2517   gboolean column_found;
2518   gboolean move_found = FALSE;
2519   gboolean stale_set = FALSE;
2520   gint column_count = 0;
2521   gint i;
2522
2523  /*
2524   * This function must determine if the change is an add, delete or
2525   * a move based upon its cache of TreeViewColumns in
2526   * gailview->col_data
2527   */
2528   tv_cols = gtk_tree_view_get_columns (tree_view);
2529
2530   /* check for adds or moves */
2531   for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2532     {
2533       column_found = FALSE;
2534
2535       for (i = 0; i < gailview->col_data->len; i++)
2536         {
2537
2538           if ((GtkTreeViewColumn *)tmp_list->data ==
2539               (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2540                GtkTreeViewColumn *, i))
2541             {
2542               column_found = TRUE;
2543
2544               /* If the column isn't in the same position, a move happened */
2545               if (!move_found && i != column_count)
2546                 {
2547                   if (!stale_set)
2548                     {
2549                       /* Set all rows to ATK_STATE_STALE */
2550                       traverse_cells (gailview, NULL, TRUE, FALSE);
2551                       stale_set = TRUE;
2552                     }
2553   
2554                   /* Just emit one column reordered signal when a move happens */
2555                   g_signal_emit_by_name (atk_obj, "column_reordered");
2556                   move_found = TRUE;
2557                 }
2558
2559               break;
2560             }
2561         }
2562
2563      /*
2564       * If column_found is FALSE, then an insert happened for column
2565       * number column_count
2566       */
2567       if (!column_found)
2568         {
2569           gint n_cols, n_rows, row;
2570
2571           if (!stale_set)
2572             {
2573               /* Set all rows to ATK_STATE_STALE */
2574               traverse_cells (gailview, NULL, TRUE, FALSE);
2575               stale_set = TRUE;
2576             }
2577
2578           /* Generate column-inserted signal */
2579           g_signal_emit_by_name (atk_obj, "column_inserted", column_count, 1);
2580
2581           /* Generate children-changed signals */
2582           n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
2583           n_cols = get_n_actual_columns (tree_view);
2584           for (row = 0; row < n_rows; row++)
2585             {
2586              /*
2587               * Pass NULL as the child object, i.e. 4th argument.
2588               */
2589               g_signal_emit_by_name (atk_obj, "children_changed::add",
2590                                     ((row * n_cols) + column_count), NULL, NULL);
2591             }
2592         }
2593
2594       column_count++;
2595     }
2596
2597   /* check for deletes */
2598   for (i = 0; i < gailview->col_data->len; i++)
2599     {
2600       column_found = FALSE;
2601
2602       for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2603         {
2604             if ((GtkTreeViewColumn *)tmp_list->data ==
2605                 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2606                  GtkTreeViewColumn *, i))
2607               {
2608                 column_found = TRUE;
2609                 break;
2610               }
2611         }
2612
2613        /*
2614         * If column_found is FALSE, then a delete happened for column
2615         * number i
2616         */
2617       if (!column_found)
2618         {
2619           gint n_rows, n_cols, row;
2620
2621           clean_cols (gailview,
2622                       (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2623                       GtkTreeViewColumn *, i));
2624
2625           if (!stale_set)
2626             {
2627               /* Set all rows to ATK_STATE_STALE */
2628               traverse_cells (gailview, NULL, TRUE, FALSE);
2629               stale_set = TRUE;
2630             }
2631
2632           /* Generate column-deleted signal */
2633           g_signal_emit_by_name (atk_obj, "column_deleted", i, 1);
2634
2635           /* Generate children-changed signals */
2636           n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
2637           n_cols = get_n_actual_columns (tree_view);
2638           for (row = 0; row < n_rows; row++)
2639             {
2640              /*
2641               * Pass NULL as the child object, 4th argument.
2642               */
2643               g_signal_emit_by_name (atk_obj, "children_changed::remove",
2644                                     ((row * n_cols) + column_count), NULL, NULL);
2645             }
2646         }
2647     }
2648    
2649   /* rebuild the array */
2650
2651   g_array_free (gailview->col_data, TRUE);
2652   gailview->col_data = g_array_sized_new (FALSE, TRUE,
2653     sizeof(GtkTreeViewColumn *), 0);
2654
2655   for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2656      g_array_append_val (gailview->col_data, tmp_list->data);
2657   g_list_free (tv_cols);
2658 }
2659
2660 static void
2661 cursor_changed (GtkTreeView *tree_view)
2662 {
2663   GailTreeView *gailview;
2664
2665   gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
2666   if (gailview->idle_cursor_changed_id != 0)
2667     return;
2668
2669   /*
2670    * We notify the focus change in a idle handler so that the processing
2671    * of the cursor change is completed when the focus handler is called.
2672    * This will allow actions to be called in the focus handler
2673    */ 
2674   gailview->idle_cursor_changed_id = gdk_threads_add_idle (idle_cursor_changed, gailview);
2675 }
2676
2677 static gint
2678 idle_cursor_changed (gpointer data)
2679 {
2680   GailTreeView *gail_tree_view = GAIL_TREE_VIEW (data);
2681   GtkTreeView *tree_view;
2682   GtkWidget *widget;
2683   AtkObject *cell;
2684
2685   gail_tree_view->idle_cursor_changed_id = 0;
2686
2687   widget = GTK_ACCESSIBLE (gail_tree_view)->widget;
2688   /*
2689    * Widget has been deleted
2690    */
2691   if (widget == NULL)
2692     return FALSE;
2693
2694   tree_view = GTK_TREE_VIEW (widget);
2695
2696   cell = gail_tree_view_ref_focus_cell (tree_view);
2697   if (cell)
2698     {
2699       if (cell != gail_tree_view->focus_cell)
2700         {
2701           if (gail_tree_view->focus_cell)
2702             {
2703               gail_cell_remove_state (GAIL_CELL (gail_tree_view->focus_cell), ATK_STATE_ACTIVE, FALSE); 
2704               g_object_unref (gail_tree_view->focus_cell);
2705             }
2706           gail_tree_view->focus_cell = cell;
2707
2708           if (GTK_WIDGET_HAS_FOCUS (widget))
2709             gail_cell_add_state (GAIL_CELL (cell), ATK_STATE_ACTIVE, FALSE);
2710           g_signal_emit_by_name (gail_tree_view,
2711                                  "active-descendant-changed",
2712                                  cell);
2713         }
2714       else
2715         g_object_unref (cell);
2716     }
2717
2718   return FALSE;
2719 }
2720
2721 static void
2722 model_row_changed (GtkTreeModel *tree_model,
2723                    GtkTreePath  *path, 
2724                    GtkTreeIter  *iter,
2725                    gpointer     user_data)
2726 {
2727   GtkTreeView *tree_view = GTK_TREE_VIEW(user_data);
2728   GailTreeView *gailview;
2729   GtkTreePath *cell_path;
2730   GList *l;
2731   GailTreeViewCellInfo *cell_info;
2732  
2733   gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
2734
2735   /* Loop through our cached cells */
2736   /* Must loop through them all */
2737   for (l = gailview->cell_data; l; l = l->next)
2738     {
2739       cell_info = (GailTreeViewCellInfo *) l->data;
2740       if (cell_info->in_use) 
2741       {
2742           cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2743
2744           if (cell_path != NULL)
2745           {
2746               if (path && gtk_tree_path_compare (cell_path, path) == 0)
2747               {
2748                   if (GAIL_IS_RENDERER_CELL (cell_info->cell))
2749                   {
2750                       update_cell_value (GAIL_RENDERER_CELL (cell_info->cell),
2751                                          gailview, TRUE);
2752                   }
2753               }
2754               gtk_tree_path_free (cell_path);
2755           }
2756       }
2757     }
2758   g_signal_emit_by_name (gailview, "visible-data-changed");
2759 }
2760
2761 static void
2762 column_visibility_changed (GObject    *object,
2763                            GParamSpec *pspec,
2764                            gpointer   user_data)
2765 {
2766   if (strcmp (pspec->name, "visible") == 0)
2767     {
2768       /*
2769        * A column has been made visible or invisible
2770        *
2771        * We update our cache of cells and emit model_changed signal
2772        */ 
2773       GtkTreeView *tree_view = (GtkTreeView *)user_data;
2774       GailTreeView *gailview;
2775       GList *l;
2776       GailTreeViewCellInfo *cell_info;
2777       GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
2778       GtkTreeViewColumn *tv_col;
2779
2780       gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
2781 );
2782       g_signal_emit_by_name (gailview, "model_changed");
2783
2784       for (l = gailview->cell_data; l; l = l->next)
2785         {
2786           cell_info = (GailTreeViewCellInfo *) l->data;
2787           if (cell_info->in_use) 
2788           {
2789               tv_col = cell_info->cell_col_ref;
2790               if (tv_col == this_col)
2791               {
2792                   GtkTreePath *row_path;
2793                   row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2794                   if (GAIL_IS_RENDERER_CELL (cell_info->cell))
2795                   {
2796                       if (gtk_tree_view_column_get_visible (tv_col))
2797                           set_cell_visibility (tree_view, 
2798                                                cell_info->cell, 
2799                                                tv_col, row_path, FALSE);
2800                       else
2801                       {
2802                           gail_cell_remove_state (cell_info->cell, 
2803                                                   ATK_STATE_VISIBLE, TRUE);
2804                           gail_cell_remove_state (cell_info->cell, 
2805                                                   ATK_STATE_SHOWING, TRUE);
2806                       }
2807                   }
2808                   gtk_tree_path_free (row_path);
2809               }
2810           }
2811         }
2812     }
2813 }
2814
2815 /*
2816  * This is the signal handler for the "destroy" signal for a GtkTreeViewColumn
2817  *
2818  * We check whether we have stored column description or column header
2819  * and if so we get rid of it.
2820  */
2821 static void
2822 column_destroy (GtkObject *obj)
2823 {
2824   GtkTreeViewColumn *tv_col = GTK_TREE_VIEW_COLUMN (obj);
2825   AtkObject *header;
2826   gchar *desc;
2827
2828   header = g_object_get_qdata (G_OBJECT (tv_col),
2829                           quark_column_header_object);
2830   if (header)
2831     g_object_unref (header);
2832   desc = g_object_get_qdata (G_OBJECT (tv_col),
2833                            quark_column_desc_object);
2834   g_free (desc); 
2835 }
2836
2837 static void
2838 model_row_inserted (GtkTreeModel *tree_model,
2839                     GtkTreePath  *path, 
2840                     GtkTreeIter  *iter, 
2841                     gpointer     user_data)
2842 {
2843   GtkTreeView *tree_view = (GtkTreeView *)user_data;
2844   GtkTreePath *path_copy;
2845   AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2846   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2847   gint row, n_inserted, child_row;
2848
2849   if (gailview->idle_expand_id)
2850     {
2851       g_source_remove (gailview->idle_expand_id);
2852       gailview->idle_expand_id = 0;
2853
2854       /* don't do this if the insertion precedes the idle path, since it will now be invalid */
2855       if (path && gailview->idle_expand_path &&
2856           (gtk_tree_path_compare (path, gailview->idle_expand_path) > 0))
2857           set_expand_state (tree_view, tree_model, gailview, gailview->idle_expand_path, FALSE);
2858       if (gailview->idle_expand_path) 
2859           gtk_tree_path_free (gailview->idle_expand_path);
2860     }
2861   /* Check to see if row is visible */
2862   row = get_row_from_tree_path (tree_view, path);
2863
2864  /*
2865   * A row insert is not necessarily visible.  For example,
2866   * a row can be draged & dropped into another row, which
2867   * causes an insert on the model that isn't visible in the
2868   * view.  Only generate a signal if the inserted row is
2869   * visible.
2870   */
2871   if (row != -1)
2872     {
2873       GtkTreeIter iter;
2874       gint n_cols, col;
2875
2876       gtk_tree_model_get_iter (tree_model, &iter, path);
2877
2878       /* Figure out number of visible children. */
2879       if (gtk_tree_model_iter_has_child (tree_model, &iter))
2880         {
2881          /*
2882           * By passing path into this function, we find the number of
2883           * visible children of path.
2884           */
2885           n_inserted = 0;
2886           iterate_thru_children (tree_view, tree_model,
2887                                  path, NULL, &n_inserted, 0);
2888
2889           /* Must add one to include the row that is being added */
2890           n_inserted++;
2891         }
2892       else
2893       n_inserted = 1;
2894
2895       /* Set rows below the inserted row to ATK_STATE_STALE */
2896       traverse_cells (gailview, path, TRUE, TRUE);
2897
2898       /* Generate row-inserted signal */
2899       g_signal_emit_by_name (atk_obj, "row_inserted", row, n_inserted);
2900
2901       /* Generate children-changed signals */
2902       n_cols = gail_tree_view_get_n_columns (ATK_TABLE (atk_obj));
2903       for (child_row = row; child_row < (row + n_inserted); child_row++)
2904         {
2905           for (col = 0; col < n_cols; col++)
2906             {
2907              /*
2908               * Pass NULL as the child object, i.e. 4th argument
2909               */
2910               g_signal_emit_by_name (atk_obj, "children_changed::add",
2911                                     ((row * n_cols) + col), NULL, NULL);
2912             }
2913         }
2914     }
2915   else
2916     {
2917      /*
2918       * The row has been inserted inside another row.  This can
2919       * cause a row that previously couldn't be expanded to now
2920       * be expandable.
2921       */
2922       path_copy = gtk_tree_path_copy (path);
2923       gtk_tree_path_up (path_copy);
2924       set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
2925       gtk_tree_path_free (path_copy);
2926     }
2927 }
2928
2929 static void
2930 model_row_deleted (GtkTreeModel *tree_model,
2931                    GtkTreePath  *path, 
2932                    gpointer     user_data)
2933 {
2934   GtkTreeView *tree_view;
2935   GtkTreePath *path_copy;
2936   AtkObject *atk_obj;
2937   GailTreeView *gailview;
2938   gint row;
2939
2940   tree_view = (GtkTreeView *)user_data;
2941   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2942   gailview = GAIL_TREE_VIEW (atk_obj);
2943
2944   if (gailview->idle_expand_id)
2945     {
2946       g_source_remove (gailview->idle_expand_id);
2947       gtk_tree_path_free (gailview->idle_expand_path);
2948       gailview->idle_expand_id = 0;
2949     }
2950   /* Check to see if row is visible */
2951   clean_rows (gailview);
2952
2953   /* Set rows at or below the specified row to ATK_STATE_STALE */
2954   traverse_cells (gailview, path, TRUE, TRUE);
2955
2956   /*
2957    * If deleting a row with a depth > 1, then this may affect the
2958    * expansion/contraction of its parent(s).  Make sure this is
2959    * handled.
2960    */
2961   if (gtk_tree_path_get_depth (path) > 1)
2962     {
2963       path_copy = gtk_tree_path_copy (path);
2964       gtk_tree_path_up (path_copy);
2965       set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
2966       gtk_tree_path_free (path_copy);
2967     }
2968   row = get_row_from_tree_path (tree_view, path);
2969   /*
2970    * If the row which is deleted is not visible because it is a child of
2971    * a collapsed row then row will be -1
2972    */
2973   if (row > 0)
2974     g_signal_emit_by_name (atk_obj, "row_deleted", row, 
2975                            gailview->n_children_deleted + 1);
2976   gailview->n_children_deleted = 0;
2977 }
2978
2979 /* 
2980  * This function gets called when a row is deleted or when rows are
2981  * removed from the view due to a collapse event.  Note that the
2982  * count is the number of visible *children* of the deleted row,
2983  * so it does not include the row being deleted.
2984  *
2985  * As this function is called before the rows are removed we just note the
2986  * number of rows and then deal with it when we get a notification that
2987  * rows were deleted or collapsed.
2988  */
2989 static void
2990 destroy_count_func (GtkTreeView *tree_view, 
2991                     GtkTreePath *path,
2992                     gint        count,
2993                     gpointer    user_data)
2994 {
2995   AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2996   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2997
2998   gail_return_if_fail (gailview->n_children_deleted == 0);
2999   gailview->n_children_deleted = count;
3000 }
3001
3002 static void 
3003 model_rows_reordered (GtkTreeModel *tree_model,
3004                       GtkTreePath  *path, 
3005                       GtkTreeIter  *iter,
3006                       gint         *new_order, 
3007                       gpointer     user_data)
3008 {
3009   GtkTreeView *tree_view = (GtkTreeView *)user_data;
3010   AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3011   GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
3012
3013   if (gailview->idle_expand_id)
3014     {
3015       g_source_remove (gailview->idle_expand_id);
3016       gtk_tree_path_free (gailview->idle_expand_path);
3017       gailview->idle_expand_id = 0;
3018     }
3019   traverse_cells (gailview, NULL, TRUE, FALSE);
3020
3021   g_signal_emit_by_name (atk_obj, "row_reordered");
3022 }
3023
3024 static void
3025 adjustment_changed (GtkAdjustment *adjustment, 
3026                     GtkTreeView   *tree_view)
3027 {
3028   AtkObject *atk_obj;
3029   GailTreeView* obj;
3030
3031   /*
3032    * The scrollbars have changed
3033    */
3034   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3035   obj = GAIL_TREE_VIEW (atk_obj);
3036
3037   traverse_cells (obj, NULL, FALSE, FALSE);
3038 }
3039
3040 static void
3041 set_cell_visibility (GtkTreeView       *tree_view,
3042                      GailCell          *cell,
3043                      GtkTreeViewColumn *tv_col,
3044                      GtkTreePath       *tree_path,
3045                      gboolean          emit_signal)
3046 {
3047   GdkRectangle cell_rect;
3048
3049   /* Get these three values in tree coords */
3050   if (GTK_WIDGET_REALIZED (GTK_WIDGET (tree_view)))
3051     gtk_tree_view_get_cell_area (tree_view, tree_path, tv_col, &cell_rect);
3052   else
3053     cell_rect.height = 0;
3054
3055   if (cell_rect.height > 0)
3056     {
3057       /*
3058        * The height will be zero for a cell for which an antecedent is not 
3059        * expanded
3060        */
3061       gail_cell_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
3062       if (is_cell_showing (tree_view, &cell_rect))
3063         gail_cell_add_state (cell, ATK_STATE_SHOWING, emit_signal);
3064       else
3065         gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
3066     }
3067   else
3068     {
3069       gail_cell_remove_state (cell, ATK_STATE_VISIBLE, emit_signal);
3070       gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
3071     }
3072 }
3073
3074 static gboolean 
3075 is_cell_showing (GtkTreeView   *tree_view,
3076                  GdkRectangle  *cell_rect)
3077 {
3078   GdkRectangle rect, *visible_rect;
3079   GdkRectangle rect1, *tree_cell_rect;
3080   gboolean is_showing;
3081  /*
3082   * A cell is considered "SHOWING" if any part of the cell is in the visible 
3083   * area.  Other ways we could do this is by a cell's midpoint or if the cell 
3084   * is fully in the visible range.  Since we have the cell_rect x,y,width,height
3085   * of the cell, any of these is easy to compute.
3086   *
3087   * It is assumed that cell's rectangle is in widget coordinates so we
3088   * must transform to tree cordinates.
3089   */
3090   visible_rect = &rect;
3091   tree_cell_rect = &rect1;
3092   tree_cell_rect->x = cell_rect->x;
3093   tree_cell_rect->width = cell_rect->width;
3094   tree_cell_rect->height = cell_rect->height;
3095
3096   gtk_tree_view_get_visible_rect (tree_view, visible_rect);
3097   gtk_tree_view_widget_to_tree_coords (tree_view, cell_rect->x, cell_rect->y,
3098                                        NULL, &(rect1.y));
3099
3100   if (((tree_cell_rect->x + tree_cell_rect->width) < visible_rect->x) ||
3101      ((tree_cell_rect->y + tree_cell_rect->height) < (visible_rect->y)) ||
3102      (tree_cell_rect->x > (visible_rect->x + visible_rect->width)) ||
3103      (tree_cell_rect->y > (visible_rect->y + visible_rect->height)))
3104     is_showing =  FALSE;
3105   else
3106     is_showing = TRUE;
3107
3108   return is_showing;
3109 }
3110
3111 /* Misc Public */
3112
3113 /*
3114  * This function is called when a cell's flyweight is created in
3115  * gail_tree_view_table_ref_at with emit_change_signal set to FALSE
3116  * and in model_row_changed() on receipt of "row-changed" signal when 
3117  * emit_change_signal is set to TRUE
3118  */
3119 static gboolean
3120 update_cell_value (GailRendererCell *renderer_cell,
3121                    GailTreeView     *gailview,
3122                    gboolean         emit_change_signal)
3123 {
3124   GailTreeViewCellInfo *cell_info;
3125   GtkTreeView *tree_view;
3126   GtkTreeModel *tree_model;
3127   GtkTreePath *path;
3128   GtkTreeIter iter;
3129   GList *renderers, *cur_renderer;
3130   GParamSpec *spec;
3131   GailRendererCellClass *gail_renderer_cell_class;
3132   GtkCellRendererClass *gtk_cell_renderer_class;
3133   GailCell *cell;
3134   gchar **prop_list;
3135   AtkObject *parent;
3136   gboolean is_expander, is_expanded;
3137   
3138   gail_renderer_cell_class = GAIL_RENDERER_CELL_GET_CLASS (renderer_cell);
3139   if (renderer_cell->renderer)
3140     gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
3141   else
3142     gtk_cell_renderer_class = NULL;
3143
3144   prop_list = gail_renderer_cell_class->property_list;
3145
3146   cell = GAIL_CELL (renderer_cell);
3147   cell_info = find_cell_info (gailview, cell, NULL, TRUE);
3148   gail_return_val_if_fail (cell_info, FALSE);
3149   gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
3150   gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
3151
3152   if (emit_change_signal && cell_info->in_use)
3153     {
3154       tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
3155       tree_model = gtk_tree_view_get_model (tree_view);
3156       path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3157       if (path == NULL)
3158         return FALSE;
3159
3160       gtk_tree_model_get_iter (tree_model, &iter, path);
3161       is_expander = FALSE;
3162       is_expanded = FALSE;
3163       if (gtk_tree_model_iter_has_child (tree_model, &iter))
3164         {
3165           GtkTreeViewColumn *expander_tv;
3166
3167           expander_tv = gtk_tree_view_get_expander_column (tree_view);
3168           if (expander_tv == cell_info->cell_col_ref)
3169             {
3170               is_expander = TRUE;
3171               is_expanded = gtk_tree_view_row_expanded (tree_view, path);
3172             }
3173         } 
3174       gtk_tree_path_free (path);
3175       gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
3176                                   tree_model, &iter, is_expander, is_expanded);
3177     }
3178   renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
3179   gail_return_val_if_fail (renderers, FALSE);
3180
3181   /*
3182    * If the cell is in a container, it's index is used to find the renderer 
3183    * in the list
3184    */
3185
3186   /*
3187    * Otherwise, we assume that the cell is represented by the first renderer 
3188    * in the list
3189    */
3190
3191   if (cell_info->in_use) {
3192       parent = atk_object_get_parent (ATK_OBJECT (cell));
3193       if (!ATK_IS_OBJECT (cell)) g_on_error_query (NULL);
3194       if (GAIL_IS_CONTAINER_CELL (parent))
3195           cur_renderer = g_list_nth (renderers, cell->index);
3196       else
3197           cur_renderer = renderers;
3198   }
3199   else {
3200       return FALSE;
3201   }
3202   
3203   gail_return_val_if_fail (cur_renderer != NULL, FALSE);
3204
3205   if (gtk_cell_renderer_class)
3206     {
3207       while (*prop_list)
3208         {
3209           spec = g_object_class_find_property
3210                            (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
3211
3212           if (spec != NULL)
3213             {
3214               GValue value = { 0, };
3215
3216               g_value_init (&value, spec->value_type);
3217               g_object_get_property (cur_renderer->data, *prop_list, &value);
3218               g_object_set_property (G_OBJECT (renderer_cell->renderer),
3219                                      *prop_list, &value);
3220               g_value_unset(&value);
3221             }
3222           else
3223             g_warning ("Invalid property: %s\n", *prop_list);
3224           prop_list++;
3225         }
3226     }
3227   g_list_free (renderers);
3228   return gail_renderer_cell_update_cache (renderer_cell, emit_change_signal);
3229 }
3230
3231 static void 
3232 set_iter_nth_row (GtkTreeView *tree_view, 
3233                   GtkTreeIter *iter, 
3234                   gint        row)
3235 {
3236   GtkTreeModel *tree_model;
3237   
3238   tree_model = gtk_tree_view_get_model (tree_view);
3239   gtk_tree_model_get_iter_root (tree_model, iter);
3240   iter = return_iter_nth_row (tree_view, tree_model, iter, 0 , row);
3241 }
3242
3243 static gint 
3244 get_row_from_tree_path (GtkTreeView *tree_view,
3245                         GtkTreePath *path)
3246 {
3247   GtkTreeModel *tree_model;
3248   GtkTreePath *root_tree;
3249   gint row;
3250
3251   tree_model = gtk_tree_view_get_model (tree_view);
3252
3253   if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
3254     row = gtk_tree_path_get_indices (path)[0];
3255   else
3256     {
3257       root_tree = gtk_tree_path_new_root ();
3258       row = 0;
3259       iterate_thru_children (tree_view, tree_model, root_tree, path, &row, 0);
3260       gtk_tree_path_free (root_tree);
3261     }
3262
3263   return row;
3264 }
3265
3266 /* Misc Private */
3267
3268 /*
3269  * Get the specified GtkTreeViewColumn in the GtkTreeView.
3270  * Only visible columns are considered.
3271  */
3272 static GtkTreeViewColumn* 
3273 get_column (GtkTreeView *tree_view, 
3274             gint        in_col)
3275 {
3276   GtkTreeViewColumn *tv_col;
3277   gint n_cols = -1;
3278   gint i = 0;
3279  
3280   if (in_col < 0)
3281     {
3282        g_warning ("Request for invalid column %d\n", in_col);
3283        return NULL;
3284     }
3285
3286   tv_col = gtk_tree_view_get_column (tree_view, i);
3287
3288   while (tv_col != NULL)
3289     {
3290       if (gtk_tree_view_column_get_visible (tv_col)) 
3291         n_cols++;
3292       if (in_col == n_cols)
3293         break;
3294       tv_col = gtk_tree_view_get_column (tree_view, ++i);
3295     }
3296
3297   if (in_col != n_cols)
3298     {
3299        g_warning ("Request for invalid column %d\n", in_col);
3300        return NULL;
3301     }
3302   return tv_col;
3303 }
3304
3305 static gint
3306 get_actual_column_number (GtkTreeView *tree_view,
3307                           gint        visible_column)
3308 {
3309   GtkTreeViewColumn *tv_col;
3310   gint actual_column = 0;
3311   gint visible_columns = -1;
3312   /*
3313    * This function calculates the column number which corresponds to the
3314    * specified visible column number
3315    */
3316   tv_col = gtk_tree_view_get_column (tree_view, actual_column);
3317
3318   while (tv_col != NULL)
3319     {
3320       if (gtk_tree_view_column_get_visible (tv_col)) 
3321         visible_columns++;
3322       if (visible_columns == visible_column)
3323         return actual_column;
3324       tv_col = gtk_tree_view_get_column (tree_view, ++actual_column);
3325     }
3326   g_warning ("get_actual_column_number failed for %d\n", visible_column);
3327   return -1;
3328 }
3329
3330 static gint
3331 get_visible_column_number (GtkTreeView *tree_view,
3332                            gint        actual_column)
3333 {
3334   GtkTreeViewColumn *tv_col;
3335   gint column = 0;
3336   gint visible_columns = -1;
3337   /*
3338    * This function calculates the visible column number which corresponds to the
3339    * specified actual column number
3340    */
3341   tv_col = gtk_tree_view_get_column (tree_view, column);
3342
3343   while (tv_col != NULL)
3344     {
3345       if (gtk_tree_view_column_get_visible (tv_col)) 
3346         {
3347           visible_columns++;
3348           if (actual_column == column)
3349             return visible_columns;
3350         }
3351       else
3352         if (actual_column == column)
3353           return -1;
3354       tv_col = gtk_tree_view_get_column (tree_view, ++column);
3355     }
3356   g_warning ("get_visible_column_number failed for %d\n", actual_column);
3357   return -1;
3358 }
3359
3360 /**
3361  * Helper recursive function that returns GtkTreeIter pointer to nth row.
3362  **/
3363 static GtkTreeIter* 
3364 return_iter_nth_row(GtkTreeView  *tree_view,
3365                     GtkTreeModel *tree_model, 
3366                     GtkTreeIter  *iter, 
3367                     gint         increment,
3368                     gint         row)
3369 {
3370   GtkTreePath *current_path = gtk_tree_model_get_path (tree_model, iter);
3371   GtkTreeIter new_iter;
3372   gboolean row_expanded;
3373
3374   if (increment == row) {
3375     gtk_tree_path_free (current_path);
3376     return iter;
3377   }
3378
3379   row_expanded = gtk_tree_view_row_expanded (tree_view, current_path);
3380   gtk_tree_path_free (current_path);
3381
3382   new_iter = *iter;
3383   if ((row_expanded && gtk_tree_model_iter_children (tree_model, iter, &new_iter)) ||
3384       (gtk_tree_model_iter_next (tree_model, iter)) ||
3385       (gtk_tree_model_iter_parent (tree_model, iter, &new_iter) &&
3386           (gtk_tree_model_iter_next (tree_model, iter))))
3387     return return_iter_nth_row (tree_view, tree_model, iter,
3388       ++increment, row);
3389
3390   return NULL;          
3391 }
3392
3393 /**
3394  * Recursively called until the row specified by orig is found.
3395  *
3396  * *count will be set to the visible row number of the child
3397  * relative to the row that was initially passed in as tree_path.
3398  *
3399  * *count will be -1 if orig is not found as a child (a row that is
3400  * not visible will not be found, e.g. if the row is inside a
3401  * collapsed row).  If NULL is passed in as orig, *count will
3402  * be a count of the visible children.
3403  *
3404  * NOTE: the value for depth must be 0 when this recursive function
3405  * is initially called, or it may not function as expected.
3406  **/
3407 static void 
3408 iterate_thru_children(GtkTreeView  *tree_view,
3409                       GtkTreeModel *tree_model,
3410                       GtkTreePath  *tree_path,
3411                       GtkTreePath  *orig,
3412                       gint         *count,
3413                       gint         depth)
3414 {
3415   GtkTreeIter iter;
3416
3417   if (!gtk_tree_model_get_iter (tree_model, &iter, tree_path))
3418     return;
3419
3420   if (tree_path && orig && !gtk_tree_path_compare (tree_path, orig)) 
3421     /* Found it! */
3422     return;
3423
3424   if (tree_path && orig && gtk_tree_path_compare (tree_path, orig) > 0)
3425     {
3426       /* Past it, so return -1 */
3427       *count = -1;
3428       return;
3429     }
3430   else if (gtk_tree_view_row_expanded (tree_view, tree_path) && 
3431     gtk_tree_model_iter_has_child (tree_model, &iter)) 
3432     {
3433       (*count)++;
3434       gtk_tree_path_append_index (tree_path, 0);
3435       iterate_thru_children (tree_view, tree_model, tree_path,
3436                              orig, count, (depth + 1));
3437       return;
3438     }
3439   else if (gtk_tree_model_iter_next (tree_model, &iter)) 
3440     {
3441       (*count)++;
3442       tree_path = gtk_tree_model_get_path (tree_model, &iter);
3443        if (tree_path)
3444          {
3445            iterate_thru_children (tree_view, tree_model, tree_path,
3446                                  orig, count, depth); 
3447            gtk_tree_path_free (tree_path);
3448          }
3449       return;
3450   }
3451   else if (gtk_tree_path_up (tree_path))
3452     {
3453       GtkTreeIter temp_iter;
3454       gboolean exit_loop = FALSE;
3455       gint new_depth = depth - 1;
3456
3457       (*count)++;
3458
3459      /*
3460       * Make sure that we back up until we find a row
3461       * where gtk_tree_path_next does not return NULL.
3462       */
3463       while (!exit_loop)
3464         {
3465           if (gtk_tree_path_get_depth (tree_path) == 0)
3466               /* depth is now zero so */
3467             return;
3468           gtk_tree_path_next (tree_path);       
3469
3470           /* Verify that the next row is a valid row! */
3471           exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
3472
3473           if (!exit_loop)
3474             {
3475               /* Keep going up until we find a row that has a valid next */
3476               if (gtk_tree_path_get_depth(tree_path) > 1)
3477                 {
3478                   new_depth--;
3479                   gtk_tree_path_up (tree_path);
3480                 }
3481               else
3482                 {
3483                  /*
3484                   * If depth is 1 and gtk_tree_model_get_iter returns FALSE,
3485                   * then we are at the last row, so just return.
3486                   */ 
3487                   if (orig != NULL)
3488                     *count = -1;
3489
3490                   return;
3491                 }
3492             }
3493         }
3494
3495      /*
3496       * This guarantees that we will stop when we hit the end of the
3497       * children.
3498       */
3499       if (new_depth < 0)
3500         return;
3501
3502       iterate_thru_children (tree_view, tree_model, tree_path,
3503                             orig, count, new_depth);
3504       return;
3505     }
3506
3507  /*
3508   * If it gets here, then the path wasn't found.  Situations
3509   * that would cause this would be if the path passed in is
3510   * invalid or contained within the last row, but not visible
3511   * because the last row is not expanded.  If NULL was passed
3512   * in then a row count is desired, so only set count to -1
3513   * if orig is not NULL.
3514   */
3515   if (orig != NULL)
3516     *count = -1;
3517
3518   return;
3519 }
3520
3521 static void
3522 clean_cell_info (GailTreeView *gailview,
3523                  GList        *list) 
3524 {
3525   GailTreeViewCellInfo *cell_info;
3526   GObject *obj;
3527
3528   g_assert (GAIL_IS_TREE_VIEW (gailview));
3529
3530   cell_info = list->data;
3531
3532   if (cell_info->in_use) {
3533       obj = G_OBJECT (cell_info->cell);
3534       
3535       gail_cell_add_state (cell_info->cell, ATK_STATE_DEFUNCT, TRUE);
3536       g_object_weak_unref (obj, (GWeakNotify) cell_destroyed, cell_info);
3537       cell_info->in_use = FALSE; 
3538       if (!gailview->garbage_collection_pending) {
3539           gailview->garbage_collection_pending = TRUE;
3540           g_assert (gailview->idle_garbage_collect_id == 0);
3541           gailview->idle_garbage_collect_id = 
3542             gdk_threads_add_idle (idle_garbage_collect_cell_data, gailview);
3543       }
3544   }
3545 }
3546
3547 static void 
3548 clean_rows (GailTreeView *gailview)
3549 {
3550   GArray *array;
3551
3552   /* Clean GailTreeViewRowInfo data */
3553
3554   array = gailview->row_data;
3555   if (array != NULL)
3556     {
3557       GailTreeViewRowInfo *row_info;
3558       GtkTreePath *row_path;
3559       gint i;
3560
3561      /*
3562       * Loop backwards so that calls to free_row_info
3563       * do not affect the index numbers 
3564       */
3565       for (i = (array->len - 1); i >= 0; i  --)
3566         {
3567           row_info = g_array_index (array, GailTreeViewRowInfo*, i);
3568           row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
3569
3570           /* Remove any rows that have become invalid */
3571           if (row_path == NULL)
3572             free_row_info (array, i, TRUE);
3573           else
3574             gtk_tree_path_free (row_path);
3575         }
3576     }
3577
3578   /* Clean GailTreeViewCellInfo data */
3579
3580   if (gailview->cell_data != NULL)
3581     {
3582       GailTreeViewCellInfo *cell_info;
3583       GtkTreePath *row_path;
3584       GList *cur_list;
3585       GList *temp_list;
3586
3587       temp_list = gailview->cell_data;
3588
3589       /* Must loop through them all */
3590       while (temp_list != NULL)
3591         {
3592           cur_list = temp_list;
3593           cell_info = temp_list->data;
3594           temp_list = temp_list->next;
3595           row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3596
3597          /*
3598           * If the cell has become invalid because the row has been removed, 
3599           * then set the cell's state to ATK_STATE_DEFUNCT and remove the cell
3600           * from gailview->cell_data.  If row_path is NULL then the row has
3601           * been removed.
3602           */
3603           if (row_path == NULL)
3604             {
3605               clean_cell_info (gailview, cur_list);
3606             }
3607           else
3608             {
3609               gtk_tree_path_free (row_path);
3610             }
3611         }
3612     }
3613 }
3614
3615 static void 
3616 clean_cols (GailTreeView      *gailview,
3617             GtkTreeViewColumn *tv_col)
3618 {
3619   /* Clean GailTreeViewCellInfo data */
3620
3621   if (gailview->cell_data != NULL)
3622     {
3623       GailTreeViewCellInfo *cell_info;
3624       GList *cur_list, *temp_list;
3625
3626       temp_list = gailview->cell_data;
3627
3628       while (temp_list != NULL)
3629         {
3630           cur_list = temp_list;
3631           cell_info = temp_list->data;
3632           temp_list = temp_list->next;
3633
3634          /*
3635           * If the cell has become invalid because the column tv_col
3636           * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
3637           * and remove the cell from gailview->cell_data. 
3638           */
3639           if (cell_info->cell_col_ref == tv_col)
3640             {
3641               clean_cell_info (gailview, cur_list);
3642             }
3643         }
3644     }
3645 }
3646
3647 static gboolean
3648 idle_garbage_collect_cell_data (gpointer data)
3649 {
3650       GailTreeView *tree_view;
3651
3652       g_assert (GAIL_IS_TREE_VIEW (data));
3653       tree_view = (GailTreeView *)data;
3654
3655       /* this is the idle handler (only one instance allowed), so
3656        * we can safely delete it.
3657        */
3658       tree_view->garbage_collection_pending = FALSE;
3659       tree_view->idle_garbage_collect_id = 0;
3660
3661       tree_view->garbage_collection_pending = garbage_collect_cell_data (data);
3662
3663       /* N.B.: if for some reason another handler has re-enterantly been queued
3664        * while this handler was being serviced, it has its own gsource, therefore this handler
3665        * should always return FALSE.
3666        */
3667       return FALSE; 
3668 }
3669
3670 static gboolean
3671 garbage_collect_cell_data (gpointer data)
3672 {
3673       GailTreeView *tree_view;
3674       GList *temp_list;
3675       GailTreeViewCellInfo *cell_info;
3676
3677       g_assert (GAIL_IS_TREE_VIEW (data));
3678       tree_view = (GailTreeView *)data;
3679       temp_list = g_list_copy (tree_view->cell_data);
3680
3681       tree_view->garbage_collection_pending = FALSE;
3682       if (tree_view->idle_garbage_collect_id != 0) 
3683       {
3684           g_source_remove (tree_view->idle_garbage_collect_id);
3685           tree_view->idle_garbage_collect_id = 0;
3686       }
3687
3688       /* Must loop through them all */
3689       while (temp_list != NULL)
3690       {
3691           cell_info = temp_list->data;
3692           if (!cell_info->in_use)
3693           {
3694               /* g_object_unref (cell_info->cell); */
3695               tree_view->cell_data = g_list_remove (tree_view->cell_data, 
3696                                                     cell_info);
3697               if (cell_info->cell_row_ref)
3698                   gtk_tree_row_reference_free (cell_info->cell_row_ref);
3699               g_free (cell_info);
3700           }
3701           temp_list = temp_list->next;
3702       }
3703       g_list_free (temp_list);
3704
3705       return tree_view->garbage_collection_pending;
3706 }
3707
3708 /**
3709  * If tree_path is passed in as NULL, then all cells are acted on.
3710  * Otherwise, just act on those cells that are on a row greater than 
3711  * the specified tree_path. If inc_row is passed in as TRUE, then rows 
3712  * greater and equal to the specified tree_path are acted on.
3713  *
3714  * if set_stale is set the ATK_STATE_STALE is set on cells which are to be
3715  * acted on. 
3716  *
3717  * The function set_cell_visibility() is called on all cells to be
3718  * acted on to update the visibility of the cell.
3719  **/
3720 static void 
3721 traverse_cells (GailTreeView *tree_view,
3722                 GtkTreePath  *tree_path,
3723                 gboolean     set_stale,
3724                 gboolean     inc_row)
3725 {
3726   if (tree_view->cell_data != NULL)
3727     {
3728       GailTreeViewCellInfo *cell_info;
3729       GtkTreeView *gtk_tree_view;
3730       GList *temp_list;
3731       GtkWidget *widget;
3732
3733       g_assert (GTK_IS_ACCESSIBLE (tree_view));
3734
3735       widget = GTK_ACCESSIBLE (tree_view)->widget;
3736       if (!widget)
3737         /* Widget is being deleted */
3738         return;
3739
3740       gtk_tree_view = GTK_TREE_VIEW (widget);
3741       temp_list = tree_view->cell_data;
3742
3743       /* Must loop through them all */
3744       while (temp_list != NULL)
3745         {
3746           GtkTreePath *row_path;
3747           gboolean act_on_cell;
3748
3749           cell_info = temp_list->data;
3750           temp_list = temp_list->next;
3751
3752           if (cell_info->in_use)
3753           {
3754               row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3755               g_assert (row_path != NULL);
3756               if (tree_path == NULL)
3757                   act_on_cell = TRUE;
3758               else 
3759               {
3760                   gint comparison;
3761                   
3762                   comparison =  gtk_tree_path_compare (row_path, tree_path);
3763                   if ((comparison > 0) ||
3764                       (comparison == 0 && inc_row))
3765                       act_on_cell = TRUE;
3766                   else
3767                       act_on_cell = FALSE;
3768               }
3769               if (!cell_info->in_use) g_warning ("warning: cell info destroyed during traversal");
3770               if (act_on_cell && cell_info->in_use)
3771               {
3772                   if (set_stale)
3773                       gail_cell_add_state (cell_info->cell, ATK_STATE_STALE, TRUE);
3774                   set_cell_visibility (gtk_tree_view,
3775                                        cell_info->cell,
3776                                        cell_info->cell_col_ref,
3777                                        row_path, TRUE);
3778               }
3779               gtk_tree_path_free (row_path);
3780           }
3781         }
3782     }
3783   g_signal_emit_by_name (tree_view, "visible-data-changed");
3784 }
3785
3786 static void
3787 free_row_info (GArray   *array,
3788                gint     array_idx,
3789                gboolean shift)
3790 {
3791   GailTreeViewRowInfo* obj;
3792
3793   obj = g_array_index (array, GailTreeViewRowInfo*, array_idx);
3794
3795   g_free (obj->description);
3796   if (obj->row_ref != NULL)
3797     gtk_tree_row_reference_free (obj->row_ref);
3798   if (obj->header)
3799     g_object_unref (obj->header);
3800   g_free (obj);
3801
3802   if (shift)
3803     g_array_remove_index (array, array_idx);
3804 }
3805
3806 /*
3807  * If the tree_path passed in has children, then
3808  * ATK_STATE_EXPANDABLE is set.  If the row is expanded
3809  * ATK_STATE_EXPANDED is turned on.  If the row is 
3810  * collapsed, then ATK_STATE_EXPANDED is removed.
3811  * 
3812  * If the tree_path passed in has no children, then
3813  * ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED are removed.
3814  *
3815  * If set_on_ancestor is TRUE, then this function will also
3816  * update all cells that are ancestors of the tree_path.
3817  */
3818 static void
3819 set_expand_state (GtkTreeView  *tree_view,
3820                   GtkTreeModel *tree_model,
3821                   GailTreeView *gailview,
3822                   GtkTreePath  *tree_path,
3823                   gboolean     set_on_ancestor)
3824 {
3825   if (gailview->cell_data != NULL)
3826     {
3827       GtkTreeViewColumn *expander_tv;
3828       GailTreeViewCellInfo *cell_info;
3829       GList *temp_list;
3830       GtkTreePath *cell_path;
3831       GtkTreeIter iter;
3832       gboolean found;
3833
3834       temp_list = gailview->cell_data;
3835
3836       while (temp_list != NULL)
3837         {
3838           cell_info = temp_list->data;
3839           temp_list = temp_list->next;
3840           if (cell_info->in_use)
3841           {
3842               cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3843               found = FALSE;
3844               
3845               if (cell_path != NULL)
3846               {
3847                   GailCell *cell  = GAIL_CELL (cell_info->cell);
3848                   
3849                   expander_tv = gtk_tree_view_get_expander_column (tree_view);
3850                   
3851                   /*
3852                    * Only set state for the cell that is in the column with the
3853                    * expander toggle
3854                    */
3855                   if (expander_tv == cell_info->cell_col_ref)
3856                   {
3857                       if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
3858                           found = TRUE;
3859                       else if (set_on_ancestor &&
3860                                gtk_tree_path_get_depth (cell_path) <
3861                                gtk_tree_path_get_depth (tree_path) && 
3862                                gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
3863                           /* Only set if set_on_ancestor was passed in as TRUE */
3864                           found = TRUE;
3865                   }
3866                   
3867                   /*
3868                    * Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
3869                    * for ancestors and found cells.
3870                    */
3871                   if (found)
3872                   {
3873                       /*
3874                        * Must check against cell_path since cell_path
3875                        * can be equal to or an ancestor of tree_path.
3876                        */
3877                       gtk_tree_model_get_iter (tree_model, &iter, cell_path);
3878                       
3879                       /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
3880                       if (gtk_tree_model_iter_has_child (tree_model, &iter)) 
3881                       {
3882                           set_cell_expandable (cell);
3883                           
3884                           if (gtk_tree_view_row_expanded (tree_view, cell_path))
3885                               gail_cell_add_state (cell, ATK_STATE_EXPANDED, TRUE);
3886                           else
3887                               gail_cell_remove_state (cell, 
3888                                                       ATK_STATE_EXPANDED, TRUE);
3889                       }
3890                       else
3891                       {
3892                           gail_cell_remove_state (cell, 
3893                                                   ATK_STATE_EXPANDED, TRUE);
3894                           if (gail_cell_remove_state (cell,
3895                                                       ATK_STATE_EXPANDABLE, TRUE))
3896                               /* The state may have been propagated to the container cell */
3897                               if (!GAIL_IS_CONTAINER_CELL (cell))
3898                                   gail_cell_remove_action_by_name (cell,
3899                                                                    "expand or contract");
3900                       }
3901                       
3902                       /*
3903                        * We assume that each cell in the cache once and
3904                        * a container cell is before its child cells so we are 
3905                        * finished if set_on_ancestor is not set to TRUE.
3906                        */
3907                       if (!set_on_ancestor)
3908                           break;
3909                   }
3910               }
3911               gtk_tree_path_free (cell_path);
3912           }
3913         }
3914     }
3915 }
3916
3917
3918 static void
3919 add_cell_actions (GailCell *cell,
3920                   gboolean editable)
3921 {
3922   if (GAIL_IS_BOOLEAN_CELL (cell))
3923     gail_cell_add_action (cell,
3924         "toggle",
3925         "toggles the cell", /* action description */
3926         NULL,
3927         toggle_cell_toggled);
3928   if (editable)
3929     gail_cell_add_action (cell,
3930         "edit",
3931         "creates a widget in which the contents of the cell can be edited", 
3932         NULL,
3933         edit_cell);
3934   gail_cell_add_action (cell,
3935         "activate",
3936         "activate the cell", 
3937         NULL,
3938         activate_cell);
3939 }
3940
3941 static void
3942 toggle_cell_expanded (GailCell *cell)
3943 {
3944   GailTreeViewCellInfo *cell_info;
3945   GtkTreeView *tree_view;
3946   GtkTreePath *path;
3947   AtkObject *parent;
3948   AtkStateSet *stateset;
3949   
3950   parent = atk_object_get_parent (ATK_OBJECT (cell));
3951   if (GAIL_IS_CONTAINER_CELL (parent))
3952     parent = atk_object_get_parent (parent);
3953
3954   cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3955   gail_return_if_fail (cell_info);
3956   gail_return_if_fail (cell_info->cell_col_ref);
3957   gail_return_if_fail (cell_info->cell_row_ref);
3958
3959   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3960   path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3961   gail_return_if_fail (path);
3962
3963   stateset = atk_object_ref_state_set (ATK_OBJECT (cell));
3964   if (atk_state_set_contains_state (stateset, ATK_STATE_EXPANDED))
3965     gtk_tree_view_collapse_row (tree_view, path);
3966   else
3967     gtk_tree_view_expand_row (tree_view, path, TRUE);
3968   g_object_unref (stateset);
3969   gtk_tree_path_free (path);
3970   return;
3971 }
3972
3973 static void
3974 toggle_cell_toggled (GailCell *cell)
3975 {
3976   GailTreeViewCellInfo *cell_info;
3977   GtkTreeView *tree_view;
3978   GtkTreePath *path;
3979   gchar *pathstring;
3980   GList *renderers, *cur_renderer;
3981   AtkObject *parent;
3982   gboolean is_container_cell = FALSE;
3983
3984   parent = atk_object_get_parent (ATK_OBJECT (cell));
3985   if (GAIL_IS_CONTAINER_CELL (parent))
3986     {
3987       is_container_cell = TRUE;
3988       parent = atk_object_get_parent (parent);
3989     }
3990
3991   cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3992   gail_return_if_fail (cell_info);
3993   gail_return_if_fail (cell_info->cell_col_ref);
3994   gail_return_if_fail (cell_info->cell_row_ref);
3995
3996   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3997   path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3998   gail_return_if_fail (path);
3999   pathstring = gtk_tree_path_to_string (path);
4000
4001   renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
4002   gail_return_if_fail (renderers);
4003
4004   /* 
4005    * if the cell is in a container, it's index is used to find the 
4006    * renderer in the list
4007    */
4008
4009   if (is_container_cell)
4010     cur_renderer = g_list_nth (renderers, cell->index);
4011   else
4012   /*
4013    * Otherwise, we assume that the cell is represented by the first 
4014    * renderer in the list 
4015    */
4016     cur_renderer = renderers;
4017
4018   gail_return_if_fail (cur_renderer);
4019
4020   g_signal_emit_by_name (cur_renderer->data, "toggled", pathstring);
4021   g_list_free (renderers);
4022   g_free (pathstring);
4023   gtk_tree_path_free (path);
4024   return;
4025 }
4026
4027 static void
4028 edit_cell (GailCell *cell)
4029 {
4030   GailTreeViewCellInfo *cell_info;
4031   GtkTreeView *tree_view;
4032   GtkTreePath *path;
4033   AtkObject *parent;
4034   gboolean is_container_cell = FALSE;
4035
4036   editing = TRUE;
4037   parent = atk_object_get_parent (ATK_OBJECT (cell));
4038   if (GAIL_IS_CONTAINER_CELL (parent))
4039     {
4040       is_container_cell = TRUE;
4041       parent = atk_object_get_parent (parent);
4042     }
4043
4044   cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4045   gail_return_if_fail (cell_info);
4046   gail_return_if_fail (cell_info->cell_col_ref);
4047   gail_return_if_fail (cell_info->cell_row_ref);
4048
4049   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4050   path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
4051   gail_return_if_fail (path);
4052   gtk_tree_view_set_cursor (tree_view, path, cell_info->cell_col_ref, TRUE);
4053   gtk_tree_path_free (path);
4054   return;
4055 }
4056
4057 static void
4058 activate_cell (GailCell *cell)
4059 {
4060   GailTreeViewCellInfo *cell_info;
4061   GtkTreeView *tree_view;
4062   GtkTreePath *path;
4063   AtkObject *parent;
4064   gboolean is_container_cell = FALSE;
4065
4066   editing = TRUE;
4067   parent = atk_object_get_parent (ATK_OBJECT (cell));
4068   if (GAIL_IS_CONTAINER_CELL (parent))
4069     {
4070       is_container_cell = TRUE;
4071       parent = atk_object_get_parent (parent);
4072     }
4073
4074   cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4075   gail_return_if_fail (cell_info);
4076   gail_return_if_fail (cell_info->cell_col_ref);
4077   gail_return_if_fail (cell_info->cell_row_ref);
4078
4079   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4080   path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
4081   gail_return_if_fail (path);
4082   gtk_tree_view_row_activated (tree_view, path, cell_info->cell_col_ref);
4083   gtk_tree_path_free (path);
4084   return;
4085 }
4086
4087 static void
4088 cell_destroyed (gpointer data)
4089 {
4090   GailTreeViewCellInfo *cell_info = data;
4091
4092   gail_return_if_fail (cell_info);
4093   if (cell_info->in_use) {
4094       cell_info->in_use = FALSE;
4095
4096       g_assert (GAIL_IS_TREE_VIEW (cell_info->view));
4097       if (!cell_info->view->garbage_collection_pending) {
4098           cell_info->view->garbage_collection_pending = TRUE;
4099           cell_info->view->idle_garbage_collect_id =
4100             gdk_threads_add_idle (idle_garbage_collect_cell_data, cell_info->view);
4101       }
4102   }
4103 }
4104
4105 #if 0
4106 static void
4107 cell_info_remove (GailTreeView *tree_view, 
4108                   GailCell     *cell)
4109 {
4110   GailTreeViewCellInfo *info;
4111   GList *temp_list;
4112
4113   info = find_cell_info (tree_view, cell, &temp_list, FALSE);
4114   if (info)
4115     {
4116       info->in_use = FALSE;
4117       return;
4118     }
4119   g_warning ("No cell removed in cell_info_remove\n");
4120 }
4121 #endif
4122
4123 static void
4124 cell_info_get_index (GtkTreeView            *tree_view, 
4125                      GailTreeViewCellInfo   *info,
4126                      gint                   *index)
4127 {
4128   GtkTreePath *path;
4129   gint column_number;
4130
4131   path = gtk_tree_row_reference_get_path (info->cell_row_ref);
4132   gail_return_if_fail (path);
4133
4134   column_number = get_column_number (tree_view, info->cell_col_ref, FALSE);
4135   *index = get_index (tree_view, path, column_number);
4136   gtk_tree_path_free (path);
4137 }
4138
4139 static void
4140 cell_info_new (GailTreeView      *gailview, 
4141                GtkTreeModel      *tree_model, 
4142                GtkTreePath       *path,
4143                GtkTreeViewColumn *tv_col,
4144                GailCell          *cell )
4145 {
4146   GailTreeViewCellInfo *cell_info;
4147
4148   g_assert (GAIL_IS_TREE_VIEW (gailview));
4149
4150   cell_info = g_new (GailTreeViewCellInfo, 1);
4151   cell_info->cell_row_ref = gtk_tree_row_reference_new (tree_model, path);
4152
4153   cell_info->cell_col_ref = tv_col;
4154   cell_info->cell = cell;
4155   cell_info->in_use = TRUE; /* if we've created it, assume it's in use */
4156   cell_info->view = gailview;
4157   gailview->cell_data = g_list_append (gailview->cell_data, cell_info);
4158       
4159   /* Setup weak reference notification */
4160
4161   g_object_weak_ref (G_OBJECT (cell),
4162                      (GWeakNotify) cell_destroyed,
4163                      cell_info);
4164 }
4165
4166 static GailCell*
4167 find_cell (GailTreeView *gailview, 
4168            gint         index)
4169 {
4170   GailTreeViewCellInfo *info;
4171   GtkTreeView *tree_view;
4172   GList *cell_list;
4173   GList *l;
4174   gint real_index;
4175   gboolean needs_cleaning = FALSE;
4176   GailCell *retval = NULL;
4177
4178   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
4179   cell_list = gailview->cell_data;
4180
4181   for (l = cell_list; l; l = l->next)
4182     {
4183       info = (GailTreeViewCellInfo *) (l->data);
4184       if (info->in_use)
4185       {
4186           cell_info_get_index (tree_view, info, &real_index);
4187           if (index == real_index)
4188           {
4189               retval =  info->cell;
4190               break;
4191           }
4192       }
4193       else
4194       {
4195           needs_cleaning = TRUE;
4196       }
4197     }
4198   if (needs_cleaning)
4199      garbage_collect_cell_data (gailview);
4200
4201   return retval;
4202 }
4203
4204 static void
4205 refresh_cell_index (GailCell *cell)
4206 {
4207   GailTreeViewCellInfo *info;
4208   AtkObject *parent;
4209   GtkTreeView *tree_view;
4210   gint index;
4211
4212   parent = atk_object_get_parent (ATK_OBJECT (cell));
4213   gail_return_if_fail (GAIL_IS_TREE_VIEW (parent));
4214
4215   tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4216
4217   /* Find this cell in the GailTreeView's cache */
4218
4219   info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4220   gail_return_if_fail (info);
4221   
4222   cell_info_get_index (tree_view, info, &index); 
4223   cell->index = index;
4224 }
4225
4226 static void
4227 get_selected_rows (GtkTreeModel *model,
4228                    GtkTreePath  *path,
4229                    GtkTreeIter  *iter,
4230                    gpointer     data)
4231 {
4232   GPtrArray *array = (GPtrArray *)data;
4233
4234   g_ptr_array_add (array, gtk_tree_path_copy (path));
4235 }
4236
4237 static void
4238 connect_model_signals (GtkTreeView  *view,
4239                        GailTreeView *gailview)
4240 {
4241   GObject *obj;
4242
4243   obj = G_OBJECT (gailview->tree_model);
4244   g_signal_connect_data (obj, "row-changed",
4245                          (GCallback) model_row_changed, view, NULL, 0);
4246   g_signal_connect_data (obj, "row-inserted",
4247                          (GCallback) model_row_inserted, view, NULL, 
4248                          G_CONNECT_AFTER);
4249   g_signal_connect_data (obj, "row-deleted",
4250                          (GCallback) model_row_deleted, view, NULL, 
4251                          G_CONNECT_AFTER);
4252   g_signal_connect_data (obj, "rows-reordered",
4253                          (GCallback) model_rows_reordered, view, NULL, 
4254                          G_CONNECT_AFTER);
4255 }
4256
4257 static void
4258 disconnect_model_signals (GailTreeView *view) 
4259 {
4260   GObject *obj;
4261   GtkWidget *widget;
4262
4263   obj = G_OBJECT (view->tree_model);
4264   widget = GTK_ACCESSIBLE (view)->widget;
4265   g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_changed, widget);
4266   g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_inserted, widget);
4267   g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_deleted, widget);
4268   g_signal_handlers_disconnect_by_func (obj, (gpointer) model_rows_reordered, widget);
4269 }
4270
4271 static void
4272 clear_cached_data (GailTreeView  *view)
4273 {
4274   GList *temp_list;
4275
4276   if (view->row_data)
4277     {
4278       GArray *array = view->row_data;
4279       gint i;
4280
4281      /*
4282       * Since the third argument to free_row_info is FALSE, we don't remove 
4283       * the element.  Therefore it is safe to loop forward.
4284       */
4285       for (i = 0; i < array->len; i++)
4286         free_row_info (array, i, FALSE);
4287
4288       g_array_free (array, TRUE);
4289
4290       view->row_data = NULL;
4291     }
4292
4293   if (view->cell_data)
4294     {
4295       /* Must loop through them all */
4296       for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
4297         {
4298             clean_cell_info (view, temp_list);
4299         }
4300     }
4301   garbage_collect_cell_data (view);
4302   if (view->cell_data)
4303       g_list_free (view->cell_data);
4304   
4305   view->cell_data = NULL;
4306 }
4307
4308 /*
4309  * Returns the column number of the specified GtkTreeViewColumn
4310  *
4311  * If visible is set, the value returned will be the visible column number, 
4312  * i.e. suitable for use in AtkTable function. If visible is not set, the
4313  * value returned is the actual column number, which is suitable for use in 
4314  * getting an index value.
4315  */
4316 static gint
4317 get_column_number (GtkTreeView       *tree_view,
4318                    GtkTreeViewColumn *column,
4319                    gboolean          visible)
4320 {
4321   GList *temp_list, *column_list;
4322   GtkTreeViewColumn *tv_column;
4323   gint ret_val;
4324
4325   column_list = gtk_tree_view_get_columns (tree_view);
4326   ret_val = 0;
4327   for (temp_list = column_list; temp_list; temp_list = temp_list->next)
4328     {
4329       tv_column = GTK_TREE_VIEW_COLUMN (temp_list->data);
4330       if (tv_column == column)
4331         break;
4332       if (!visible || gtk_tree_view_column_get_visible (tv_column))
4333         ret_val++;
4334     }
4335   if (temp_list == NULL)
4336     {
4337       ret_val = -1;
4338     }
4339   g_list_free (column_list);
4340   return ret_val;
4341
4342
4343 static gint
4344 get_index (GtkTreeView       *tree_view,
4345            GtkTreePath       *path,
4346            gint              actual_column)
4347 {
4348   gint depth = 0;
4349   gint index = 1;
4350   gint *indices = NULL;
4351
4352
4353   if (path)
4354     {
4355       depth = gtk_tree_path_get_depth (path);
4356       indices = gtk_tree_path_get_indices (path);
4357     }
4358
4359   if (depth > 1)
4360     {
4361       GtkTreePath *copy_path;
4362       GtkTreeModel *model;
4363
4364       model = gtk_tree_view_get_model (tree_view);
4365       copy_path = gtk_tree_path_copy (path);
4366       gtk_tree_path_up (copy_path);
4367       count_rows (model, NULL, copy_path, &index, 0, depth);
4368       gtk_tree_path_free (copy_path);
4369     }
4370
4371   if (path)
4372     index += indices[depth-1];
4373   index *= get_n_actual_columns (tree_view);
4374   index +=  actual_column;
4375   return index;
4376 }
4377
4378 /*
4379  * The function count_rows counts the number of rows starting at iter and ending
4380  * at end_path. The value of level is the depth of iter and the value of depth
4381  * is the depth of end_path. Rows at depth before end_path are counted.
4382  * This functions counts rows which are not visible because an ancestor is 
4383  * collapsed.
4384  */
4385 static void 
4386 count_rows (GtkTreeModel *model,
4387             GtkTreeIter *iter,
4388             GtkTreePath *end_path,
4389             gint        *count,
4390             gint        level,
4391             gint        depth)
4392 {
4393   GtkTreeIter child_iter;
4394   
4395   if (!model) return;
4396
4397   level++;
4398
4399   *count += gtk_tree_model_iter_n_children (model, iter);
4400
4401 #if 0
4402   g_print ("count_rows : %d level: %d depth: %d\n", *count, level, depth);
4403   if (iter != NULL)
4404     g_print ("path: %s\n",
4405             gtk_tree_path_to_string (gtk_tree_model_get_path (model, iter)));
4406 #endif
4407
4408   if (level >= depth)
4409     return;
4410
4411   if (gtk_tree_model_iter_children (model, &child_iter, iter))
4412     {
4413       gboolean ret_val = TRUE;
4414
4415       while (ret_val)
4416         {
4417           if (level == depth - 1)
4418             {
4419               GtkTreePath *iter_path; 
4420               gboolean finished = FALSE;
4421
4422               iter_path = gtk_tree_model_get_path (model, &child_iter);
4423               if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
4424                 finished = TRUE;
4425               gtk_tree_path_free (iter_path);
4426               if (finished)
4427                 break;
4428             }
4429           if (gtk_tree_model_iter_has_child (model, &child_iter))
4430             count_rows (model, &child_iter, end_path, count, level, depth);
4431           ret_val = gtk_tree_model_iter_next (model, &child_iter);
4432         }
4433     }
4434 }
4435
4436 /*
4437  * Find the next node, which has children, at the specified depth below
4438  * the specified iter. The level is the depth of the current iter.
4439  * The position of the node is returned in path and the return value of TRUE 
4440  * means that a node was found.
4441  */
4442
4443 gboolean get_next_node_with_child_at_depth (GtkTreeModel *model,
4444                                             GtkTreeIter  *iter,
4445                                             GtkTreePath  **path,
4446                                             gint         level,
4447                                             gint         depth)
4448 {
4449   GtkTreeIter child_iter;
4450
4451   *path = NULL;
4452
4453   if (gtk_tree_model_iter_children (model, &child_iter, iter))
4454     {
4455       level++;
4456
4457       while (TRUE)
4458         {
4459           while (!gtk_tree_model_iter_has_child (model, &child_iter))
4460             {
4461               if (!gtk_tree_model_iter_next (model, &child_iter))
4462                 return FALSE;
4463             }
4464
4465           if (level == depth)
4466           /* We have found what we were looking for */
4467             {
4468               *path = gtk_tree_model_get_path (model, &child_iter);
4469               return TRUE;
4470             }
4471
4472           if (get_next_node_with_child_at_depth (model, &child_iter, path,
4473                                                  level, depth))
4474             return TRUE;
4475
4476           if (!gtk_tree_model_iter_next (model, &child_iter))
4477             return FALSE;
4478         }
4479     }
4480   return FALSE;
4481 }
4482
4483 /*
4484  * Find the next node, which has children, at the same depth as 
4485  * the specified GtkTreePath.
4486  */
4487 static gboolean 
4488 get_next_node_with_child (GtkTreeModel *model,
4489                           GtkTreePath  *path,
4490                           GtkTreePath  **return_path)
4491 {
4492   GtkTreeIter iter;
4493   gint depth;
4494
4495   gtk_tree_model_get_iter (model, &iter, path);
4496
4497   while (gtk_tree_model_iter_next (model, &iter))
4498     {
4499       if (gtk_tree_model_iter_has_child (model, &iter))
4500         {
4501           *return_path = gtk_tree_model_get_path (model, &iter);
4502           return TRUE;
4503         }
4504     }
4505   depth = gtk_tree_path_get_depth (path);
4506   while (gtk_tree_path_up (path))
4507     {
4508       if (gtk_tree_path_get_depth (path) == 0)
4509         break;
4510
4511       gtk_tree_model_get_iter (model, &iter, path);
4512       while (gtk_tree_model_iter_next (model, &iter))
4513         if (get_next_node_with_child_at_depth (model, &iter, return_path,
4514                                          gtk_tree_path_get_depth (path), depth))
4515           return TRUE;
4516     }
4517   *return_path = NULL;
4518   return FALSE;
4519 }
4520
4521 static gboolean 
4522 get_tree_path_from_row_index (GtkTreeModel *model,
4523                               gint         row_index,
4524                               GtkTreePath  **tree_path)
4525 {
4526   GtkTreeIter iter;
4527   gint count;
4528   gint depth;
4529
4530   count = gtk_tree_model_iter_n_children (model, NULL);
4531   if (count > row_index)
4532     {
4533       if (gtk_tree_model_iter_nth_child (model, &iter, NULL, row_index))
4534         {
4535           *tree_path = gtk_tree_model_get_path (model, &iter);
4536           return TRUE;
4537         }
4538       else
4539         return FALSE;
4540     }
4541   else
4542      row_index -= count;
4543
4544   depth = 0;
4545   while (TRUE)
4546     {
4547       depth++;
4548
4549       if (get_next_node_with_child_at_depth (model, NULL, tree_path, 0, depth))
4550         {
4551           GtkTreePath *next_path;
4552
4553           while (TRUE)
4554             {
4555               gtk_tree_model_get_iter (model, &iter, *tree_path);
4556               count = gtk_tree_model_iter_n_children (model, &iter);
4557               if (count > row_index)
4558                 {
4559                   gtk_tree_path_append_index (*tree_path, row_index);
4560                   return TRUE;
4561                 }
4562               else
4563                 row_index -= count;
4564
4565               if (!get_next_node_with_child (model,  *tree_path, &next_path))
4566                 break;
4567            
4568               gtk_tree_path_free (*tree_path);
4569               *tree_path = next_path;
4570             }
4571         }
4572       else
4573         {
4574           g_warning ("Index value is too large\n");
4575           gtk_tree_path_free (*tree_path);
4576            *tree_path = NULL;
4577           return FALSE;
4578         }
4579     }  
4580 }
4581
4582 /*
4583  * This function returns the number of rows, including those which are collapsed
4584  */
4585 static gint
4586 get_row_count (GtkTreeModel *model)
4587 {
4588   gint n_rows = 1;
4589
4590   count_rows (model, NULL, NULL, &n_rows, 0, G_MAXINT);
4591
4592   return n_rows;
4593 }
4594
4595 static gboolean
4596 get_path_column_from_index (GtkTreeView       *tree_view,
4597                             gint              index,
4598                             GtkTreePath       **path,
4599                             GtkTreeViewColumn **column)
4600 {
4601   GtkTreeModel *tree_model;
4602   gint n_columns;
4603
4604   tree_model = gtk_tree_view_get_model (tree_view);
4605   n_columns = get_n_actual_columns (tree_view);
4606   if (n_columns == 0)
4607     return FALSE;
4608   /* First row is the column headers */
4609   index -= n_columns;
4610   if (index < 0)
4611     return FALSE;
4612
4613   if (path)
4614     {
4615       gint row_index;
4616       gboolean retval;
4617
4618       row_index = index / n_columns;
4619       retval = get_tree_path_from_row_index (tree_model, row_index, path);
4620       gail_return_val_if_fail (retval, FALSE);
4621       if (*path == NULL)
4622         return FALSE;
4623     }    
4624
4625   if (column)
4626     {
4627       *column = gtk_tree_view_get_column (tree_view, index % n_columns);
4628       if (*column == NULL)
4629         {
4630           if (path)
4631             gtk_tree_path_free (*path);
4632           return FALSE;
4633         }
4634   }
4635   return TRUE;
4636 }
4637
4638 static void
4639 set_cell_expandable (GailCell *cell)
4640 {
4641   if (gail_cell_add_state (cell, 
4642                            ATK_STATE_EXPANDABLE,
4643                            FALSE))
4644     gail_cell_add_action (cell,
4645                           "expand or contract", /* action name */
4646                           "expands or contracts the row in the tree view "
4647                           "containing this cell", /* description */
4648                           NULL, /* Keybinding */
4649                           toggle_cell_expanded);
4650 }
4651
4652 static GailTreeViewCellInfo*
4653 find_cell_info (GailTreeView *view,
4654                 GailCell     *cell,
4655                 GList**      list,
4656                 gboolean     live_only)
4657 {
4658   GList *temp_list;
4659   GailTreeViewCellInfo *cell_info;
4660
4661   for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
4662     {
4663       cell_info = (GailTreeViewCellInfo *) temp_list->data;
4664       if (cell_info->cell == cell && (!live_only || cell_info->in_use))
4665         {
4666           if (list)
4667             *list = temp_list;
4668           return cell_info;
4669         }
4670     }
4671   return NULL;
4672 }
4673
4674 static AtkObject *
4675 get_header_from_column (GtkTreeViewColumn *tv_col)
4676 {
4677   AtkObject *rc;
4678   GtkWidget *header_widget;
4679
4680   if (tv_col == NULL)
4681     return NULL;
4682
4683   /* If the user has set a header object, use that */
4684
4685   rc = g_object_get_qdata (G_OBJECT (tv_col), quark_column_header_object);
4686
4687   if (rc == NULL)
4688     {
4689       /* If the user has not set a header object, grab the column */
4690       /* header object defined by the GtkTreeView */
4691
4692       header_widget = tv_col->button;
4693
4694       if (header_widget)
4695         {
4696           rc = gtk_widget_get_accessible (header_widget);
4697         }
4698       else
4699         rc = NULL;
4700     }
4701   return rc;
4702 }