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