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