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