]> Pileus Git - ~andy/gtk/blob - modules/other/gail/gailclist.c
Include "config.h" instead of <config.h> Command used: find -name
[~andy/gtk] / modules / other / gail / gailclist.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <gtk/gtk.h>
23 #include <stdio.h>
24 #include "gailclist.h"
25 #include "gailclistcell.h"
26 #include "gailcellparent.h"
27
28 /* Copied from gtkclist.c */
29 /* this defigns the base grid spacing */
30 #define CELL_SPACING 1
31
32 /* added the horizontal space at the beginning and end of a row*/
33 #define COLUMN_INSET 3
34
35
36 /* gives the top pixel of the given row in context of
37  * the clist's voffset */
38 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
39                                     (((row) + 1) * CELL_SPACING) + \
40                                     (clist)->voffset)
41
42 /* returns the row index from a y pixel location in the
43  * context of the clist's voffset */
44 #define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
45                                     ((clist)->row_height + CELL_SPACING))
46 /* gives the left pixel of the given column in context of
47  * the clist's hoffset */
48 #define COLUMN_LEFT_XPIXEL(clist, colnum)  ((clist)->column[(colnum)].area.x + \
49                                             (clist)->hoffset)
50
51 /* returns the column index from a x pixel location in the
52  * context of the clist's hoffset */
53 static inline gint
54 COLUMN_FROM_XPIXEL (GtkCList * clist,
55                     gint x)
56 {
57   gint i, cx;
58
59   for (i = 0; i < clist->columns; i++)
60     if (clist->column[i].visible)
61       {
62         cx = clist->column[i].area.x + clist->hoffset;
63
64         if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
65             x <= (cx + clist->column[i].area.width + COLUMN_INSET))
66           return i;
67       }
68
69   /* no match */
70   return -1;
71 }
72
73 /* returns the top pixel of the given row in the context of
74  * the list height */
75 #define ROW_TOP(clist, row)        (((clist)->row_height + CELL_SPACING) * (row))
76
77 /* returns the left pixel of the given column in the context of
78  * the list width */
79 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
80
81 /* returns the total height of the list */
82 #define LIST_HEIGHT(clist)         (((clist)->row_height * ((clist)->rows)) + \
83                                     (CELL_SPACING * ((clist)->rows + 1)))
84
85 static inline gint
86 LIST_WIDTH (GtkCList * clist)
87 {
88   gint last_column;
89
90   for (last_column = clist->columns - 1;
91        last_column >= 0 && !clist->column[last_column].visible; last_column--);
92
93   if (last_column >= 0)
94     return (clist->column[last_column].area.x +
95             clist->column[last_column].area.width +
96             COLUMN_INSET + CELL_SPACING);
97   return 0;
98 }
99
100 /* returns the GList item for the nth row */
101 #define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \
102                                  (clist)->row_list_end : \
103                                  g_list_nth ((clist)->row_list, (row)))
104
105 typedef struct _GailCListRow        GailCListRow;
106 typedef struct _GailCListCellData   GailCListCellData;
107
108
109 static void       gail_clist_class_init            (GailCListClass    *klass);
110 static void       gail_clist_init                  (GailCList         *clist);
111 static void       gail_clist_real_initialize       (AtkObject         *obj,
112                                                     gpointer          data);
113 static void       gail_clist_finalize              (GObject           *object);
114
115 static gint       gail_clist_get_n_children        (AtkObject         *obj);
116 static AtkObject* gail_clist_ref_child             (AtkObject         *obj,
117                                                     gint              i);
118 static AtkStateSet* gail_clist_ref_state_set       (AtkObject         *obj);
119
120
121 static void       atk_selection_interface_init     (AtkSelectionIface *iface);
122 static gboolean   gail_clist_clear_selection       (AtkSelection   *selection);
123
124 static AtkObject* gail_clist_ref_selection         (AtkSelection   *selection,
125                                                     gint           i);
126 static gint       gail_clist_get_selection_count   (AtkSelection   *selection);
127 static gboolean   gail_clist_is_child_selected     (AtkSelection   *selection,
128                                                     gint           i);
129 static gboolean   gail_clist_select_all_selection  (AtkSelection   *selection);
130
131 static void       atk_table_interface_init         (AtkTableIface     *iface);
132 static gint       gail_clist_get_index_at          (AtkTable      *table,
133                                                     gint          row,
134                                                     gint          column);
135 static gint       gail_clist_get_column_at_index   (AtkTable      *table,
136                                                     gint          index);
137 static gint       gail_clist_get_row_at_index      (AtkTable      *table,
138                                                     gint          index);
139 static AtkObject* gail_clist_ref_at                (AtkTable      *table,
140                                                     gint          row,
141                                                     gint          column);
142 static AtkObject* gail_clist_ref_at_actual         (AtkTable      *table,
143                                                     gint          row,
144                                                     gint          column);
145 static AtkObject*
146                   gail_clist_get_caption           (AtkTable      *table);
147
148 static gint       gail_clist_get_n_columns         (AtkTable      *table);
149 static gint       gail_clist_get_n_actual_columns  (GtkCList      *clist);
150
151 static G_CONST_RETURN gchar*
152                   gail_clist_get_column_description(AtkTable      *table,
153                                                     gint          column);
154 static AtkObject*  gail_clist_get_column_header     (AtkTable      *table,
155                                                     gint          column);
156 static gint       gail_clist_get_n_rows            (AtkTable      *table);
157 static G_CONST_RETURN gchar*
158                   gail_clist_get_row_description   (AtkTable      *table,
159                                                     gint          row);
160 static AtkObject*  gail_clist_get_row_header        (AtkTable      *table,
161                                                     gint          row);
162 static AtkObject* gail_clist_get_summary           (AtkTable      *table);
163 static gboolean   gail_clist_add_row_selection     (AtkTable      *table,
164                                                     gint          row);
165 static gboolean   gail_clist_remove_row_selection  (AtkTable      *table,
166                                                     gint          row);
167 static gint       gail_clist_get_selected_rows     (AtkTable      *table,
168                                                     gint          **rows_selected);
169 static gboolean   gail_clist_is_row_selected       (AtkTable      *table,
170                                                     gint          row);
171 static gboolean   gail_clist_is_selected           (AtkTable      *table,
172                                                     gint          row,
173                                                     gint          column);
174 static void       gail_clist_set_caption           (AtkTable      *table,
175                                                     AtkObject     *caption);
176 static void       gail_clist_set_column_description(AtkTable      *table,
177                                                     gint          column,
178                                                     const gchar   *description);
179 static void       gail_clist_set_column_header     (AtkTable      *table,
180                                                     gint          column,
181                                                     AtkObject     *header);
182 static void       gail_clist_set_row_description   (AtkTable      *table,
183                                                     gint          row,
184                                                     const gchar   *description);
185 static void       gail_clist_set_row_header        (AtkTable      *table,
186                                                     gint          row,
187                                                     AtkObject     *header);
188 static void       gail_clist_set_summary           (AtkTable      *table,
189                                                     AtkObject     *accessible);
190
191 /* gailcellparent.h */
192
193 static void       gail_cell_parent_interface_init  (GailCellParentIface *iface);
194 static void       gail_clist_get_cell_extents      (GailCellParent      *parent,
195                                                     GailCell            *cell,
196                                                     gint                *x,
197                                                     gint                *y,
198                                                     gint                *width,
199                                                     gint                *height,
200                                                     AtkCoordType        coord_type);
201
202 static void       gail_clist_get_cell_area         (GailCellParent      *parent,
203                                                     GailCell            *cell,
204                                                     GdkRectangle        *cell_rect);
205
206 static void       gail_clist_select_row_gtk        (GtkCList      *clist,
207                                                     int           row,
208                                                     int           column,
209                                                     GdkEvent      *event,
210                                                     gpointer      data);
211 static void       gail_clist_unselect_row_gtk      (GtkCList      *clist,
212                                                     int           row,
213                                                     int           column,
214                                                     GdkEvent      *event,
215                                                     gpointer      data);
216 static gint       gail_clist_get_visible_column    (AtkTable      *table,
217                                                     int           column);
218 static gint       gail_clist_get_actual_column     (AtkTable      *table,
219                                                     int           visible_column);
220 static void       gail_clist_set_row_data          (AtkTable      *table,
221                                                     gint          row,
222                                                     const gchar   *description,
223                                                     AtkObject     *header,
224                                                     gboolean      is_header);
225 static GailCListRow*
226                   gail_clist_get_row_data          (AtkTable      *table,
227                                                     gint          row);
228 static void       gail_clist_get_visible_rect      (GtkCList      *clist,
229                                                     GdkRectangle  *clist_rect);
230 static gboolean   gail_clist_is_cell_visible       (GdkRectangle  *cell_rect,
231                                                     GdkRectangle  *visible_rect);
232 static void       gail_clist_cell_data_new         (GailCList     *clist,
233                                                     GailCell      *cell,
234                                                     gint          column,
235                                                     gint          row);
236 static void       gail_clist_cell_destroyed        (gpointer      data);
237 static void       gail_clist_cell_data_remove      (GailCList     *clist,
238                                                     GailCell      *cell);
239 static GailCell*  gail_clist_find_cell             (GailCList     *clist,
240                                                     gint          index);
241 static void       gail_clist_adjustment_changed    (GtkAdjustment *adjustment,
242                                                     GtkCList      *clist);
243
244 struct _GailCListColumn
245 {
246   gchar *description;
247   AtkObject *header;
248 };
249
250 struct _GailCListRow
251 {
252   GtkCListRow *row_data;
253   int row_number;
254   gchar *description;
255   AtkObject *header;
256 };
257
258 struct _GailCListCellData
259 {
260   GtkCell *gtk_cell;
261   GailCell *gail_cell;
262   int row_number;
263   int column_number;
264 };
265
266 G_DEFINE_TYPE_WITH_CODE (GailCList, gail_clist, GAIL_TYPE_CONTAINER,
267                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE, atk_table_interface_init)
268                          G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init)
269                          G_IMPLEMENT_INTERFACE (GAIL_TYPE_CELL_PARENT, gail_cell_parent_interface_init))
270
271 static void
272 gail_clist_class_init (GailCListClass *klass)
273 {
274   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
275   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
276
277   class->get_n_children = gail_clist_get_n_children;
278   class->ref_child = gail_clist_ref_child;
279   class->ref_state_set = gail_clist_ref_state_set;
280   class->initialize = gail_clist_real_initialize;
281
282   gobject_class->finalize = gail_clist_finalize;
283 }
284
285 static void
286 gail_clist_init (GailCList *clist)
287 {
288 }
289
290 static void
291 gail_clist_real_initialize (AtkObject *obj,
292                             gpointer  data)
293 {
294   GailCList *clist;
295   GtkCList *gtk_clist;
296   gint i;
297
298   ATK_OBJECT_CLASS (gail_clist_parent_class)->initialize (obj, data);
299
300   obj->role = ATK_ROLE_TABLE;
301
302   clist = GAIL_CLIST (obj);
303
304   clist->caption = NULL;
305   clist->summary = NULL;
306   clist->row_data = NULL;
307   clist->cell_data = NULL;
308   clist->previous_selected_cell = NULL;
309
310   gtk_clist = GTK_CLIST (data);
311  
312   clist->n_cols = gtk_clist->columns;
313   clist->columns = g_new (GailCListColumn, gtk_clist->columns);
314   for (i = 0; i < gtk_clist->columns; i++)
315     {
316       clist->columns[i].description = NULL;
317       clist->columns[i].header = NULL;
318     }
319   /*
320    * Set up signal handlers for select-row and unselect-row
321    */
322   g_signal_connect (gtk_clist,
323                     "select-row",
324                     G_CALLBACK (gail_clist_select_row_gtk),
325                     obj);
326   g_signal_connect (gtk_clist,
327                     "unselect-row",
328                     G_CALLBACK (gail_clist_unselect_row_gtk),
329                     obj);
330   /*
331    * Adjustment callbacks
332    */
333   if (gtk_clist->hadjustment)
334     {
335       g_signal_connect (gtk_clist->hadjustment,
336                         "value_changed",
337                         G_CALLBACK (gail_clist_adjustment_changed),
338                         gtk_clist);
339     }
340   if (gtk_clist->vadjustment)
341     {
342       g_signal_connect (gtk_clist->vadjustment,
343                         "value_changed",
344                         G_CALLBACK (gail_clist_adjustment_changed),
345                         gtk_clist);
346     }
347 }
348
349 static void
350 gail_clist_finalize (GObject            *object)
351 {
352   GailCList *clist = GAIL_CLIST (object);
353   gint i;
354   GArray *array;
355
356   if (clist->caption)
357     g_object_unref (clist->caption);
358   if (clist->summary)
359     g_object_unref (clist->summary);
360
361   for (i = 0; i < clist->n_cols; i++)
362     {
363       g_free (clist->columns[i].description);
364       if (clist->columns[i].header)
365         g_object_unref (clist->columns[i].header);
366     }
367   g_free (clist->columns);
368
369   array = clist->row_data;
370
371   if (clist->previous_selected_cell)
372     g_object_unref (clist->previous_selected_cell);
373
374   if (array)
375     {
376       for (i = 0; i < array->len; i++)
377         {
378           GailCListRow *row_data;
379
380           row_data = g_array_index (array, GailCListRow*, i);
381
382           if (row_data->header)
383             g_object_unref (row_data->header);
384           g_free (row_data->description);
385         }
386     }
387
388   if (clist->cell_data)
389     {
390       GList *temp_list;
391
392       for (temp_list = clist->cell_data; temp_list; temp_list = temp_list->next)
393         {
394           g_list_free (temp_list->data);
395         }
396       g_list_free (clist->cell_data);
397     }
398
399   G_OBJECT_CLASS (gail_clist_parent_class)->finalize (object);
400 }
401
402 static gint
403 gail_clist_get_n_children (AtkObject *obj)
404 {
405   GtkWidget *widget;
406   gint row, col;
407
408   g_return_val_if_fail (GAIL_IS_CLIST (obj), 0);
409
410   widget = GTK_ACCESSIBLE (obj)->widget;
411   if (widget == NULL)
412     /*
413      * State is defunct
414      */
415     return 0;
416
417   row = gail_clist_get_n_rows (ATK_TABLE (obj));
418   col = gail_clist_get_n_actual_columns (GTK_CLIST (widget));
419   return (row * col);
420 }
421
422 static AtkObject*
423 gail_clist_ref_child (AtkObject *obj,
424                       gint      i)
425 {
426   GtkWidget *widget;
427   gint row, col;
428   gint n_columns;
429
430   g_return_val_if_fail (GAIL_IS_CLIST (obj), NULL);
431   g_return_val_if_fail (i >= 0, NULL);
432
433   widget = GTK_ACCESSIBLE (obj)->widget;
434   if (widget == NULL)
435     /*
436      * State is defunct
437      */
438     return NULL;
439
440   n_columns = gail_clist_get_n_actual_columns (GTK_CLIST (widget));
441   if (!n_columns)
442     return NULL;
443
444   row = i / n_columns;
445   col = i % n_columns;
446   return gail_clist_ref_at_actual (ATK_TABLE (obj), row, col);
447 }
448
449 static AtkStateSet*
450 gail_clist_ref_state_set (AtkObject *obj)
451 {
452   AtkStateSet *state_set;
453   GtkWidget *widget;
454
455   state_set = ATK_OBJECT_CLASS (gail_clist_parent_class)->ref_state_set (obj);
456   widget = GTK_ACCESSIBLE (obj)->widget;
457
458   if (widget != NULL)
459     atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
460
461   return state_set;
462 }
463
464 static void
465 atk_selection_interface_init (AtkSelectionIface *iface)
466 {
467   iface->clear_selection = gail_clist_clear_selection;
468   iface->ref_selection = gail_clist_ref_selection;
469   iface->get_selection_count = gail_clist_get_selection_count;
470   iface->is_child_selected = gail_clist_is_child_selected;
471   iface->select_all_selection = gail_clist_select_all_selection;
472 }
473
474 static gboolean
475 gail_clist_clear_selection (AtkSelection   *selection)
476 {
477   GtkCList *clist;
478   GtkWidget *widget;
479   
480   widget = GTK_ACCESSIBLE (selection)->widget;
481   if (widget == NULL)
482     /* State is defunct */
483     return FALSE;
484   
485   clist = GTK_CLIST (widget);
486   gtk_clist_unselect_all(clist);
487   return TRUE;
488 }
489
490 static AtkObject*
491 gail_clist_ref_selection (AtkSelection   *selection,
492                           gint           i)
493 {
494   gint visible_columns;
495   gint selected_row;
496   gint selected_column;
497   gint *selected_rows;
498
499   if ( i < 0 && i >= gail_clist_get_selection_count (selection))
500     return NULL;
501
502   visible_columns = gail_clist_get_n_columns (ATK_TABLE (selection));
503   gail_clist_get_selected_rows (ATK_TABLE (selection), &selected_rows);
504   selected_row = selected_rows[i / visible_columns];
505   g_free (selected_rows);
506   selected_column = gail_clist_get_actual_column (ATK_TABLE (selection), 
507                                                   i % visible_columns);
508
509   return gail_clist_ref_at (ATK_TABLE (selection), selected_row, 
510                             selected_column);
511 }
512
513 static gint
514 gail_clist_get_selection_count (AtkSelection   *selection)
515 {
516   gint n_rows_selected;
517
518   n_rows_selected = gail_clist_get_selected_rows (ATK_TABLE (selection), NULL);
519
520   if (n_rows_selected > 0)
521     /*
522      * The number of cells selected is the number of columns
523      * times the number of selected rows
524      */
525     return gail_clist_get_n_columns (ATK_TABLE (selection)) * n_rows_selected;
526   return 0;
527 }
528
529 static gboolean
530 gail_clist_is_child_selected (AtkSelection   *selection,
531                               gint           i)
532 {
533   gint row;
534
535   row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
536
537   if (row == 0 && i >= gail_clist_get_n_columns (ATK_TABLE (selection)))
538     return FALSE;
539   return gail_clist_is_row_selected (ATK_TABLE (selection), row);
540 }
541
542 static gboolean
543 gail_clist_select_all_selection (AtkSelection   *selection)
544 {
545   GtkCList *clist;
546   GtkWidget *widget;
547   /* GtkArg arg; */
548   
549   widget = GTK_ACCESSIBLE (selection)->widget;
550   if (widget == NULL)
551     /* State is defunct */
552     return FALSE;
553
554   clist = GTK_CLIST (widget);
555   gtk_clist_select_all(clist);
556
557   return TRUE;
558 }
559
560 static void
561 atk_table_interface_init (AtkTableIface *iface)
562 {
563   iface->ref_at = gail_clist_ref_at;
564   iface->get_index_at = gail_clist_get_index_at;
565   iface->get_column_at_index = gail_clist_get_column_at_index;
566   iface->get_row_at_index = gail_clist_get_row_at_index;
567   iface->get_caption = gail_clist_get_caption;
568   iface->get_n_columns = gail_clist_get_n_columns;
569   iface->get_column_description = gail_clist_get_column_description;
570   iface->get_column_header = gail_clist_get_column_header;
571   iface->get_n_rows = gail_clist_get_n_rows;
572   iface->get_row_description = gail_clist_get_row_description;
573   iface->get_row_header = gail_clist_get_row_header;
574   iface->get_summary = gail_clist_get_summary;
575   iface->add_row_selection = gail_clist_add_row_selection;
576   iface->remove_row_selection = gail_clist_remove_row_selection;
577   iface->get_selected_rows = gail_clist_get_selected_rows;
578   iface->is_row_selected = gail_clist_is_row_selected;
579   iface->is_selected = gail_clist_is_selected;
580   iface->set_caption = gail_clist_set_caption;
581   iface->set_column_description = gail_clist_set_column_description;
582   iface->set_column_header = gail_clist_set_column_header;
583   iface->set_row_description = gail_clist_set_row_description;
584   iface->set_row_header = gail_clist_set_row_header;
585   iface->set_summary = gail_clist_set_summary;
586 }
587
588 static AtkObject*
589 gail_clist_ref_at (AtkTable *table,
590                    gint     row,
591                    gint     column)
592 {
593   GtkWidget *widget;
594   gint actual_column;
595
596   widget = GTK_ACCESSIBLE (table)->widget;
597   if (widget == NULL)
598     /* State is defunct */
599     return NULL;
600
601   actual_column = gail_clist_get_actual_column (table, column);
602   return gail_clist_ref_at_actual (table, row, actual_column);
603 }
604
605
606 static AtkObject*
607 gail_clist_ref_at_actual (AtkTable      *table,
608                           gint          row,
609                           gint          column)
610 {
611   /*
612    * The column number pased to this function is the actual column number
613    * whereas the column number passed to gail_clist_ref_at is the
614    * visible column number
615    */
616   GtkCList *clist;
617   GtkWidget *widget;
618   GtkCellType cellType;
619   AtkObject *return_object;
620   gint n_rows, n_columns;
621   gint index;
622   GailCell *cell;
623
624   g_return_val_if_fail (GTK_IS_ACCESSIBLE (table), NULL);
625   
626   widget = GTK_ACCESSIBLE (table)->widget;
627   if (widget == NULL)
628     /* State is defunct */
629     return NULL;
630
631   clist = GTK_CLIST (widget);
632   n_rows = gail_clist_get_n_rows (table); 
633   n_columns = gail_clist_get_n_actual_columns (clist); 
634
635   if (row < 0 || row >= n_rows)
636     return NULL;
637   if (column < 0 || column >= n_columns)
638     return NULL;
639
640   /*
641    * Check whether the child is cached
642    */
643   index =  column + row * n_columns;
644   cell = gail_clist_find_cell (GAIL_CLIST (table), index);
645   if (cell)
646     {
647       g_object_ref (cell);
648       return ATK_OBJECT (cell);
649     }
650   cellType = gtk_clist_get_cell_type(clist, row, column);
651   switch (cellType) 
652     {
653     case GTK_CELL_TEXT:
654     case GTK_CELL_PIXTEXT:
655       return_object = gail_clist_cell_new ();
656       break;
657     case GTK_CELL_PIXMAP:
658       return_object = NULL;
659       break;
660     default:
661       /* Don't handle GTK_CELL_EMPTY or GTK_CELL_WIDGET, return NULL */
662       return_object = NULL;
663       break;
664     }
665   if (return_object)
666     {
667       cell = GAIL_CELL (return_object);
668
669       g_return_val_if_fail (ATK_IS_OBJECT (table), NULL);
670
671       gail_cell_initialise (cell, widget, ATK_OBJECT (table),
672                             index);
673       /*
674        * Store the cell in a cache
675        */
676       gail_clist_cell_data_new (GAIL_CLIST (table), cell, column, row);
677       /*
678        * If the column is visible, sets the cell's state
679        */
680       if (clist->column[column].visible)
681         {
682           GdkRectangle cell_rect, visible_rect;
683   
684           gail_clist_get_cell_area (GAIL_CELL_PARENT (table), cell, &cell_rect);
685           gail_clist_get_visible_rect (clist, &visible_rect);
686           gail_cell_add_state (cell, ATK_STATE_VISIBLE, FALSE);
687           if (gail_clist_is_cell_visible (&cell_rect, &visible_rect))
688             gail_cell_add_state (cell, ATK_STATE_SHOWING, FALSE);
689         }
690       /*
691        * If a row is selected, all cells in the row are selected
692        */
693       if (gail_clist_is_row_selected (table, row))
694         {
695           gail_cell_add_state (cell, ATK_STATE_SELECTED, FALSE);
696           if (clist->columns == 1)
697             gail_cell_add_state (cell, ATK_STATE_FOCUSED, FALSE);
698         }
699     }
700
701   return return_object; 
702 }
703
704 static gint
705 gail_clist_get_index_at (AtkTable *table,
706                          gint     row,
707                          gint     column)
708 {
709   gint n_cols, n_rows;
710
711   n_cols = atk_table_get_n_columns (table);
712   n_rows = atk_table_get_n_rows (table);
713
714   g_return_val_if_fail (row < n_rows, 0);
715   g_return_val_if_fail (column < n_cols, 0);
716
717   return row * n_cols + column;
718 }
719
720 static gint
721 gail_clist_get_column_at_index (AtkTable *table,
722                                 gint     index)
723 {
724   gint n_cols;
725
726   n_cols = atk_table_get_n_columns (table);
727
728   if (n_cols == 0)
729     return 0;
730   else
731     return (gint) (index % n_cols);
732 }
733
734 static gint
735 gail_clist_get_row_at_index (AtkTable *table,
736                              gint     index)
737 {
738   gint n_cols;
739
740   n_cols = atk_table_get_n_columns (table);
741
742   if (n_cols == 0)
743     return 0;
744   else
745     return (gint) (index / n_cols);
746 }
747
748 static AtkObject*
749 gail_clist_get_caption (AtkTable      *table)
750 {
751   GailCList* obj = GAIL_CLIST (table);
752
753   return obj->caption;
754 }
755
756 static gint
757 gail_clist_get_n_columns (AtkTable      *table)
758 {
759   GtkWidget *widget;
760   GtkCList *clist;
761
762   widget = GTK_ACCESSIBLE (table)->widget;
763   if (widget == NULL)
764     /* State is defunct */
765     return 0;
766
767   clist = GTK_CLIST (widget);
768
769   return gail_clist_get_visible_column (table, 
770                                   gail_clist_get_n_actual_columns (clist)); 
771 }
772
773 static gint
774 gail_clist_get_n_actual_columns (GtkCList *clist)
775 {
776   return clist->columns;
777 }
778
779 static G_CONST_RETURN gchar*
780 gail_clist_get_column_description (AtkTable      *table,
781                                    gint          column)
782 {
783   GailCList *clist = GAIL_CLIST (table);
784   GtkWidget *widget;
785   gint actual_column;
786
787   if (column < 0 || column >= gail_clist_get_n_columns (table))
788     return NULL;
789
790   actual_column = gail_clist_get_actual_column (table, column);
791   if (clist->columns[actual_column].description)
792     return (clist->columns[actual_column].description);
793
794   widget = GTK_ACCESSIBLE (clist)->widget;
795   if (widget == NULL)
796     return NULL;
797
798   return gtk_clist_get_column_title (GTK_CLIST (widget), actual_column);
799 }
800
801 static AtkObject*
802 gail_clist_get_column_header (AtkTable      *table,
803                               gint          column)
804 {
805   GailCList *clist = GAIL_CLIST (table);
806   GtkWidget *widget;
807   GtkWidget *return_widget;
808   gint actual_column;
809
810   if (column < 0 || column >= gail_clist_get_n_columns (table))
811     return NULL;
812
813   actual_column = gail_clist_get_actual_column (table, column);
814
815   if (clist->columns[actual_column].header)
816     return (clist->columns[actual_column].header);
817
818   widget = GTK_ACCESSIBLE (clist)->widget;
819   if (widget == NULL)
820     return NULL;
821
822   return_widget = gtk_clist_get_column_widget (GTK_CLIST (widget), 
823                                                actual_column);
824   if (return_widget == NULL)
825     return NULL;
826
827   g_return_val_if_fail (GTK_IS_BIN (return_widget), NULL);
828   return_widget = gtk_bin_get_child (GTK_BIN(return_widget));
829
830   return gtk_widget_get_accessible (return_widget);
831 }
832
833 static gint
834 gail_clist_get_n_rows (AtkTable      *table)
835 {
836   GtkWidget *widget;
837   GtkCList *clist;
838
839   widget = GTK_ACCESSIBLE (table)->widget;
840   if (widget == NULL)
841     /* State is defunct */
842     return 0;
843
844   clist = GTK_CLIST (widget);
845   return clist->rows;
846 }
847
848 static G_CONST_RETURN gchar*
849 gail_clist_get_row_description (AtkTable      *table,
850                                 gint          row)
851 {
852   GailCListRow* row_data;
853
854   row_data = gail_clist_get_row_data (table, row);
855   if (row_data == NULL)
856     return NULL;
857   return row_data->description;
858 }
859
860 static AtkObject*
861 gail_clist_get_row_header (AtkTable      *table,
862                            gint          row)
863 {
864   GailCListRow* row_data;
865
866   row_data = gail_clist_get_row_data (table, row);
867   if (row_data == NULL)
868     return NULL;
869   return row_data->header;
870 }
871
872 static AtkObject*
873 gail_clist_get_summary (AtkTable      *table)
874 {
875   GailCList* obj = GAIL_CLIST (table);
876
877   return obj->summary;
878 }
879
880 static gboolean
881 gail_clist_add_row_selection (AtkTable      *table,
882                               gint          row)
883 {
884   GtkWidget *widget;
885   GtkCList *clist;
886
887   widget = GTK_ACCESSIBLE (table)->widget;
888   if (widget == NULL)
889     /* State is defunct */
890     return 0;
891
892   clist = GTK_CLIST (widget);
893   gtk_clist_select_row (clist, row, -1);
894   if (gail_clist_is_row_selected (table, row))
895     return TRUE;
896   
897   return FALSE;
898 }
899
900 static gboolean
901 gail_clist_remove_row_selection (AtkTable      *table,
902                                  gint          row)
903 {
904   GtkWidget *widget;
905   GtkCList *clist;
906
907   widget = GTK_ACCESSIBLE (table)->widget;
908   if (widget == NULL)
909     /* State is defunct */
910     return 0;
911
912   clist = GTK_CLIST (widget);
913   if (gail_clist_is_row_selected (table, row))
914   {
915     gtk_clist_select_row (clist, row, -1);
916     return TRUE;
917   }
918   return FALSE;
919 }
920
921 static gint
922 gail_clist_get_selected_rows (AtkTable *table,
923                               gint     **rows_selected)
924 {
925   GtkWidget *widget;
926   GtkCList *clist;
927   GList *list;
928   gint n_selected;
929   gint i;
930
931   widget = GTK_ACCESSIBLE (table)->widget;
932   if (widget == NULL)
933     /* State is defunct */
934     return 0;
935
936   clist = GTK_CLIST (widget);
937  
938   n_selected = g_list_length (clist->selection);
939
940   if (n_selected == 0) 
941     return 0;
942
943   if (rows_selected)
944     {
945       gint *selected_rows;
946
947       selected_rows = (gint*) g_malloc (sizeof (gint) * n_selected);
948       list = clist->selection;
949
950       i = 0;
951       while (list)
952         {
953           selected_rows[i++] = GPOINTER_TO_INT (list->data);
954           list = list->next;
955         }
956       *rows_selected = selected_rows;
957     }
958   return n_selected;
959 }
960
961 static gboolean
962 gail_clist_is_row_selected (AtkTable      *table,
963                             gint          row)
964 {
965   GList *elem;
966   GtkWidget *widget;
967   GtkCList *clist;
968   GtkCListRow *clist_row;
969
970   widget = GTK_ACCESSIBLE (table)->widget;
971   if (widget == NULL)
972     /* State is defunct */
973         return FALSE;
974
975   clist = GTK_CLIST (widget);
976       
977   if (row < 0 || row >= clist->rows)
978     return FALSE;
979
980   elem = ROW_ELEMENT (clist, row);
981   if (!elem)
982     return FALSE;
983   clist_row = elem->data;
984
985   return (clist_row->state == GTK_STATE_SELECTED);
986 }
987
988 static gboolean
989 gail_clist_is_selected (AtkTable      *table,
990                         gint          row,
991                         gint          column)
992 {
993   return gail_clist_is_row_selected (table, row);
994 }
995
996 static void
997 gail_clist_set_caption (AtkTable      *table,
998                         AtkObject     *caption)
999 {
1000   GailCList* obj = GAIL_CLIST (table);
1001   AtkPropertyValues values = { NULL };
1002   AtkObject *old_caption;
1003
1004   old_caption = obj->caption;
1005   obj->caption = caption;
1006   if (obj->caption)
1007     g_object_ref (obj->caption);
1008
1009   g_value_init (&values.old_value, G_TYPE_POINTER);
1010   g_value_set_pointer (&values.old_value, old_caption);
1011   g_value_init (&values.new_value, G_TYPE_POINTER);
1012   g_value_set_pointer (&values.new_value, obj->caption);
1013
1014   values.property_name = "accessible-table-caption";
1015   g_signal_emit_by_name (table, 
1016                          "property_change::accessible-table-caption", 
1017                          &values, NULL);
1018   if (old_caption)
1019     g_object_unref (old_caption);
1020 }
1021
1022 static void
1023 gail_clist_set_column_description (AtkTable      *table,
1024                                    gint          column,
1025                                    const gchar   *description)
1026 {
1027   GailCList *clist = GAIL_CLIST (table);
1028   AtkPropertyValues values = { NULL };
1029   gint actual_column;
1030
1031   if (column < 0 || column >= gail_clist_get_n_columns (table))
1032     return;
1033
1034   if (description == NULL)
1035     return;
1036
1037   actual_column = gail_clist_get_actual_column (table, column);
1038   g_free (clist->columns[actual_column].description);
1039   clist->columns[actual_column].description = g_strdup (description);
1040
1041   g_value_init (&values.new_value, G_TYPE_INT);
1042   g_value_set_int (&values.new_value, column);
1043
1044   values.property_name = "accessible-table-column-description";
1045   g_signal_emit_by_name (table, 
1046                          "property_change::accessible-table-column-description",
1047                           &values, NULL);
1048
1049 }
1050
1051 static void
1052 gail_clist_set_column_header (AtkTable      *table,
1053                               gint          column,
1054                               AtkObject     *header)
1055 {
1056   GailCList *clist = GAIL_CLIST (table);
1057   AtkPropertyValues values = { NULL };
1058   gint actual_column;
1059
1060   if (column < 0 || column >= gail_clist_get_n_columns (table))
1061     return;
1062
1063   actual_column = gail_clist_get_actual_column (table, column);
1064   if (clist->columns[actual_column].header)
1065     g_object_unref (clist->columns[actual_column].header);
1066   if (header)
1067     g_object_ref (header);
1068   clist->columns[actual_column].header = header;
1069
1070   g_value_init (&values.new_value, G_TYPE_INT);
1071   g_value_set_int (&values.new_value, column);
1072
1073   values.property_name = "accessible-table-column-header";
1074   g_signal_emit_by_name (table, 
1075                          "property_change::accessible-table-column-header",
1076                          &values, NULL);
1077 }
1078
1079 static void
1080 gail_clist_set_row_description (AtkTable      *table,
1081                                 gint          row,
1082                                 const gchar   *description)
1083 {
1084   gail_clist_set_row_data (table, row, description, NULL, FALSE);
1085 }
1086
1087 static void
1088 gail_clist_set_row_header (AtkTable      *table,
1089                            gint          row,
1090                            AtkObject     *header)
1091 {
1092   gail_clist_set_row_data (table, row, NULL, header, TRUE);
1093 }
1094
1095 static void
1096 gail_clist_set_summary (AtkTable      *table,
1097                         AtkObject     *accessible)
1098 {
1099   GailCList* obj = GAIL_CLIST (table);
1100   AtkPropertyValues values = { 0, };
1101   AtkObject *old_summary;
1102
1103   old_summary = obj->summary;
1104   obj->summary = accessible;
1105   if (obj->summary)
1106     g_object_ref (obj->summary);
1107
1108   g_value_init (&values.old_value, G_TYPE_POINTER);
1109   g_value_set_pointer (&values.old_value, old_summary);
1110   g_value_init (&values.new_value, G_TYPE_POINTER);
1111   g_value_set_pointer (&values.new_value, obj->summary);
1112
1113   values.property_name = "accessible-table-summary";
1114   g_signal_emit_by_name (table, 
1115                          "property_change::accessible-table-summary", 
1116                          &values, NULL);
1117   if (old_summary)
1118     g_object_unref (old_summary);
1119 }
1120
1121
1122 static void gail_cell_parent_interface_init (GailCellParentIface *iface)
1123 {
1124   iface->get_cell_extents = gail_clist_get_cell_extents;
1125   iface->get_cell_area = gail_clist_get_cell_area;
1126 }
1127
1128 static void
1129 gail_clist_get_cell_extents (GailCellParent *parent,
1130                              GailCell       *cell,
1131                              gint           *x,
1132                              gint           *y,
1133                              gint           *width,
1134                              gint           *height,
1135                              AtkCoordType   coord_type)
1136 {
1137   GtkWidget* widget;
1138   GtkCList *clist;
1139   gint widget_x, widget_y, widget_width, widget_height;
1140   GdkRectangle cell_rect;
1141   GdkRectangle visible_rect;
1142
1143   widget = GTK_ACCESSIBLE (parent)->widget;
1144   if (widget == NULL)
1145     return;
1146   clist = GTK_CLIST (widget);
1147
1148   atk_component_get_extents (ATK_COMPONENT (parent), &widget_x, &widget_y,
1149                              &widget_width, &widget_height,
1150                              coord_type);
1151
1152   gail_clist_get_cell_area (parent, cell, &cell_rect);
1153   *width = cell_rect.width;
1154   *height = cell_rect.height;
1155   gail_clist_get_visible_rect (clist, &visible_rect);
1156   if (gail_clist_is_cell_visible (&cell_rect, &visible_rect))
1157     {
1158       *x = cell_rect.x + widget_x;
1159       *y = cell_rect.y + widget_y;
1160     }
1161   else
1162     {
1163       *x = G_MININT;
1164       *y = G_MININT;
1165     }
1166 }
1167
1168 static void
1169 gail_clist_get_cell_area (GailCellParent *parent,
1170                           GailCell       *cell,
1171                           GdkRectangle   *cell_rect)
1172 {
1173   GtkWidget* widget;
1174   GtkCList *clist;
1175   gint column, row, n_columns;
1176
1177   widget = GTK_ACCESSIBLE (parent)->widget;
1178   if (widget == NULL)
1179     return;
1180   clist = GTK_CLIST (widget);
1181
1182   n_columns = gail_clist_get_n_actual_columns (clist);
1183   g_return_if_fail (n_columns > 0);
1184   column = cell->index % n_columns;
1185   row = cell->index / n_columns; 
1186   cell_rect->x = COLUMN_LEFT (clist, column);
1187   cell_rect->y = ROW_TOP (clist, row);
1188   cell_rect->width = clist->column[column].area.width;
1189   cell_rect->height = clist->row_height;
1190 }
1191
1192 static void
1193 gail_clist_select_row_gtk (GtkCList *clist,
1194                            gint      row,
1195                            gint      column,
1196                            GdkEvent *event,
1197                            gpointer data)
1198 {
1199   GailCList *gail_clist;
1200   GList *temp_list;
1201   AtkObject *selected_cell;
1202
1203   gail_clist = GAIL_CLIST (data);
1204
1205   for (temp_list = gail_clist->cell_data; temp_list; temp_list = temp_list->next)
1206     {
1207       GailCListCellData *cell_data;
1208
1209       cell_data = (GailCListCellData *) (temp_list->data);
1210
1211       if (row == cell_data->row_number)
1212         {
1213           /*
1214            * Row is selected
1215            */
1216           gail_cell_add_state (cell_data->gail_cell, ATK_STATE_SELECTED, TRUE);
1217         }
1218     }
1219   if (clist->columns == 1)
1220     {
1221       selected_cell = gail_clist_ref_at (ATK_TABLE (data), row, 1);
1222       if (selected_cell)
1223         {
1224           if (gail_clist->previous_selected_cell)
1225             g_object_unref (gail_clist->previous_selected_cell);
1226           gail_clist->previous_selected_cell = selected_cell;
1227           gail_cell_add_state (GAIL_CELL (selected_cell), ATK_STATE_FOCUSED, FALSE);
1228           g_signal_emit_by_name (gail_clist,
1229                                  "active-descendant-changed",
1230                                   selected_cell);
1231        }
1232     }
1233
1234   g_signal_emit_by_name (gail_clist, "selection_changed");
1235 }
1236
1237 static void
1238 gail_clist_unselect_row_gtk (GtkCList *clist,
1239                              gint      row,
1240                              gint      column,
1241                              GdkEvent *event,
1242                              gpointer data)
1243 {
1244   GailCList *gail_clist;
1245   GList *temp_list;
1246
1247   gail_clist = GAIL_CLIST (data);
1248
1249   for (temp_list = gail_clist->cell_data; temp_list; temp_list = temp_list->next)
1250     {
1251       GailCListCellData *cell_data;
1252
1253       cell_data = (GailCListCellData *) (temp_list->data);
1254
1255       if (row == cell_data->row_number)
1256         {
1257           /*
1258            * Row is unselected
1259            */
1260           gail_cell_add_state (cell_data->gail_cell, ATK_STATE_FOCUSED, FALSE);
1261           gail_cell_remove_state (cell_data->gail_cell, ATK_STATE_SELECTED, TRUE);
1262        }
1263     }
1264
1265   g_signal_emit_by_name (gail_clist, "selection_changed");
1266 }
1267
1268 /*
1269  * This function determines the number of visible columns
1270  * up to and including the specified column
1271  */
1272 static gint
1273 gail_clist_get_visible_column (AtkTable *table,
1274                                int      column)
1275 {
1276   GtkWidget *widget;
1277   GtkCList *clist;
1278   gint i;
1279   gint vis_columns;
1280
1281   widget = GTK_ACCESSIBLE (table)->widget;
1282   if (widget == NULL)
1283     /* State is defunct */
1284     return 0;
1285
1286   clist = GTK_CLIST (widget);
1287   for (i = 0, vis_columns = 0; i < column; i++)
1288     if (clist->column[i].visible)
1289       vis_columns++;
1290
1291   return vis_columns;  
1292 }
1293
1294 static gint
1295 gail_clist_get_actual_column (AtkTable *table,
1296                               int      visible_column)
1297 {
1298   GtkWidget *widget;
1299   GtkCList *clist;
1300   gint i;
1301   gint vis_columns;
1302
1303   widget = GTK_ACCESSIBLE (table)->widget;
1304   if (widget == NULL)
1305     /* State is defunct */
1306     return 0;
1307
1308   clist = GTK_CLIST (widget);
1309   for (i = 0, vis_columns = 0; i < clist->columns; i++)
1310     {
1311       if (clist->column[i].visible)
1312         {
1313           if (visible_column == vis_columns)
1314             return i;
1315           vis_columns++;
1316         }
1317     }
1318   return 0;  
1319 }
1320
1321 static void
1322 gail_clist_set_row_data (AtkTable      *table,
1323                          gint          row,
1324                          const gchar   *description,
1325                          AtkObject     *header,
1326                          gboolean      is_header)
1327 {
1328   GtkWidget *widget;
1329   GtkCList *gtk_clist;
1330   GailCList *gail_clist;
1331   GArray *array;
1332   GailCListRow* row_data;
1333   gint i;
1334   gboolean found = FALSE;
1335   AtkPropertyValues values = { NULL };
1336   gchar *signal_name;
1337
1338   widget = GTK_ACCESSIBLE (table)->widget;
1339   if (widget == NULL)
1340     /* State is defunct */
1341     return;
1342
1343   gtk_clist = GTK_CLIST (widget);
1344   if (row < 0 || row >= gtk_clist->rows)
1345     return;
1346
1347   gail_clist = GAIL_CLIST (table);
1348
1349   if (gail_clist->row_data == NULL)
1350     gail_clist->row_data = g_array_sized_new (FALSE, TRUE, 
1351                                               sizeof (GailCListRow *), 0);
1352
1353   array = gail_clist->row_data;
1354
1355   for (i = 0; i < array->len; i++)
1356     {
1357       row_data = g_array_index (array, GailCListRow*, i);
1358
1359       if (row == row_data->row_number)
1360         {
1361           found = TRUE;
1362           if (is_header)
1363             {
1364               if (row_data->header)
1365                 g_object_unref (row_data->header);
1366               row_data->header = header;
1367               if (row_data->header)
1368                 g_object_ref (row_data->header);
1369             }
1370           else
1371             {
1372               g_free (row_data->description);
1373               row_data->description = g_strdup (row_data->description);
1374             }
1375           break;
1376         }
1377     } 
1378   if (!found)
1379     {
1380       GList *elem;
1381
1382       elem = ROW_ELEMENT (gtk_clist, row);
1383       g_return_if_fail (elem != NULL);
1384
1385       row_data = g_new (GailCListRow, 1);
1386       row_data->row_number = row;
1387       row_data->row_data = elem->data;
1388       if (is_header)
1389         {
1390           row_data->header = header;
1391           if (row_data->header)
1392             g_object_ref (row_data->header);
1393           row_data->description = NULL;
1394         }
1395       else
1396         {
1397           row_data->description = g_strdup (row_data->description);
1398           row_data->header = NULL;
1399         }
1400       g_array_append_val (array, row_data);
1401     }
1402
1403   g_value_init (&values.new_value, G_TYPE_INT);
1404   g_value_set_int (&values.new_value, row);
1405
1406   if (is_header)
1407     {
1408       values.property_name = "accessible-table-row-header";
1409       signal_name = "property_change::accessible-table-row-header";
1410     }
1411   else
1412     {
1413       values.property_name = "accessible-table-row-description";
1414       signal_name = "property_change::accessible-table-row-description";
1415     }
1416   g_signal_emit_by_name (table, 
1417                          signal_name,
1418                          &values, NULL);
1419
1420 }
1421
1422 static GailCListRow*
1423 gail_clist_get_row_data (AtkTable      *table,
1424                          gint          row)
1425 {
1426   GtkWidget *widget;
1427   GtkCList *clist;
1428   GailCList *obj;
1429   GArray *array;
1430   GailCListRow* row_data;
1431   gint i;
1432
1433   widget = GTK_ACCESSIBLE (table)->widget;
1434   if (widget == NULL)
1435     /* State is defunct */
1436     return NULL;
1437
1438   clist = GTK_CLIST (widget);
1439   if (row < 0 || row >= clist->rows)
1440     return NULL;
1441
1442   obj = GAIL_CLIST (table);
1443
1444   if (obj->row_data == NULL)
1445     return NULL;
1446
1447   array = obj->row_data;
1448
1449   for (i = 0; i < array->len; i++)
1450     {
1451       row_data = g_array_index (array, GailCListRow*, i);
1452
1453       if (row == row_data->row_number)
1454         return row_data;
1455     }
1456  
1457   return NULL;
1458 }
1459
1460 static void
1461 gail_clist_get_visible_rect (GtkCList      *clist,
1462                              GdkRectangle  *clist_rect)
1463 {
1464   clist_rect->x = - clist->hoffset;
1465   clist_rect->y = - clist->voffset;
1466   clist_rect->width = clist->clist_window_width;
1467   clist_rect->height = clist->clist_window_height;
1468 }
1469
1470 static gboolean
1471 gail_clist_is_cell_visible (GdkRectangle  *cell_rect,
1472                             GdkRectangle  *visible_rect)
1473 {
1474   /*
1475    * A cell is reported as visible if any part of the cell is visible
1476    */
1477   if (((cell_rect->x + cell_rect->width) < visible_rect->x) ||
1478      ((cell_rect->y + cell_rect->height) < visible_rect->y) ||
1479      (cell_rect->x > (visible_rect->x + visible_rect->width)) ||
1480      (cell_rect->y > (visible_rect->y + visible_rect->height)))
1481     return FALSE;
1482   else
1483     return TRUE;
1484 }
1485
1486 static void
1487 gail_clist_cell_data_new (GailCList     *clist,
1488                           GailCell      *cell,
1489                           gint          column,
1490                           gint          row)
1491 {
1492   GList *elem;
1493   GailCListCellData *cell_data;
1494   GtkCList *gtk_clist;
1495   GtkCListRow *clist_row;
1496
1497   gtk_clist = GTK_CLIST (GTK_ACCESSIBLE (clist)->widget);
1498   elem = g_list_nth (gtk_clist->row_list, row);
1499   g_return_if_fail (elem != NULL);
1500   clist_row = (GtkCListRow *) elem->data;
1501   cell_data = g_new (GailCListCellData, 1);
1502   cell_data->gail_cell = cell;
1503   cell_data->gtk_cell = &(clist_row->cell[column]);
1504   cell_data->column_number = column;
1505   cell_data->row_number = row;
1506   clist->cell_data = g_list_append (clist->cell_data, cell_data);
1507
1508   g_object_weak_ref (G_OBJECT (cell),
1509                      (GWeakNotify) gail_clist_cell_destroyed,
1510                      cell);
1511 }
1512
1513 static void
1514 gail_clist_cell_destroyed (gpointer      data)
1515 {
1516   GailCell *cell = GAIL_CELL (data);
1517   AtkObject* parent;
1518
1519   parent = atk_object_get_parent (ATK_OBJECT (cell));
1520
1521   gail_clist_cell_data_remove (GAIL_CLIST (parent), cell);
1522 }
1523
1524 static void
1525 gail_clist_cell_data_remove (GailCList *clist,
1526                              GailCell  *cell)
1527 {
1528   GList *temp_list;
1529
1530   for (temp_list = clist->cell_data; temp_list; temp_list = temp_list->next)
1531     {
1532       GailCListCellData *cell_data;
1533
1534       cell_data = (GailCListCellData *) temp_list->data;
1535       if (cell_data->gail_cell == cell)
1536         {
1537           clist->cell_data = g_list_remove_link (clist->cell_data, temp_list);
1538           g_free (cell_data);
1539           return;
1540         }
1541     }
1542   g_warning ("No cell removed in gail_clist_cell_data_remove\n");
1543 }
1544
1545 static GailCell*
1546 gail_clist_find_cell (GailCList     *clist,
1547                       gint          index)
1548 {
1549   GList *temp_list;
1550   gint n_cols;
1551
1552   n_cols = clist->n_cols;
1553
1554   for (temp_list = clist->cell_data; temp_list; temp_list = temp_list->next)
1555     {
1556       GailCListCellData *cell_data;
1557       gint real_index;
1558
1559       cell_data = (GailCListCellData *) (temp_list->data);
1560
1561       real_index = cell_data->column_number + n_cols * cell_data->row_number;
1562       if (real_index == index)
1563         return cell_data->gail_cell;
1564     }
1565   return NULL;
1566 }
1567
1568 static void
1569 gail_clist_adjustment_changed (GtkAdjustment *adjustment,
1570                                GtkCList      *clist)
1571 {
1572   AtkObject *atk_obj;
1573   GdkRectangle visible_rect;
1574   GdkRectangle cell_rect;
1575   GailCList* obj;
1576   GList *temp_list;
1577
1578   /*
1579    * The scrollbars have changed
1580    */
1581   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (clist));
1582   obj = GAIL_CLIST (atk_obj);
1583
1584   /* Get the currently visible area */
1585   gail_clist_get_visible_rect (clist, &visible_rect);
1586
1587   /* loop over the cells and report if they are visible or not. */
1588   /* Must loop through them all */
1589   for (temp_list = obj->cell_data; temp_list; temp_list = temp_list->next)
1590     {
1591       GailCell *cell;
1592       GailCListCellData *cell_data;
1593
1594       cell_data = (GailCListCellData *) (temp_list->data);
1595       cell = cell_data->gail_cell;
1596
1597       gail_clist_get_cell_area (GAIL_CELL_PARENT (atk_obj), 
1598                                 cell, &cell_rect);
1599       if (gail_clist_is_cell_visible (&cell_rect, &visible_rect))
1600         gail_cell_add_state (cell, ATK_STATE_SHOWING, TRUE);
1601       else
1602         gail_cell_remove_state (cell, ATK_STATE_SHOWING, TRUE);
1603     }
1604   g_signal_emit_by_name (atk_obj, "visible_data_changed");
1605 }
1606