]> Pileus Git - ~andy/gtk/blob - gtk/gtkclist.c
main part for GtkArgSetFunc/GtkArgGetFunc implementation.
[~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 width of the column resize windows */
24 #define DRAG_WIDTH  5
25
26 /* minimum allowed width of a column */
27 #define COLUMN_MIN_WIDTH 5
28
29 /* this defigns the base grid spacing */
30 #define CELL_SPACING 1
31
32 /* added the horizontal space at the beginning and end of a row*/
33 #define COLUMN_INSET 3
34
35 /* scrollbar spacing class macro */
36 #define SCROLLBAR_SPACING(w) (GTK_CLIST_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
37
38 /* gives the top pixel of the given row in context of
39  * the clist's voffset */
40 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
41                                     (((row) + 1) * CELL_SPACING) + \
42                                     (clist)->voffset)
43
44 /* returns the row index from a y pixel location in the 
45  * context of the clist's voffset */
46 #define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
47                                     ((clist)->row_height + CELL_SPACING))
48
49 /* gives the left pixel of the given column in context of
50  * the clist's hoffset */
51 #define COLUMN_LEFT_YPIXEL(clist, column)  ((clist)->column[(column)].area.x + \
52                                             (clist)->hoffset)
53
54 /* returns the column index from a x pixel location in the 
55  * context of the clist's hoffset */
56 static inline gint
57 COLUMN_FROM_XPIXEL (GtkCList * clist,
58                     gint x)
59 {
60   gint i, cx;
61
62   for (i = 0; i < clist->columns; i++)
63     {
64       cx = clist->column[i].area.x + clist->hoffset;
65
66       if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
67           x <= (cx + clist->column[i].area.width + COLUMN_INSET))
68         return i;
69     }
70
71   /* no match */
72   return -1;
73 }
74
75 /* returns the top pixel of the given row in the context of
76  * the list height */
77 #define ROW_TOP(clist, row)        (((clist)->row_height + CELL_SPACING) * (row))
78
79 /* returns the left pixel of the given column in the context of
80  * the list width */
81 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
82
83 /* returns the total height of the list */
84 #define LIST_HEIGHT(clist)         (((clist)->row_height * ((clist)->rows)) + \
85                                     (CELL_SPACING * ((clist)->rows + 1)))
86
87 /* returns the total width of the list */
88 #define LIST_WIDTH(clist)          ((clist)->column[(clist)->columns - 1].area.x + \
89                                     (clist)->column[(clist)->columns - 1].area.width + \
90                                     COLUMN_INSET + CELL_SPACING)
91
92
93 /* Signals */
94 enum
95 {
96   SELECT_ROW,
97   UNSELECT_ROW,
98   CLICK_COLUMN,
99   LAST_SIGNAL
100 };
101
102 typedef void (*GtkCListSignal1) (GtkObject * object,
103                                  gint arg1,
104                                  gint arg2,
105                                  GdkEventButton * arg3,
106                                  gpointer data);
107
108 typedef void (*GtkCListSignal2) (GtkObject * object,
109                                  gint arg1,
110                                  gpointer data);
111
112
113 /* GtkCList Methods */
114 static void gtk_clist_class_init (GtkCListClass * klass);
115 static void gtk_clist_init (GtkCList * clist);
116
117 static gint gtk_clist_row_isvisable (GtkCList * clist,
118                                      gint row);
119
120 static void gtk_clist_draw_row (GtkCList * clist,
121                                 GdkRectangle * area,
122                                 gint row,
123                                 GtkCListRow * clist_row);
124
125 static void gtk_clist_draw_rows (GtkCList * clist,
126                                  GdkRectangle * area);
127
128 static gint gtk_clist_get_selection_info (GtkCList * clist,
129                                           gint x,
130                                           gint y,
131                                           gint * row,
132                                           gint * column);
133
134 static void gtk_clist_real_select_row (GtkCList * clist,
135                                        gint row,
136                                        gint column,
137                                        GdkEventButton * event);
138 static void gtk_clist_real_unselect_row (GtkCList * clist,
139                                          gint row,
140                                          gint column,
141                                          GdkEventButton * event);
142
143 static void gtk_clist_size_allocate_title_buttons (GtkCList * clist);
144 static void gtk_clist_size_allocate_columns (GtkCList * clist);
145
146
147 /* GtkObject Methods */
148 static void gtk_clist_destroy (GtkObject * object);
149
150
151 /* GtkWidget Methods */
152 static void gtk_clist_realize (GtkWidget * widget);
153 static void gtk_clist_unrealize (GtkWidget * widget);
154 static void gtk_clist_map (GtkWidget * widget);
155 static void gtk_clist_unmap (GtkWidget * widget);
156 static void gtk_clist_draw (GtkWidget * widget,
157                             GdkRectangle * area);
158 static gint gtk_clist_expose (GtkWidget * widget,
159                               GdkEventExpose * event);
160 static gint gtk_clist_button_press (GtkWidget * widget,
161                                     GdkEventButton * event);
162
163 static void gtk_clist_size_request (GtkWidget * widget,
164                                     GtkRequisition * requisition);
165 static void gtk_clist_size_allocate (GtkWidget * widget,
166                                      GtkAllocation * allocation);
167
168
169 /* GtkContainer Methods */
170 static void gtk_clist_foreach (GtkContainer * container,
171                                GtkCallback callback,
172                                gpointer callback_data);
173
174
175 /* Buttons */
176 static void gtk_clist_column_button_realize (GtkWidget * widget,
177                                              gpointer data);
178 static void gtk_clist_column_button_clicked (GtkWidget * widget,
179                                              gpointer data);
180
181
182 /* Scrollbars */
183 static void gtk_clist_adjust_scrollbars (GtkCList * clist);
184 static void gtk_clist_vadjustment_changed (GtkAdjustment * adjustment,
185                                            gpointer data);
186 static void gtk_clist_vadjustment_value_changed (GtkAdjustment * adjustment,
187                                                  gpointer data);
188 static void gtk_clist_hadjustment_changed (GtkAdjustment * adjustment,
189                                            gpointer data);
190 static void gtk_clist_hadjustment_value_changed (GtkAdjustment * adjustment,
191                                                  gpointer data);
192
193
194 /* Memory Allocation/Distruction Routines */
195 static GtkCListColumn *gtk_clist_columns_new (GtkCList * clist);
196
197 static void gtk_clist_column_title_new (GtkCList * clist,
198                                         gint column,
199                                         gchar * title);
200 static void gtk_clist_columns_delete (GtkCList * clist);
201
202 static GtkCListRow *gtk_clist_row_new (GtkCList * clist);
203
204 static void gtk_clist_row_delete (GtkCList * clist,
205                                   GtkCListRow * clist_row);
206 static void gtk_clist_cell_empty (GtkCList * clist,
207                                   GtkCListRow * clist_row,
208                                   gint column);
209 static void gtk_clist_cell_set_text (GtkCList * clist,
210                                      GtkCListRow * clist_row,
211                                      gint column,
212                                      gchar * text);
213 static void gtk_clist_cell_set_pixmap (GtkCList * clist,
214                                        GtkCListRow * clist_row,
215                                        gint column,
216                                        GdkPixmap * pixmap,
217                                        GdkBitmap * mask);
218 static void gtk_clist_cell_set_pixtext (GtkCList * clist,
219                                         GtkCListRow * clist_row,
220                                         gint column,
221                                         gchar * text,
222                                         guint8 spacing,
223                                         GdkPixmap * pixmap,
224                                         GdkBitmap * mask);
225
226 /* Signals */
227 static void gtk_clist_marshal_signal_1 (GtkObject * object,
228                                         GtkSignalFunc func,
229                                         gpointer func_data,
230                                         GtkArg * args);
231 static void gtk_clist_marshal_signal_2 (GtkObject * object,
232                                         GtkSignalFunc func,
233                                         gpointer func_data,
234                                         GtkArg * args);
235
236
237 static GtkContainerClass *parent_class = NULL;
238 static gint clist_signals[LAST_SIGNAL] = {0};
239
240
241 guint
242 gtk_clist_get_type ()
243 {
244   static guint clist_type = 0;
245
246   if (!clist_type)
247     {
248       GtkTypeInfo clist_info =
249       {
250         "GtkCList",
251         sizeof (GtkCList),
252         sizeof (GtkCListClass),
253         (GtkClassInitFunc) gtk_clist_class_init,
254         (GtkObjectInitFunc) gtk_clist_init,
255         (GtkArgSetFunc) NULL,
256         (GtkArgGetFunc) NULL,
257       };
258
259       clist_type = gtk_type_unique (gtk_container_get_type (), &clist_info);
260     }
261
262   return clist_type;
263 }
264
265 static void
266 gtk_clist_class_init (GtkCListClass * klass)
267 {
268   GtkObjectClass *object_class;
269   GtkWidgetClass *widget_class;
270   GtkContainerClass *container_class;
271
272   object_class = (GtkObjectClass *) klass;
273   widget_class = (GtkWidgetClass *) klass;
274   container_class = (GtkContainerClass *) klass;
275
276   parent_class = gtk_type_class (gtk_container_get_type ());
277
278   clist_signals[SELECT_ROW] =
279     gtk_signal_new ("select_row",
280                     GTK_RUN_LAST,
281                     object_class->type,
282                     GTK_SIGNAL_OFFSET (GtkCListClass, select_row),
283                     gtk_clist_marshal_signal_1,
284             GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
285   clist_signals[UNSELECT_ROW] =
286     gtk_signal_new ("unselect_row",
287                     GTK_RUN_LAST,
288                     object_class->type,
289                     GTK_SIGNAL_OFFSET (GtkCListClass, unselect_row),
290                     gtk_clist_marshal_signal_1,
291             GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
292   clist_signals[CLICK_COLUMN] =
293     gtk_signal_new ("click_column",
294                     GTK_RUN_LAST,
295                     object_class->type,
296                     GTK_SIGNAL_OFFSET (GtkCListClass, click_column),
297                     gtk_clist_marshal_signal_2,
298                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
299
300   gtk_object_class_add_signals (object_class, clist_signals, LAST_SIGNAL);
301
302   object_class->destroy = gtk_clist_destroy;
303
304   widget_class->realize = gtk_clist_realize;
305   widget_class->unrealize = gtk_clist_unrealize;
306   widget_class->map = gtk_clist_map;
307   widget_class->unmap = gtk_clist_unmap;
308   widget_class->draw = gtk_clist_draw;
309   widget_class->button_press_event = gtk_clist_button_press;
310   widget_class->expose_event = gtk_clist_expose;
311   widget_class->size_request = gtk_clist_size_request;
312   widget_class->size_allocate = gtk_clist_size_allocate;
313
314   container_class->add = NULL;
315   container_class->remove = NULL;
316   container_class->foreach = gtk_clist_foreach;
317
318   klass->select_row = gtk_clist_real_select_row;
319   klass->unselect_row = gtk_clist_real_unselect_row;
320   klass->click_column = NULL;
321
322   klass->scrollbar_spacing = 5;
323 }
324
325 static void
326 gtk_clist_marshal_signal_1 (GtkObject * object,
327                             GtkSignalFunc func,
328                             gpointer func_data,
329                             GtkArg * args)
330 {
331   GtkCListSignal1 rfunc;
332
333   rfunc = (GtkCListSignal1) func;
334
335   (*rfunc) (object, GTK_VALUE_INT (args[0]),
336             GTK_VALUE_INT (args[1]),
337             GTK_VALUE_POINTER (args[2]),
338             func_data);
339 }
340
341 static void
342 gtk_clist_marshal_signal_2 (GtkObject * object,
343                             GtkSignalFunc func,
344                             gpointer func_data,
345                             GtkArg * args)
346 {
347   GtkCListSignal2 rfunc;
348
349   rfunc = (GtkCListSignal2) func;
350
351   (*rfunc) (object, GTK_VALUE_INT (args[0]),
352             func_data);
353 }
354
355 static void
356 gtk_clist_init (GtkCList * clist)
357 {
358   clist->flags = 0;
359
360   GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW);
361   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
362
363   clist->rows = 0;
364   clist->row_center_offset = 0;
365   clist->row_height = 0;
366   clist->row_list = NULL;
367   clist->row_list_end = NULL;
368
369   clist->columns = 0;
370
371   clist->column_title_area.x = 0;
372   clist->column_title_area.y = 0;
373   clist->column_title_area.width = 0;
374   clist->column_title_area.height = 0;
375
376   clist->clist_window = NULL;
377   clist->clist_window_width = 0;
378   clist->clist_window_height = 0;
379
380   clist->hoffset = 0;
381   clist->voffset = 0;
382
383   clist->shadow_type = GTK_SHADOW_IN;
384   clist->hscrollbar_policy = GTK_POLICY_ALWAYS;
385   clist->vscrollbar_policy = GTK_POLICY_ALWAYS;
386
387   clist->cursor_drag = NULL;
388   clist->xor_gc = NULL;
389   clist->fg_gc = NULL;
390   clist->bg_gc = NULL;
391   clist->x_drag = 0;
392
393   clist->selection_mode = GTK_SELECTION_SINGLE;
394   clist->selection = NULL;
395 }
396
397 GtkWidget *
398 gtk_clist_new (int columns,
399                gchar * titles[])
400 {
401   int i;
402   GtkCList *clist;
403   GtkAdjustment *adjustment;
404
405   /* sanity check */
406   if (columns < 1 || titles == NULL)
407     return NULL;
408
409   clist = gtk_type_new (gtk_clist_get_type ());
410
411   /* initalize memory chunks */
412   clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk",
413                                           sizeof (GtkCListRow),
414                                           sizeof (GtkCListRow) * 1024, 
415                                           G_ALLOC_AND_FREE);
416   clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk",
417                                            sizeof (GtkCell) * columns,
418                                            sizeof (GtkCell) * columns * 1024, 
419                                            G_ALLOC_AND_FREE);
420
421   /* set number of columns, allocate memory */
422   clist->columns = columns;
423   clist->column = gtk_clist_columns_new (clist);
424
425   /* create column button and connect signals */
426   for (i = 0; i < columns; i++)
427     {
428       clist->column[i].button = gtk_button_new ();
429       gtk_widget_set_parent (clist->column[i].button, GTK_WIDGET (clist));
430
431       gtk_signal_connect_after (GTK_OBJECT (clist->column[i].button),
432                                 "realize",
433                                 (GtkSignalFunc) gtk_clist_column_button_realize,
434                                 (gpointer) clist);
435
436       gtk_signal_connect (GTK_OBJECT (clist->column[i].button),
437                           "clicked",
438                           (GtkSignalFunc) gtk_clist_column_button_clicked,
439                           (gpointer) clist);
440
441       /* set column title */
442       gtk_clist_set_column_title (clist, i, titles[i]);
443
444       clist->column[i].width = 
445         gdk_string_width (GTK_WIDGET (clist)->style->font, clist->column[i].title);
446
447       gtk_widget_show (clist->column[i].button);
448     }
449
450
451   /* create and connect scrollbars */
452   clist->vscrollbar = gtk_vscrollbar_new (NULL);
453   adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
454
455   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
456                       (GtkSignalFunc) gtk_clist_vadjustment_changed,
457                       (gpointer) clist);
458
459   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
460                       (GtkSignalFunc) gtk_clist_vadjustment_value_changed,
461                       (gpointer) clist);
462
463   gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist));
464   gtk_widget_show (clist->vscrollbar);
465
466   clist->hscrollbar = gtk_hscrollbar_new (NULL);
467   adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
468
469   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
470                       (GtkSignalFunc) gtk_clist_hadjustment_changed,
471                       (gpointer) clist);
472
473   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
474                       (GtkSignalFunc) gtk_clist_hadjustment_value_changed,
475                       (gpointer) clist);
476
477   gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist));
478   gtk_widget_show (clist->hscrollbar);
479
480   return GTK_WIDGET (clist);
481 }
482
483 void
484 gtk_clist_set_border (GtkCList * clist,
485                       GtkShadowType border)
486 {
487   g_return_if_fail (clist != NULL);
488
489   clist->shadow_type = border;
490
491   if (GTK_WIDGET_VISIBLE (clist))
492     gtk_widget_queue_resize (GTK_WIDGET (clist));
493 }
494
495 void
496 gtk_clist_set_selection_mode (GtkCList * clist,
497                               GtkSelectionMode mode)
498 {
499   g_return_if_fail (clist != NULL);
500
501   clist->selection_mode = mode;
502 }
503
504 void
505 gtk_clist_freeze (GtkCList * clist)
506 {
507   g_return_if_fail (clist != NULL);
508
509   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
510 }
511
512 void
513 gtk_clist_thaw (GtkCList * clist)
514 {
515   g_return_if_fail (clist != NULL);
516
517   GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
518
519   gtk_clist_adjust_scrollbars (clist);
520   gtk_clist_draw_rows (clist, NULL);
521 }
522
523
524 void
525 gtk_clist_set_column_title (GtkCList * clist,
526                             gint column,
527                             gchar * title)
528 {
529   GtkWidget *old_widget;
530   GtkWidget *alignment = NULL;
531   GtkWidget *label;
532
533   g_return_if_fail (clist != NULL);
534
535   if (column < 0 || column >= clist->columns)
536     return;
537
538   gtk_clist_column_title_new (clist, column, title);
539
540   /* remove and destroy the old widget */
541   old_widget = GTK_BUTTON (clist->column[column].button)->child;
542   if (old_widget)
543     {
544       gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
545       gtk_widget_destroy (old_widget);
546     }
547
548   switch (clist->column[column].justification)
549     {
550     case GTK_JUSTIFY_LEFT:
551       alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
552       break;
553
554     case GTK_JUSTIFY_RIGHT:
555       alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
556       break;
557
558     case GTK_JUSTIFY_CENTER:
559       alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
560       break;
561
562     case GTK_JUSTIFY_FILL:
563       alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
564       break;
565     }
566
567   if (alignment)
568     {
569       label = gtk_label_new (clist->column[column].title);
570       gtk_container_add (GTK_CONTAINER (alignment), label);
571       gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment);
572       gtk_widget_show (label);
573       gtk_widget_show (alignment);
574     }
575 }
576
577 void
578 gtk_clist_set_column_widget (GtkCList * clist,
579                              gint column,
580                              GtkWidget * widget)
581 {
582   GtkWidget *old_widget;
583
584   g_return_if_fail (clist != NULL);
585
586   if (column < 0 || column >= clist->columns)
587     return;
588
589   gtk_clist_column_title_new (clist, column, NULL);
590
591   /* remove and destroy the old widget */
592   old_widget = GTK_BUTTON (clist->column[column].button)->child;
593   if (old_widget)
594     {
595       gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget);
596       gtk_widget_destroy (old_widget);
597     }
598
599   /* add and show the widget */
600   if (widget)
601     {
602       gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget);
603       gtk_widget_show (widget);
604     }
605 }
606
607 void
608 gtk_clist_set_column_justification (GtkCList * clist,
609                                     gint column,
610                                     GtkJustification justification)
611 {
612   GtkWidget *alignment;
613
614   g_return_if_fail (clist != NULL);
615
616   if (column < 0 || column >= clist->columns)
617     return;
618
619   clist->column[column].justification = justification;
620
621   /* change the alinment of the button title if it's not a
622    * custom widget */
623   if (clist->column[column].title)
624     {
625       alignment = GTK_BUTTON (clist->column[column].button)->child;
626
627       switch (clist->column[column].justification)
628         {
629         case GTK_JUSTIFY_LEFT:
630           gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0);
631           break;
632
633         case GTK_JUSTIFY_RIGHT:
634           gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0);
635           break;
636
637         case GTK_JUSTIFY_CENTER:
638           gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
639           break;
640
641         case GTK_JUSTIFY_FILL:
642           gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0);
643           break;
644
645         default:
646           break;
647         }
648     }
649
650   if (!GTK_CLIST_FROZEN (clist))
651     gtk_clist_draw_rows (clist, NULL);
652 }
653
654 void
655 gtk_clist_set_column_width (GtkCList * clist,
656                             gint column,
657                             gint width)
658 {
659   g_return_if_fail (clist != NULL);
660
661   if (column < 0 || column >= clist->columns)
662     return;
663
664   clist->column[column].width = width;
665
666   gtk_clist_size_allocate_title_buttons (clist);
667
668   if (!GTK_CLIST_FROZEN (clist))
669     {
670       gtk_clist_adjust_scrollbars (clist);
671       gtk_clist_draw_rows (clist, NULL);
672     }
673 }
674
675 void
676 gtk_clist_set_row_height (GtkCList * clist,
677                           gint height)
678 {
679   gint text_height;
680
681   g_return_if_fail (clist != NULL);
682
683   if (height > 0)
684     clist->row_height = height;
685   else
686     return;
687
688   GTK_CLIST_SET_FLAGS (clist, CLIST_ROW_HEIGHT_SET);
689
690   text_height = height - (GTK_WIDGET (clist)->style->font->ascent +
691                           GTK_WIDGET (clist) ->style->font->descent + 1);
692   clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5;
693
694   if (!GTK_CLIST_FROZEN (clist))
695     {
696       gtk_clist_adjust_scrollbars (clist);
697       gtk_clist_draw_rows (clist, NULL);
698     }
699 }
700
701 void
702 gtk_clist_moveto (GtkCList * clist,
703                   gint row,
704                   gint column,
705                   gfloat row_align,
706                   gfloat col_align)
707 {
708   gint x, y;
709
710   g_return_if_fail (clist != NULL);
711
712   if (row < -1 || row >= clist->rows)
713     return;
714   if (column < -1 || column >= clist->columns)
715     return;
716
717   /* adjust vertical scrollbar */
718   if (row >= 0)
719     {
720       x = ROW_TOP (clist, row) - (row_align * (clist->clist_window_height - 
721                                                (clist->row_height + 2 * CELL_SPACING)));
722       
723       if (x < 0)
724         GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
725       else if (x > LIST_HEIGHT (clist) - clist->clist_window_height)
726         GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - 
727           clist->clist_window_height;
728       else
729         GTK_RANGE (clist->vscrollbar)->adjustment->value = x;
730       
731       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
732                                "value_changed");
733     } 
734      
735   /* adjust horizontal scrollbar */
736   if (column >= 0)
737     {
738       y = COLUMN_LEFT (clist, column) - (col_align * (clist->clist_window_width - 
739                                                       clist->column[column].area.width + 
740                                                       2 * (CELL_SPACING + COLUMN_INSET)));
741       
742       if (y < 0)
743         GTK_RANGE (clist->hscrollbar)->adjustment->value = 0.0;
744       else if (y > LIST_WIDTH (clist) - clist->clist_window_width)
745         GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - 
746           clist->clist_window_width;
747       else
748         GTK_RANGE (clist->hscrollbar)->adjustment->value = y;
749       
750       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
751                                "value_changed");
752     }
753 }
754
755 void
756 gtk_clist_set_text (GtkCList * clist,
757                     gint row,
758                     gint column,
759                     gchar * text)
760 {
761   GtkCListRow *clist_row;
762
763   g_return_if_fail (clist != NULL);
764
765   if (row < 0 || row >= clist->rows)
766     return;
767   if (column < 0 || column >= clist->columns)
768     return;
769
770   clist_row = (g_list_nth (clist->row_list, row))->data;
771
772   /* if text is null, then the cell is empty */
773   if (text)
774     gtk_clist_cell_set_text (clist, clist_row, column, text);
775   else
776     gtk_clist_cell_empty (clist, clist_row, column);
777
778   /* redraw the list if it's not frozen */
779   if (!GTK_CLIST_FROZEN (clist))
780     {
781       if (gtk_clist_row_isvisable (clist, row))
782         gtk_clist_draw_row (clist, NULL, row, clist_row);
783     }
784 }
785
786 void
787 gtk_clist_set_pixmap (GtkCList * clist,
788                       gint row,
789                       gint column,
790                       GdkPixmap * pixmap,
791                       GdkBitmap * mask)
792 {
793   GtkCListRow *clist_row;
794
795   g_return_if_fail (clist != NULL);
796
797   if (row < 0 || row >= clist->rows)
798     return;
799   if (column < 0 || column >= clist->columns)
800     return;
801
802   clist_row = (g_list_nth (clist->row_list, row))->data;
803   
804   gdk_pixmap_ref (pixmap);
805   gdk_pixmap_ref (mask);
806   gtk_clist_cell_set_pixmap (clist, clist_row, column, pixmap, mask);
807
808   /* redraw the list if it's not frozen */
809   if (!GTK_CLIST_FROZEN (clist))
810     {
811       if (gtk_clist_row_isvisable (clist, row))
812         gtk_clist_draw_row (clist, NULL, row, clist_row);
813     }
814 }
815
816 void
817 gtk_clist_set_pixtext (GtkCList * clist,
818                        gint row,
819                        gint column,
820                        gchar * text,
821                        guint8 spacing,
822                        GdkPixmap * pixmap,
823                        GdkBitmap * mask)
824 {
825   GtkCListRow *clist_row;
826
827   g_return_if_fail (clist != NULL);
828
829   if (row < 0 || row >= clist->rows)
830     return;
831   if (column < 0 || column >= clist->columns)
832     return;
833
834   clist_row = (g_list_nth (clist->row_list, row))->data;
835   
836   gdk_pixmap_ref (pixmap);
837   gdk_pixmap_ref (mask);
838   gtk_clist_cell_set_pixtext (clist, clist_row, column, text, spacing, pixmap, mask);
839
840   /* redraw the list if it's not frozen */
841   if (!GTK_CLIST_FROZEN (clist))
842     {
843       if (gtk_clist_row_isvisable (clist, row))
844         gtk_clist_draw_row (clist, NULL, row, clist_row);
845     }
846 }
847
848 void
849 gtk_clist_set_foreground (GtkCList * clist,
850                           gint row,
851                           GdkColor * color)
852 {
853   GtkCListRow *clist_row;
854
855   g_return_if_fail (clist != NULL);
856   g_return_if_fail (color != NULL);
857
858   if (row < 0 || row >= clist->rows)
859     return;
860
861   clist_row = (g_list_nth (clist->row_list, row))->data;
862   clist_row->foreground = *color;
863
864   if (!GTK_CLIST_FROZEN (clist))
865     if (gtk_clist_row_isvisable (clist, row))
866       gtk_clist_draw_row (clist, NULL, row, clist_row);
867 }
868
869 void gtk_clist_set_background (GtkCList * clist,
870                                gint row,
871                                GdkColor * color)
872 {
873   GtkCListRow *clist_row;
874
875   g_return_if_fail (clist != NULL);
876   g_return_if_fail (color != NULL);
877
878   if (row < 0 || row >= clist->rows)
879     return;
880
881   clist_row = (g_list_nth (clist->row_list, row))->data;
882   clist_row->background = *color;
883
884   if (!GTK_CLIST_FROZEN (clist))
885     if (gtk_clist_row_isvisable (clist, row))
886       gtk_clist_draw_row (clist, NULL, row, clist_row);
887 }
888
889 void
890 gtk_clist_set_shift (GtkCList * clist,
891                      gint row,
892                      gint column,
893                      gint verticle,
894                      gint horizontal)
895 {
896   GtkCListRow *clist_row;
897
898   g_return_if_fail (clist != NULL);
899
900   if (row < 0 || row >= clist->rows)
901     return;
902   if (column < 0 || column >= clist->columns)
903     return;
904
905   clist_row = (g_list_nth (clist->row_list, row))->data;
906
907   clist_row->cell[column].verticle = verticle;
908   clist_row->cell[column].horizontal = horizontal;
909
910   if (!GTK_CLIST_FROZEN (clist))
911     if (gtk_clist_row_isvisable (clist, row))
912       gtk_clist_draw_row (clist, NULL, row, clist_row);
913 }
914
915 gint
916 gtk_clist_append (GtkCList * clist,
917                   gchar * text[])
918 {
919   gint i;
920   GtkCListRow *clist_row;
921
922   g_return_val_if_fail (clist != NULL, -1);
923
924   clist_row = gtk_clist_row_new (clist);
925   clist->rows++;
926
927   /* keeps track of the end of the list so the list 
928    * doesn't have to be traversed every time a item is added */
929   if (!clist->row_list)
930     {
931       clist->row_list = g_list_append (clist->row_list, clist_row);
932       clist->row_list_end = clist->row_list;
933
934       /* check the selection mode to see if we should select
935        * the first row automaticly */
936       switch (clist->selection_mode)
937         {
938         case GTK_SELECTION_BROWSE:
939           gtk_clist_select_row (clist, 0, -1);
940           break;
941
942         default:
943           break;
944         }
945     }
946   else
947     clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
948
949   /* set the text in the row's columns */
950   if (text)
951     for (i = 0; i < clist->columns; i++)
952       if (text[i])
953         gtk_clist_cell_set_text (clist, clist_row, i, text[i]);
954   
955   /* redraw the list if it's not frozen */
956   if (!GTK_CLIST_FROZEN (clist))
957     {
958       gtk_clist_adjust_scrollbars (clist);
959
960       if (gtk_clist_row_isvisable (clist, clist->rows - 1))
961         gtk_clist_draw_rows (clist, NULL);
962     }
963
964   /* return index of the row */
965   return clist->rows - 1;
966 }
967
968 void
969 gtk_clist_insert (GtkCList * clist,
970                   gint row,
971                   gchar * text[])
972 {
973   gint i;
974   GtkCListRow *clist_row;
975
976   g_return_if_fail (clist != NULL);
977   g_return_if_fail (text != NULL);
978
979   /* return if out of bounds */
980   if (row < 0 || row > (clist->rows - 1))
981     return;
982
983   /* create the row */
984   clist_row = gtk_clist_row_new (clist);
985
986   /* reset the row end pointer if we're inserting at the
987    * end of the list */
988   if (row == clist->rows)
989     clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next;
990   else
991     clist->row_list = g_list_insert (clist->row_list, clist_row, row);
992
993   clist->rows++;
994
995   /* set the text in the row's columns */
996   if (text)
997     for (i = 0; i < clist->columns; i++)
998       if (text[i])
999         gtk_clist_cell_set_text (clist, clist_row, i, text[i]);
1000
1001   /* redraw the list if it isn't frozen */
1002   if (!GTK_CLIST_FROZEN (clist))
1003     {
1004       gtk_clist_adjust_scrollbars (clist);
1005
1006       if (gtk_clist_row_isvisable (clist, row))
1007         gtk_clist_draw_rows (clist, NULL);
1008     }
1009 }
1010
1011 void
1012 gtk_clist_remove (GtkCList * clist,
1013                   gint row)
1014 {
1015   gint was_visible;
1016   GList *list;
1017   GtkCListRow *clist_row;
1018
1019   g_return_if_fail (clist != NULL);
1020
1021   /* return if out of bounds */
1022   if (row < 0 || row > (clist->rows - 1))
1023     return;
1024
1025   was_visible = gtk_clist_row_isvisable (clist, row);
1026
1027   /* get the row we're going to delete */
1028   list = g_list_nth (clist->row_list, row);
1029   clist_row = list->data;
1030
1031   /* reset the row end pointer if we're removing at the
1032    * end of the list */
1033   if (row == clist->rows - 1)
1034     clist->row_list_end = list->prev;
1035
1036   clist->row_list = g_list_remove (clist->row_list, clist_row);
1037   clist->rows--;
1038
1039   /* redraw the row if it isn't frozen */
1040   if (!GTK_CLIST_FROZEN (clist))
1041     {
1042       gtk_clist_adjust_scrollbars (clist);
1043
1044       if (was_visible)
1045         gtk_clist_draw_rows (clist, NULL);
1046     }
1047
1048   if (clist_row->state == GTK_STATE_SELECTED)
1049     {
1050       switch (clist->selection_mode)
1051         {
1052         case GTK_SELECTION_BROWSE:
1053           if (row >= clist->rows)
1054             row--;
1055           gtk_clist_select_row (clist, row, -1);
1056           break;
1057           
1058         default:
1059           break;
1060         }
1061
1062       /* remove from selection list */
1063       clist->selection = g_list_remove (clist->selection, clist_row);
1064     }
1065
1066   gtk_clist_row_delete (clist, clist_row);
1067 }
1068
1069 void
1070 gtk_clist_clear (GtkCList * clist)
1071 {
1072   GList *list;
1073   GtkCListRow *clist_row;
1074
1075   g_return_if_fail (clist != NULL);
1076
1077   /* remove all the rows */
1078   list = clist->row_list;
1079   while (list)
1080     {
1081       clist_row = list->data;
1082       list = list->next;
1083
1084       gtk_clist_row_delete (clist, clist_row);
1085     }
1086   g_list_free (clist->row_list);
1087
1088   /* free up the selection list */
1089   g_list_free (clist->selection);
1090
1091   clist->row_list = NULL;
1092   clist->row_list_end = NULL;
1093   clist->selection = NULL;
1094   clist->voffset = 0;
1095   clist->rows = 0;
1096
1097   /* zero-out the scrollbars */
1098   GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0;
1099   gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
1100
1101   if (!GTK_CLIST_FROZEN (clist))
1102     {
1103       gtk_clist_adjust_scrollbars (clist);
1104       gtk_clist_draw_rows (clist, NULL);
1105     }
1106 }
1107
1108 void
1109 gtk_clist_set_row_data (GtkCList * clist,
1110                         gint row,
1111                         gpointer data)
1112 {
1113   GtkCListRow *clist_row;
1114
1115   g_return_if_fail (clist != NULL);
1116
1117   if (row < 0 || row > (clist->rows - 1))
1118     return;
1119
1120   clist_row = (g_list_nth (clist->row_list, row))->data;
1121   clist_row->data = data;
1122
1123   /*
1124    * re-send the selected signal if data is changed/added
1125    * so the application can respond to the new data -- 
1126    * this could be questionable behavior
1127    */
1128   if (clist_row->state == GTK_STATE_SELECTED)
1129     gtk_clist_select_row (clist, 0, 0);
1130 }
1131
1132 gpointer
1133 gtk_clist_get_row_data (GtkCList * clist,
1134                         gint row)
1135 {
1136   GtkCListRow *clist_row;
1137
1138   g_return_val_if_fail (clist != NULL, NULL);
1139
1140   if (row < 0 || row > (clist->rows - 1))
1141     return NULL;
1142
1143   clist_row = (g_list_nth (clist->row_list, row))->data;
1144   return clist_row->data;
1145 }
1146
1147 void
1148 gtk_clist_select_row (GtkCList * clist,
1149                       gint row,
1150                       gint column)
1151 {
1152   g_return_if_fail (clist != NULL);
1153
1154   if (row < 0 || row >= clist->rows)
1155     return;
1156
1157   if (column < -1 || column >= clist->columns)
1158     return;
1159
1160   gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], row, column, NULL);
1161 }
1162
1163 void
1164 gtk_clist_unselect_row (GtkCList * clist,
1165                         gint row,
1166                         gint column)
1167 {
1168   g_return_if_fail (clist != NULL);
1169
1170   if (row < 0 || row >= clist->rows)
1171     return;
1172
1173   if (column < -1 || column >= clist->columns)
1174     return;
1175
1176   gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], row, column, NULL);
1177 }
1178
1179 static gint
1180 gtk_clist_row_isvisable (GtkCList * clist,
1181                          gint row)
1182 {
1183   g_return_val_if_fail (clist != NULL, 0);
1184
1185   if (row < 0 || row >= clist->rows)
1186     return 0;
1187
1188   if (clist->row_height == 0)
1189     return 0;
1190
1191   if (row < ROW_FROM_YPIXEL (clist, 0))
1192     return 0;
1193
1194   if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height))
1195     return 0;
1196
1197   return 1;
1198 }
1199
1200 GtkAdjustment *
1201 gtk_clist_get_vadjustment (GtkCList * clist)
1202 {
1203   g_return_val_if_fail (clist != NULL, NULL);
1204   g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1205
1206   return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar));
1207 }
1208
1209 GtkAdjustment *
1210 gtk_clist_get_hadjustment (GtkCList * clist)
1211 {
1212   g_return_val_if_fail (clist != NULL, NULL);
1213   g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
1214
1215   return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar));
1216 }
1217
1218 void
1219 gtk_clist_set_policy (GtkCList * clist,
1220                       GtkPolicyType vscrollbar_policy,
1221                       GtkPolicyType hscrollbar_policy)
1222 {
1223   g_return_if_fail (clist != NULL);
1224   g_return_if_fail (GTK_IS_CLIST (clist));
1225
1226   if (clist->vscrollbar_policy != vscrollbar_policy)
1227     {
1228       clist->vscrollbar_policy = vscrollbar_policy;
1229
1230       if (GTK_WIDGET (clist)->parent)
1231         gtk_widget_queue_resize (GTK_WIDGET (clist));
1232     }
1233
1234   if (clist->hscrollbar_policy != hscrollbar_policy)
1235     {
1236       clist->hscrollbar_policy = hscrollbar_policy;
1237
1238       if (GTK_WIDGET (clist)->parent)
1239         gtk_widget_queue_resize (GTK_WIDGET (clist));
1240     }
1241 }
1242
1243 static void
1244 gtk_clist_destroy (GtkObject * object)
1245 {
1246   gint i;
1247   GtkCList *clist;
1248
1249   g_return_if_fail (object != NULL);
1250   g_return_if_fail (GTK_IS_CLIST (object));
1251
1252   clist = GTK_CLIST (object);
1253
1254   /* freeze the list */
1255   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1256
1257   /* get rid of all the rows */
1258   gtk_clist_clear (clist);
1259
1260   /* destroy the scrollbars */
1261   gtk_widget_destroy (clist->vscrollbar);
1262   gtk_widget_destroy (clist->hscrollbar);
1263
1264   /* get rid of all the column buttons */
1265   for (i = 0; i < clist->columns; i++)
1266     gtk_widget_destroy (clist->column[i].button);
1267
1268   gtk_clist_columns_delete (clist);
1269
1270   /* get rid of the memory chunks */
1271   g_mem_chunk_destroy (clist->cell_mem_chunk);
1272   g_mem_chunk_destroy (clist->row_mem_chunk);
1273
1274   if (GTK_OBJECT_CLASS (parent_class)->destroy)
1275     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
1276 }
1277
1278 static void
1279 gtk_clist_realize (GtkWidget * widget)
1280 {
1281   GtkCList *clist;
1282   GdkWindowAttr attributes;
1283   gint attributes_mask;
1284   GdkGCValues values;
1285
1286   g_return_if_fail (widget != NULL);
1287   g_return_if_fail (GTK_IS_CLIST (widget));
1288
1289   clist = GTK_CLIST (widget);
1290
1291   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1292
1293   attributes.window_type = GDK_WINDOW_CHILD;
1294   attributes.x = widget->allocation.x;
1295   attributes.y = widget->allocation.y;
1296   attributes.width = widget->allocation.width;
1297   attributes.height = widget->allocation.height;
1298   attributes.wclass = GDK_INPUT_OUTPUT;
1299   attributes.visual = gtk_widget_get_visual (widget);
1300   attributes.colormap = gtk_widget_get_colormap (widget);
1301   attributes.event_mask = gtk_widget_get_events (widget);
1302   attributes.event_mask |= (GDK_EXPOSURE_MASK |
1303                             GDK_BUTTON_PRESS_MASK |
1304                             GDK_BUTTON_RELEASE_MASK |
1305                             GDK_KEY_PRESS_MASK);
1306   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1307
1308
1309   /* main window */
1310   widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
1311   gdk_window_set_user_data (widget->window, clist);
1312
1313   widget->style = gtk_style_attach (widget->style, widget->window);
1314
1315   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
1316
1317   /* column-title window */
1318   clist->title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1319   gdk_window_set_user_data (clist->title_window, clist);
1320
1321   gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_SELECTED);
1322   gdk_window_show (clist->title_window);
1323
1324   /* clist-window */
1325   clist->clist_window = gdk_window_new (widget->window, &attributes, attributes_mask);
1326   gdk_window_set_user_data (clist->clist_window, clist);
1327
1328   gdk_window_set_background (clist->clist_window, &widget->style->white);
1329   gdk_window_show (clist->clist_window);
1330   gdk_window_get_size (clist->clist_window, &clist->clist_window_width,
1331                        &clist->clist_window_height);
1332
1333   /* cursor's and GC's */
1334   clist->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1335
1336   clist->fg_gc = gdk_gc_new (widget->window);
1337   clist->bg_gc = gdk_gc_new (widget->window);
1338
1339   values.foreground = widget->style->white;
1340   values.function = GDK_XOR;
1341   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
1342   clist->xor_gc = gdk_gc_new_with_values (widget->window,
1343                                           &values,
1344                                           GDK_GC_FOREGROUND |
1345                                           GDK_GC_FUNCTION |
1346                                           GDK_GC_SUBWINDOW);
1347
1348   /* text properties */
1349   if (!GTK_CLIST_ROW_HEIGHT_SET (clist))
1350     {
1351       clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1;
1352       clist->row_center_offset = widget->style->font->ascent + 1.5;
1353     }
1354 }
1355
1356 static void
1357 gtk_clist_unrealize (GtkWidget * widget)
1358 {
1359   GtkCList *clist;
1360
1361   g_return_if_fail (widget != NULL);
1362   g_return_if_fail (GTK_IS_CLIST (widget));
1363
1364   clist = GTK_CLIST (widget);
1365   GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED);
1366   GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1367
1368   gdk_cursor_destroy (clist->cursor_drag);
1369   gdk_gc_destroy (clist->xor_gc);
1370   gdk_gc_destroy (clist->fg_gc);
1371   gdk_gc_destroy (clist->bg_gc);
1372
1373   gtk_style_detach (widget->style);
1374
1375   gdk_window_destroy (clist->clist_window);
1376   gdk_window_destroy (clist->title_window);
1377   gdk_window_set_user_data (widget->window, NULL);
1378   gdk_window_destroy (widget->window);
1379
1380   widget->window = NULL;
1381   clist->clist_window = NULL;
1382   clist->title_window = NULL;
1383   clist->cursor_drag = NULL;
1384   clist->xor_gc = NULL;
1385   clist->fg_gc = NULL;
1386   clist->bg_gc = NULL;
1387 }
1388
1389 static void
1390 gtk_clist_map (GtkWidget * widget)
1391 {
1392   gint i;
1393   GtkCList *clist;
1394
1395   g_return_if_fail (widget != NULL);
1396   g_return_if_fail (GTK_IS_CLIST (widget));
1397
1398   clist = GTK_CLIST (widget);
1399
1400   if (!GTK_WIDGET_MAPPED (widget))
1401     {
1402       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1403
1404       gdk_window_show (widget->window);
1405       gdk_window_show (clist->title_window);
1406       gdk_window_show (clist->clist_window);
1407
1408       /* map column buttons*/
1409       for (i = 0; i < clist->columns; i++)
1410         if (GTK_WIDGET_VISIBLE (clist->column[i].button) &&
1411             !GTK_WIDGET_MAPPED (clist->column[i].button))
1412           gtk_widget_map (clist->column[i].button);
1413       
1414       /* map vscrollbars */
1415       if (GTK_WIDGET_VISIBLE (clist->vscrollbar) &&
1416           !GTK_WIDGET_MAPPED (clist->vscrollbar))
1417         gtk_widget_map (clist->vscrollbar);
1418
1419       if (GTK_WIDGET_VISIBLE (clist->hscrollbar) &&
1420           !GTK_WIDGET_MAPPED (clist->hscrollbar))
1421         gtk_widget_map (clist->hscrollbar);
1422
1423       /* unfreeze the list */
1424       GTK_CLIST_UNSET_FLAGS (clist, CLIST_FROZEN);
1425     }
1426 }
1427
1428 static void
1429 gtk_clist_unmap (GtkWidget * widget)
1430 {
1431   gint i;
1432   GtkCList *clist;
1433
1434   g_return_if_fail (widget != NULL);
1435   g_return_if_fail (GTK_IS_CLIST (widget));
1436
1437   clist = GTK_CLIST (widget);
1438
1439   if (GTK_WIDGET_MAPPED (widget))
1440     {
1441       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1442
1443       gdk_window_hide (clist->clist_window);
1444       gdk_window_hide (clist->title_window);
1445       gdk_window_hide (widget->window);
1446
1447       /* unmap scrollbars */
1448       if (GTK_WIDGET_MAPPED (clist->vscrollbar))
1449         gtk_widget_unmap (clist->vscrollbar);
1450
1451       if (GTK_WIDGET_MAPPED (clist->hscrollbar))
1452         gtk_widget_unmap (clist->hscrollbar);
1453
1454       /* unmap column buttons */
1455       for (i = 0; i < clist->columns; i++)
1456         if (GTK_WIDGET_MAPPED (clist->column[i].button))
1457           gtk_widget_unmap (clist->column[i].button);
1458
1459       /* freeze the list */
1460       GTK_CLIST_SET_FLAGS (clist, CLIST_FROZEN);
1461     }
1462 }
1463
1464 static void
1465 gtk_clist_draw_row (GtkCList * clist,
1466                     GdkRectangle * area,
1467                     gint row,
1468                     GtkCListRow * clist_row)
1469 {
1470   GtkWidget *widget;
1471   GdkGC *fg_gc, *bg_gc;
1472   GdkRectangle row_rectangle, cell_rectangle, clip_rectangle, intersect_rectangle,
1473    *rect;
1474   gint i, offset = 0, width, height, pixmap_width = 0;
1475   gint xsrc, ysrc, xdest, ydest;
1476
1477   g_return_if_fail (clist != NULL);
1478
1479   /* bail now if we arn't drawable yet */
1480   if (!GTK_WIDGET_DRAWABLE (clist))
1481     return;
1482
1483   if (row < 0 || row >= clist->rows)
1484     return;
1485
1486   widget = GTK_WIDGET (clist);
1487
1488   /* if the function is passed the pointer to the row instead of null,
1489    * it avoids this expensive lookup */
1490   if (!clist_row)
1491     clist_row = (g_list_nth (clist->row_list, row))->data;
1492
1493   /* rectangle of the entire row */
1494   row_rectangle.x = 0;
1495   row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
1496   row_rectangle.width = clist->clist_window_width;
1497   row_rectangle.height = clist->row_height;
1498
1499   /* rectangle of the cell spacing above the row */
1500   cell_rectangle.x = 0;
1501   cell_rectangle.y = row_rectangle.y - CELL_SPACING;
1502   cell_rectangle.width = row_rectangle.width;
1503   cell_rectangle.height = CELL_SPACING;
1504
1505   /* rectangle used to clip drawing operations, it's y and height
1506    * positions only need to be set once, so we set them once here. 
1507    * the x and width are set withing the drawing loop below once per
1508    * column */
1509   clip_rectangle.y = row_rectangle.y;
1510   clip_rectangle.height = row_rectangle.height;
1511
1512   /* select GC for background rectangle */
1513   if (clist_row->state == GTK_STATE_SELECTED)
1514     {
1515       fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
1516       bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
1517     }
1518   else
1519     {
1520       gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
1521       gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
1522
1523       fg_gc = clist->fg_gc;
1524       bg_gc = clist->bg_gc;
1525     }
1526
1527
1528   if (area)
1529     {
1530       if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
1531         gdk_window_clear_area (clist->clist_window,
1532                                intersect_rectangle.x,
1533                                intersect_rectangle.y,
1534                                intersect_rectangle.width,
1535                                intersect_rectangle.height);
1536
1537       /* the last row has to clear it's bottom cell spacing too */
1538       if (clist_row == clist->row_list_end->data)
1539         {
1540           cell_rectangle.y += clist->row_height + CELL_SPACING;
1541
1542           if (gdk_rectangle_intersect (area, &cell_rectangle, &intersect_rectangle))
1543             gdk_window_clear_area (clist->clist_window,
1544                                    intersect_rectangle.x,
1545                                    intersect_rectangle.y,
1546                                    intersect_rectangle.width,
1547                                    intersect_rectangle.height);
1548         }         
1549
1550       if (!gdk_rectangle_intersect (area, &row_rectangle, &intersect_rectangle))
1551         return;
1552
1553       gdk_draw_rectangle (clist->clist_window,
1554                           bg_gc,
1555                           TRUE,
1556                           intersect_rectangle.x,
1557                           intersect_rectangle.y,
1558                           intersect_rectangle.width,
1559                           intersect_rectangle.height);
1560     }
1561   else
1562     {
1563       gdk_window_clear_area (clist->clist_window,
1564                              cell_rectangle.x,
1565                              cell_rectangle.y,
1566                              cell_rectangle.width,
1567                              cell_rectangle.height);
1568
1569       cell_rectangle.y += clist->row_height + CELL_SPACING;
1570       gdk_window_clear_area (clist->clist_window,
1571                              cell_rectangle.x,
1572                              cell_rectangle.y,
1573                              cell_rectangle.width,
1574                              cell_rectangle.height);
1575       
1576       gdk_draw_rectangle (clist->clist_window,
1577                           bg_gc,
1578                           TRUE,
1579                           row_rectangle.x,
1580                           row_rectangle.y,
1581                           row_rectangle.width,
1582                           row_rectangle.height);
1583     }
1584
1585
1586   /* iterate and draw all the columns (row cells) and draw their contents */
1587   for (i = 0; i < clist->columns; i++)
1588     {
1589       clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
1590       clip_rectangle.width = clist->column[i].area.width;
1591
1592       /* calculate clipping region clipping region */
1593       if (!area)
1594         {
1595           rect = &clip_rectangle;
1596         }
1597       else
1598         {
1599           if (!gdk_rectangle_intersect (area, &clip_rectangle, &intersect_rectangle))
1600             continue;
1601           rect = &intersect_rectangle;
1602         }
1603
1604       /* calculate real width for column justification */
1605       switch (clist_row->cell[i].type)
1606         {
1607         case GTK_CELL_EMPTY:
1608           continue;
1609           break;
1610
1611         case GTK_CELL_TEXT:
1612           width = gdk_string_width (GTK_WIDGET (clist)->style->font,
1613                                     GTK_CELL_TEXT (clist_row->cell[i])->text);
1614           break;
1615
1616         case GTK_CELL_PIXMAP:
1617           gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &width, &height);
1618           pixmap_width = width;
1619           break;
1620
1621         case GTK_CELL_PIXTEXT:
1622           gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, &width, &height);
1623           pixmap_width = width;
1624           width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1625           width = gdk_string_width (GTK_WIDGET (clist)->style->font,
1626                                     GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
1627           break;
1628
1629         case GTK_CELL_WIDGET:
1630           /* unimplimented */
1631           continue;
1632           break;
1633
1634         default:
1635           continue;
1636           break;
1637         }
1638
1639       switch (clist->column[i].justification)
1640         {
1641         case GTK_JUSTIFY_LEFT:
1642           offset = clip_rectangle.x;
1643           break;
1644
1645         case GTK_JUSTIFY_RIGHT:
1646           offset = (clip_rectangle.x + clip_rectangle.width) - width;
1647           break;
1648
1649         case GTK_JUSTIFY_CENTER:
1650           offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
1651           break;
1652
1653         case GTK_JUSTIFY_FILL:
1654           offset = (clip_rectangle.x + (clip_rectangle.width / 2)) - (width / 2);
1655           break;
1656
1657         default:
1658           offset = 0;
1659           break;
1660         };
1661
1662       /* Draw Text or Pixmap */
1663       switch (clist_row->cell[i].type)
1664         {
1665         case GTK_CELL_EMPTY:
1666           continue;
1667           break;
1668
1669         case GTK_CELL_TEXT:
1670           gdk_gc_set_clip_rectangle (fg_gc, rect);
1671
1672           gdk_draw_string (clist->clist_window, 
1673                            widget->style->font,
1674                            fg_gc,
1675                            offset + clist_row->cell[i].horizontal,
1676                            row_rectangle.y + clist->row_center_offset + 
1677                            clist_row->cell[i].verticle,
1678                            GTK_CELL_TEXT (clist_row->cell[i])->text);
1679
1680           gdk_gc_set_clip_rectangle (fg_gc, NULL);
1681           break;
1682
1683         case GTK_CELL_PIXMAP:
1684           xsrc = 0;
1685           ysrc = 0;
1686           xdest = offset + clist_row->cell[i].horizontal;
1687           ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
1688             clist_row->cell[i].verticle;
1689
1690           gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP (clist_row->cell[i])->mask);
1691           gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
1692
1693           gdk_draw_pixmap (clist->clist_window,
1694                            fg_gc,
1695                            GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
1696                            xsrc, ysrc,
1697                            xdest,
1698                            ydest,
1699                            pixmap_width, height);
1700
1701           gdk_gc_set_clip_origin (fg_gc, 0, 0);
1702           gdk_gc_set_clip_mask (fg_gc, NULL);
1703           break;
1704
1705         case GTK_CELL_PIXTEXT:
1706           /* draw the pixmap */
1707           xsrc = 0;
1708           ysrc = 0;
1709           xdest = offset + clist_row->cell[i].horizontal;
1710           ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) - height / 2 +
1711             clist_row->cell[i].verticle;
1712
1713           gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
1714           gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
1715
1716           gdk_draw_pixmap (clist->clist_window,
1717                            fg_gc,
1718                            GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
1719                            xsrc, ysrc,
1720                            xdest,
1721                            ydest,
1722                            pixmap_width, height);
1723
1724           gdk_gc_set_clip_origin (fg_gc, 0, 0);
1725
1726           offset += pixmap_width + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1727           
1728           /* draw the string */
1729           gdk_gc_set_clip_rectangle (fg_gc, rect);
1730
1731           gdk_draw_string (clist->clist_window, 
1732                            widget->style->font,
1733                            fg_gc,
1734                            offset + clist_row->cell[i].horizontal,
1735                            row_rectangle.y + clist->row_center_offset + 
1736                            clist_row->cell[i].verticle,
1737                            GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
1738
1739           gdk_gc_set_clip_rectangle (fg_gc, NULL);
1740
1741           break;
1742
1743         case GTK_CELL_WIDGET:
1744           /* unimplimented */
1745           continue;
1746           break;
1747
1748         default:
1749           continue;
1750           break;
1751         }
1752     }
1753 }
1754
1755 static void
1756 gtk_clist_draw_rows (GtkCList * clist,
1757                      GdkRectangle * area)
1758 {
1759   GList *list;
1760   GtkCListRow *clist_row;
1761   int i, first_row, last_row;
1762
1763   g_return_if_fail (clist != NULL);
1764   g_return_if_fail (GTK_IS_CLIST (clist));
1765
1766   if (clist->row_height == 0)
1767     return;
1768
1769   if (area)
1770     {
1771       first_row = ROW_FROM_YPIXEL (clist, area->y);
1772       last_row = ROW_FROM_YPIXEL (clist, area->y + area->height);
1773     }
1774   else
1775     {
1776       first_row = ROW_FROM_YPIXEL (clist, 0);
1777       last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height);
1778     }
1779
1780   list = g_list_nth (clist->row_list, first_row);
1781   i = first_row;
1782   while (list)
1783     {
1784       clist_row = list->data;
1785       list = list->next;
1786
1787       if (i > last_row)
1788         return;
1789
1790       gtk_clist_draw_row (clist, area, i, clist_row);
1791       i++;
1792     }
1793
1794   if (!area)
1795     gdk_window_clear_area (clist->clist_window,
1796                            0, ROW_TOP_YPIXEL (clist, i) - CELL_SPACING,
1797                            -1, -1);
1798 }
1799
1800 static gint
1801 gtk_clist_get_selection_info (GtkCList * clist,
1802                               gint x,
1803                               gint y,
1804                               gint * row,
1805                               gint * column)
1806 {
1807   gint trow, tcol;
1808
1809   g_return_val_if_fail (clist != NULL, 0);
1810
1811   /* bounds checking, return false if the user clicked 
1812    * on a blank area */
1813   trow = ROW_FROM_YPIXEL (clist, y);
1814   if (trow >= clist->rows)
1815     return 0;
1816
1817   if (row)
1818     *row = trow;
1819
1820   tcol = COLUMN_FROM_XPIXEL (clist, x);
1821   if (tcol >= clist->columns)
1822     return 0;
1823
1824   if (column)
1825     *column = tcol;
1826
1827   return 1;
1828 }
1829
1830 static void
1831 gtk_clist_real_select_row (GtkCList * clist,
1832                            gint row,
1833                            gint column,
1834                            GdkEventButton * event)
1835 {
1836   gint i;
1837   GList *list;
1838   GtkCListRow *clist_row;
1839
1840   g_return_if_fail (clist != NULL);
1841
1842   if (row < 0 || row >= clist->rows)
1843     return;
1844
1845   switch (clist->selection_mode)
1846     {
1847     case GTK_SELECTION_SINGLE:
1848       i = 0;
1849       list = clist->row_list;
1850       while (list)
1851         {
1852           clist_row = list->data;
1853           list = list->next;
1854
1855           if (row == i)
1856             {
1857               if (clist_row->state == GTK_STATE_SELECTED)
1858                 {
1859                   clist_row->state = GTK_STATE_NORMAL;
1860                   gtk_clist_unselect_row (clist, i, column);
1861                 }
1862               else
1863                 {
1864                   clist_row->state = GTK_STATE_SELECTED;
1865                   clist->selection = g_list_append (clist->selection, clist_row);
1866                 }
1867
1868               if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1869                 gtk_clist_draw_row (clist, NULL, row, clist_row);
1870             }
1871           else if (clist_row->state == GTK_STATE_SELECTED)
1872             {
1873               gtk_clist_unselect_row (clist, i, column);
1874             }
1875
1876           i++;
1877         }
1878       break;
1879
1880     case GTK_SELECTION_BROWSE:
1881       i = 0;
1882       list = clist->row_list;
1883       while (list)
1884         {
1885           clist_row = list->data;
1886           list = list->next;
1887
1888           if (row == i)
1889             {
1890               if (clist_row->state != GTK_STATE_SELECTED)
1891                 {
1892                   clist_row->state = GTK_STATE_SELECTED;
1893                   clist->selection = g_list_append (clist->selection, clist_row);
1894                 
1895                   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1896                     gtk_clist_draw_row (clist, NULL, row, clist_row);
1897                 }
1898             }
1899           else if (clist_row->state == GTK_STATE_SELECTED)
1900             {
1901               gtk_clist_unselect_row (clist, i, column);
1902             }
1903
1904           i++;
1905         }
1906       break;
1907
1908     case GTK_SELECTION_MULTIPLE:
1909       i = 0;
1910       list = clist->row_list;
1911       while (list)
1912         {
1913           clist_row = list->data;
1914           list = list->next;
1915
1916           if (row == i)
1917             {
1918               if (clist_row->state == GTK_STATE_SELECTED)
1919                 {
1920                   clist_row->state = GTK_STATE_NORMAL;
1921                   gtk_clist_unselect_row (clist, i, column);
1922                 }
1923               else
1924                 {
1925                   clist->selection = g_list_append (clist->selection, clist_row);
1926                   clist_row->state = GTK_STATE_SELECTED;
1927                 }
1928
1929               if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1930                 gtk_clist_draw_row (clist, NULL, row, clist_row);
1931             }
1932
1933           i++;
1934         }
1935       break;
1936
1937     case GTK_SELECTION_EXTENDED:
1938       break;
1939
1940     default:
1941       break;
1942     }
1943 }
1944
1945 static void
1946 gtk_clist_real_unselect_row (GtkCList * clist,
1947                              gint row,
1948                              gint column,
1949                              GdkEventButton * event)
1950 {
1951   GtkCListRow *clist_row;
1952
1953   g_return_if_fail (clist != NULL);
1954
1955   if (row < 0 || row > (clist->rows - 1))
1956     return;
1957
1958   clist_row = (g_list_nth (clist->row_list, row))->data;
1959   clist_row->state = GTK_STATE_NORMAL;
1960   clist->selection = g_list_remove (clist->selection, clist_row);
1961
1962   if (!GTK_CLIST_FROZEN (clist) && gtk_clist_row_isvisable (clist, row))
1963     gtk_clist_draw_row (clist, NULL, row, clist_row);
1964 }
1965
1966 static void
1967 gtk_clist_draw (GtkWidget * widget,
1968                 GdkRectangle * area)
1969 {
1970   GtkCList *clist;
1971
1972   g_return_if_fail (widget != NULL);
1973   g_return_if_fail (GTK_IS_CLIST (widget));
1974   g_return_if_fail (area != NULL);
1975
1976   if (GTK_WIDGET_DRAWABLE (widget))
1977     {
1978       clist = GTK_CLIST (widget);
1979
1980       gdk_window_clear_area (widget->window,
1981                              area->x, area->y,
1982                              area->width, area->height);
1983
1984       /* draw list shadow/border */
1985       gtk_draw_shadow (widget->style, widget->window,
1986                        GTK_STATE_NORMAL, clist->shadow_type,
1987                        0, 0, 
1988                        clist->clist_window_width + (2 * widget->style->klass->xthickness),
1989                        clist->clist_window_height + (2 * widget->style->klass->ythickness) +
1990                        clist->column_title_area.height);
1991
1992       gdk_window_clear_area (clist->clist_window,
1993                              0, 0, -1, -1);
1994
1995       gtk_clist_draw_rows (clist, NULL);
1996     }
1997 }
1998
1999 static gint
2000 gtk_clist_expose (GtkWidget * widget,
2001                   GdkEventExpose * event)
2002 {
2003   GtkCList *clist;
2004
2005   g_return_val_if_fail (widget != NULL, FALSE);
2006   g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2007   g_return_val_if_fail (event != NULL, FALSE);
2008
2009   if (GTK_WIDGET_DRAWABLE (widget))
2010     {
2011       clist = GTK_CLIST (widget);
2012
2013       /* draw border */
2014       if (event->window == widget->window)
2015         gtk_draw_shadow (widget->style, widget->window,
2016                          GTK_STATE_NORMAL, clist->shadow_type,
2017                          0, 0,
2018                          clist->clist_window_width + (2 * widget->style->klass->xthickness),
2019                          clist->clist_window_height + (2 * widget->style->klass->ythickness) +
2020                          clist->column_title_area.height);
2021
2022       /* exposure events on the list */
2023       if (event->window == clist->clist_window)
2024         gtk_clist_draw_rows (clist, &event->area);
2025     }
2026
2027   return FALSE;
2028 }
2029
2030 static gint
2031 gtk_clist_button_press (GtkWidget * widget,
2032                         GdkEventButton * event)
2033 {
2034   GtkCList *clist;
2035   gint x, y, row, column;
2036
2037   g_return_val_if_fail (widget != NULL, FALSE);
2038   g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE);
2039   g_return_val_if_fail (event != NULL, FALSE);
2040
2041   clist = GTK_CLIST (widget);
2042
2043   /* selections on the list */
2044   if (event->window == clist->clist_window)
2045     {
2046       x = event->x;
2047       y = event->y;
2048
2049       if (gtk_clist_get_selection_info (clist, x, y, &row, &column))
2050         gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW],
2051                          row, column, event);
2052     }
2053
2054   return FALSE;
2055 }
2056
2057 static void
2058 gtk_clist_size_request (GtkWidget * widget,
2059                         GtkRequisition * requisition)
2060 {
2061   gint i;
2062   GtkCList *clist;
2063
2064   g_return_if_fail (widget != NULL);
2065   g_return_if_fail (GTK_IS_CLIST (widget));
2066   g_return_if_fail (requisition != NULL);
2067
2068   clist = GTK_CLIST (widget);
2069
2070   requisition->width = 0;
2071   requisition->height = 0;
2072
2073   /* compute the size of the column title (title) area */
2074   clist->column_title_area.height = 0;
2075   for (i = 0; i < clist->columns; i++)
2076     {
2077       gtk_widget_size_request (clist->column[i].button, &clist->column[i].button->requisition);
2078       clist->column_title_area.height = MAX (clist->column_title_area.height,
2079                                              clist->column[i].button->requisition.height);
2080     }
2081   requisition->height += clist->column_title_area.height;
2082
2083   /* add the vscrollbar space */
2084   if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2085       GTK_WIDGET_VISIBLE (clist->vscrollbar))
2086     {
2087       gtk_widget_size_request (clist->vscrollbar, &clist->vscrollbar->requisition);
2088
2089       requisition->width += clist->vscrollbar->requisition.width + SCROLLBAR_SPACING (clist);
2090       requisition->height = MAX (requisition->height,
2091                                  clist->vscrollbar->requisition.height);
2092     }
2093
2094   /* add the hscrollbar space */
2095   if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
2096       GTK_WIDGET_VISIBLE (clist->hscrollbar))
2097     {
2098       gtk_widget_size_request (clist->hscrollbar, &clist->hscrollbar->requisition);
2099
2100       requisition->height += clist->hscrollbar->requisition.height + SCROLLBAR_SPACING (clist);
2101       requisition->width = MAX (clist->hscrollbar->requisition.width, 
2102                                 requisition->width - 
2103                                 clist->vscrollbar->requisition.width);
2104
2105     }
2106
2107   requisition->width += widget->style->klass->xthickness * 2 +
2108     GTK_CONTAINER (widget)->border_width * 2;
2109   requisition->height += widget->style->klass->ythickness * 2 +
2110     GTK_CONTAINER (widget)->border_width * 2;
2111 }
2112
2113 static void
2114 gtk_clist_size_allocate (GtkWidget * widget,
2115                          GtkAllocation * allocation)
2116 {
2117   GtkCList *clist;
2118   GtkAllocation clist_allocation;
2119   GtkAllocation child_allocation;
2120   gint i, vscrollbar_vis, hscrollbar_vis;
2121
2122   g_return_if_fail (widget != NULL);
2123   g_return_if_fail (GTK_IS_CLIST (widget));
2124   g_return_if_fail (allocation != NULL);
2125
2126   clist = GTK_CLIST (widget);
2127   widget->allocation = *allocation;
2128
2129   if (GTK_WIDGET_REALIZED (widget))
2130     {
2131       gdk_window_move_resize (widget->window,
2132                               allocation->x + GTK_CONTAINER (widget)->border_width,
2133                               allocation->y + GTK_CONTAINER (widget)->border_width,
2134                               allocation->width - GTK_CONTAINER (widget)->border_width * 2,
2135                               allocation->height - GTK_CONTAINER (widget)->border_width * 2);
2136
2137       /* use internal allocation structure for all the math
2138        * because it's easier than always subtracting the container
2139        * border width */
2140       clist->internal_allocation.x = 0;
2141       clist->internal_allocation.y = 0;
2142       clist->internal_allocation.width = allocation->width -
2143         GTK_CONTAINER (widget)->border_width * 2;
2144       clist->internal_allocation.height = allocation->height -
2145         GTK_CONTAINER (widget)->border_width * 2;
2146         
2147       /* allocate clist window assuming no scrollbars */
2148       clist_allocation.x = clist->internal_allocation.x + widget->style->klass->xthickness;
2149       clist_allocation.y = clist->internal_allocation.y + widget->style->klass->ythickness +
2150         clist->column_title_area.height;
2151       clist_allocation.width = clist->internal_allocation.width - 
2152         (2 * widget->style->klass->xthickness);
2153       clist_allocation.height = clist->internal_allocation.height -
2154         (2 * widget->style->klass->xthickness) -
2155         clist->column_title_area.height;
2156
2157       /* 
2158        * here's where we decide to show/not show the scrollbars
2159        */
2160       vscrollbar_vis = 0;
2161       hscrollbar_vis = 0;
2162
2163       for (i = 0; i <= 1; i++)
2164         {
2165           if (LIST_HEIGHT (clist) <= clist_allocation.height &&
2166               clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2167             {
2168               vscrollbar_vis = 0;
2169             }
2170           else
2171             {
2172               if (!vscrollbar_vis)
2173                 {
2174                   vscrollbar_vis = 1;
2175                   clist_allocation.width -= clist->vscrollbar->requisition.width +
2176                     SCROLLBAR_SPACING (clist);
2177                 }  
2178             }
2179           
2180           if (LIST_WIDTH (clist) <= clist_allocation.width &&
2181               clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2182             {
2183               hscrollbar_vis = 0;
2184             }
2185           else
2186             {
2187               if (!hscrollbar_vis)
2188                 {
2189                   hscrollbar_vis = 1;
2190                   clist_allocation.height -= clist->hscrollbar->requisition.height + 
2191                     SCROLLBAR_SPACING (clist);  
2192                 }  
2193             }
2194         }
2195
2196       clist->clist_window_width = clist_allocation.width;
2197       clist->clist_window_height = clist_allocation.height;
2198
2199       gdk_window_move_resize (clist->clist_window,
2200                               clist_allocation.x,
2201                               clist_allocation.y,
2202                               clist_allocation.width,
2203                               clist_allocation.height);
2204
2205       /* position the window which holds the column title buttons */
2206       clist->column_title_area.x = widget->style->klass->xthickness;
2207       clist->column_title_area.y = widget->style->klass->ythickness;
2208       clist->column_title_area.width = clist_allocation.width;
2209
2210       gdk_window_move_resize (clist->title_window,
2211                               clist->column_title_area.x,
2212                               clist->column_title_area.y,
2213                               clist->column_title_area.width,
2214                               clist->column_title_area.height);
2215
2216       /* column button allocation */
2217       gtk_clist_size_allocate_title_buttons (clist);
2218       gtk_clist_size_allocate_columns (clist);
2219
2220       /* allocate the vscrollbar */
2221       if (vscrollbar_vis)
2222         {
2223           if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
2224             gtk_widget_show (clist->vscrollbar);
2225               
2226           child_allocation.x = clist->internal_allocation.x + 
2227             clist->internal_allocation.width -
2228             clist->vscrollbar->requisition.width;
2229           child_allocation.y = clist->internal_allocation.y;
2230           child_allocation.width = clist->vscrollbar->requisition.width;
2231           child_allocation.height = clist->internal_allocation.height -
2232             SCROLLBAR_SPACING (clist) -
2233             (hscrollbar_vis ? clist->hscrollbar->requisition.height : 0);
2234
2235           gtk_widget_size_allocate (clist->vscrollbar, &child_allocation);
2236         }
2237       else
2238         {
2239            if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
2240                 gtk_widget_hide (clist->vscrollbar);
2241         }
2242
2243       if (hscrollbar_vis)
2244         {
2245           if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
2246             gtk_widget_show (clist->hscrollbar);
2247       
2248           child_allocation.x = clist->internal_allocation.x;
2249           child_allocation.y = clist->internal_allocation.y +
2250             clist->internal_allocation.height -
2251             clist->hscrollbar->requisition.height;
2252           child_allocation.width = clist->internal_allocation.width - 
2253             SCROLLBAR_SPACING (clist) -
2254             (vscrollbar_vis ? clist->vscrollbar->requisition.width : 0);
2255           child_allocation.height = clist->hscrollbar->requisition.height;
2256
2257           gtk_widget_size_allocate (clist->hscrollbar, &child_allocation);
2258         }
2259       else
2260         {
2261           if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
2262                 gtk_widget_hide (clist->hscrollbar);
2263         }
2264     }
2265
2266   /*
2267    * set the vscrollbar adjustments
2268    */
2269   gtk_clist_adjust_scrollbars (clist);
2270 }
2271
2272 static void
2273 gtk_clist_size_allocate_title_buttons (GtkCList * clist)
2274 {
2275   gint i;
2276   GtkAllocation button_allocation;
2277
2278   button_allocation.x = clist->hoffset;
2279   button_allocation.y = 0;
2280   button_allocation.height = clist->column_title_area.height;
2281
2282   for (i = 0; i < clist->columns; i++)
2283     {
2284       button_allocation.width = clist->column[i].width;
2285
2286       if (i == clist->columns - 1)
2287         {
2288           button_allocation.width += 2 * (CELL_SPACING + COLUMN_INSET);
2289
2290           if (button_allocation.width < (clist->column_title_area.width - button_allocation.x))
2291             button_allocation.width = clist->column_title_area.width - button_allocation.x;
2292         }
2293       else
2294         {
2295           button_allocation.width += CELL_SPACING + (2 * COLUMN_INSET);
2296         }
2297
2298       gtk_widget_size_allocate (clist->column[i].button, &button_allocation);
2299       button_allocation.x += button_allocation.width;
2300     }
2301 }
2302
2303 static void
2304 gtk_clist_size_allocate_columns (GtkCList * clist)
2305 {
2306   gint i, xoffset;
2307
2308   xoffset = 0;
2309
2310   for (i = 0; i < clist->columns; i++)
2311     {
2312       clist->column[i].area.x = xoffset + CELL_SPACING + COLUMN_INSET;
2313
2314       if (i == clist->columns - 1)
2315         {
2316           clist->column[i].area.width = MAX (clist->column[i].width,
2317                                              clist->column_title_area.width -
2318                                              xoffset - (2 * (CELL_SPACING + COLUMN_INSET)));
2319         }
2320       else
2321         {
2322           clist->column[i].area.width = clist->column[i].width;
2323         }
2324
2325       xoffset += clist->column[i].area.width + CELL_SPACING + (2 * COLUMN_INSET);
2326     }
2327 }
2328
2329 static void
2330 gtk_clist_foreach (GtkContainer * container,
2331                    GtkCallback callback,
2332                    gpointer callback_data)
2333 {
2334   gint i;
2335   GtkCList *clist;
2336
2337   g_return_if_fail (container != NULL);
2338   g_return_if_fail (GTK_IS_CLIST (container));
2339   g_return_if_fail (callback != NULL);
2340
2341   clist = GTK_CLIST (container);
2342
2343   /* callback for the column buttons */
2344   for (i = 0; i < clist->columns; i++)
2345     (*callback) (clist->column[i].button, callback_data);
2346
2347   /* callbacks for the scrollbars */
2348   (*callback) (clist->vscrollbar, callback_data);
2349   (*callback) (clist->hscrollbar, callback_data);
2350 }
2351
2352 /* BUTTONS */
2353 static void
2354 gtk_clist_column_button_realize (GtkWidget * widget,
2355                                  gpointer data)
2356 {
2357   GtkCList *clist;
2358
2359   g_return_if_fail (widget != NULL);
2360   g_return_if_fail (GTK_IS_CLIST (data));
2361
2362   clist = GTK_CLIST (data);
2363
2364   if (widget->window && clist->title_window)
2365     gdk_window_reparent (widget->window, clist->title_window,
2366                          widget->allocation.x, 0);
2367 }
2368
2369 static void
2370 gtk_clist_column_button_clicked (GtkWidget * widget,
2371                                  gpointer data)
2372 {
2373   gint i;
2374   GtkCList *clist;
2375
2376   g_return_if_fail (widget != NULL);
2377   g_return_if_fail (GTK_IS_CLIST (data));
2378
2379   clist = GTK_CLIST (data);
2380
2381   /* find the column who's button was pressed */
2382   for (i = 0; i < clist->columns; i++)
2383     if (clist->column[i].button == widget)
2384       break;
2385
2386   gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
2387 }
2388
2389 /*
2390  * SCROLLBARS
2391  *
2392  * functions:
2393  *   gtk_clist_adjust_scrollbars
2394  *   gtk_clist_vadjustment_changed
2395  *   gtk_clist_hadjustment_changed
2396  *   gtk_clist_vadjustment_value_changed
2397  *   gtk_clist_hadjustment_value_changed
2398  */
2399 static void
2400 gtk_clist_adjust_scrollbars (GtkCList * clist)
2401 {
2402   GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height;
2403   GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2;
2404   GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10;
2405   GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0;
2406   GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist);
2407
2408   if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist))
2409     {
2410       GTK_RANGE (clist->vscrollbar)->adjustment->value = LIST_HEIGHT (clist) - 
2411         clist->clist_window_height;
2412       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), 
2413                                "value_changed");
2414     }
2415
2416   GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width;
2417   GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2;
2418   GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10;
2419   GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0;
2420   GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist);
2421
2422   if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist))
2423     {
2424       GTK_RANGE (clist->hscrollbar)->adjustment->value = LIST_WIDTH (clist) - 
2425         clist->clist_window_width;
2426       gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), 
2427                                "value_changed");
2428     }
2429
2430   if (LIST_HEIGHT (clist) <= clist->clist_window_height &&
2431       clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
2432     {
2433       if (GTK_WIDGET_VISIBLE (clist->vscrollbar))
2434         {
2435           gtk_widget_hide (clist->vscrollbar);
2436           gtk_widget_queue_resize (GTK_WIDGET (clist));
2437         }
2438     }
2439   else
2440     {
2441       if (!GTK_WIDGET_VISIBLE (clist->vscrollbar))
2442         {
2443           gtk_widget_show (clist->vscrollbar);
2444           gtk_widget_queue_resize (GTK_WIDGET (clist));
2445         }
2446     }
2447
2448   if (LIST_WIDTH (clist) <= clist->clist_window_width &&
2449       clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
2450     {
2451       if (GTK_WIDGET_VISIBLE (clist->hscrollbar))
2452         {
2453           gtk_widget_hide (clist->hscrollbar);
2454           gtk_widget_queue_resize (GTK_WIDGET (clist));
2455         }
2456     }
2457   else
2458     {
2459       if (!GTK_WIDGET_VISIBLE (clist->hscrollbar))
2460         {
2461           gtk_widget_show (clist->hscrollbar);
2462           gtk_widget_queue_resize (GTK_WIDGET (clist));
2463         }
2464     }
2465
2466   gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed");
2467   gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed");
2468 }
2469
2470 static void
2471 gtk_clist_vadjustment_changed (GtkAdjustment * adjustment,
2472                                gpointer data)
2473 {
2474   GtkCList *clist;
2475
2476   g_return_if_fail (adjustment != NULL);
2477   g_return_if_fail (data != NULL);
2478
2479   clist = GTK_CLIST (data);
2480 }
2481
2482 static void
2483 gtk_clist_hadjustment_changed (GtkAdjustment * adjustment,
2484                                gpointer data)
2485 {
2486   GtkCList *clist;
2487
2488   g_return_if_fail (adjustment != NULL);
2489   g_return_if_fail (data != NULL);
2490
2491   clist = GTK_CLIST (data);
2492 }
2493
2494 static void
2495 gtk_clist_vadjustment_value_changed (GtkAdjustment * adjustment,
2496                                      gpointer data)
2497 {
2498   GtkCList *clist;
2499   GdkRectangle area;
2500   gint diff, value;
2501
2502   g_return_if_fail (adjustment != NULL);
2503   g_return_if_fail (data != NULL);
2504   g_return_if_fail (GTK_IS_CLIST (data));
2505
2506   clist = GTK_CLIST (data);
2507
2508   value = adjustment->value;
2509
2510   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)))
2511     {
2512       if (value > -clist->voffset)
2513         {
2514           /* scroll down */
2515           diff = value + clist->voffset;
2516
2517           /* we have to re-draw the whole screen here... */
2518           if (diff >= clist->clist_window_height)
2519             {
2520               clist->voffset = -value;
2521               gtk_clist_draw_rows (clist, NULL);
2522               return;
2523             }
2524
2525           gdk_window_copy_area (clist->clist_window,
2526                                 GTK_WIDGET (clist)->style->white_gc,
2527                                 0, 0,
2528                                 clist->clist_window,
2529                                 0,
2530                                 diff,
2531                                 clist->clist_window_width,
2532                                 clist->clist_window_height - diff);
2533
2534           area.x = 0;
2535           area.y = clist->clist_window_height - diff;
2536           area.width = clist->clist_window_width;
2537           area.height = diff;
2538         }
2539       else
2540         {
2541           /* scroll up */
2542           diff = -clist->voffset - value;
2543
2544           /* we have to re-draw the whole screen here... */
2545           if (diff >= clist->clist_window_height)
2546             {
2547               clist->voffset = -value;
2548               gtk_clist_draw_rows (clist, NULL);
2549               return;
2550             }
2551
2552           gdk_window_copy_area (clist->clist_window,
2553                                 GTK_WIDGET (clist)->style->white_gc,
2554                                 0, diff,
2555                                 clist->clist_window,
2556                                 0,
2557                                 0,
2558                                 clist->clist_window_width,
2559                                 clist->clist_window_height - diff);
2560
2561           area.x = 0;
2562           area.y = 0;
2563           area.width = clist->clist_window_width;
2564           area.height = diff;
2565
2566         }
2567
2568       clist->voffset = -value;
2569     }
2570
2571   gtk_clist_draw_rows (clist, &area);
2572 }
2573
2574 static void
2575 gtk_clist_hadjustment_value_changed (GtkAdjustment * adjustment,
2576                                      gpointer data)
2577 {
2578   GtkCList *clist;
2579   GdkRectangle area;
2580   gint i, diff, value;
2581
2582   g_return_if_fail (adjustment != NULL);
2583   g_return_if_fail (data != NULL);
2584   g_return_if_fail (GTK_IS_CLIST (data));
2585
2586   clist = GTK_CLIST (data);
2587
2588   value = adjustment->value;
2589
2590   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)))
2591     {
2592       for (i = 0; i < clist->columns; i++)
2593         {
2594           clist->column[i].button->allocation.x -= value + clist->hoffset;
2595
2596           if (clist->column[i].button->window)
2597             gdk_window_move (clist->column[i].button->window,
2598                              clist->column[i].button->allocation.x,
2599                              clist->column[i].button->allocation.y);
2600         }
2601
2602       if (value > -clist->hoffset)
2603         {
2604           /* scroll right */
2605           diff = value + clist->hoffset;
2606
2607           /* we have to re-draw the whole screen here... */
2608           if (diff >= clist->clist_window_width)
2609             {
2610               clist->hoffset = -value;
2611               gtk_clist_draw_rows (clist, NULL);
2612               return;
2613             }
2614
2615           gdk_window_copy_area (clist->clist_window,
2616                                 GTK_WIDGET (clist)->style->white_gc,
2617                                 0, 0,
2618                                 clist->clist_window,
2619                                 diff,
2620                                 0,
2621                                 clist->clist_window_width - diff,
2622                                 clist->clist_window_height);
2623
2624           area.x = clist->clist_window_width - diff;
2625           area.y = 0;
2626           area.width = diff;
2627           area.height = clist->clist_window_height;
2628         }
2629       else
2630         {
2631           /* scroll left */
2632           diff = -clist->hoffset - value;
2633
2634           /* we have to re-draw the whole screen here... */
2635           if (diff >= clist->clist_window_width)
2636             {
2637               clist->hoffset = -value;
2638               gtk_clist_draw_rows (clist, NULL);
2639               return;
2640             }
2641
2642           gdk_window_copy_area (clist->clist_window,
2643                                 GTK_WIDGET (clist)->style->white_gc,
2644                                 diff, 0,
2645                                 clist->clist_window,
2646                                 0,
2647                                 0,
2648                                 clist->clist_window_width - diff,
2649                                 clist->clist_window_height);
2650
2651           area.x = 0;
2652           area.y = 0;
2653           area.width = diff;
2654           area.height = clist->clist_window_height;
2655         }
2656
2657       clist->hoffset = -value;
2658     }
2659
2660   gtk_clist_draw_rows (clist, &area);
2661 }
2662
2663 /*
2664  * Memory Allocation/Distruction Routines for GtkCList stuctures
2665  *
2666  * functions:
2667  *   gtk_clist_columns_new
2668  *   gtk_clist_column_title_new
2669  *   gtk_clist_columns_delete
2670  *   gtk_clist_row_new
2671  *   gtk_clist_row_delete
2672  *   gtk_clist_cell_empty
2673  *   gtk_clist_cell_set_text
2674  *   gtk_clist_cell_set_pixmap
2675  */
2676 static GtkCListColumn *
2677 gtk_clist_columns_new (GtkCList * clist)
2678 {
2679   gint i;
2680   GtkCListColumn *column;
2681
2682   column = g_new (GtkCListColumn, clist->columns);
2683
2684   for (i = 0; i < clist->columns; i++)
2685     {
2686       column[i].area.x = 0;
2687       column[i].area.y = 0;
2688       column[i].area.width = 0;
2689       column[i].area.height = 0;
2690       column[i].title = NULL;
2691       column[i].button = NULL;
2692       column[i].width = 0;
2693       column[i].justification = GTK_JUSTIFY_LEFT;
2694     }
2695
2696   return column;
2697 }
2698
2699 static void
2700 gtk_clist_column_title_new (GtkCList * clist,
2701                             gint column,
2702                             gchar * title)
2703 {
2704   if (clist->column[column].title)
2705     g_free (clist->column[column].title);
2706
2707   clist->column[column].title = g_strdup (title);
2708 }
2709
2710 static void
2711 gtk_clist_columns_delete (GtkCList * clist)
2712 {
2713   gint i;
2714
2715   for (i = 0; i < clist->columns; i++)
2716     if (clist->column[i].title)
2717       g_free (clist->column[i].title);
2718       
2719   g_free (clist->column);
2720 }
2721
2722 static GtkCListRow *
2723 gtk_clist_row_new (GtkCList * clist)
2724 {
2725   int i;
2726   GtkCListRow *clist_row;
2727
2728   clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk);
2729   clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
2730
2731   for (i = 0; i < clist->columns; i++)
2732     {
2733       clist_row->cell[i].type = GTK_CELL_EMPTY;
2734       clist_row->cell[i].verticle = 0;
2735       clist_row->cell[i].horizontal = 0;
2736     }
2737
2738   clist_row->foreground = GTK_WIDGET (clist)->style->fg[GTK_STATE_NORMAL];
2739   clist_row->background = GTK_WIDGET (clist)->style->bg[GTK_STATE_PRELIGHT];
2740   clist_row->state = GTK_STATE_NORMAL;
2741   clist_row->data = NULL;
2742
2743   return clist_row;
2744 }
2745
2746 static void
2747 gtk_clist_row_delete (GtkCList * clist,
2748                       GtkCListRow * clist_row)
2749 {
2750   gint i;
2751
2752   for (i = 0; i < clist->columns; i++)
2753     gtk_clist_cell_empty (clist, clist_row, i);
2754
2755   g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell);
2756   g_mem_chunk_free (clist->row_mem_chunk, clist_row);
2757
2758 }
2759
2760 static void
2761 gtk_clist_cell_empty (GtkCList * clist,
2762                       GtkCListRow * clist_row,
2763                       gint column)
2764 {
2765   switch (clist_row->cell[column].type)
2766     {
2767     case GTK_CELL_EMPTY:
2768       break;
2769       
2770     case GTK_CELL_TEXT:
2771       g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
2772       break;
2773       
2774     case GTK_CELL_PIXMAP:
2775       gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
2776       gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
2777       break;
2778       
2779     case GTK_CELL_PIXTEXT:
2780       g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
2781       gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
2782       gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
2783       break;
2784
2785     case GTK_CELL_WIDGET:
2786       /* unimplimented */
2787       break;
2788       
2789     default:
2790       break;
2791     }
2792
2793   clist_row->cell[column].type = GTK_CELL_EMPTY;
2794 }
2795
2796 static void
2797 gtk_clist_cell_set_text (GtkCList * clist,
2798                          GtkCListRow * clist_row,
2799                          gint column,
2800                          gchar * text)
2801 {
2802   gtk_clist_cell_empty (clist, clist_row, column);
2803
2804   if (text)
2805     {
2806       clist_row->cell[column].type = GTK_CELL_TEXT;
2807       GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2808     }
2809 }
2810
2811 static void
2812 gtk_clist_cell_set_pixmap (GtkCList * clist,
2813                            GtkCListRow * clist_row,
2814                            gint column,
2815                            GdkPixmap * pixmap,
2816                            GdkBitmap * mask)
2817 {
2818   gtk_clist_cell_empty (clist, clist_row, column);
2819
2820   if (pixmap && mask)
2821     {
2822       clist_row->cell[column].type = GTK_CELL_PIXMAP;
2823       GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
2824       GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
2825     }
2826 }
2827
2828 static void
2829 gtk_clist_cell_set_pixtext (GtkCList * clist,
2830                             GtkCListRow * clist_row,
2831                             gint column,
2832                             gchar * text,
2833                             guint8 spacing,
2834                             GdkPixmap * pixmap,
2835                             GdkBitmap * mask)
2836 {
2837   gtk_clist_cell_empty (clist, clist_row, column);
2838
2839   if (text && pixmap && mask)
2840     {
2841       clist_row->cell[column].type = GTK_CELL_PIXTEXT;
2842       GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
2843       GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
2844       GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
2845       GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
2846     }
2847 }