]> Pileus Git - ~andy/gtk/blob - gtk/gtkclist.c
A couple of compiler warning fixes, GtkCList signal changes, changed
[~andy/gtk] / gtk / gtkclist.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, 
3  * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>  
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 #include <stdlib.h>
20 #include "../config.h"
21 #include "gtkclist.h"
22
23 /* the number rows memchunk expands at a time */
24 #define CLIST_OPTIMUM_SIZE 512
25
26 /* the width of the column resize windows */
27 #define DRAG_WIDTH  6
28
29 /* minimum allowed width of a column */
30 #define COLUMN_MIN_WIDTH 5
31
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 /* scrollbar spacing class macro */
39 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
40
41 /* gives the top pixel of the given row in context of
42  * the clist's voffset */
43 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
44                                     (((row) + 1) * CELL_SPACING) + \
45                                     (clist)->voffset)
46
47 /* returns the row index from a y pixel location in the 
48  * context of the clist's voffset */
49 #define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
50                                     ((clist)->row_height + CELL_SPACING))
51
52 /* gives the left pixel of the given column in context of
53  * the clist's hoffset */
54 #define COLUMN_LEFT_XPIXEL(clist, column)  ((clist)->column[(column)].area.x + \
55                                             (clist)->hoffset)
56
57 /* returns the column index from a x pixel location in the 
58  * context of the clist's hoffset */
59 static inline gint
60 COLUMN_FROM_XPIXEL (GtkCList * clist,
61                     gint x)
62 {
63   gint i, cx;
64
65   for (i = 0; i < clist->columns; i++)
66     {
67       cx = clist->column[i].area.x + clist->hoffset;
68
69       if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
70           x <= (cx + clist->column[i].area.width + COLUMN_INSET))
71         return i;
72     }
73
74   /* no match */
75   return -1;
76 }
77
78 /* returns the top pixel of the given row in the context of
79  * the list height */
80 #define ROW_TOP(clist, row)        (((clist)->row_height + CELL_SPACING) * (row))
81
82 /* returns the left pixel of the given column in the context of
83  * the list width */
84 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
85
86 /* returns the total height of the list */
87 #define LIST_HEIGHT(clist)         (((clist)->row_height * ((clist)->rows)) + \
88                                     (CELL_SPACING * ((clist)->rows + 1)))
89
90 /* returns the total width of the list */
91 #define LIST_WIDTH(clist)          ((clist)->column[(clist)->columns - 1].area.x + \
92                                     (clist)->column[(clist)->columns - 1].area.width + \
93                                     COLUMN_INSET + CELL_SPACING)
94
95 /* Signals */
96 enum
97 {
98   MOUSE_CLICK,
99   MOUSE_DOUBLE_CLICK,
100   SELECT_ROW,
101   UNSELECT_ROW,
102   CLICK_COLUMN,
103   LAST_SIGNAL
104 };
105
106 typedef void (*GtkCListSignal1) (GtkObject * object,
107                                  gint arg1,
108                                  gint arg2,
109                                  gint arg3,
110                                  gpointer data);
111
112 typedef void (*GtkCListSignal2) (GtkObject * object,
113                                  gint arg1,
114                                  gpointer data);
115
116
117 /* GtkCList Methods */
118 static void gtk_clist_class_init (GtkCListClass * klass);
119 static void gtk_clist_init (GtkCList * clist);
120
121 /* GtkObject Methods */
122 static void gtk_clist_destroy (GtkObject * object);
123 static void gtk_clist_finalize (GtkObject * object);
124
125
126 /* GtkWidget Methods */
127 static void gtk_clist_realize (GtkWidget * widget);
128 static void gtk_clist_unrealize (GtkWidget * widget);
129 static void gtk_clist_map (GtkWidget * widget);
130 static void gtk_clist_unmap (GtkWidget * widget);
131 static void gtk_clist_draw (GtkWidget * widget,
132                             GdkRectangle * area);
133 static gint gtk_clist_expose (GtkWidget * widget,
134                               GdkEventExpose * event);
135 static gint gtk_clist_button_press (GtkWidget * widget,
136                                     GdkEventButton * event);
137 static gint gtk_clist_button_release (GtkWidget * widget,
138                                       GdkEventButton * event);
139 static gint gtk_clist_motion (GtkWidget * widget, 
140                               GdkEventMotion * event);
141
142 static void gtk_clist_size_request (GtkWidget * widget,
143                                     GtkRequisition * requisition);
144 static void gtk_clist_size_allocate (GtkWidget * widget,
145                                      GtkAllocation * allocation);
146
147 /* GtkContainer Methods */
148 static void gtk_clist_foreach (GtkContainer * container,
149                                GtkCallback callback,
150                                gpointer callback_data);
151
152 /* Drawing */
153 static void draw_row (GtkCList * clist,
154                       GdkRectangle * area,
155                       gint row,
156                       GtkCListRow * clist_row);
157 static void draw_rows (GtkCList * clist,
158                        GdkRectangle * area);
159
160 /* Size Allocation */
161 static void size_allocate_title_buttons (GtkCList * clist);
162 static void size_allocate_columns (GtkCList * clist);
163
164 /* Selection */
165 static void real_select_row (GtkCList * clist,
166                              gint row,
167                              gint column,
168                              gint button);
169 static void real_unselect_row (GtkCList * clist,
170                                gint row,
171                                gint column,
172                                gint button);
173 static gint get_selection_info (GtkCList * clist,
174                                 gint x,
175                                 gint y,
176                                 gint * row,
177                                 gint * column);
178
179 /* Resize Columns */
180 static void draw_xor_line (GtkCList * clist);
181 static gint new_column_width (GtkCList * clist,
182                               gint column,
183                               gint * x,
184                               gint * visible);
185 static void resize_column (GtkCList * clist,
186                            gint column,
187                            gint width);
188
189 /* Buttons */
190 static void column_button_create (GtkCList * clist,
191                                   gint column);
192 static void column_button_clicked (GtkWidget * widget,
193                                    gpointer data);
194
195 /* Scrollbars */
196 static void create_scrollbars (GtkCList * clist);
197 static void adjust_scrollbars (GtkCList * clist);
198 static void check_exposures   (GtkCList * clist);
199 static void vadjustment_changed (GtkAdjustment * adjustment,
200                                  gpointer data);
201 static void vadjustment_value_changed (GtkAdjustment * adjustment,
202                                        gpointer data);
203 static void hadjustment_changed (GtkAdjustment * adjustment,
204                                  gpointer data);
205 static void hadjustment_value_changed (GtkAdjustment * adjustment,
206                                        gpointer data);
207
208
209 /* Memory Allocation/Distruction Routines */
210 static GtkCListColumn *columns_new (GtkCList * clist);
211
212 static void column_title_new (GtkCList * clist,
213                               gint column,
214                               gchar * title);
215 static void columns_delete (GtkCList * clist);
216
217 static GtkCListRow *row_new (GtkCList * clist);
218
219 static void row_delete (GtkCList * clist,
220                         GtkCListRow * clist_row);
221 static void cell_empty (GtkCList * clist,
222                         GtkCListRow * clist_row,
223                         gint column);
224 static void cell_set_text (GtkCList * clist,
225                            GtkCListRow * clist_row,
226                            gint column,
227                            gchar * text);
228 static void cell_set_pixmap (GtkCList * clist,
229                              GtkCListRow * clist_row,
230                              gint column,
231                              GdkPixmap * pixmap,
232                              GdkBitmap * mask);
233 static void cell_set_pixtext (GtkCList * clist,
234                               GtkCListRow * clist_row,
235                               gint column,
236                               gchar * text,
237                               guint8 spacing,
238                               GdkPixmap * pixmap,
239                               GdkBitmap * mask);
240
241 /* Signals */
242 static void gtk_clist_marshal_signal_1 (GtkObject * object,
243                                         GtkSignalFunc func,
244                                         gpointer func_data,
245                                         GtkArg * args);
246 static void gtk_clist_marshal_signal_2 (GtkObject * object,
247                                         GtkSignalFunc func,
248                                         gpointer func_data,
249                                         GtkArg * args);
250
251 /* Fill in data after widget is realized and has style */
252 static void add_style_data (GtkCList * clist);
253
254 static GtkContainerClass *parent_class = NULL;
255 static gint clist_signals[LAST_SIGNAL] = {0};
256
257 guint
258 gtk_clist_get_type ()
259 {
260   static guint clist_type = 0;
261
262   if (!clist_type)
263     {
264       GtkTypeInfo clist_info =
265       {
266         "GtkCList",
267         sizeof (GtkCList),
268         sizeof (GtkCListClass),
269         (GtkClassInitFunc) gtk_clist_class_init,
270         (GtkObjectInitFunc) gtk_clist_init,
271         (GtkArgSetFunc) NULL,
272         (GtkArgGetFunc) NULL,
273       };
274
275       clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info);
276     }
277
278   return clist_type;
279 }
280
281 static void
282 gtk_clist_class_init (GtkCListClass * klass)
283 {
284   GtkObjectClass *object_class;
285   GtkWidgetClass *widget_class;
286   GtkContainerClass *container_class;
287
288   object_class = (GtkObjectClass *) klass;
289   widget_class = (GtkWidgetClass *) klass;
290   container_class = (GtkContainerClass *) klass;
291
292   parent_class = gtk_type_class (gtk_container_get_type ());
293   clist_signals[MOUSE_CLICK] =
294     gtk_signal_new ("mouse_click",
295                     GTK_RUN_LAST,
296                     object_class->type,
297                     GTK_SIGNAL_OFFSET (GtkCListClass, mouse_click),
298                     gtk_clist_marshal_signal_1,
299                     GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
300   clist_signals[MOUSE_DOUBLE_CLICK] =
301     gtk_signal_new ("mouse_double_click",
302                     GTK_RUN_LAST,
303                     object_class->type,
304                     GTK_SIGNAL_OFFSET (GtkCListClass, mouse_double_click),
305                     gtk_clist_marshal_signal_1,
306                     GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
307   clist_signals[SELECT_ROW] =
308     gtk_signal_new ("select_row",
309                     GTK_RUN_LAST,
310                     object_class->type,
311                     GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
312                     gtk_clist_marshal_signal_1,
313                     GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
314   clist_signals[UNSELECT_ROW] =
315     gtk_signal_new ("unselect_row",
316                     GTK_RUN_LAST,
317                     object_class->type,
318                     GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
319                     gtk_clist_marshal_signal_1,
320                     GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
321   clist_signals[CLICK_COLUMN] =
322     gtk_signal_new ("click_column",
323                     GTK_RUN_LAST,
324                     object_class->type,
325                     GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
326                     gtk_clist_marshal_signal_2,
327                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
328
329   gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
330
331   object_class->destroy = gtk_clist_destroy;
332   object_class->finalize = gtk_clist_finalize;
333
334   widget_class->realize = gtk_clist_realize;
335   widget_class->unrealize = gtk_clist_unrealize;
336   widget_class->map = gtk_clist_map;
337   widget_class->unmap = gtk_clist_unmap;
338   widget_class->draw = gtk_clist_draw;
339   widget_class->button_press_event = gtk_clist_button_press;
340   widget_class->button_release_event = gtk_clist_button_release;
341   widget_class->motion_notify_event = gtk_clist_motion;
342   widget_class->expose_event = gtk_clist_expose;
343   widget_class->size_request = gtk_clist_size_request;
344   widget_class->size_allocate = gtk_clist_size_allocate;
345
346   container_class->add = NULL;
347   container_class->remove = NULL;
348   container_class->foreach = gtk_clist_foreach;
349
350   klass->mouse_click = NULL;
351   klass->mouse_double_click = NULL;
352   klass->select_row = real_select_row;
353   klass->unselect_row = real_unselect_row;
354   klass->click_column = NULL;
355
356   klass->scrollbar_spacing = 5;
357 }
358
359 static void
360 gtk_clist_marshal_signal_1 (GtkObject * object,
361                             GtkSignalFunc func,
362                             gpointer func_data,
363                             GtkArg * args)
364 {
365   GtkCListSignal1 rfunc;
366
367   rfunc = (GtkCListSignal1) func;
368
369   (*rfunc) (object, 
370             GTK_VALUE_INT (args[0]),
371             GTK_VALUE_INT (args[1]),
372             GTK_VALUE_INT (args[2]),
373             func_data);
374 }
375
376 static void
377 gtk_clist_marshal_signal_2 (GtkObject * object,
378                             GtkSignalFunc func,
379                             gpointer func_data,
380                             GtkArg * args)
381 {
382   GtkCListSignal2 rfunc;
383
384   rfunc = (GtkCListSignal2) func;
385
386   (*rfunc) (object, 
387             GTK_VALUE_INT (args[0]),
388             func_data);
389 }
390
391 static void
392 gtk_clist_init (GtkCList * clist)
393 {
394   clist->flags = 0;
395
396   GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
397   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
398
399   clist->rows = 0;
400   clist->row_center_offset = 0;
401   clist->row_height = 0;
402   clist->row_list = NULL;
403   clist->row_list_end = NULL;
404
405   clist->columns = 0;
406
407   clist->title_window = NULL;
408   clist->column_title_area.x = 0;
409   clist->column_title_area.y = 0;
410   clist->column_title_area.width = 0;
411   clist->column_title_area.height = 0;
412
413   clist->clist_window = NULL;
414   clist->clist_window_width = 0;
415   clist->clist_window_height = 0;
416
417   clist->hoffset = 0;
418   clist->voffset = 0;
419
420   clist->shadow_type = GTK_SHADOW_IN;
421   clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
422   clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
423
424   clist->cursor_drag = NULL;
425   clist->xor_gc = NULL;
426   clist->fg_gc = NULL;
427   clist->bg_gc = NULL;
428   clist->x_drag = 0;
429
430   clist->selection_mode = GTK_SELECTION_SINGLE;
431   clist->selection = NULL;
432 }
433
434 /*
435  * GTKCLIST PUBLIC INTERFACE
436  *   gtk_clist_new_with_titles
437  *   gtk_clist_new
438  */
439 GtkWidget *
440 gtk_clist_new_with_titles (int columns,
441                            gchar * titles[])
442 {
443   int i;
444   GtkWidget *widget;
445   GtkCList *clist;
446
447   if (titles == NULL)
448     return NULL;
449
450   widget = gtk_clist_new (columns);
451   if (!widget)
452     return NULL;
453   else
454     clist = GTK_CLIST (widget);
455
456   /* set column titles */
457   GTK_CLIST_SET_FLAGS (clist, CLIST_SHOW_TITLES);
458   for (i = 0; i < columns; i++)
459     {
460       gtk_clist_set_column_title (clist, i, titles[i]);
461     }
462
463   return widget;
464 }
465
466 GtkWidget *
467 gtk_clist_new (int columns)
468 {
469   GtkCList *clist;
470
471   /* sanity check */
472   if (columns < 1)
473     return NULL;
474
475   clist = gtk_type_new (gtk_clist_get_type ());
476   GTK_CLIST_UNSET_FLAGS (clist, CLIST_SHOW_TITLES);
477
478   /* initalize memory chunks */
479   clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
480                                           sizeof (GtkCListRow),
481                                           sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE, 
482                                           G_ALLOC_AND_FREE);
483
484   clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
485                                            sizeof (GtkCell) * columns,
486                                            sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE, 
487                                            G_ALLOC_AND_FREE);
488
489   /* set number of columns, allocate memory */
490   clist->columns = columns;
491   clist->column = columns_new (clist);
492
493   /* there needs to be at least one column button 
494    * because there is alot of code that will break if it
495    * isn't there*/
496   column_button_create (clist, 0);
497
498   /* create scrollbars */
499   create_scrollbars (clist);
500
501   return GTK_WIDGET (clist);
502 }
503
504 void
505 gtk_clist_set_border (GtkCList * clist,
506                       GtkShadowType border)
507 {
508   g_return_if_fail (clist != NULL);
509
510   clist->shadow_type = border;
511
512   if (GTK_WIDGET_VISIBLE (clist))
513     gtk_widget_queue_resize (GTK_WIDGET (clist));
514 }
515
516 void
517 gtk_clist_set_selection_mode (GtkCList * clist,
518                               GtkSelectionMode mode)
519 {
520   g_return_if_fail (clist != NULL);
521
522   clist->selection_mode = mode;
523 }
524
525 void
526 gtk_clist_freeze (GtkCList * clist)
527 {
528   g_return_if_fail (clist != NULL);
529
530   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
531 }
532
533 void
534 gtk_clist_thaw (GtkCList * clist)
535 {
536   g_return_if_fail (clist != NULL);
537
538   GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
539
540   adjust_scrollbars (clist);
541   draw_rows (clist, NULL);
542 }
543
544 void
545 gtk_clist_column_titles_show (GtkCList * clist)
546 {
547   g_return_if_fail (clist != NULL);
548
549   if (!GTK_CLIST_SHOW_TITLES (clist))
550     {
551       GTK_CLIST_SET_FLAGS (clist, CLIST_SHOW_TITLES);
552       gdk_window_show (clist->title_window);
553       gtk_widget_queue_resize (GTK_WIDGET (clist));
554     }
555 }
556
557 void 
558 gtk_clist_column_titles_hide (GtkCList * clist)
559 {
560   g_return_if_fail (clist != NULL);
561
562   if (GTK_CLIST_SHOW_TITLES (clist))
563     {
564       GTK_CLIST_UNSET_FLAGS (clist, CLIST_SHOW_TITLES);
565       gdk_window_hide (clist->title_window);
566       gtk_widget_queue_resize (GTK_WIDGET (clist));
567     }
568 }
569
570 void
571 gtk_clist_column_title_active (GtkCList * clist,
572                                gint column)
573 {
574   g_return_if_fail (clist != NULL);
575
576   if (column < 0 || column >= clist->columns)
577     return;
578
579   if (!GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
580       !GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
581     {
582       GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
583       if (GTK_WIDGET_VISIBLE (clist))
584         gtk_widget_queue_draw (clist->column[column].button);
585     }
586 }
587
588 void
589 gtk_clist_column_title_passive (GtkCList * clist,
590                                 gint column)
591 {
592   g_return_if_fail (clist != NULL);
593
594   if (column < 0 || column >= clist->columns)
595     return;
596
597   if (GTK_WIDGET_SENSITIVE (clist->column[column].button) ||
598       GTK_WIDGET_CAN_FOCUS (clist->column[column].button))
599     {
600       GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS);
601       if (GTK_WIDGET_VISIBLE (clist))
602         gtk_widget_queue_draw (clist->column[column].button);
603     }
604 }
605
606 void
607 gtk_clist_column_titles_active (GtkCList * clist)
608 {
609   gint i;
610
611   g_return_if_fail (clist != NULL);
612
613   for (i = 0; i < clist->columns; i++)
614     if (clist->column[i].button)
615       gtk_clist_column_title_active (clist, i);
616 }
617
618 void
619 gtk_clist_column_titles_passive (GtkCList * clist)
620 {
621   gint i;
622
623   g_return_if_fail (clist != NULL);
624
625   for (i = 0; i < clist->columns; i++)
626     if (clist->column[i].button)
627       gtk_clist_column_title_passive (clist, i);
628 }
629
630 void
631 gtk_clist_set_column_title (GtkCList * clist,
632                             gint column,
633                             gchar * title)
634 {
635   gint new_button = 0;
636   GtkWidget *old_widget;
637   GtkWidget *alignment = NULL;
638   GtkWidget *label;
639
640   g_return_if_fail (clist != NULL);
641
642   if (column < 0 || column >= clist->columns)
643     return;
644
645   /* if the column button doesn't currently exist,
646    * it has to be created first */
647   if (!clist->column[column].button)
648     {
649       column_button_create (clist, column);
650       new_button = 1;
651     }
652
653   column_title_new (clist, column, title);
654
655   /* remove and destroy the old widget */
656   old_widget = GTK_BUTTON (clist->column[column].button)->child;
657   if (old_widget)
658     {
659       gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
660       gtk_widget_destroy (old_widget);
661     }
662
663   /* create new alignment based no column justification */
664   switch (clist->column[column].justification)
665     {
666     case GTK_JUSTIFY_LEFT:
667       alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
668       break;
669
670     case GTK_JUSTIFY_RIGHT:
671       alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
672       break;
673
674     case GTK_JUSTIFY_CENTER:
675       alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
676       break;
677
678     case GTK_JUSTIFY_FILL:
679       alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
680       break;
681     }
682
683   label = gtk_label_new (clist->column[column].title);
684   gtk_container_add (GTK_CONTAINER (alignment), label);
685   gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
686   gtk_widget_show (label);
687   gtk_widget_show (alignment);
688
689   /* if this button didn't previously exist, then the
690    * column button positions have to be re-computed */
691   if (GTK_WIDGET_VISIBLE (clist) && new_button)
692     size_allocate_title_buttons (clist);
693 }
694
695 void
696 gtk_clist_set_column_widget (GtkCList * clist,
697                              gint column,
698                              GtkWidget * widget)
699 {
700   gint new_button = 0;
701   GtkWidget *old_widget;
702
703   g_return_if_fail (clist != NULL);
704
705   if (column < 0 || column >= clist->columns)
706     return;
707
708   /* if the column button doesn't currently exist,
709    * it has to be created first */
710   if (!clist->column[column].button)
711     {
712       column_button_create (clist, column);
713       new_button = 1;
714     }
715
716   column_title_new (clist, column, NULL);
717
718   /* remove and destroy the old widget */
719   old_widget = GTK_BUTTON (clist->column[column].button)->child;
720   if (old_widget)
721     {
722       gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
723       gtk_widget_destroy (old_widget);
724     }
725
726   /* add and show the widget */
727   if (widget)
728     {
729       gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
730       gtk_widget_show (widget);
731     }
732
733   /* if this button didn't previously exist, then the
734    * column button positions have to be re-computed */
735   if (GTK_WIDGET_VISIBLE (clist) && new_button)
736     size_allocate_title_buttons (clist);
737 }
738
739 void
740 gtk_clist_set_column_justification (GtkCList * clist,
741                                     gint column,
742                                     GtkJustification justification)
743 {
744   GtkWidget *alignment;
745
746   g_return_if_fail (clist != NULL);
747
748   if (column < 0 || column >= clist->columns)
749     return;
750
751   clist->column[column].justification = justification;
752
753   /* change the alinment of the button title if it's not a
754    * custom widget */
755   if (clist->column[column].title)
756     {
757       alignment = GTK_BUTTON (clist->column[column].button)->child;
758
759       switch (clist->column[column].justification)
760         {
761         case GTK_JUSTIFY_LEFT:
762           gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
763           break;
764
765         case GTK_JUSTIFY_RIGHT:
766           gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
767           break;
768
769         case GTK_JUSTIFY_CENTER:
770           gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
771           break;
772
773         case GTK_JUSTIFY_FILL:
774           gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
775           break;
776
777         default:
778           break;
779         }
780     }
781
782   if (!GTK_CLIST_FROZEN (clist))
783     draw_rows (clist, NULL);
784 }
785
786 void
787 gtk_clist_set_column_width (GtkCList * clist,
788                             gint column,
789                             gint width)
790 {
791   g_return_if_fail (clist != NULL);
792
793   if (column < 0 || column >= clist->columns)
794     return;
795
796   clist->column[column].width = width;
797   clist->column[column].width_set = TRUE;
798
799   /* FIXME: this is quite expensive to do if the widget hasn't
800    *        been size_allocated yet, and pointless. Should
801    *        a flag be kept
802    */
803   size_allocate_columns (clist);
804   size_allocate_title_buttons (clist);
805
806   if (!GTK_CLIST_FROZEN (clist))
807     {
808       adjust_scrollbars (clist);
809       draw_rows (clist, NULL);
810     }
811 }
812
813 void
814 gtk_clist_set_row_height (GtkCList * clist,
815                           gint height)
816 {
817   gint text_height;
818
819   g_return_if_fail (clist != NULL);
820
821   if (height > 0)
822     clist->row_height = height;
823   else
824     return;
825
826   GTK_CLIST_SET_FLAGS (clist, CLIST_ROW_HEIGHT_SET);
827   
828   if (GTK_WIDGET_REALIZED (clist))
829     {
830       text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
831                               GTK_WIDGET (clist)->style->font->descent + 1);
832       clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
833     }
834       
835   if (!GTK_CLIST_FROZEN (clist))
836     {
837       adjust_scrollbars (clist);
838       draw_rows (clist, NULL);
839     }
840 }
841
842 void
843 gtk_clist_moveto (GtkCList * clist,
844                   gint row,
845                   gint column,
846                   gfloat row_align,
847                   gfloat col_align)
848 {
849   gint x, y;
850
851   g_return_if_fail (clist != NULL);
852
853   if (row < -1 || row >= clist->rows)
854     return;
855   if (column < -1 || column >= clist->columns)
856     return;
857
858   /* adjust vertical scrollbar */
859   if (row >= 0)
860     {
861       x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height - 
862                                                (clist->row_height + 2 * CELL_SPACING)));
863       
864       if (x < 0)
865         GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
866       else if (x > LIST_HEIGHT (clist) - clist->clist_window_height)
867         GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - 
868           clist->clist_window_height;
869       else
870         GTK_RANGE (clist->vscrollbar)->adjustment->value = x;
871       
872       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
873                                "value_changed");
874     } 
875      
876   /* adjust horizontal scrollbar */
877   if (column >= 0)
878     {
879       y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width - 
880                                                       clist->column[column].area.width + 
881                                                       2 * (CELL_SPACING + COLUMN_INSET)));
882       
883       if (y < 0)
884         GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0;
885       else if (y > LIST_WIDTH (clist) - clist->clist_window_width)
886         GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - 
887           clist->clist_window_width;
888       else
889         GTK_RANGE (clist->hscrollbar)->adjustment->value = y;
890       
891       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
892                                "value_changed");
893     }
894 }
895
896 GtkCellType 
897 gtk_clist_get_cell_type (GtkCList * clist,
898                          gint row,
899                          gint column)
900 {
901   GtkCListRow *clist_row;
902
903   g_return_val_if_fail (clist != NULL, -1);
904
905   if (row < 0 || row >= clist->rows)
906     return -1;
907   if (column < 0 || column >= clist->columns)
908     return -1;
909
910   clist_row = (g_list_nth (clist->row_list, row))->data;
911
912   return clist_row->cell[column].type;
913 }
914
915 void
916 gtk_clist_set_text (GtkCList * clist,
917                     gint row,
918                     gint column,
919                     gchar * text)
920 {
921   GtkCListRow *clist_row;
922
923   g_return_if_fail (clist != NULL);
924
925   if (row < 0 || row >= clist->rows)
926     return;
927   if (column < 0 || column >= clist->columns)
928     return;
929
930   clist_row = (g_list_nth (clist->row_list, row))->data;
931
932   /* if text is null, then the cell is empty */
933   if (text)
934     cell_set_text (clist, clist_row, column, text);
935   else
936     cell_empty (clist, clist_row, column);
937
938   /* redraw the list if it's not frozen */
939   if (!GTK_CLIST_FROZEN (clist))
940     {
941       if (gtk_clist_row_isvisable (clist, row))
942         draw_row (clist, NULL, row, clist_row);
943     }
944 }
945
946 gint
947 gtk_clist_get_text (GtkCList * clist,
948                     gint row,
949                     gint column,
950                     gchar ** text)
951 {
952   GtkCListRow *clist_row;
953
954   g_return_val_if_fail (clist != NULL, 0);
955
956   if (row < 0 || row >= clist->rows)
957     return 0;
958   if (column < 0 || column >= clist->columns)
959     return 0;
960
961   clist_row = (g_list_nth (clist->row_list, row))->data;
962
963   if (clist_row->cell[column].type != GTK_CELL_TEXT)
964     return 0;
965
966   if (text)
967     *text = GTK_CELL_TEXT (clist_row->cell[column])->text;
968
969   return 1;
970 }
971
972 void
973 gtk_clist_set_pixmap (GtkCList * clist,
974                       gint row,
975                       gint column,
976                       GdkPixmap * pixmap,
977                       GdkBitmap * mask)
978 {
979   GtkCListRow *clist_row;
980
981   g_return_if_fail (clist != NULL);
982
983   if (row < 0 || row >= clist->rows)
984     return;
985   if (column < 0 || column >= clist->columns)
986     return;
987
988   clist_row = (g_list_nth (clist->row_list, row))->data;
989   
990   gdk_pixmap_ref (pixmap);
991   gdk_pixmap_ref (mask);
992   cell_set_pixmap (clist, clist_row, column, pixmap, mask);
993
994   /* redraw the list if it's not frozen */
995   if (!GTK_CLIST_FROZEN (clist))
996     {
997       if (gtk_clist_row_isvisable (clist, row))
998         draw_row (clist, NULL, row, clist_row);
999     }
1000 }
1001
1002 gint
1003 gtk_clist_get_pixmap (GtkCList * clist,
1004                       gint row,
1005                       gint column,
1006                       GdkPixmap ** pixmap,
1007                       GdkBitmap ** mask)
1008 {
1009   GtkCListRow *clist_row;
1010
1011   g_return_val_if_fail (clist != NULL, 0);
1012
1013   if (row < 0 || row >= clist->rows)
1014     return 0;
1015   if (column < 0 || column >= clist->columns)
1016     return 0;
1017
1018   clist_row = (g_list_nth (clist->row_list, row))->data;
1019
1020   if (clist_row->cell[column].type != GTK_CELL_PIXMAP)
1021     return 0;
1022
1023   if (pixmap)
1024     *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
1025   if (mask)
1026     *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
1027
1028   return 1;
1029 }
1030
1031 void
1032 gtk_clist_set_pixtext (GtkCList * clist,
1033                        gint row,
1034                        gint column,
1035                        gchar * text,
1036                        guint8 spacing,
1037                        GdkPixmap * pixmap,
1038                        GdkBitmap * mask)
1039 {
1040   GtkCListRow *clist_row;
1041
1042   g_return_if_fail (clist != NULL);
1043
1044   if (row < 0 || row >= clist->rows)
1045     return;
1046   if (column < 0 || column >= clist->columns)
1047     return;
1048
1049   clist_row = (g_list_nth (clist->row_list, row))->data;
1050   
1051   gdk_pixmap_ref (pixmap);
1052   gdk_pixmap_ref (mask);
1053   cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
1054
1055   /* redraw the list if it's not frozen */
1056   if (!GTK_CLIST_FROZEN (clist))
1057     {
1058       if (gtk_clist_row_isvisable (clist, row))
1059         draw_row (clist, NULL, row, clist_row);
1060     }
1061 }
1062
1063 gint
1064 gtk_clist_get_pixtext (GtkCList * clist,
1065                        gint row,
1066                        gint column,
1067                        gchar ** text,
1068                        guint8 * spacing,
1069                        GdkPixmap ** pixmap,
1070                        GdkBitmap ** mask)
1071 {
1072   GtkCListRow *clist_row;
1073
1074   g_return_val_if_fail (clist != NULL, 0);
1075
1076   if (row < 0 || row >= clist->rows)
1077     return 0;
1078   if (column < 0 || column >= clist->columns)
1079     return 0;
1080
1081   clist_row = (g_list_nth (clist->row_list, row))->data;
1082
1083   if (clist_row->cell[column].type != GTK_CELL_PIXTEXT)
1084     return 0;
1085
1086   if (text)
1087     *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
1088   if (spacing)
1089     *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
1090   if (pixmap)
1091     *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
1092   if (mask)
1093     *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
1094
1095   return 1;
1096 }
1097
1098 void
1099 gtk_clist_set_foreground (GtkCList * clist,
1100                           gint row,
1101                           GdkColor * color)
1102 {
1103   GtkCListRow *clist_row;
1104
1105   g_return_if_fail (clist != NULL);
1106   g_return_if_fail (color != NULL);
1107
1108   if (row < 0 || row >= clist->rows)
1109     return;
1110
1111   clist_row = (g_list_nth (clist->row_list, row))->data;
1112   clist_row->foreground = *color;
1113   clist_row->fg_set = TRUE;
1114
1115   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1116     draw_row (clist, NULL, row, clist_row);
1117 }
1118
1119 void gtk_clist_set_background (GtkCList * clist,
1120                                gint row,
1121                                GdkColor * color)
1122 {
1123   GtkCListRow *clist_row;
1124
1125   g_return_if_fail (clist != NULL);
1126   g_return_if_fail (color != NULL);
1127
1128   if (row < 0 || row >= clist->rows)
1129     return;
1130
1131   clist_row = (g_list_nth (clist->row_list, row))->data;
1132   clist_row->background = *color;
1133   clist_row->bg_set = TRUE;
1134
1135   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1136     draw_row (clist, NULL, row, clist_row);
1137 }
1138
1139 void
1140 gtk_clist_set_shift (GtkCList * clist,
1141                      gint row,
1142                      gint column,
1143                      gint vertical,
1144                      gint horizontal)
1145 {
1146   GtkCListRow *clist_row;
1147
1148   g_return_if_fail (clist != NULL);
1149
1150   if (row < 0 || row >= clist->rows)
1151     return;
1152   if (column < 0 || column >= clist->columns)
1153     return;
1154
1155   clist_row = (g_list_nth (clist->row_list, row))->data;
1156
1157   clist_row->cell[column].vertical = vertical;
1158   clist_row->cell[column].horizontal = horizontal;
1159
1160   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1161     draw_row (clist, NULL, row, clist_row);
1162 }
1163
1164 gint
1165 gtk_clist_append (GtkCList * clist,
1166                   gchar * text[])
1167 {
1168   gint i;
1169   GtkCListRow *clist_row;
1170
1171   g_return_val_if_fail (clist != NULL, -1);
1172
1173   clist_row = row_new (clist);
1174   clist->rows++;
1175
1176   /* set the text in the row's columns */
1177   if (text)
1178     for (i = 0; i < clist->columns; i++)
1179       if (text[i])
1180         cell_set_text (clist, clist_row, i, text[i]);
1181
1182   /* keeps track of the end of the list so the list 
1183    * doesn't have to be traversed every time a item is added */
1184   if (!clist->row_list)
1185     {
1186       clist->row_list = g_list_append (clist->row_list, clist_row);
1187       clist->row_list_end = clist->row_list;
1188
1189       /* check the selection mode to see if we should select
1190        * the first row automaticly */
1191       switch (clist->selection_mode)
1192         {
1193         case GTK_SELECTION_BROWSE:
1194           gtk_clist_select_row (clist, 0, -1);
1195           break;
1196
1197         default:
1198           break;
1199         }
1200     }
1201   else
1202     clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1203   
1204   /* redraw the list if it's not frozen */
1205   if (!GTK_CLIST_FROZEN (clist))
1206     {
1207       adjust_scrollbars (clist);
1208
1209       if (gtk_clist_row_isvisable (clist, clist->rows - 1))
1210         draw_rows (clist, NULL);
1211     }
1212
1213   /* return index of the row */
1214   return clist->rows - 1;
1215 }
1216
1217 void
1218 gtk_clist_insert (GtkCList * clist,
1219                   gint row,
1220                   gchar * text[])
1221 {
1222   gint i;
1223   GtkCListRow *clist_row;
1224
1225   g_return_if_fail (clist != NULL);
1226   g_return_if_fail (text != NULL);
1227
1228   /* return if out of bounds */
1229   if (row < 0 || row > (clist->rows - 1))
1230     return;
1231
1232   /* create the row */
1233   clist_row = row_new (clist);
1234
1235   /* set the text in the row's columns */
1236   if (text)
1237     for (i = 0; i < clist->columns; i++)
1238       if (text[i])
1239         cell_set_text (clist, clist_row, i, text[i]);
1240
1241   /* reset the row end pointer if we're inserting at the
1242    * end of the list */
1243   if (row == clist->rows)
1244     clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
1245   else
1246     clist->row_list = g_list_insert (clist->row_list, clist_row, row);
1247
1248   clist->rows++;
1249
1250   /* redraw the list if it isn't frozen */
1251   if (!GTK_CLIST_FROZEN (clist))
1252     {
1253       adjust_scrollbars (clist);
1254
1255       if (gtk_clist_row_isvisable (clist, row))
1256         draw_rows (clist, NULL);
1257     }
1258 }
1259
1260 void
1261 gtk_clist_remove (GtkCList * clist,
1262                   gint row)
1263 {
1264   gint was_visible;
1265   GList *list;
1266   GtkCListRow *clist_row;
1267
1268   g_return_if_fail (clist != NULL);
1269
1270   /* return if out of bounds */
1271   if (row < 0 || row > (clist->rows - 1))
1272     return;
1273
1274   was_visible = gtk_clist_row_isvisable (clist, row);
1275
1276   /* get the row we're going to delete */
1277   list = g_list_nth (clist->row_list, row);
1278   clist_row = list->data;
1279
1280   /* reset the row end pointer if we're removing at the
1281    * end of the list */
1282   if (row == clist->rows - 1)
1283     clist->row_list_end = list->prev;
1284
1285   clist->row_list = g_list_remove (clist->row_list, clist_row);
1286   clist->rows--;
1287
1288   /* redraw the row if it isn't frozen */
1289   if (!GTK_CLIST_FROZEN (clist))
1290     {
1291       adjust_scrollbars (clist);
1292
1293       if (was_visible)
1294         draw_rows (clist, NULL);
1295     }
1296
1297   if (clist_row->state == GTK_STATE_SELECTED)
1298     {
1299       switch (clist->selection_mode)
1300         {
1301         case GTK_SELECTION_BROWSE:
1302           if (row >= clist->rows)
1303             row--;
1304           gtk_clist_select_row (clist, row, -1);
1305           break;
1306           
1307         default:
1308           break;
1309         }
1310
1311       /* remove from selection list */
1312       clist->selection = g_list_remove (clist->selection, clist_row);
1313     }
1314
1315   row_delete (clist, clist_row);
1316 }
1317
1318 void
1319 gtk_clist_clear (GtkCList * clist)
1320 {
1321   GList *list;
1322   GtkCListRow *clist_row;
1323
1324   g_return_if_fail (clist != NULL);
1325
1326   /* remove all the rows */
1327   list = clist->row_list;
1328   while (list)
1329     {
1330       clist_row = list->data;
1331       list = list->next;
1332
1333       row_delete (clist, clist_row);
1334     }
1335   g_list_free (clist->row_list);
1336
1337   /* free up the selection list */
1338   g_list_free (clist->selection);
1339
1340   clist->row_list = NULL;
1341   clist->row_list_end = NULL;
1342   clist->selection = NULL;
1343   clist->voffset = 0;
1344   clist->rows = 0;
1345
1346   /* zero-out the scrollbars */
1347   if (clist->vscrollbar)
1348     {
1349       GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1350       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1351       
1352       if (!GTK_CLIST_FROZEN (clist))
1353         {
1354           adjust_scrollbars (clist);
1355           draw_rows (clist, NULL);
1356         }
1357     }
1358 }
1359
1360 void
1361 gtk_clist_set_row_data (GtkCList * clist,
1362                         gint row,
1363                         gpointer data)
1364 {
1365   GtkCListRow *clist_row;
1366
1367   g_return_if_fail (clist != NULL);
1368
1369   if (row < 0 || row > (clist->rows - 1))
1370     return;
1371
1372   clist_row = (g_list_nth (clist->row_list, row))->data;
1373   clist_row->data = data;
1374
1375   /*
1376    * re-send the selected signal if data is changed/added
1377    * so the application can respond to the new data -- 
1378    * this could be questionable behavior
1379    */
1380   if (clist_row->state == GTK_STATE_SELECTED)
1381     gtk_clist_select_row (clist, 0, 0);
1382 }
1383
1384 gpointer
1385 gtk_clist_get_row_data (GtkCList * clist,
1386                         gint row)
1387 {
1388   GtkCListRow *clist_row;
1389
1390   g_return_val_if_fail (clist != NULL, NULL);
1391
1392   if (row < 0 || row > (clist->rows - 1))
1393     return NULL;
1394
1395   clist_row = (g_list_nth (clist->row_list, row))->data;
1396   return clist_row->data;
1397 }
1398
1399 gint
1400 gtk_clist_find_row_from_data (GtkCList * clist,
1401                               gpointer data)
1402 {
1403   GList *list;
1404   gint n;
1405
1406   g_return_val_if_fail (clist != NULL, -1);
1407   g_return_val_if_fail (GTK_IS_CLIST (clist), -1);
1408
1409   if (clist->rows < 1)
1410     return -1; /* is this an optimization or just worthless? */
1411
1412   n = 0;
1413   list = clist->row_list;
1414   while (list)
1415     {
1416       GtkCListRow *clist_row;
1417
1418       clist_row = list->data;
1419       if (clist_row->data == data)
1420         break;
1421       n++;
1422       list = list->next;
1423     }
1424
1425   if (list)
1426     return n;
1427
1428   return -1;
1429 }
1430
1431 void
1432 gtk_clist_select_row (GtkCList * clist,
1433                       gint row,
1434                       gint column)
1435 {
1436   g_return_if_fail (clist != NULL);
1437
1438   if (row < 0 || row >= clist->rows)
1439     return;
1440
1441   if (column < -1 || column >= clist->columns)
1442     return;
1443
1444   gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], row, column, 0);
1445 }
1446
1447 void
1448 gtk_clist_unselect_row (GtkCList * clist,
1449                         gint row,
1450                         gint column)
1451 {
1452   g_return_if_fail (clist != NULL);
1453
1454   if (row < 0 || row >= clist->rows)
1455     return;
1456
1457   if (column < -1 || column >= clist->columns)
1458     return;
1459
1460   gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], row, column, 0);
1461 }
1462
1463 gint
1464 gtk_clist_row_isvisable (GtkCList * clist,
1465                          gint row)
1466 {
1467   g_return_val_if_fail (clist != NULL, 0);
1468
1469   if (row < 0 || row >= clist->rows)
1470     return 0;
1471
1472   if (clist->row_height == 0)
1473     return 0;
1474
1475   if (row < ROW_FROM_YPIXEL (clist, 0))
1476     return 0;
1477
1478   if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
1479     return 0;
1480
1481   return 1;
1482 }
1483
1484 GtkAdjustment *
1485 gtk_clist_get_vadjustment (GtkCList * clist)
1486 {
1487   g_return_val_if_fail (clist != NULL, NULL);
1488   g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1489
1490   return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
1491 }
1492
1493 GtkAdjustment *
1494 gtk_clist_get_hadjustment (GtkCList * clist)
1495 {
1496   g_return_val_if_fail (clist != NULL, NULL);
1497   g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1498
1499   return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
1500 }
1501
1502 void
1503 gtk_clist_set_policy (GtkCList * clist,
1504                       GtkPolicyType vscrollbar_policy,
1505                       GtkPolicyType hscrollbar_policy)
1506 {
1507   g_return_if_fail (clist != NULL);
1508   g_return_if_fail (GTK_IS_CLIST (clist));
1509
1510   if (clist->vscrollbar_policy != vscrollbar_policy)
1511     {
1512       clist->vscrollbar_policy = vscrollbar_policy;
1513
1514       if (GTK_WIDGET (clist)->parent)
1515         gtk_widget_queue_resize (GTK_WIDGET (clist));
1516     }
1517
1518   if (clist->hscrollbar_policy != hscrollbar_policy)
1519     {
1520       clist->hscrollbar_policy = hscrollbar_policy;
1521
1522       if (GTK_WIDGET (clist)->parent)
1523         gtk_widget_queue_resize (GTK_WIDGET (clist));
1524     }
1525 }
1526
1527 /*
1528  * GTKOBJECT
1529  *   gtk_clist_destroy
1530  *   gtk_clist_finalize
1531  */
1532 static void
1533 gtk_clist_destroy (GtkObject * object)
1534 {
1535   gint i;
1536   GtkCList *clist;
1537
1538   g_return_if_fail (object != NULL);
1539   g_return_if_fail (GTK_IS_CLIST (object));
1540
1541   clist = GTK_CLIST (object);
1542
1543   /* freeze the list */
1544   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1545
1546   /* get rid of all the rows */
1547   gtk_clist_clear (clist);
1548
1549   /* Since we don't have a _remove method, unparent the children
1550    * instead of destroying them so the focus will be unset properly.
1551    * (For other containers, the _remove method takes care of the
1552    * unparent) The destroy will happen when the refcount drops
1553    * to zero.
1554    */
1555
1556   /* destroy the scrollbars */
1557   if (clist->vscrollbar)
1558     {
1559       gtk_widget_unparent (clist->vscrollbar);
1560       clist->vscrollbar = NULL;
1561     }
1562   if (clist->hscrollbar)
1563     {
1564       gtk_widget_unparent (clist->hscrollbar);
1565       clist->hscrollbar = NULL;
1566     }
1567
1568   /* destroy the column buttons */
1569   for (i = 0; i < clist->columns; i++)
1570     if (clist->column[i].button)
1571       {
1572         gtk_widget_unparent (clist->column[i].button);
1573         clist->column[i].button = NULL;
1574       }
1575
1576   if (GTK_OBJECT_CLASS (parent_class)->destroy)
1577     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1578 }
1579
1580 static void
1581 gtk_clist_finalize (GtkObject * object)
1582 {
1583   GtkCList *clist;
1584
1585   g_return_if_fail (object != NULL);
1586   g_return_if_fail (GTK_IS_CLIST (object));
1587
1588   clist = GTK_CLIST (object);
1589
1590   columns_delete (clist);
1591
1592   g_mem_chunk_destroy (clist->cell_mem_chunk);
1593   g_mem_chunk_destroy (clist->row_mem_chunk);
1594
1595   if (GTK_OBJECT_CLASS (parent_class)->finalize)
1596     (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
1597 }
1598
1599 /*
1600  * GTKWIDGET
1601  *   gtk_clist_realize
1602  *   gtk_clist_unrealize
1603  *   gtk_clist_map
1604  *   gtk_clist_unmap
1605  *   gtk_clist_draw
1606  *   gtk_clist_expose
1607  *   gtk_clist_button_press
1608  *   gtk_clist_button_release
1609  *   gtk_clist_button_motion
1610  *   gtk_clist_size_request
1611  *   gtk_clist_size_allocate
1612  */
1613 static void
1614 gtk_clist_realize (GtkWidget * widget)
1615 {
1616   gint i;
1617   GtkCList *clist;
1618   GdkWindowAttr attributes;
1619   gint attributes_mask;
1620   GdkGCValues values;
1621
1622   g_return_if_fail (widget != NULL);
1623   g_return_if_fail (GTK_IS_CLIST (widget));
1624
1625   clist = GTK_CLIST (widget);
1626
1627   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1628
1629   attributes.window_type = GDK_WINDOW_CHILD;
1630   attributes.x = widget->allocation.x;
1631   attributes.y = widget->allocation.y;
1632   attributes.width = widget->allocation.width;
1633   attributes.height = widget->allocation.height;
1634   attributes.wclass = GDK_INPUT_OUTPUT;
1635   attributes.visual = gtk_widget_get_visual (widget);
1636   attributes.colormap = gtk_widget_get_colormap (widget);
1637   attributes.event_mask = gtk_widget_get_events (widget);
1638   attributes.event_mask |= (GDK_EXPOSURE_MASK |
1639                             GDK_BUTTON_PRESS_MASK |
1640                             GDK_BUTTON_RELEASE_MASK |
1641                             GDK_KEY_PRESS_MASK);
1642   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1643
1644
1645   /* main window */
1646   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
1647   gdk_window_set_user_data (widget->window, clist);
1648
1649   widget->style = gtk_style_attach (widget->style, widget->window);
1650
1651   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
1652
1653   /* column-title window */
1654   clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1655   gdk_window_set_user_data (clist->title_window, clist);
1656
1657   gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
1658   gdk_window_show (clist->title_window);
1659
1660   /* set things up so column buttons are drawn in title window */
1661   for (i = 0; i < clist->columns; i++)
1662     if (clist->column[i].button)
1663       gtk_widget_set_parent_window (clist->column[i].button, clist->title_window);
1664
1665   /* clist-window */
1666   clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1667   gdk_window_set_user_data (clist->clist_window, clist);
1668
1669   gdk_window_set_background (clist->clist_window, &widget->style->bg[GTK_STATE_PRELIGHT]);
1670   gdk_window_show (clist->clist_window);
1671   gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
1672                        &clist->clist_window_height);
1673
1674   /* create resize windows */
1675   attributes.wclass = GDK_INPUT_ONLY;
1676   attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
1677                            GDK_BUTTON_RELEASE_MASK |
1678                            GDK_POINTER_MOTION_MASK |
1679                            GDK_POINTER_MOTION_HINT_MASK);
1680   attributes.cursor = clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1681   attributes_mask = GDK_WA_CURSOR;
1682   
1683   for (i = 0; i < clist->columns; i++)
1684     {
1685       clist->column[i].window = gdk_window_new (clist->title_window, &attributes, attributes_mask);
1686       gdk_window_set_user_data (clist->column[i].window, clist);
1687       gdk_window_show (clist->column[i].window);
1688     }
1689
1690   /* GCs */
1691   clist->fg_gc = gdk_gc_new (widget->window);
1692   clist->bg_gc = gdk_gc_new (widget->window);
1693   
1694   /* We'll use this gc to do scrolling as well */
1695   gdk_gc_set_exposures (clist->fg_gc, TRUE);
1696
1697   values.foreground = widget->style->white;
1698   values.function = GDK_XOR;
1699   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1700   clist->xor_gc = gdk_gc_new_with_values (widget->window,
1701                                           &values,
1702                                           GDK_GC_FOREGROUND |
1703                                           GDK_GC_FUNCTION |
1704                                           GDK_GC_SUBWINDOW);
1705
1706   add_style_data (clist);
1707 }
1708
1709 static void
1710 gtk_clist_unrealize (GtkWidget * widget)
1711 {
1712   gint i;
1713   GtkCList *clist;
1714
1715   g_return_if_fail (widget != NULL);
1716   g_return_if_fail (GTK_IS_CLIST (widget));
1717
1718   clist = GTK_CLIST (widget);
1719
1720   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1721
1722   gdk_cursor_destroy (clist->cursor_drag);
1723   gdk_gc_destroy (clist->xor_gc);
1724   gdk_gc_destroy (clist->fg_gc);
1725   gdk_gc_destroy (clist->bg_gc);
1726
1727   for (i = 0; i < clist->columns; i++)
1728     if (clist->column[i].window)
1729       {
1730         gdk_window_set_user_data (clist->column[i].window, NULL);
1731         gdk_window_destroy (clist->column[i].window);
1732         clist->column[i].window = NULL;
1733       }
1734
1735   gdk_window_set_user_data (clist->clist_window, NULL);
1736   gdk_window_destroy (clist->clist_window);
1737   clist->clist_window = NULL;
1738
1739   gdk_window_set_user_data (clist->title_window, NULL);
1740   gdk_window_destroy (clist->title_window);
1741   clist->title_window = NULL;
1742
1743   clist->cursor_drag = NULL;
1744   clist->xor_gc = NULL;
1745   clist->fg_gc = NULL;
1746   clist->bg_gc = NULL;
1747
1748   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1749     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1750 }
1751
1752 static void
1753 gtk_clist_map (GtkWidget * widget)
1754 {
1755   gint i;
1756   GtkCList *clist;
1757
1758   g_return_if_fail (widget != NULL);
1759   g_return_if_fail (GTK_IS_CLIST (widget));
1760
1761   clist = GTK_CLIST (widget);
1762
1763   if (!GTK_WIDGET_MAPPED (widget))
1764     {
1765       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1766
1767       gdk_window_show (widget->window);
1768       gdk_window_show (clist->title_window);
1769       gdk_window_show (clist->clist_window);
1770
1771       /* map column buttons */
1772       for (i = 0; i < clist->columns; i++)
1773         if (clist->column[i].button &&
1774             GTK_WIDGET_VISIBLE (clist->column[i].button) &&
1775             !GTK_WIDGET_MAPPED (clist->column[i].button))
1776           gtk_widget_map (clist->column[i].button);
1777       
1778       /* map resize windows AFTER column buttons (above) */
1779       for (i = 0; i < clist->columns; i++)
1780         if (clist->column[i].window && clist->column[i].button)
1781           gdk_window_show (clist->column[i].window);
1782        
1783       /* map vscrollbars */
1784       if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
1785           !GTK_WIDGET_MAPPED (clist->vscrollbar))
1786         gtk_widget_map (clist->vscrollbar);
1787
1788       if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
1789           !GTK_WIDGET_MAPPED (clist->hscrollbar))
1790         gtk_widget_map (clist->hscrollbar);
1791
1792       /* unfreeze the list */
1793       GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
1794     }
1795 }
1796
1797 static void
1798 gtk_clist_unmap (GtkWidget * widget)
1799 {
1800   gint i;
1801   GtkCList *clist;
1802
1803   g_return_if_fail (widget != NULL);
1804   g_return_if_fail (GTK_IS_CLIST (widget));
1805
1806   clist = GTK_CLIST (widget);
1807
1808   if (GTK_WIDGET_MAPPED (widget))
1809     {
1810       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1811
1812       for (i = 0; i < clist->columns; i++)
1813         if (clist->column[i].window)
1814           gdk_window_hide (clist->column[i].window);
1815
1816       gdk_window_hide (clist->clist_window);
1817       gdk_window_hide (clist->title_window);
1818       gdk_window_hide (widget->window);
1819
1820       /* unmap scrollbars */
1821       if (GTK_WIDGET_MAPPED (clist->vscrollbar))
1822         gtk_widget_unmap (clist->vscrollbar);
1823
1824       if (GTK_WIDGET_MAPPED (clist->hscrollbar))
1825         gtk_widget_unmap (clist->hscrollbar);
1826
1827       /* unmap column buttons */
1828       for (i = 0; i < clist->columns; i++)
1829         if (clist->column[i].button &&
1830             GTK_WIDGET_MAPPED (clist->column[i].button))
1831           gtk_widget_unmap (clist->column[i].button);
1832
1833       /* freeze the list */
1834       GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1835     }
1836 }
1837
1838 static void
1839 gtk_clist_draw (GtkWidget * widget,
1840                 GdkRectangle * area)
1841 {
1842   GtkCList *clist;
1843
1844   g_return_if_fail (widget != NULL);
1845   g_return_if_fail (GTK_IS_CLIST (widget));
1846   g_return_if_fail (area != NULL);
1847
1848   if (GTK_WIDGET_DRAWABLE (widget))
1849     {
1850       clist = GTK_CLIST (widget);
1851
1852       gdk_window_clear_area (widget->window,
1853                              area->x, area->y,
1854                              area->width, area->height);
1855
1856       /* draw list shadow/border */
1857       gtk_draw_shadow (widget->style, widget->window,
1858                        GTK_STATE_NORMAL, clist->shadow_type,
1859                        0, 0, 
1860                        clist->clist_window_width + (2 * widget->style->klass->xthickness),
1861                        clist->clist_window_height + (2 * widget->style->klass->ythickness) +
1862                        clist->column_title_area.height);
1863
1864       gdk_window_clear_area (clist->clist_window,
1865                              0, 0, -1, -1);
1866
1867       draw_rows (clist, NULL);
1868     }
1869 }
1870
1871 static gint
1872 gtk_clist_expose (GtkWidget * widget,
1873                   GdkEventExpose * event)
1874 {
1875   GtkCList *clist;
1876
1877   g_return_val_if_fail (widget != NULL, FALSE);
1878   g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
1879   g_return_val_if_fail (event != NULL, FALSE);
1880
1881   if (GTK_WIDGET_DRAWABLE (widget))
1882     {
1883       clist = GTK_CLIST (widget);
1884
1885       /* draw border */
1886       if (event->window == widget->window)
1887         gtk_draw_shadow (widget->style, widget->window,
1888                          GTK_STATE_NORMAL, clist->shadow_type,
1889                          0, 0,
1890                          clist->clist_window_width + (2 * widget->style->klass->xthickness),
1891                          clist->clist_window_height + (2 * widget->style->klass->ythickness) +
1892                          clist->column_title_area.height);
1893
1894       /* exposure events on the list */
1895       if (event->window == clist->clist_window)
1896         draw_rows (clist, &event->area);
1897     }
1898
1899   return FALSE;
1900 }
1901
1902 static gint
1903 gtk_clist_button_press (GtkWidget * widget,
1904                         GdkEventButton * event)
1905 {
1906   gint i;
1907   GtkCList *clist;
1908   gint x, y, row, column;
1909
1910   g_return_val_if_fail (widget != NULL, FALSE);
1911   g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
1912   g_return_val_if_fail (event != NULL, FALSE);
1913
1914   clist = GTK_CLIST (widget);
1915
1916   /* selections on the list */
1917   if (event->window == clist->clist_window)
1918     {
1919       x = event->x;
1920       y = event->y;
1921
1922       if (get_selection_info (clist, x, y, &row, &column))
1923         {
1924           switch (event->type)                                                     
1925             {             
1926             case GDK_BUTTON_PRESS:
1927               gtk_signal_emit (GTK_OBJECT (clist), clist_signals[MOUSE_CLICK],
1928                                row, column, event->button);
1929               gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
1930                                row, column, event->button);
1931               break;
1932               
1933             case GDK_2BUTTON_PRESS:
1934               gtk_signal_emit (GTK_OBJECT (clist), clist_signals[MOUSE_DOUBLE_CLICK],
1935                                row, column, event->button);
1936               break;
1937               
1938             default:
1939               break;
1940             }
1941         }
1942
1943       return FALSE;
1944     }
1945
1946   /* press on resize windows */
1947   for (i = 0; i < clist->columns; i++)
1948     if (clist->column[i].window && event->window == clist->column[i].window)
1949       {
1950         GTK_CLIST_SET_FLAGS (clist, CLIST_IN_DRAG);
1951         gtk_widget_get_pointer (widget, &clist->x_drag, NULL);
1952
1953         gdk_pointer_grab (clist->column[i].window, FALSE,
1954                           GDK_POINTER_MOTION_HINT_MASK |
1955                           GDK_BUTTON1_MOTION_MASK |
1956                           GDK_BUTTON_RELEASE_MASK,
1957                           NULL, NULL, event->time);
1958
1959         draw_xor_line (clist);
1960         return FALSE;
1961       }
1962
1963   return FALSE;
1964 }
1965
1966 static gint
1967 gtk_clist_button_release (GtkWidget * widget,
1968                           GdkEventButton * event)
1969 {
1970   gint i, x, width, visible;
1971   GtkCList *clist;
1972
1973   g_return_val_if_fail (widget != NULL, FALSE);
1974   g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
1975   g_return_val_if_fail (event != NULL, FALSE);
1976
1977   clist = GTK_CLIST (widget);
1978
1979   /* release on resize windows */
1980   if (GTK_CLIST_IN_DRAG (clist))
1981     for (i = 0; i < clist->columns; i++)
1982       if (clist->column[i].window && event->window == clist->column[i].window)
1983         {
1984           GTK_CLIST_UNSET_FLAGS (clist, CLIST_IN_DRAG);
1985           gtk_widget_get_pointer (widget, &x, NULL);
1986           width = new_column_width (clist, i, &x, &visible);
1987           gdk_pointer_ungrab (event->time);
1988           
1989           if (visible)
1990             draw_xor_line (clist);
1991
1992           resize_column (clist, i, width);
1993           return FALSE;
1994         }
1995
1996   return FALSE;
1997 }
1998
1999 static gint
2000 gtk_clist_motion (GtkWidget * widget,
2001                   GdkEventMotion * event)
2002 {
2003   gint i, x, visible;
2004   GtkCList *clist;
2005
2006   g_return_val_if_fail (widget != NULL, FALSE);
2007   g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2008
2009   clist = GTK_CLIST (widget);
2010
2011   if (GTK_CLIST_IN_DRAG (clist))
2012     for (i = 0; i < clist->columns; i++)
2013       if (clist->column[i].window && event->window == clist->column[i].window)
2014         {
2015           if (event->is_hint || event->window != widget->window)
2016             gtk_widget_get_pointer (widget, &x, NULL);
2017           else
2018             x = event->x;
2019
2020           new_column_width (clist, i, &x, &visible);
2021           /* Welcome to my hack!  I'm going to use a value of x_drage = -99999 to
2022            * indicate the the xor line is already no visible */
2023           if (!visible && clist->x_drag != -99999)
2024             {
2025               draw_xor_line (clist);
2026               clist->x_drag = -99999;
2027             }
2028
2029           if (x != clist->x_drag && visible)
2030             {
2031               if (clist->x_drag != -99999)
2032                 draw_xor_line (clist);
2033
2034               clist->x_drag = x;
2035               draw_xor_line (clist);
2036             }
2037         }
2038
2039   return TRUE;
2040 }
2041
2042 static void
2043 gtk_clist_size_request (GtkWidget * widget,
2044                         GtkRequisition * requisition)
2045 {
2046   gint i;
2047   GtkCList *clist;
2048
2049   g_return_if_fail (widget != NULL);
2050   g_return_if_fail (GTK_IS_CLIST (widget));
2051   g_return_if_fail (requisition != NULL);
2052
2053   clist = GTK_CLIST (widget);
2054
2055   requisition->width = 0;
2056   requisition->height = 0;
2057
2058   /* compute the size of the column title (title) area */
2059   clist->column_title_area.height = 0;
2060   if (GTK_CLIST_SHOW_TITLES (clist))
2061     for (i = 0; i < clist->columns; i++)
2062       if (clist->column[i].button)
2063         {
2064           gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
2065           clist->column_title_area.height = MAX (clist->column_title_area.height,
2066                                                  clist->column[i].button->requisition.height);
2067         }
2068   requisition->height += clist->column_title_area.height;
2069
2070   /* add the vscrollbar space */
2071   if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2072       GTK_WIDGET_VISIBLE (clist->vscrollbar))
2073     {
2074       gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
2075
2076       requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
2077       requisition->height = MAX (requisition->height,
2078                                  clist->vscrollbar->requisition.height);
2079     }
2080
2081   /* add the hscrollbar space */
2082   if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2083       GTK_WIDGET_VISIBLE (clist->hscrollbar))
2084     {
2085       gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
2086
2087       requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
2088       requisition->width = MAX (clist->hscrollbar->requisition.width, 
2089                                 requisition->width - 
2090                                 clist->vscrollbar->requisition.width);
2091
2092     }
2093
2094   requisition->width += widget->style->klass->xthickness * 2 +
2095     GTK_CONTAINER (widget)->border_width * 2;
2096   requisition->height += widget->style->klass->ythickness * 2 +
2097     GTK_CONTAINER (widget)->border_width * 2;
2098 }
2099
2100 static void
2101 gtk_clist_size_allocate (GtkWidget * widget,
2102                          GtkAllocation * allocation)
2103 {
2104   GtkCList *clist;
2105   GtkAllocation clist_allocation;
2106   GtkAllocation child_allocation;
2107   gint i, vscrollbar_vis, hscrollbar_vis;
2108
2109   g_return_if_fail (widget != NULL);
2110   g_return_if_fail (GTK_IS_CLIST (widget));
2111   g_return_if_fail (allocation != NULL);
2112
2113   clist = GTK_CLIST (widget);
2114   widget->allocation = *allocation;
2115
2116   if (GTK_WIDGET_REALIZED (widget))
2117     {
2118       gdk_window_move_resize (widget->window,
2119                               allocation->x + GTK_CONTAINER (widget)->border_width,
2120                               allocation->y + GTK_CONTAINER (widget)->border_width,
2121                               allocation->width - GTK_CONTAINER (widget)->border_width * 2,
2122                               allocation->height - GTK_CONTAINER (widget)->border_width * 2);
2123
2124       /* use internal allocation structure for all the math
2125        * because it's easier than always subtracting the container
2126        * border width */
2127       clist->internal_allocation.x = 0;
2128       clist->internal_allocation.y = 0;
2129       clist->internal_allocation.width = allocation->width -
2130         GTK_CONTAINER (widget)->border_width * 2;
2131       clist->internal_allocation.height = allocation->height -
2132         GTK_CONTAINER (widget)->border_width * 2;
2133         
2134       /* allocate clist window assuming no scrollbars */
2135       clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2136       clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2137         clist->column_title_area.height;
2138       clist_allocation.width = clist->internal_allocation.width - 
2139         (2 * widget->style->klass->xthickness);
2140       clist_allocation.height = clist->internal_allocation.height -
2141         (2 * widget->style->klass->xthickness) -
2142         clist->column_title_area.height;
2143
2144       /* 
2145        * here's where we decide to show/not show the scrollbars
2146        */
2147       vscrollbar_vis = 0;
2148       hscrollbar_vis = 0;
2149
2150       for (i = 0; i <= 1; i++)
2151         {
2152           if (LIST_HEIGHT (clist) <= clist_allocation.height &&
2153               clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2154             {
2155               vscrollbar_vis = 0;
2156             }
2157           else
2158             {
2159               if (!vscrollbar_vis)
2160                 {
2161                   vscrollbar_vis = 1;
2162                   clist_allocation.width -= clist->vscrollbar->requisition.width +
2163                     SCROLLBAR_SPACING (clist);
2164                 }  
2165             }
2166           
2167           if (LIST_WIDTH (clist) <= clist_allocation.width &&
2168               clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2169             {
2170               hscrollbar_vis = 0;
2171             }
2172           else
2173             {
2174               if (!hscrollbar_vis)
2175                 {
2176                   hscrollbar_vis = 1;
2177                   clist_allocation.height -= clist->hscrollbar->requisition.height + 
2178                     SCROLLBAR_SPACING (clist);  
2179                 }  
2180             }
2181         }
2182
2183       clist->clist_window_width = clist_allocation.width;
2184       clist->clist_window_height = clist_allocation.height;
2185
2186       gdk_window_move_resize (clist->clist_window,
2187                               clist_allocation.x,
2188                               clist_allocation.y,
2189                               clist_allocation.width,
2190                               clist_allocation.height);
2191
2192       /* position the window which holds the column title buttons */
2193       clist->column_title_area.x = widget->style->klass->xthickness;
2194       clist->column_title_area.y = widget->style->klass->ythickness;
2195       clist->column_title_area.width = clist_allocation.width;
2196
2197       gdk_window_move_resize (clist->title_window,
2198                               clist->column_title_area.x,
2199                               clist->column_title_area.y,
2200                               clist->column_title_area.width,
2201                               clist->column_title_area.height);
2202
2203       /* column button allocation */
2204       size_allocate_columns (clist);
2205       size_allocate_title_buttons (clist);
2206       adjust_scrollbars (clist);
2207
2208       /* allocate the vscrollbar */
2209       if (vscrollbar_vis)
2210         {
2211           if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
2212             gtk_widget_show (clist->vscrollbar);
2213               
2214           child_allocation.x = clist->internal_allocation.x + 
2215             clist->internal_allocation.width -
2216             clist->vscrollbar->requisition.width;
2217           child_allocation.y = clist->internal_allocation.y;
2218           child_allocation.width = clist->vscrollbar->requisition.width;
2219           child_allocation.height = clist->internal_allocation.height -
2220             (hscrollbar_vis ? (clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist)) : 0);
2221
2222           gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
2223         }
2224       else
2225         {
2226            if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
2227                 gtk_widget_hide (clist->vscrollbar);
2228         }
2229
2230       if (hscrollbar_vis)
2231         {
2232           if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
2233             gtk_widget_show (clist->hscrollbar);
2234       
2235           child_allocation.x = clist->internal_allocation.x;
2236           child_allocation.y = clist->internal_allocation.y +
2237             clist->internal_allocation.height -
2238             clist->hscrollbar->requisition.height;
2239           child_allocation.width = clist->internal_allocation.width -
2240             (vscrollbar_vis ? (clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist)) : 0);
2241           child_allocation.height = clist->hscrollbar->requisition.height;
2242
2243           gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
2244         }
2245       else
2246         {
2247           if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
2248                 gtk_widget_hide (clist->hscrollbar);
2249         }
2250     }
2251
2252   /* set the vscrollbar adjustments */
2253   adjust_scrollbars (clist);
2254 }
2255
2256 /* 
2257  * GTKCONTAINER
2258  *   gtk_clist_foreach
2259  */
2260 static void
2261 gtk_clist_foreach (GtkContainer * container,
2262                    GtkCallback callback,
2263                    gpointer callback_data)
2264 {
2265   gint i;
2266   GtkCList *clist;
2267
2268   g_return_if_fail (container != NULL);
2269   g_return_if_fail (GTK_IS_CLIST (container));
2270   g_return_if_fail (callback != NULL);
2271
2272   clist = GTK_CLIST (container);
2273
2274   /* callback for the column buttons */
2275   for (i = 0; i < clist->columns; i++)
2276     if (clist->column[i].button)
2277       (*callback) (clist->column[i].button, callback_data);
2278
2279   /* callbacks for the scrollbars */
2280   if (clist->vscrollbar)
2281     (*callback) (clist->vscrollbar, callback_data);
2282   if (clist->hscrollbar)
2283     (*callback) (clist->hscrollbar, callback_data);
2284 }
2285
2286 /*
2287  * DRAWING
2288  *   draw_row
2289  *   draw_rows
2290  */
2291 static void
2292 draw_row (GtkCList * clist,
2293           GdkRectangle * area,
2294           gint row,
2295           GtkCListRow * clist_row)
2296 {
2297   GtkWidget *widget;
2298   GdkGC *fg_gc, *bg_gc;
2299   GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
2300    *rect;
2301   gint i, offset = 0, width, height, pixmap_width = 0;
2302   gint xsrc, ysrc, xdest, ydest;
2303
2304   g_return_if_fail (clist != NULL);
2305
2306   /* bail now if we arn't drawable yet */
2307   if (!GTK_WIDGET_DRAWABLE (clist))
2308     return;
2309
2310   if (row < 0 || row >= clist->rows)
2311     return;
2312
2313   widget = GTK_WIDGET (clist);
2314
2315   /* if the function is passed the pointer to the row instead of null,
2316    * it avoids this expensive lookup */
2317   if (!clist_row)
2318     clist_row = (g_list_nth (clist->row_list, row))->data;
2319
2320   /* rectangle of the entire row */
2321   row_rectangle.x = 0;
2322   row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
2323   row_rectangle.width = clist->clist_window_width;
2324   row_rectangle.height = clist->row_height;
2325
2326   /* rectangle of the cell spacing above the row */
2327   cell_rectangle.x = 0;
2328   cell_rectangle.y = row_rectangle.y - CELL_SPACING;
2329   cell_rectangle.width = row_rectangle.width;
2330   cell_rectangle.height = CELL_SPACING;
2331
2332   /* rectangle used to clip drawing operations, it's y and height
2333    * positions only need to be set once, so we set them once here. 
2334    * the x and width are set withing the drawing loop below once per
2335    * column */
2336   clip_rectangle.y = row_rectangle.y;
2337   clip_rectangle.height = row_rectangle.height;
2338
2339   /* select GC for background rectangle */
2340   if (clist_row->state == GTK_STATE_SELECTED)
2341     {
2342       fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
2343       bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
2344     }
2345   else
2346     {
2347       if (clist_row->fg_set)
2348         {
2349           gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
2350           fg_gc = clist->fg_gc;
2351         }
2352       else
2353         fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
2354         
2355       if (clist_row->bg_set)
2356         {
2357           gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
2358           bg_gc = clist->bg_gc;
2359         }
2360       else
2361         bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
2362     }
2363
2364   /* draw the cell borders and background */
2365   if (area)
2366     {
2367       if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
2368         gdk_draw_rectangle (clist->clist_window,
2369                             widget->style->white_gc,
2370                             TRUE,
2371                             intersect_rectangle.x,
2372                             intersect_rectangle.y,
2373                             intersect_rectangle.width,
2374                             intersect_rectangle.height);
2375
2376       /* the last row has to clear it's bottom cell spacing too */
2377       if (clist_row == clist->row_list_end->data)
2378         {
2379           cell_rectangle.y += clist->row_height + CELL_SPACING;
2380
2381           if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
2382             gdk_draw_rectangle (clist->clist_window,
2383                                 widget->style->white_gc,
2384                                 TRUE,
2385                                 intersect_rectangle.x,
2386                                 intersect_rectangle.y,
2387                                 intersect_rectangle.width,
2388                                 intersect_rectangle.height);
2389         }         
2390
2391       if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
2392         return;
2393
2394       if (clist_row->state == GTK_STATE_SELECTED || clist_row->fg_set)
2395         gdk_draw_rectangle (clist->clist_window,
2396                             bg_gc,
2397                             TRUE,
2398                             intersect_rectangle.x,
2399                             intersect_rectangle.y,
2400                             intersect_rectangle.width,
2401                             intersect_rectangle.height);
2402       else
2403         gdk_window_clear_area (clist->clist_window,
2404                                intersect_rectangle.x,
2405                                intersect_rectangle.y,
2406                                intersect_rectangle.width,
2407                                intersect_rectangle.height);
2408     }
2409   else
2410     {
2411       gdk_draw_rectangle (clist->clist_window,
2412                           widget->style->white_gc,
2413                           TRUE,
2414                           cell_rectangle.x,
2415                           cell_rectangle.y,
2416                           cell_rectangle.width,
2417                           cell_rectangle.height);
2418
2419       /* the last row has to clear it's bottom cell spacing too */
2420       if (clist_row == clist->row_list_end->data)
2421         {
2422           cell_rectangle.y += clist->row_height + CELL_SPACING;
2423
2424           gdk_draw_rectangle (clist->clist_window,
2425                               widget->style->white_gc,
2426                               TRUE,
2427                               cell_rectangle.x,
2428                               cell_rectangle.y,
2429                               cell_rectangle.width,
2430                               cell_rectangle.height);     
2431         }         
2432
2433       if (clist_row->state == GTK_STATE_SELECTED || clist_row->fg_set)
2434         gdk_draw_rectangle (clist->clist_window,
2435                             bg_gc,
2436                             TRUE,
2437                             row_rectangle.x,
2438                             row_rectangle.y,
2439                             row_rectangle.width,
2440                             row_rectangle.height);
2441       else
2442         gdk_window_clear_area (clist->clist_window,
2443                                row_rectangle.x,
2444                                row_rectangle.y,
2445                                row_rectangle.width,
2446                                row_rectangle.height);
2447     }
2448
2449   /* iterate and draw all the columns (row cells) and draw their contents */
2450   for (i = 0; i < clist->columns; i++)
2451     {
2452       clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
2453       clip_rectangle.width = clist->column[i].area.width;
2454
2455       /* calculate clipping region clipping region */
2456       if (!area)
2457         {
2458           rect = &clip_rectangle;
2459         }
2460       else
2461         {
2462           if (!gdk_rectangle_intersect (area, &clip_rectangle, &intersect_rectangle))
2463             continue;
2464           rect = &intersect_rectangle;
2465         }
2466
2467       /* calculate real width for column justification */
2468       switch (clist_row->cell[i].type)
2469         {
2470         case GTK_CELL_EMPTY:
2471           continue;
2472           break;
2473
2474         case GTK_CELL_TEXT:
2475           width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2476                                     GTK_CELL_TEXT (clist_row->cell[i])->text);
2477           break;
2478
2479         case GTK_CELL_PIXMAP:
2480           gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
2481           pixmap_width = width;
2482           break;
2483
2484         case GTK_CELL_PIXTEXT:
2485           gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
2486           pixmap_width = width;
2487           width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
2488           width = gdk_string_width (GTK_WIDGET (clist)->style->font,
2489                                     GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2490           break;
2491
2492         case GTK_CELL_WIDGET:
2493           /* unimplimented */
2494           continue;
2495           break;
2496
2497         default:
2498           continue;
2499           break;
2500         }
2501
2502       switch (clist->column[i].justification)
2503         {
2504         case GTK_JUSTIFY_LEFT:
2505           offset = clip_rectangle.x;
2506           break;
2507
2508         case GTK_JUSTIFY_RIGHT:
2509           offset = (clip_rectangle.x + clip_rectangle.width) - width;
2510           break;
2511
2512         case GTK_JUSTIFY_CENTER:
2513           offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
2514           break;
2515
2516         case GTK_JUSTIFY_FILL:
2517           offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
2518           break;
2519
2520         default:
2521           offset = 0;
2522           break;
2523         };
2524
2525       /* Draw Text or Pixmap */
2526       switch (clist_row->cell[i].type)
2527         {
2528         case GTK_CELL_EMPTY:
2529           continue;
2530           break;
2531
2532         case GTK_CELL_TEXT:
2533           gdk_gc_set_clip_rectangle (fg_gc, rect);
2534
2535           gdk_draw_string (clist->clist_window, 
2536                            widget->style->font,
2537                            fg_gc,
2538                            offset + clist_row->cell[i].horizontal,
2539                            row_rectangle.y + clist->row_center_offset + 
2540                            clist_row->cell[i].vertical,
2541                            GTK_CELL_TEXT (clist_row->cell[i])->text);
2542
2543           gdk_gc_set_clip_rectangle (fg_gc, NULL);
2544           break;
2545
2546         case GTK_CELL_PIXMAP:
2547           xsrc = 0;
2548           ysrc = 0;
2549           xdest = offset + clist_row->cell[i].horizontal;
2550           ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
2551             clist_row->cell[i].vertical;
2552
2553           gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
2554           gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2555
2556           gdk_draw_pixmap (clist->clist_window,
2557                            fg_gc,
2558                            GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
2559                            xsrc, ysrc,
2560                            xdest,
2561                            ydest,
2562                            pixmap_width, height);
2563
2564           gdk_gc_set_clip_origin (fg_gc, 0, 0);
2565           gdk_gc_set_clip_mask (fg_gc, NULL);
2566           break;
2567
2568         case GTK_CELL_PIXTEXT:
2569           /* draw the pixmap */
2570           xsrc = 0;
2571           ysrc = 0;
2572           xdest = offset + clist_row->cell[i].horizontal;
2573           ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
2574             clist_row->cell[i].vertical;
2575
2576           gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
2577           gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2578
2579           gdk_draw_pixmap (clist->clist_window,
2580                            fg_gc,
2581                            GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
2582                            xsrc, ysrc,
2583                            xdest,
2584                            ydest,
2585                            pixmap_width, height);
2586
2587           gdk_gc_set_clip_origin (fg_gc, 0, 0);
2588
2589           offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
2590           
2591           /* draw the string */
2592           gdk_gc_set_clip_rectangle (fg_gc, rect);
2593
2594           gdk_draw_string (clist->clist_window, 
2595                            widget->style->font,
2596                            fg_gc,
2597                            offset + clist_row->cell[i].horizontal,
2598                            row_rectangle.y + clist->row_center_offset + 
2599                            clist_row->cell[i].vertical,
2600                            GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2601
2602           gdk_gc_set_clip_rectangle (fg_gc, NULL);
2603
2604           break;
2605
2606         case GTK_CELL_WIDGET:
2607           /* unimplimented */
2608           continue;
2609           break;
2610
2611         default:
2612           continue;
2613           break;
2614         }
2615     }
2616 }
2617
2618 static void
2619 draw_rows (GtkCList * clist,
2620            GdkRectangle * area)
2621 {
2622   GList *list;
2623   GtkCListRow *clist_row;
2624   int i, first_row, last_row;
2625
2626   g_return_if_fail (clist != NULL);
2627   g_return_if_fail (GTK_IS_CLIST (clist));
2628
2629   if (clist->row_height == 0 ||
2630       !GTK_WIDGET_DRAWABLE (clist))
2631     return;
2632
2633   if (area)
2634     {
2635       first_row = ROW_FROM_YPIXEL (clist, area->y);
2636       last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
2637     }
2638   else
2639     {
2640       first_row = ROW_FROM_YPIXEL (clist, 0);
2641       last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
2642     }
2643
2644   /* this is a small special case which exposes the bottom cell line
2645    * on the last row -- it might go away if I change the wall the cell spacings
2646    * are drawn */
2647   if (clist->rows == first_row)
2648     first_row--;
2649
2650   list = g_list_nth (clist->row_list, first_row);
2651   i = first_row;
2652   while (list)
2653     {
2654       clist_row = list->data;
2655       list = list->next;
2656
2657       if (i > last_row)
2658         return;
2659
2660       draw_row (clist, area, i, clist_row);
2661       i++;
2662     }
2663
2664   if (!area)
2665     gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1);
2666 }
2667
2668 /*
2669  * SIZE ALLOCATION
2670  *   size_allocate_title_buttons
2671  *   size_allocate_columns
2672  */
2673 static void
2674 size_allocate_title_buttons (GtkCList * clist)
2675 {
2676   gint i, last_button = 0;
2677   GtkAllocation button_allocation;
2678
2679   if (!GTK_WIDGET_REALIZED (clist))
2680     return;
2681
2682   button_allocation.x = clist->hoffset;
2683   button_allocation.y = 0;
2684   button_allocation.width = 0;
2685   button_allocation.height = clist->column_title_area.height;
2686
2687   for (i = 0; i < clist->columns; i++)
2688     {
2689       button_allocation.width += clist->column[i].area.width;
2690
2691       if (i == clist->columns - 1)
2692         button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
2693       else
2694         button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
2695
2696       if (i == (clist->columns - 1) || clist->column[i + 1].button)
2697         {
2698           gtk_widget_size_allocate (clist->column[last_button].button, &button_allocation);
2699           button_allocation.x += button_allocation.width;
2700           button_allocation.width = 0;
2701
2702           gdk_window_show (clist->column[last_button].window);
2703           gdk_window_move_resize (clist->column[last_button].window,
2704                                   button_allocation.x - (DRAG_WIDTH / 2), 
2705                                   0, DRAG_WIDTH, clist->column_title_area.height);
2706           
2707           last_button = i + 1;
2708         }
2709       else
2710         {
2711           gdk_window_hide (clist->column[i].window);
2712         }
2713     }
2714 }
2715
2716 static void
2717 size_allocate_columns (GtkCList * clist)
2718 {
2719   gint i, xoffset = 0;
2720
2721   if (!GTK_WIDGET_REALIZED (clist))
2722     return;
2723
2724   for (i = 0; i < clist->columns; i++)
2725     {
2726       clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
2727
2728       if (i == clist->columns - 1)
2729         {
2730           gint width;
2731
2732           if (clist->column[i].width_set)
2733             width = clist->column[i].width;
2734           else
2735             width = gdk_string_width (GTK_WIDGET (clist)->style->font, clist->column[i].title);
2736           clist->column[i].area.width = MAX (width,
2737                                              clist->clist_window_width -
2738                                              xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
2739                                             
2740         }
2741       else
2742         {
2743           clist->column[i].area.width = clist->column[i].width;
2744         }
2745
2746       xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
2747     }
2748 }
2749
2750 /*
2751  * SELECTION
2752  *   real_select_row
2753  *   real_unselect_row
2754  *   get_selection_info
2755  */
2756 static void
2757 real_select_row (GtkCList * clist,
2758                  gint row,
2759                  gint column,
2760                  gint button)
2761 {
2762   gint i;
2763   GList *list;
2764   GtkCListRow *clist_row;
2765
2766   g_return_if_fail (clist != NULL);
2767
2768   if (row < 0 || row >= clist->rows)
2769     return;
2770
2771   switch (clist->selection_mode)
2772     {
2773     case GTK_SELECTION_SINGLE:
2774       i = 0;
2775       list = clist->row_list;
2776       while (list)
2777         {
2778           clist_row = list->data;
2779           list = list->next;
2780
2781           if (row == i)
2782             {
2783               if (clist_row->state == GTK_STATE_SELECTED)
2784                 {
2785                   clist_row->state = GTK_STATE_NORMAL;
2786                   gtk_clist_unselect_row (clist, i, column);
2787                 }
2788               else
2789                 {
2790                   clist_row->state = GTK_STATE_SELECTED;
2791                   clist->selection = g_list_append (clist->selection, clist_row);
2792                 }
2793
2794               if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2795                 draw_row (clist, NULL, row, clist_row);
2796             }
2797           else if (clist_row->state == GTK_STATE_SELECTED)
2798             {
2799               gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], i, column, button);
2800             }
2801
2802           i++;
2803         }
2804       break;
2805
2806     case GTK_SELECTION_BROWSE:
2807       i = 0;
2808       list = clist->row_list;
2809       while (list)
2810         {
2811           clist_row = list->data;
2812           list = list->next;
2813
2814           if (row == i)
2815             {
2816               if (clist_row->state != GTK_STATE_SELECTED)
2817                 {
2818                   clist_row->state = GTK_STATE_SELECTED;
2819                   clist->selection = g_list_append (clist->selection, clist_row);
2820                 
2821                   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2822                     draw_row (clist, NULL, row, clist_row);
2823                 }
2824             }
2825           else if (clist_row->state == GTK_STATE_SELECTED)
2826             {
2827               gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], i, column, button);
2828             }
2829
2830           i++;
2831         }
2832       break;
2833
2834     case GTK_SELECTION_MULTIPLE:
2835       i = 0;
2836       list = clist->row_list;
2837       while (list)
2838         {
2839           clist_row = list->data;
2840           list = list->next;
2841
2842           if (row == i)
2843             {
2844               if (clist_row->state == GTK_STATE_SELECTED)
2845                 {
2846                   clist_row->state = GTK_STATE_NORMAL;
2847                  gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], i, column, button);
2848                 }
2849               else
2850                 {
2851                   clist->selection = g_list_append (clist->selection, clist_row);
2852                   clist_row->state = GTK_STATE_SELECTED;
2853                 }
2854
2855               if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2856                 draw_row (clist, NULL, row, clist_row);
2857             }
2858
2859           i++;
2860         }
2861       break;
2862
2863     case GTK_SELECTION_EXTENDED:
2864       break;
2865
2866     default:
2867       break;
2868     }
2869 }
2870
2871 static void
2872 real_unselect_row (GtkCList * clist,
2873                    gint row,
2874                    gint column,
2875                    gint button)
2876 {
2877   GtkCListRow *clist_row;
2878
2879   g_return_if_fail (clist != NULL);
2880
2881   if (row < 0 || row > (clist->rows - 1))
2882     return;
2883
2884   clist_row = (g_list_nth (clist->row_list, row))->data;
2885   clist_row->state = GTK_STATE_NORMAL;
2886   clist->selection = g_list_remove (clist->selection, clist_row);
2887
2888   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
2889     draw_row (clist, NULL, row, clist_row);
2890 }
2891
2892 static gint
2893 get_selection_info (GtkCList * clist,
2894                     gint x,
2895                     gint y,
2896                     gint * row,
2897                     gint * column)
2898 {
2899   gint trow, tcol;
2900
2901   g_return_val_if_fail (clist != NULL, 0);
2902
2903   /* bounds checking, return false if the user clicked 
2904    * on a blank area */
2905   trow = ROW_FROM_YPIXEL (clist, y);
2906   if (trow >= clist->rows)
2907     return 0;
2908
2909   if (row)
2910     *row = trow;
2911
2912   tcol = COLUMN_FROM_XPIXEL (clist, x);
2913   if (tcol >= clist->columns)
2914     return 0;
2915
2916   if (column)
2917     *column = tcol;
2918
2919   return 1;
2920 }
2921
2922 /* 
2923  * RESIZE COLUMNS
2924  *   draw_xor_line
2925  *   new_column_width
2926  *   resize_column
2927  */
2928 static void                          
2929 draw_xor_line (GtkCList * clist)
2930 {
2931   GtkWidget *widget;
2932   
2933   g_return_if_fail (clist != NULL);
2934   
2935   widget = GTK_WIDGET (clist);
2936
2937   gdk_draw_line (widget->window, clist->xor_gc,  
2938                  clist->x_drag,                                       
2939                  widget->style->klass->ythickness,                               
2940                  clist->x_drag,                                             
2941                  clist->column_title_area.height + clist->clist_window_height + 1);
2942 }
2943
2944 /* this function returns the new width of the column being resized given
2945  * the column and x position of the cursor; the x cursor position is passed
2946  * in as a pointer and automagicly corrected if it's beyond min/max limits */
2947 static gint
2948 new_column_width (GtkCList * clist,
2949                   gint column,
2950                   gint * x,
2951                   gint * visible)
2952 {
2953   gint cx, rx, width;
2954
2955   cx = *x;
2956
2957   /* first translate the x position from widget->window
2958    * to clist->clist_window */
2959   cx -= GTK_WIDGET (clist)->style->klass->xthickness;
2960
2961   /* rx is x from the list beginning */
2962   rx = cx - clist->hoffset;
2963
2964   /* you can't shrink a column to less than its minimum width */
2965   if (cx < (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH))
2966     {
2967       *x = cx = COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET + COLUMN_MIN_WIDTH +
2968         GTK_WIDGET (clist)->style->klass->xthickness;
2969       cx -= GTK_WIDGET (clist)->style->klass->xthickness;
2970       rx = cx - clist->hoffset;
2971     }
2972
2973   if (cx > clist->clist_window_width)
2974     *visible = 0;
2975   else
2976     *visible = 1;
2977
2978   /* calculate new column width making sure it doesn't end up
2979    * less than the minimum width */
2980   width = (rx - COLUMN_LEFT (clist, column)) - COLUMN_INSET -
2981     ((clist->columns == (column - 1)) ? CELL_SPACING : 0);
2982   if (width < COLUMN_MIN_WIDTH)
2983     width = COLUMN_MIN_WIDTH;
2984
2985   return width;
2986 }
2987
2988 /* this will do more later */
2989 static void
2990 resize_column (GtkCList * clist,
2991                gint column,
2992                gint width)
2993 {
2994   gtk_clist_set_column_width (clist, column, width);
2995 }
2996
2997 /* BUTTONS */
2998 static void
2999 column_button_create (GtkCList * clist,
3000                       gint column)
3001 {
3002   GtkWidget *button;
3003
3004   button = clist->column[column].button = gtk_button_new ();
3005   gtk_widget_set_parent (button, GTK_WIDGET (clist));
3006   if (GTK_WIDGET_REALIZED (clist) && clist->title_window)
3007     gtk_widget_set_parent_window (clist->column[column].button, clist->title_window);
3008   
3009   gtk_signal_connect (GTK_OBJECT (button),
3010                       "clicked",
3011                       (GtkSignalFunc) column_button_clicked,
3012                       (gpointer) clist);
3013
3014   gtk_widget_show (button);
3015 }
3016
3017 static void
3018 column_button_clicked (GtkWidget * widget,
3019                        gpointer data)
3020 {
3021   gint i;
3022   GtkCList *clist;
3023
3024   g_return_if_fail (widget != NULL);
3025   g_return_if_fail (GTK_IS_CLIST (data));
3026
3027   clist = GTK_CLIST (data);
3028
3029   /* find the column who's button was pressed */
3030   for (i = 0; i < clist->columns; i++)
3031     if (clist->column[i].button == widget)
3032       break;
3033
3034   gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
3035 }
3036
3037 /* 
3038  * SCROLLBARS
3039  *
3040  * functions:
3041  *   create_scrollbars
3042  *   adjust_scrollbars
3043  *   vadjustment_changed
3044  *   hadjustment_changed
3045  *   vadjustment_value_changed
3046  *   hadjustment_value_changed 
3047  */
3048 static void
3049 create_scrollbars (GtkCList * clist)
3050 {
3051   GtkAdjustment *adjustment;
3052
3053   clist->vscrollbar = gtk_vscrollbar_new (NULL);
3054   adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
3055
3056   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
3057                       (GtkSignalFunc) vadjustment_changed,
3058                       (gpointer) clist);
3059
3060   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
3061                       (GtkSignalFunc) vadjustment_value_changed,
3062                       (gpointer) clist);
3063
3064   gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
3065   gtk_widget_show (clist->vscrollbar);
3066
3067   clist->hscrollbar = gtk_hscrollbar_new (NULL);
3068   adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
3069
3070   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
3071                       (GtkSignalFunc) hadjustment_changed,
3072                       (gpointer) clist);
3073
3074   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
3075                       (GtkSignalFunc) hadjustment_value_changed,
3076                       (gpointer) clist);
3077
3078   gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
3079   gtk_widget_show (clist->hscrollbar);
3080 }
3081
3082 static void
3083 adjust_scrollbars (GtkCList * clist)
3084 {
3085   GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
3086   GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
3087   GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
3088   GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
3089   GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
3090
3091   if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
3092     {
3093       GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - 
3094         clist->clist_window_height;
3095       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
3096                                "value_changed");
3097     }
3098
3099   GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
3100   GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
3101   GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
3102   GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
3103   GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
3104
3105   if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
3106     {
3107       GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - 
3108         clist->clist_window_width;
3109       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
3110                                "value_changed");
3111     }
3112
3113   if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
3114       clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
3115     {
3116       if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
3117         {
3118           gtk_widget_hide (clist->vscrollbar);
3119           gtk_widget_queue_resize (GTK_WIDGET (clist));
3120         }
3121     }
3122   else
3123     {
3124       if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
3125         {
3126           gtk_widget_show (clist->vscrollbar);
3127           gtk_widget_queue_resize (GTK_WIDGET (clist));
3128         }
3129     }
3130
3131   if (LIST_WIDTH (clist) <= clist->clist_window_width &&
3132       clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
3133     {
3134       if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
3135         {
3136           gtk_widget_hide (clist->hscrollbar);
3137           gtk_widget_queue_resize (GTK_WIDGET (clist));
3138         }
3139     }
3140   else
3141     {
3142       if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
3143         {
3144           gtk_widget_show (clist->hscrollbar);
3145           gtk_widget_queue_resize (GTK_WIDGET (clist));
3146         }
3147     }
3148
3149   gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
3150   gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
3151 }
3152
3153 static void
3154 vadjustment_changed (GtkAdjustment * adjustment,
3155                                gpointer data)
3156 {
3157   GtkCList *clist;
3158
3159   g_return_if_fail (adjustment != NULL);
3160   g_return_if_fail (data != NULL);
3161
3162   clist = GTK_CLIST (data);
3163 }
3164
3165 static void
3166 hadjustment_changed (GtkAdjustment * adjustment,
3167                                gpointer data)
3168 {
3169   GtkCList *clist;
3170
3171   g_return_if_fail (adjustment != NULL);
3172   g_return_if_fail (data != NULL);
3173
3174   clist = GTK_CLIST (data);
3175 }
3176
3177 static void
3178 check_exposures (GtkCList *clist)
3179 {
3180   GdkEvent *event;
3181
3182   if (!GTK_WIDGET_REALIZED (clist))
3183     return;
3184
3185   /* Make sure graphics expose events are processed before scrolling
3186    * again */
3187   while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL)
3188     {
3189       gtk_widget_event (GTK_WIDGET (clist), event);
3190       if (event->expose.count == 0)
3191         {
3192           gdk_event_free (event);
3193           break;
3194         }
3195       gdk_event_free (event);
3196     }
3197 }
3198
3199 static void
3200 vadjustment_value_changed (GtkAdjustment * adjustment,
3201                                      gpointer data)
3202 {
3203   GtkCList *clist;
3204   GdkRectangle area;
3205   gint diff, value;
3206
3207   g_return_if_fail (adjustment != NULL);
3208   g_return_if_fail (data != NULL);
3209   g_return_if_fail (GTK_IS_CLIST (data));
3210
3211   clist = GTK_CLIST (data);
3212
3213   if (!GTK_WIDGET_DRAWABLE (clist))
3214     return;
3215
3216   value = adjustment->value;
3217
3218   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
3219     {
3220       if (value > -clist->voffset)
3221         {
3222           /* scroll down */
3223           diff = value + clist->voffset;
3224
3225           /* we have to re-draw the whole screen here... */
3226           if (diff >= clist->clist_window_height)
3227             {
3228               clist->voffset = -value;
3229               draw_rows (clist, NULL);
3230               return;
3231             }
3232
3233           if ((diff != 0) && (diff != clist->clist_window_height))
3234             gdk_window_copy_area (clist->clist_window,
3235                                   clist->fg_gc,
3236                                   0, 0,
3237                                   clist->clist_window,
3238                                   0,
3239                                   diff,
3240                                   clist->clist_window_width,
3241                                   clist->clist_window_height - diff);
3242
3243           area.x = 0;
3244           area.y = clist->clist_window_height - diff;
3245           area.width = clist->clist_window_width;
3246           area.height = diff;
3247         }
3248       else
3249         {
3250           /* scroll up */
3251           diff = -clist->voffset - value;
3252
3253           /* we have to re-draw the whole screen here... */
3254           if (diff >= clist->clist_window_height)
3255             {
3256               clist->voffset = -value;
3257               draw_rows (clist, NULL);
3258               return;
3259             }
3260
3261           if ((diff != 0) && (diff != clist->clist_window_height))
3262             gdk_window_copy_area (clist->clist_window,
3263                                   clist->fg_gc,
3264                                   0, diff,
3265                                   clist->clist_window,
3266                                   0,
3267                                   0,
3268                                   clist->clist_window_width,
3269                                   clist->clist_window_height - diff);
3270
3271           area.x = 0;
3272           area.y = 0;
3273           area.width = clist->clist_window_width;
3274           area.height = diff;
3275
3276         }
3277
3278       clist->voffset = -value;
3279       if ((diff != 0) && (diff != clist->clist_window_height))
3280         check_exposures (clist);
3281     }
3282
3283   draw_rows (clist, &area);
3284 }
3285
3286 static void
3287 hadjustment_value_changed (GtkAdjustment * adjustment,
3288                                      gpointer data)
3289 {
3290   GtkCList *clist;
3291   GdkRectangle area;
3292   gint i, diff, value;
3293
3294   g_return_if_fail (adjustment != NULL);
3295   g_return_if_fail (data != NULL);
3296   g_return_if_fail (GTK_IS_CLIST (data));
3297
3298   clist = GTK_CLIST (data);
3299
3300   if (!GTK_WIDGET_DRAWABLE (clist))
3301     return;
3302
3303   value = adjustment->value;
3304
3305   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
3306     {
3307       /* move the column buttons and resize windows */
3308       for (i = 0; i < clist->columns; i++)
3309         {
3310           if (clist->column[i].button)
3311             {
3312               clist->column[i].button->allocation.x -= value + clist->hoffset;
3313
3314               if (clist->column[i].button->window)
3315                 {
3316                   gdk_window_move (clist->column[i].button->window,
3317                                    clist->column[i].button->allocation.x,
3318                                    clist->column[i].button->allocation.y);
3319
3320                   if (clist->column[i].window)
3321                     gdk_window_move (clist->column[i].window,
3322                                      clist->column[i].button->allocation.x +
3323                                      clist->column[i].button->allocation.width - 
3324                                      (DRAG_WIDTH / 2), 0); 
3325                 }
3326             }
3327         }
3328
3329       if (value > -clist->hoffset)
3330         {
3331           /* scroll right */
3332           diff = value + clist->hoffset;
3333
3334           /* we have to re-draw the whole screen here... */
3335           if (diff >= clist->clist_window_width)
3336             {
3337               clist->hoffset = -value;
3338               draw_rows (clist, NULL);
3339               return;
3340             }
3341
3342           if ((diff != 0) && (diff != clist->clist_window_width))
3343             gdk_window_copy_area (clist->clist_window,
3344                                   clist->fg_gc,
3345                                   0, 0,
3346                                   clist->clist_window,
3347                                   diff,
3348                                   0,
3349                                   clist->clist_window_width - diff,
3350                                   clist->clist_window_height);
3351
3352           area.x = clist->clist_window_width - diff;
3353           area.y = 0;
3354           area.width = diff;
3355           area.height = clist->clist_window_height;
3356         }
3357       else
3358         {
3359           /* scroll left */
3360           diff = -clist->hoffset - value;
3361
3362           /* we have to re-draw the whole screen here... */
3363           if (diff >= clist->clist_window_width)
3364             {
3365               clist->hoffset = -value;
3366               draw_rows (clist, NULL);
3367               return;
3368             }
3369
3370           if ((diff != 0) && (diff != clist->clist_window_width))
3371             gdk_window_copy_area (clist->clist_window,
3372                                   clist->fg_gc,
3373                                   diff, 0,
3374                                   clist->clist_window,
3375                                   0,
3376                                   0,
3377                                   clist->clist_window_width - diff,
3378                                   clist->clist_window_height);
3379
3380           area.x = 0;
3381           area.y = 0;
3382           area.width = diff;
3383           area.height = clist->clist_window_height;
3384         }
3385
3386       clist->hoffset = -value;
3387       if ((diff != 0) && (diff != clist->clist_window_width))
3388         check_exposures (clist);
3389     }
3390
3391   draw_rows (clist, &area);
3392 }
3393
3394 /* 
3395  * Memory Allocation/Distruction Routines for GtkCList stuctures
3396  *
3397  * functions:
3398  *   columns_new
3399  *   column_title_new
3400  *   columns_delete
3401  *   row_new
3402  *   row_delete
3403  *   cell_empty
3404  *   cell_set_text
3405  *   cell_set_pixmap 
3406  */
3407 static GtkCListColumn *
3408 columns_new (GtkCList * clist)
3409 {
3410   gint i;
3411   GtkCListColumn *column;
3412
3413   column = g_new (GtkCListColumn, clist->columns);
3414
3415   for (i = 0; i < clist->columns; i++)
3416     {
3417       column[i].area.x = 0;
3418       column[i].area.y = 0;
3419       column[i].area.width = 0;
3420       column[i].area.height = 0;
3421       column[i].title = NULL;
3422       column[i].button = NULL;
3423       column[i].window = NULL;
3424       column[i].width = 0;
3425       column[i].width_set = FALSE;
3426       column[i].justification = GTK_JUSTIFY_LEFT;
3427     }
3428
3429   return column;
3430 }
3431
3432 static void
3433 column_title_new (GtkCList * clist,
3434                   gint column,
3435                   gchar * title)
3436 {
3437   if (clist->column[column].title)
3438     g_free (clist->column[column].title);
3439
3440   clist->column[column].title = g_strdup (title);
3441 }
3442
3443 static void
3444 columns_delete (GtkCList * clist)
3445 {
3446   gint i;
3447
3448   for (i = 0; i < clist->columns; i++)
3449     if (clist->column[i].title)
3450       g_free (clist->column[i].title);
3451       
3452   g_free (clist->column);
3453 }
3454
3455 static GtkCListRow *
3456 row_new (GtkCList * clist)
3457 {
3458   int i;
3459   GtkCListRow *clist_row;
3460
3461   clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
3462   clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
3463
3464   for (i = 0; i < clist->columns; i++)
3465     {
3466       clist_row->cell[i].type = GTK_CELL_EMPTY;
3467       clist_row->cell[i].vertical = 0;
3468       clist_row->cell[i].horizontal = 0;
3469     }
3470
3471   clist_row->fg_set = FALSE;
3472   clist_row->bg_set = FALSE;
3473   clist_row->state = GTK_STATE_NORMAL;
3474   clist_row->data = NULL;
3475
3476   return clist_row;
3477 }
3478
3479 static void
3480 row_delete (GtkCList * clist,
3481             GtkCListRow * clist_row)
3482 {
3483   gint i;
3484
3485   for (i = 0; i < clist->columns; i++)
3486     cell_empty (clist, clist_row, i);
3487
3488   g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
3489   g_mem_chunk_free (clist->row_mem_chunk, clist_row);
3490 }
3491
3492 static void
3493 cell_empty (GtkCList * clist,
3494             GtkCListRow * clist_row,
3495             gint column)
3496 {
3497   switch (clist_row->cell[column].type)
3498     {
3499     case GTK_CELL_EMPTY:
3500       break;
3501       
3502     case GTK_CELL_TEXT:
3503       g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
3504       break;
3505       
3506     case GTK_CELL_PIXMAP:
3507       gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
3508       gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
3509       break;
3510       
3511     case GTK_CELL_PIXTEXT:
3512       g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
3513       gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
3514       gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
3515       break;
3516
3517     case GTK_CELL_WIDGET:
3518       /* unimplimented */
3519       break;
3520       
3521     default:
3522       break;
3523     }
3524
3525   clist_row->cell[column].type = GTK_CELL_EMPTY;
3526 }
3527
3528 static void
3529 cell_set_text (GtkCList * clist,
3530                GtkCListRow * clist_row,
3531                gint column,
3532                gchar * text)
3533 {
3534   cell_empty (clist, clist_row, column);
3535
3536   if (text)
3537     {
3538       clist_row->cell[column].type = GTK_CELL_TEXT;
3539       GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
3540     }
3541 }
3542
3543 static void
3544 cell_set_pixmap (GtkCList * clist,
3545                  GtkCListRow * clist_row,
3546                  gint column,
3547                  GdkPixmap * pixmap,
3548                  GdkBitmap * mask)
3549 {
3550   cell_empty (clist, clist_row, column);
3551
3552   if (pixmap && mask)
3553     {
3554       clist_row->cell[column].type = GTK_CELL_PIXMAP;
3555       GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
3556       GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
3557     }
3558 }
3559
3560 static void
3561 cell_set_pixtext (GtkCList * clist,
3562                   GtkCListRow * clist_row,
3563                   gint column,
3564                   gchar * text,
3565                   guint8 spacing,
3566                   GdkPixmap * pixmap,
3567                   GdkBitmap * mask)
3568 {
3569   cell_empty (clist, clist_row, column);
3570
3571   if (text && pixmap && mask)
3572     {
3573       clist_row->cell[column].type = GTK_CELL_PIXTEXT;
3574       GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3575       GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3576       GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3577       GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3578     }
3579 }
3580
3581 /* Fill in data after widget is realized and has style */
3582
3583 static void 
3584 add_style_data (GtkCList * clist)
3585 {
3586   GtkWidget *widget;
3587
3588   widget = GTK_WIDGET(clist);
3589
3590   /* text properties */
3591   if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
3592     {
3593       clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
3594       clist->row_center_offset = widget->style->font->ascent + 1.5;
3595     }
3596   else
3597     {
3598       gint text_height;
3599       text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent +
3600                           GTK_WIDGET (clist) ->style->font->descent + 1);
3601       clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
3602     }
3603
3604   /* Column widths */
3605 }