]> Pileus Git - ~andy/gtk/blob - gtk/gtkctree.c
e69dfac88a07f9f249ba7e609c681ed3641cae2e
[~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 "gtkbindings.h"
27 #include "gtkmain.h"
28 #include <gdk/gdkx.h>
29 #include <gdk/gdkkeysyms.h>
30
31 #define PM_SIZE                    8
32 #define TAB_SIZE                   (PM_SIZE + 6)
33 #define CELL_SPACING               1
34 #define CLIST_OPTIMUM_SIZE         512
35 #define COLUMN_INSET               3
36 #define DRAG_WIDTH                 6
37
38 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
39                                     (((row) + 1) * CELL_SPACING) + \
40                                     (clist)->voffset)
41 #define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
42                                     ((clist)->row_height + CELL_SPACING))
43 #define COLUMN_LEFT_XPIXEL(clist, col)  ((clist)->column[(col)].area.x \
44                                     + (clist)->hoffset)
45 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
46
47 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (GTK_OBJECT (_widget_)->klass)
48
49
50 static void gtk_ctree_class_init        (GtkCTreeClass  *klass);
51 static void gtk_ctree_init              (GtkCTree       *ctree);
52 static void gtk_ctree_destroy           (GtkObject      *object);
53
54 static void gtk_ctree_realize           (GtkWidget      *widget);
55 static void gtk_ctree_unrealize         (GtkWidget      *widget);
56 static gint gtk_ctree_button_press      (GtkWidget      *widget,
57                                          GdkEventButton *event);
58 static gint gtk_ctree_button_release    (GtkWidget      *widget,
59                                          GdkEventButton *event);
60 static gint gtk_ctree_button_motion     (GtkWidget      *widget, 
61                                          GdkEventMotion *event);
62 static void draw_row                    (GtkCList       *clist,
63                                          GdkRectangle   *area,
64                                          gint            row,
65                                          GtkCListRow   *clist_row);
66 static void create_xor_gc               (GtkCTree       *ctree);
67 static void draw_xor_line               (GtkCTree       *ctree);
68 static void draw_xor_rect               (GtkCTree       *ctree);
69 static void create_drag_icon            (GtkCTree       *ctree,
70                                          GtkCTreeRow    *row);
71 static void tree_draw_node              (GtkCTree      *ctree,
72                                          GtkCTreeNode  *node);
73 static void cell_empty                  (GtkCList      *clist,
74                                          GtkCListRow   *clist_row,
75                                          gint           column);
76 static void cell_set_text               (GtkCList      *clist,
77                                          GtkCListRow   *clist_row,
78                                          gint           column,
79                                          gchar         *text);
80 static void cell_set_pixmap             (GtkCList      *clist,
81                                          GtkCListRow   *clist_row,
82                                          gint           column,
83                                          GdkPixmap     *pixmap,
84                                          GdkBitmap     *mask);
85 static void cell_set_pixtext            (GtkCList      *clist,
86                                          GtkCListRow   *clist_row,
87                                          gint           column,
88                                          gchar         *text,
89                                          guint8         spacing,
90                                          GdkPixmap     *pixmap,
91                                          GdkBitmap     *mask);
92 static void set_node_info               (GtkCTree      *ctree,
93                                          GtkCTreeNode  *node,
94                                          gchar         *text,
95                                          guint8         spacing,
96                                          GdkPixmap     *pixmap_closed,
97                                          GdkBitmap     *mask_closed,
98                                          GdkPixmap     *pixmap_opened,
99                                          GdkBitmap     *mask_opened,
100                                          gboolean       is_leaf,
101                                          gboolean       expanded);
102 static GtkCTreeRow *row_new             (GtkCTree      *ctree);
103 static void row_delete                  (GtkCTree      *ctree,
104                                          GtkCTreeRow   *ctree_row);
105 static void tree_delete                 (GtkCTree      *ctree, 
106                                          GtkCTreeNode  *node, 
107                                          gpointer       data);
108 static void tree_delete_row             (GtkCTree      *ctree, 
109                                          GtkCTreeNode  *node, 
110                                          gpointer       data);
111 static void real_clear                  (GtkCList      *clist);
112 static void tree_update_level           (GtkCTree      *ctree, 
113                                          GtkCTreeNode  *node, 
114                                          gpointer       data);
115 static void tree_select                 (GtkCTree      *ctree, 
116                                          GtkCTreeNode  *node, 
117                                          gpointer       data);
118 static void tree_unselect               (GtkCTree      *ctree, 
119                                          GtkCTreeNode  *node, 
120                                          gpointer       data);
121 static void real_select_all             (GtkCList      *clist);
122 static void real_unselect_all           (GtkCList      *clist);
123 static void tree_expand                 (GtkCTree      *ctree, 
124                                          GtkCTreeNode  *node,
125                                          gpointer       data);
126 static void tree_collapse               (GtkCTree      *ctree, 
127                                          GtkCTreeNode  *node,
128                                          gpointer       data);
129 static void tree_collapse_to_depth      (GtkCTree      *ctree, 
130                                          GtkCTreeNode  *node, 
131                                          gint           depth);
132 static void tree_toggle_expansion       (GtkCTree      *ctree,
133                                          GtkCTreeNode  *node,
134                                          gpointer       data);
135 static void change_focus_row_expansion  (GtkCTree      *ctree,
136                                          GtkCTreeExpansionType expansion);
137 static void real_select_row             (GtkCList      *clist,
138                                          gint           row,
139                                          gint           column,
140                                          GdkEvent      *event);
141 static void real_unselect_row           (GtkCList      *clist,
142                                          gint           row,
143                                          gint           column,
144                                          GdkEvent      *event);
145 static void real_tree_select            (GtkCTree      *ctree,
146                                          GtkCTreeNode  *node,
147                                          gint           column);
148 static void real_tree_unselect          (GtkCTree      *ctree,
149                                          GtkCTreeNode  *node,
150                                          gint           column);
151 static void tree_toggle_selection       (GtkCTree      *ctree, 
152                                          GtkCTreeNode  *node, 
153                                          gint           column);
154 static void real_tree_expand            (GtkCTree      *ctree,
155                                          GtkCTreeNode  *node);
156 static void real_tree_collapse          (GtkCTree      *ctree,
157                                          GtkCTreeNode  *node);
158 static void real_tree_move              (GtkCTree      *ctree,
159                                          GtkCTreeNode  *node,
160                                          GtkCTreeNode  *new_parent, 
161                                          GtkCTreeNode  *new_sibling);
162 static void gtk_ctree_link              (GtkCTree      *ctree,
163                                          GtkCTreeNode  *node,
164                                          GtkCTreeNode  *parent,
165                                          GtkCTreeNode  *sibling,
166                                          gboolean       update_focus_row);
167 static void gtk_ctree_unlink            (GtkCTree      *ctree, 
168                                          GtkCTreeNode  *node,
169                                          gboolean       update_focus_row);
170 static GtkCTreeNode * gtk_ctree_last_visible (GtkCTree     *ctree,
171                                               GtkCTreeNode *node);
172 static gboolean ctree_is_hot_spot       (GtkCTree      *ctree, 
173                                          GtkCTreeNode  *node,
174                                          gint           row, 
175                                          gint           x, 
176                                          gint           y);
177 static void tree_sort                   (GtkCTree      *ctree,
178                                          GtkCTreeNode  *node,
179                                          gpointer       data);
180 static gint default_compare             (GtkCList     *clist,
181                                          gconstpointer ptr1,
182                                          gconstpointer ptr2);
183 static void fake_unselect_all           (GtkCList      *clist,
184                                          gint           row);
185 static GList * selection_find           (GtkCList      *clist,
186                                          gint           row_number,
187                                          GList         *row_list_element);
188 static void resync_selection            (GtkCList      *clist,
189                                          GdkEvent      *event);
190 static void real_undo_selection         (GtkCList      *clist);
191 static void select_row_recursive        (GtkCTree      *ctree, 
192                                          GtkCTreeNode  *node, 
193                                          gpointer       data);
194
195
196
197
198 enum
199 {
200   TREE_SELECT_ROW,
201   TREE_UNSELECT_ROW,
202   TREE_EXPAND,
203   TREE_COLLAPSE,
204   TREE_MOVE,
205   CHANGE_FOCUS_ROW_EXPANSION,
206   LAST_SIGNAL
207 };
208
209 typedef void (*GtkCTreeSignal1) (GtkObject    *object,
210                                  GtkCTreeNode *arg1,
211                                  gint          arg2,
212                                  gpointer      data);
213
214 typedef void (*GtkCTreeSignal2) (GtkObject    *object,
215                                  GtkCTreeNode *arg1,
216                                  GtkCTreeNode *arg2,
217                                  GtkCTreeNode *arg3,
218                                  gpointer      data);
219
220 typedef void (*GtkCTreeSignal3) (GtkObject    *object,
221                                  GtkCTreeNode *arg1,
222                                  gpointer      data);
223
224 typedef void (*GtkCTreeSignal4) (GtkObject         *object,
225                                  GtkCTreeExpansionType arg1,
226                                  gpointer           data);
227
228
229 static GtkCListClass *parent_class = NULL;
230 static GtkContainerClass *container_class = NULL;
231 static guint ctree_signals[LAST_SIGNAL] = {0};
232
233
234 GtkType
235 gtk_ctree_get_type (void)
236 {
237   static GtkType ctree_type = 0;
238
239   if (!ctree_type)
240     {
241       GtkTypeInfo ctree_info =
242       {
243         "GtkCTree",
244         sizeof (GtkCTree),
245         sizeof (GtkCTreeClass),
246         (GtkClassInitFunc) gtk_ctree_class_init,
247         (GtkObjectInitFunc) gtk_ctree_init,
248         /* reserved_1 */ NULL,
249         /* reserved_2 */ NULL,
250         (GtkClassInitFunc) NULL,
251       };
252
253       ctree_type = gtk_type_unique (GTK_TYPE_CLIST, &ctree_info);
254     }
255
256   return ctree_type;
257 }
258
259 static void
260 gtk_ctree_class_init (GtkCTreeClass *klass)
261 {
262   GtkObjectClass *object_class;
263   GtkWidgetClass *widget_class;
264   GtkCListClass *clist_class;
265
266   object_class = (GtkObjectClass *) klass;
267   widget_class = (GtkWidgetClass *) klass;
268   container_class = (GtkContainerClass *) klass;
269   clist_class = (GtkCListClass *) klass;
270
271   parent_class = gtk_type_class (GTK_TYPE_CLIST);
272   container_class = gtk_type_class (GTK_TYPE_CONTAINER);
273
274   ctree_signals[TREE_SELECT_ROW] =
275     gtk_signal_new ("tree_select_row",
276                     GTK_RUN_FIRST,
277                     object_class->type,
278                     GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_select_row),
279                     gtk_marshal_NONE__POINTER_INT,
280                     GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_INT);
281   ctree_signals[TREE_UNSELECT_ROW] =
282     gtk_signal_new ("tree_unselect_row",
283                     GTK_RUN_FIRST,
284                     object_class->type,
285                     GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_unselect_row),
286                     gtk_marshal_NONE__POINTER_INT,
287                     GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_INT);
288   ctree_signals[TREE_EXPAND] =
289     gtk_signal_new ("tree_expand",
290                     GTK_RUN_LAST,
291                     object_class->type,
292                     GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_expand),
293                     gtk_marshal_NONE__POINTER,
294                     GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
295   ctree_signals[TREE_COLLAPSE] =
296     gtk_signal_new ("tree_collapse",
297                     GTK_RUN_LAST,
298                     object_class->type,
299                     GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_collapse),
300                     gtk_marshal_NONE__POINTER,
301                     GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
302   ctree_signals[TREE_MOVE] =
303     gtk_signal_new ("tree_move",
304                     GTK_RUN_LAST,
305                     object_class->type,
306                     GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_move),
307                     gtk_marshal_NONE__POINTER_POINTER_POINTER,
308                     GTK_TYPE_NONE, 3, GTK_TYPE_POINTER, GTK_TYPE_POINTER, 
309                     GTK_TYPE_POINTER);
310   ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
311     gtk_signal_new ("change_focus_row_expansion",
312                     GTK_RUN_LAST | GTK_RUN_ACTION,
313                     object_class->type,
314                     GTK_SIGNAL_OFFSET (GtkCTreeClass,
315                                        change_focus_row_expansion),
316                     gtk_marshal_NONE__ENUM,
317                     GTK_TYPE_NONE, 1, GTK_TYPE_C_TREE_EXPANSION_TYPE);
318
319   gtk_object_class_add_signals (object_class, ctree_signals, LAST_SIGNAL);
320
321   object_class->destroy = gtk_ctree_destroy;
322
323   widget_class->realize = gtk_ctree_realize;
324   widget_class->unrealize = gtk_ctree_unrealize;
325   widget_class->button_press_event = gtk_ctree_button_press;
326   widget_class->button_release_event = gtk_ctree_button_release;
327   widget_class->motion_notify_event = gtk_ctree_button_motion;
328
329   clist_class->select_row = real_select_row;
330   clist_class->unselect_row = real_unselect_row;
331   clist_class->undo_selection = real_undo_selection;
332   clist_class->resync_selection = resync_selection;
333   clist_class->selection_find = selection_find;
334   clist_class->click_column = NULL;
335   clist_class->draw_row = draw_row;
336   clist_class->clear = real_clear;
337   clist_class->select_all = real_select_all;
338   clist_class->unselect_all = real_unselect_all;
339   clist_class->fake_unselect_all = fake_unselect_all;
340
341   klass->tree_select_row = real_tree_select;
342   klass->tree_unselect_row = real_tree_unselect;
343   klass->tree_expand = real_tree_expand;
344   klass->tree_collapse = real_tree_collapse;
345   klass->tree_move = real_tree_move;
346   klass->change_focus_row_expansion = change_focus_row_expansion;
347
348   {
349     GtkBindingSet *binding_set;
350
351     binding_set = gtk_binding_set_by_class (klass);
352     gtk_binding_entry_add_signal (binding_set,
353                                   '+', GDK_SHIFT_MASK,
354                                   "change_focus_row_expansion", 1,
355                                   GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND);
356     gtk_binding_entry_add_signal (binding_set,
357                                   GDK_KP_Add, 0,
358                                   "change_focus_row_expansion", 1,
359                                   GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND);
360     gtk_binding_entry_add_signal (binding_set,
361                                   GDK_KP_Add, GDK_CONTROL_MASK,
362                                   "change_focus_row_expansion", 1,
363                                   GTK_TYPE_ENUM,
364                                   GTK_CTREE_EXPANSION_EXPAND_RECURSIVE);
365     gtk_binding_entry_add_signal (binding_set,
366                                   '-', 0,
367                                   "change_focus_row_expansion", 1,
368                                   GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE);
369     gtk_binding_entry_add_signal (binding_set,
370                                   GDK_KP_Subtract, 0,
371                                   "change_focus_row_expansion", 1,
372                                   GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE);
373     gtk_binding_entry_add_signal (binding_set,
374                                   GDK_KP_Subtract, GDK_CONTROL_MASK,
375                                   "change_focus_row_expansion", 1,
376                                   GTK_TYPE_ENUM,
377                                   GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE);
378     gtk_binding_entry_add_signal (binding_set,
379                                   '=', 0,
380                                   "change_focus_row_expansion", 1,
381                                   GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
382     gtk_binding_entry_add_signal (binding_set,
383                                   GDK_KP_Multiply, 0,
384                                   "change_focus_row_expansion", 1,
385                                   GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
386     gtk_binding_entry_add_signal (binding_set,
387                                   GDK_KP_Multiply, GDK_CONTROL_MASK,
388                                   "change_focus_row_expansion", 1,
389                                   GTK_TYPE_ENUM,
390                                   GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE);
391   }
392
393 }
394
395 static void
396 gtk_ctree_init (GtkCTree *ctree)
397 {
398   ctree->xor_gc         = NULL;
399   ctree->drag_icon      = NULL;
400   ctree->tree_indent    = 20;
401   ctree->tree_column    = 0;
402   ctree->drag_row       = -1;
403   ctree->drag_source    = NULL;
404   ctree->drag_target    = NULL;
405   ctree->insert_pos     = GTK_CTREE_POS_AS_CHILD;
406   GTK_CLIST (ctree)->compare = default_compare;
407   ctree->reorderable    = FALSE;
408   ctree->use_icons      = TRUE;
409   ctree->in_drag        = FALSE;
410   ctree->drag_rect      = FALSE;
411   ctree->line_style     = GTK_CTREE_LINES_SOLID;
412 }
413
414 static void
415 gtk_ctree_destroy (GtkObject *object)
416 {
417   gint i;
418   GtkCList *clist;
419
420   g_return_if_fail (object != NULL);
421   g_return_if_fail (GTK_IS_CTREE (object));
422
423   clist = GTK_CLIST (object);
424
425   GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
426
427   gtk_clist_clear (GTK_CLIST (object));
428
429   if (clist->vscrollbar)
430     {
431       gtk_widget_unparent (clist->vscrollbar);
432       clist->vscrollbar = NULL;
433     }
434   if (clist->hscrollbar)
435     {
436       gtk_widget_unparent (clist->hscrollbar);
437       clist->hscrollbar = NULL;
438     }
439
440   for (i = 0; i < clist->columns; i++)
441     if (clist->column[i].button)
442       {
443         gtk_widget_unparent (clist->column[i].button);
444         clist->column[i].button = NULL;
445       }
446
447   if (GTK_OBJECT_CLASS (container_class)->destroy)
448     (*GTK_OBJECT_CLASS (container_class)->destroy) (object);
449 }
450
451 static void
452 gtk_ctree_realize (GtkWidget *widget)
453 {
454   GtkCTree *ctree;
455   GdkGCValues values;
456
457   g_return_if_fail (widget != NULL);
458   g_return_if_fail (GTK_IS_CTREE (widget));
459
460   (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
461
462   ctree = GTK_CTREE (widget);
463
464   values.foreground = widget->style->fg[GTK_STATE_NORMAL];
465   values.background = widget->style->bg[GTK_STATE_NORMAL];
466   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
467   values.line_style = GDK_LINE_SOLID;
468   ctree->lines_gc = gdk_gc_new_with_values (GTK_CLIST(widget)->clist_window, 
469                                             &values,
470                                             GDK_GC_FOREGROUND |
471                                             GDK_GC_BACKGROUND |
472                                             GDK_GC_SUBWINDOW |
473                                             GDK_GC_LINE_STYLE);
474
475   if (ctree->line_style == GTK_CTREE_LINES_DOTTED)
476     {
477       gdk_gc_set_line_attributes (ctree->lines_gc, 1, 
478                                   GDK_LINE_ON_OFF_DASH, None, None);
479       gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2);
480     }
481
482   if (ctree->reorderable)
483     create_xor_gc (ctree);
484 }
485
486 static void
487 gtk_ctree_unrealize (GtkWidget *widget)
488 {
489   GtkCTree *ctree;
490
491   g_return_if_fail (widget != NULL);
492   g_return_if_fail (GTK_IS_CTREE (widget));
493
494   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
495
496   ctree = GTK_CTREE (widget);
497
498   gdk_gc_destroy (ctree->lines_gc);
499
500   if (ctree->reorderable)
501     gdk_gc_destroy (ctree->xor_gc);
502 }
503
504 static gint
505 gtk_ctree_button_press (GtkWidget      *widget,
506                         GdkEventButton *event)
507 {
508   GtkCTree *ctree;
509   GtkCList *clist;
510
511   g_return_val_if_fail (widget != NULL, FALSE);
512   g_return_val_if_fail (GTK_IS_CTREE (widget), FALSE);
513   g_return_val_if_fail (event != NULL, FALSE);
514
515   ctree = GTK_CTREE (widget);
516   clist = GTK_CLIST (widget);
517
518   if (event->window == clist->clist_window)
519     {
520       gboolean collapse_expand = FALSE;
521       GtkCTreeNode *work;
522       gint x;
523       gint y;
524       gint row;
525       gint column;
526
527       x = event->x;
528       y = event->y;
529
530       if (!gtk_clist_get_selection_info (clist, x, y, &row, &column))
531         return FALSE;
532
533       if (event->button == 2)
534         ctree->drag_row = - 1 - ROW_FROM_YPIXEL (clist, y);
535
536       work = GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
537           
538       if (ctree->reorderable && event->button == 2 && !ctree->in_drag &&
539           clist->anchor == -1)
540         {
541           gdk_pointer_grab (event->window, FALSE,
542                             GDK_POINTER_MOTION_HINT_MASK |
543                             GDK_BUTTON2_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
544                             NULL, NULL, event->time);
545           gtk_grab_add (widget);
546           ctree->in_drag = TRUE;
547           ctree->drag_source = work;
548           ctree->drag_target = NULL;
549           return FALSE;
550         }
551       else if (event->button == 1 &&
552                (GTK_CTREE_ROW (work)->children &&
553                 (event->type == GDK_2BUTTON_PRESS ||
554                  ctree_is_hot_spot (ctree, work, row, x, y))))
555         {
556           if (GTK_CTREE_ROW (work)->expanded)
557             gtk_ctree_collapse (ctree, work);
558           else
559             gtk_ctree_expand (ctree, work);
560
561           collapse_expand = TRUE;
562         }
563       if (event->button == 1)
564         {
565           gint old_row = clist->focus_row;
566           gboolean no_focus_row = FALSE;
567
568           switch (clist->selection_mode)
569             {
570             case GTK_SELECTION_MULTIPLE:
571             case GTK_SELECTION_SINGLE:
572               if (!collapse_expand)
573                 break;
574
575               if (clist->focus_row == -1)
576                 {
577                   old_row = row;
578                   no_focus_row = TRUE;
579                 }
580                   
581               GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION);
582               gdk_pointer_grab (clist->clist_window, FALSE,
583                                 GDK_POINTER_MOTION_HINT_MASK |
584                                 GDK_BUTTON1_MOTION_MASK |
585                                 GDK_BUTTON_RELEASE_MASK,
586                                 NULL, NULL, event->time);
587               gtk_grab_add (widget);
588
589               if (GTK_CLIST_ADD_MODE (clist))
590                 {
591                   GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE);
592                   if (GTK_WIDGET_HAS_FOCUS (widget))
593                     {
594                       gtk_widget_draw_focus (widget);
595                       gdk_gc_set_line_attributes (clist->xor_gc, 1,
596                                                   GDK_LINE_SOLID, 0, 0);
597                       clist->focus_row = row;
598                       gtk_widget_draw_focus (widget);
599                     }
600                   else
601                     {
602                       gdk_gc_set_line_attributes (clist->xor_gc, 1,
603                                                   GDK_LINE_SOLID, 0, 0);
604                       clist->focus_row = row;
605                     }
606                 }
607               else if (row != clist->focus_row)
608                 {
609                   if (GTK_WIDGET_HAS_FOCUS (widget))
610                     {
611                       gtk_widget_draw_focus (widget);
612                       clist->focus_row = row;
613                       gtk_widget_draw_focus (widget);
614                     }
615                   else
616                     clist->focus_row = row;
617                 }
618
619               if (!GTK_WIDGET_HAS_FOCUS (widget))
620                 gtk_widget_grab_focus (widget);
621
622               return FALSE;
623
624             default:
625               break;
626             }
627         }
628     }
629   return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
630 }
631
632 static gint
633 gtk_ctree_button_motion (GtkWidget      *widget, 
634                          GdkEventMotion *event)
635 {
636   GtkCTree *ctree;
637   GtkCList *clist;
638   gint x;
639   gint y;
640   gint row;
641   gint insert_pos = GTK_CTREE_POS_AS_CHILD;
642
643   g_return_val_if_fail (widget != NULL, FALSE);
644   g_return_val_if_fail (GTK_IS_CTREE (widget), FALSE);
645   g_return_val_if_fail (event != NULL, FALSE);
646
647   ctree = GTK_CTREE (widget);
648   clist = GTK_CLIST (widget);
649
650   if (GTK_CLIST_IN_DRAG (clist))
651     return  GTK_WIDGET_CLASS (parent_class)->motion_notify_event
652       (widget, event);
653
654   if (event->window == clist->clist_window && 
655       ctree->in_drag && ctree->reorderable)
656     {
657       GdkModifierType modmask;
658       gint root_x;
659       gint root_y;
660
661       x = event->x;
662       y = event->y;
663       if (event->is_hint)
664         gdk_window_get_pointer (event->window, &x, &y, NULL);
665
666       /* delayed drag start */
667       if (!ctree->drag_target &&
668           y >= ROW_TOP_YPIXEL (clist, -ctree->drag_row-1) &&
669           y <= ROW_TOP_YPIXEL (clist, -ctree->drag_row-1) + clist->row_height)
670         return 
671           GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
672
673       if (ctree->use_icons)
674         {
675           if (!ctree->drag_icon)
676             create_drag_icon (ctree, GTK_CTREE_ROW (ctree->drag_source));
677           else
678             {
679               gdk_window_get_pointer (NULL, &root_x, &root_y, &modmask);
680               gdk_window_move (ctree->drag_icon, root_x - ctree->icon_width /2,
681                                root_y - ctree->icon_height);
682             }
683         }
684
685       /* out of bounds check */
686       if (x < 0 || y < -3 || x > clist->clist_window_width ||
687           y > clist->clist_window_height + 3 ||
688           y > ROW_TOP_YPIXEL (clist, clist->rows-1) + clist->row_height + 3)
689         {
690           if (ctree->drag_row >= 0)
691             {
692               if (ctree->drag_rect)
693                 {
694                   draw_xor_rect (ctree);
695                   ctree->drag_rect = FALSE;
696                 }
697               else
698                 draw_xor_line (ctree);
699               ctree->drag_row = -1;
700             }
701           return 
702             (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) 
703             (widget, event);
704         }
705
706       row = ROW_FROM_YPIXEL (clist, y);
707
708       /* re-calculate target (mouse left the window) */
709       if (ctree->drag_target && ctree->drag_row == -1)
710         ctree->drag_target = GTK_CTREE_NODE (g_list_nth (clist->row_list,row));
711       
712       if (y < 0 || y > clist->clist_window_height || 
713           ROW_TOP_YPIXEL (clist, row + 1) > clist->clist_window_height
714           || row >= clist->rows)
715         return GTK_WIDGET_CLASS (parent_class)->motion_notify_event
716           (widget, event);
717
718       if (y - ROW_TOP_YPIXEL (clist, row) < clist->row_height / 4)
719         insert_pos = GTK_CTREE_POS_BEFORE;
720       else if (ROW_TOP_YPIXEL (clist, row) + clist->row_height - y 
721                < clist->row_height / 4)
722         insert_pos = GTK_CTREE_POS_AFTER;
723
724       if (row != ctree->drag_row || 
725           (row == ctree->drag_row && ctree->insert_pos != insert_pos))
726         {
727           if (insert_pos != GTK_CTREE_POS_AS_CHILD)
728             {
729               if (ctree->drag_row >= 0)
730                 {
731                   if (ctree->drag_rect)
732                     {
733                       draw_xor_rect (ctree);
734                       ctree->drag_rect = FALSE;
735                     }
736                   else
737                     draw_xor_line (ctree);
738                 }
739               ctree->insert_pos = insert_pos;
740               ctree->drag_target =
741                 GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
742               ctree->drag_row = row;
743               draw_xor_line (ctree);
744             }
745           else if (ctree->drag_target &&
746                    !GTK_CTREE_ROW (ctree->drag_target)->is_leaf)
747             {
748               if (ctree->drag_row >= 0)
749                 {
750                   if (ctree->drag_rect)
751                     draw_xor_rect (ctree);
752                   else
753                     draw_xor_line (ctree);
754                 }
755               ctree->drag_rect = TRUE;
756               ctree->insert_pos = insert_pos;
757               ctree->drag_target =
758                 GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
759               ctree->drag_row = row;
760               draw_xor_rect (ctree);
761             }
762         }
763     }
764   return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
765 }
766
767 static gint
768 gtk_ctree_button_release (GtkWidget      *widget, 
769                           GdkEventButton *event)
770 {
771   GtkCTree *ctree;
772   GtkCList *clist;
773
774   g_return_val_if_fail (widget != NULL, FALSE);
775   g_return_val_if_fail (GTK_IS_CTREE (widget), FALSE);
776   g_return_val_if_fail (event != NULL, FALSE);
777
778   ctree = GTK_CTREE (widget);
779   clist = GTK_CLIST (widget);
780
781   if (event->button == 2 && clist->anchor == -1)
782     {
783       gtk_grab_remove (widget);
784       gdk_pointer_ungrab (event->time);
785
786       ctree->in_drag = FALSE;
787
788       if (ctree->use_icons && ctree->drag_icon)
789         {
790           gdk_window_destroy (ctree->drag_icon);
791           ctree->drag_icon = NULL;
792         }
793
794       if (ctree->drag_row >= 0)
795         {
796           if (ctree->drag_rect)
797             {
798               draw_xor_rect (ctree);
799               ctree->drag_rect = FALSE;
800             }
801           else
802             draw_xor_line (ctree);
803           ctree->drag_row = -1;
804         }
805
806       /* nop if out of bounds / source == target */
807       if (event->x < 0 || event->y < -3 ||
808           event->x > clist->clist_window_width ||
809           event->y > clist->clist_window_height + 3 ||
810           ctree->drag_target == ctree->drag_source ||
811           !ctree->drag_target)
812         return GTK_WIDGET_CLASS (parent_class)->button_release_event
813           (widget, event);
814
815       if (!GTK_CTREE_ROW (ctree->drag_source)->children ||
816           !gtk_ctree_is_ancestor (ctree, ctree->drag_source,
817                                   ctree->drag_target))
818         {
819           if (ctree->insert_pos == GTK_CTREE_POS_AFTER)
820             {
821               if (GTK_CTREE_ROW (ctree->drag_target)->sibling != 
822                   ctree->drag_source)
823                 gtk_signal_emit (GTK_OBJECT (ctree), 
824                                  ctree_signals[TREE_MOVE],
825                                  ctree->drag_source,
826                                  GTK_CTREE_ROW (ctree->drag_target)->parent,
827                                  GTK_CTREE_ROW (ctree->drag_target)->sibling);
828             }
829           else if (ctree->insert_pos == GTK_CTREE_POS_BEFORE)
830             {
831               if (GTK_CTREE_ROW (ctree->drag_source)->sibling != 
832                   ctree->drag_target)
833                 gtk_signal_emit (GTK_OBJECT (ctree), 
834                                  ctree_signals[TREE_MOVE],
835                                  ctree->drag_source,
836                                  GTK_CTREE_ROW (ctree->drag_target)->parent,
837                                  ctree->drag_target);
838             }
839           else if (!GTK_CTREE_ROW (ctree->drag_target)->is_leaf)
840             {
841               if (GTK_CTREE_ROW (ctree->drag_target)->children !=
842                   ctree->drag_source)
843                 gtk_signal_emit (GTK_OBJECT (ctree), 
844                                  ctree_signals[TREE_MOVE],
845                                  ctree->drag_source,
846                                  ctree->drag_target,
847                                  GTK_CTREE_ROW (ctree->drag_target)->children);
848             }
849         }
850       ctree->drag_source = NULL;
851       ctree->drag_target = NULL;
852     }
853   else if (event->button == 1 && GTK_CLIST_DRAG_SELECTION (clist) &&
854            (clist->selection_mode == GTK_SELECTION_SINGLE ||
855             clist->selection_mode == GTK_SELECTION_MULTIPLE))
856     {
857       gint row;
858       gint column;
859       GtkCTreeNode *work;
860
861       if (gtk_clist_get_selection_info
862           (clist, event->x, event->y, &row, &column))
863         {
864           if (clist->anchor == clist->focus_row &&
865               (work = GTK_CTREE_NODE (g_list_nth (clist->row_list, row))))
866             tree_toggle_selection (ctree, work, column);
867         }
868       clist->anchor = -1;
869     }
870   return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
871 }
872
873 static void
874 create_drag_icon (GtkCTree    *ctree,
875                   GtkCTreeRow *row)
876 {
877   GtkCList *clist;
878   GtkWidget *widget;
879   GdkWindow *window = NULL;
880   GdkWindowAttr attributes;
881   gint attributes_mask;
882   GdkPixmap *pixmap;
883   GdkBitmap *mask;
884   GdkModifierType modmask;
885   gint root_x;
886   gint root_y;
887
888   clist  = GTK_CLIST (ctree);
889   widget = GTK_WIDGET (ctree);
890
891   if (!(pixmap = GTK_CELL_PIXTEXT (row->row.cell[ctree->tree_column])->pixmap))
892     return;
893   mask = GTK_CELL_PIXTEXT (row->row.cell[ctree->tree_column])->mask;
894
895   gdk_window_get_pointer (NULL, &root_x, &root_y, &modmask);
896   gdk_window_get_size (pixmap, &ctree->icon_width, &ctree->icon_height);
897
898   attributes.window_type = GDK_WINDOW_TEMP;
899   attributes.x = root_x - ctree->icon_width / 2;
900   attributes.y = root_y - ctree->icon_height;
901   attributes.width = ctree->icon_width;
902   attributes.height = ctree->icon_height;
903   attributes.wclass = GDK_INPUT_OUTPUT;
904   attributes.visual = gtk_widget_get_visual (widget);
905   attributes.colormap = gtk_widget_get_colormap (widget);
906   attributes.event_mask = gtk_widget_get_events (widget);
907
908   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
909
910   window = gdk_window_new (widget->window, &attributes, attributes_mask);
911   gdk_window_set_back_pixmap (window, pixmap, FALSE);
912   if (mask)
913     gdk_window_shape_combine_mask (window, mask, 0, 0);
914   gdk_window_show (window);
915
916   ctree->drag_icon = window;
917 }
918
919 static void
920 create_xor_gc (GtkCTree *ctree)
921 {
922   GtkCList *clist;
923   GdkGCValues values;
924
925   clist = GTK_CLIST (ctree);
926
927   values.foreground = GTK_WIDGET (clist)->style->bg[GTK_STATE_NORMAL];
928   values.function = GDK_XOR;
929   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
930   ctree->xor_gc = gdk_gc_new_with_values (clist->clist_window, &values,
931                                           GDK_GC_FOREGROUND |
932                                           GDK_GC_FUNCTION |
933                                           GDK_GC_SUBWINDOW);
934   gdk_gc_set_line_attributes (ctree->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 
935                               None, None);
936   gdk_gc_set_dashes (ctree->xor_gc, 0, "\2\2", 2);
937 }
938
939 static void
940 draw_xor_line (GtkCTree *ctree)
941 {
942   GtkCList *clist;
943   gint level;
944   gint y = 0;
945
946   clist = GTK_CLIST (ctree);
947
948   level = GTK_CTREE_ROW (ctree->drag_target)->level;
949
950   if (ctree->insert_pos == GTK_CTREE_POS_AFTER)
951     y = ROW_TOP_YPIXEL (clist, ctree->drag_row) + clist->row_height;
952   else 
953     y = ROW_TOP_YPIXEL (clist, ctree->drag_row) - 1;
954
955   switch (clist->column[ctree->tree_column].justification)
956     {
957     case GTK_JUSTIFY_CENTER:
958     case GTK_JUSTIFY_FILL:
959     case GTK_JUSTIFY_LEFT:
960       if (ctree->tree_column > 0)
961         gdk_draw_line (clist->clist_window, ctree->xor_gc, 
962                        COLUMN_LEFT_XPIXEL(clist, 0), y,
963                        COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1) +
964                        clist->column[ctree->tree_column - 1].area.width, y);
965       
966       gdk_draw_line (clist->clist_window, ctree->xor_gc, 
967                      COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + 
968                      ctree->tree_indent * level -
969                      (ctree->tree_indent - PM_SIZE) / 2, y,
970                      GTK_WIDGET (ctree)->allocation.width, y);
971       break;
972     case GTK_JUSTIFY_RIGHT:
973       if (ctree->tree_column < clist->columns - 1)
974         gdk_draw_line (clist->clist_window, ctree->xor_gc, 
975                        COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1), y,
976                        COLUMN_LEFT_XPIXEL(clist, clist->columns - 1) +
977                        clist->column[clist->columns - 1].area.width, y);
978       
979       gdk_draw_line (clist->clist_window, ctree->xor_gc, 
980                      0, y, COLUMN_LEFT_XPIXEL(clist, ctree->tree_column)
981                      + clist->column[ctree->tree_column].area.width
982                      - ctree->tree_indent * level +
983                      (ctree->tree_indent - PM_SIZE) / 2, y);
984       break;
985     }
986 }
987
988 static void
989 draw_xor_rect (GtkCTree *ctree)
990 {
991   GtkCList *clist;
992   GdkPoint points[4];
993   guint level;
994   gint i;
995   gint y;
996
997   clist = GTK_CLIST (ctree);
998
999   level = GTK_CTREE_ROW (ctree->drag_target)->level;
1000
1001   y = ROW_TOP_YPIXEL (clist, ctree->drag_row) + clist->row_height;
1002
1003   switch (clist->column[ctree->tree_column].justification)
1004     {
1005     case GTK_JUSTIFY_CENTER:
1006     case GTK_JUSTIFY_FILL:
1007     case GTK_JUSTIFY_LEFT:
1008       points[0].x =  COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + 
1009         ctree->tree_indent * level - (ctree->tree_indent - PM_SIZE) / 2;
1010       points[0].y = y;
1011       points[3].x = points[0].x;
1012       points[3].y = y - clist->row_height - 1;
1013       points[1].x = clist->clist_window_width - 1;
1014       points[1].y = points[0].y;
1015       points[2].x = points[1].x;
1016       points[2].y = points[3].y;
1017
1018       for (i = 0; i < 3; i++)
1019         gdk_draw_line (clist->clist_window, ctree->xor_gc,
1020                        points[i].x, points[i].y, points[i+1].x, points[i+1].y);
1021
1022       if (ctree->tree_column > 0)
1023         {
1024           points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1) +
1025             clist->column[ctree->tree_column - 1].area.width ;
1026           points[0].y = y;
1027           points[3].x = points[0].x;
1028           points[3].y = y - clist->row_height - 1;
1029           points[1].x = 0;
1030           points[1].y = points[0].y;
1031           points[2].x = 0;
1032           points[2].y = points[3].y;
1033
1034           for (i = 0; i < 3; i++)
1035             gdk_draw_line (clist->clist_window, ctree->xor_gc,
1036                            points[i].x, points[i].y, points[i+1].x, 
1037                            points[i+1].y);
1038         }
1039       break;
1040     case GTK_JUSTIFY_RIGHT:
1041       points[0].x =  COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) - 
1042         ctree->tree_indent * level + (ctree->tree_indent - PM_SIZE) / 2  +
1043         clist->column[ctree->tree_column].area.width;
1044       points[0].y = y;
1045       points[3].x = points[0].x;
1046       points[3].y = y - clist->row_height - 1;
1047       points[1].x = 0;
1048       points[1].y = points[0].y;
1049       points[2].x = 0;
1050       points[2].y = points[3].y;
1051
1052       for (i = 0; i < 3; i++)
1053         gdk_draw_line (clist->clist_window, ctree->xor_gc,
1054                        points[i].x, points[i].y, points[i+1].x, points[i+1].y);
1055
1056       if (ctree->tree_column < clist->columns - 1)
1057         {
1058           points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1);
1059           points[0].y = y;
1060           points[3].x = points[0].x;
1061           points[3].y = y - clist->row_height - 1;
1062           points[1].x = clist->clist_window_width - 1;
1063           points[1].y = points[0].y;
1064           points[2].x = points[1].x;
1065           points[2].y = points[3].y;
1066
1067           for (i = 0; i < 3; i++)
1068             gdk_draw_line (clist->clist_window, ctree->xor_gc,
1069                            points[i].x, points[i].y, points[i+1].x, 
1070                            points[i+1].y);
1071         }
1072       break;
1073     }      
1074 }
1075
1076 static void
1077 draw_row (GtkCList     *clist,
1078           GdkRectangle *area,
1079           gint          row,
1080           GtkCListRow  *clist_row)
1081 {
1082   GtkWidget *widget;
1083   GtkCTree  *ctree;
1084   GdkGC *fg_gc; 
1085   GdkGC *bg_gc;
1086   GdkRectangle row_rectangle;
1087   GdkRectangle cell_rectangle; 
1088   GdkRectangle clip_rectangle;
1089   GdkRectangle intersect_rectangle;
1090   GdkRectangle *rect;
1091
1092   gint i, offset = 0, width, height, pixmap_width = 0, string_width = 0;
1093   gint xsrc, ysrc, xdest = 0, ydest;
1094   gboolean need_redraw = TRUE;
1095   gboolean draw_pixmap = FALSE;
1096
1097   g_return_if_fail (clist != NULL);
1098
1099   /* bail now if we arn't drawable yet */
1100   if (!GTK_WIDGET_DRAWABLE (clist))
1101     return;
1102
1103   if (row < 0 || row >= clist->rows)
1104     return;
1105
1106   widget = GTK_WIDGET (clist);
1107   ctree  = GTK_CTREE  (clist);
1108
1109   /* if the function is passed the pointer to the row instead of null,
1110    * it avoids this expensive lookup */
1111   if (!clist_row)
1112     clist_row = (g_list_nth (clist->row_list, row))->data;
1113
1114   /* rectangle of the entire row */
1115   row_rectangle.x = 0;
1116   row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
1117   row_rectangle.width = clist->clist_window_width;
1118   row_rectangle.height = clist->row_height;
1119
1120   /* rectangle of the cell spacing above the row */
1121   cell_rectangle.x = 0;
1122   cell_rectangle.y = row_rectangle.y - CELL_SPACING;
1123   cell_rectangle.width = row_rectangle.width;
1124   cell_rectangle.height = CELL_SPACING;
1125
1126   /* rectangle used to clip drawing operations, it's y and height
1127    * positions only need to be set once, so we set them once here. 
1128    * the x and width are set withing the drawing loop below once per
1129    * column */
1130   clip_rectangle.y = row_rectangle.y;
1131   clip_rectangle.height = row_rectangle.height;
1132
1133   /* select GC for background rectangle */
1134   if (clist_row->state == GTK_STATE_SELECTED)
1135     {
1136       fg_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
1137       bg_gc = widget->style->bg_gc[GTK_STATE_SELECTED];
1138     }
1139   else
1140     {
1141       if (clist_row->fg_set)
1142         {
1143           gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
1144           fg_gc = clist->fg_gc;
1145         }
1146       else
1147         fg_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
1148         
1149       if (clist_row->bg_set)
1150         {
1151           gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
1152           bg_gc = clist->bg_gc;
1153         }
1154       else
1155         bg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
1156
1157     }
1158
1159   /* draw the cell borders and background */
1160   if (area)
1161     {
1162       if (gdk_rectangle_intersect (area, &cell_rectangle, 
1163                                    &intersect_rectangle))
1164         gdk_draw_rectangle (clist->clist_window,
1165                             widget->style->base_gc[GTK_STATE_NORMAL],
1166                             TRUE,
1167                             intersect_rectangle.x,
1168                             intersect_rectangle.y,
1169                             intersect_rectangle.width,
1170                             intersect_rectangle.height);
1171
1172       /* the last row has to clear it's bottom cell spacing too */
1173       if (clist_row == clist->row_list_end->data)
1174         {
1175           cell_rectangle.y += clist->row_height + CELL_SPACING;
1176
1177           if (gdk_rectangle_intersect (area, &cell_rectangle, 
1178                                        &intersect_rectangle))
1179             gdk_draw_rectangle (clist->clist_window,
1180                                 widget->style->base_gc[GTK_STATE_NORMAL],
1181                                 TRUE,
1182                                 intersect_rectangle.x,
1183                                 intersect_rectangle.y,
1184                                 intersect_rectangle.width,
1185                                 intersect_rectangle.height);
1186         }
1187
1188       if (gdk_rectangle_intersect 
1189           (area, &row_rectangle, &intersect_rectangle))
1190         {
1191           if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
1192             gdk_draw_rectangle (clist->clist_window,
1193                                 bg_gc,
1194                                 TRUE,
1195                                 intersect_rectangle.x,
1196                                 intersect_rectangle.y,
1197                                 intersect_rectangle.width,
1198                                 intersect_rectangle.height);
1199           else
1200             gdk_window_clear_area (clist->clist_window,
1201                                    intersect_rectangle.x,
1202                                    intersect_rectangle.y,
1203                                    intersect_rectangle.width,
1204                                    intersect_rectangle.height);
1205         }
1206       else 
1207         need_redraw = FALSE;
1208     }
1209   else
1210     {
1211       gdk_draw_rectangle (clist->clist_window,
1212                           widget->style->base_gc[GTK_STATE_NORMAL],
1213                           TRUE,
1214                           cell_rectangle.x,
1215                           cell_rectangle.y,
1216                           cell_rectangle.width,
1217                           cell_rectangle.height);
1218
1219       /* the last row has to clear it's bottom cell spacing too */
1220       if (clist_row == clist->row_list_end->data)
1221         {
1222           cell_rectangle.y += clist->row_height + CELL_SPACING;
1223
1224           gdk_draw_rectangle (clist->clist_window,
1225                               widget->style->base_gc[GTK_STATE_NORMAL],
1226                               TRUE,
1227                               cell_rectangle.x,
1228                               cell_rectangle.y,
1229                               cell_rectangle.width,
1230                               cell_rectangle.height);     
1231         }         
1232
1233       if (clist_row->state == GTK_STATE_SELECTED || clist_row->bg_set)
1234         gdk_draw_rectangle (clist->clist_window,
1235                             bg_gc,
1236                             TRUE,
1237                             row_rectangle.x,
1238                             row_rectangle.y,
1239                             row_rectangle.width,
1240                             row_rectangle.height);
1241       else
1242         gdk_window_clear_area (clist->clist_window,
1243                                row_rectangle.x,
1244                                row_rectangle.y,
1245                                row_rectangle.width,
1246                                row_rectangle.height);
1247     }
1248
1249   /* iterate and draw all the columns (row cells) and draw their contents */
1250   for (i = 0; i < clist->columns; i++)
1251     {
1252         
1253       if (!need_redraw && ctree->tree_column != i)
1254         continue;
1255
1256       clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
1257       clip_rectangle.width = clist->column[i].area.width;
1258
1259       /* calculate clipping region */
1260       if (i == ctree->tree_column)
1261         {
1262           clip_rectangle.y -= CELL_SPACING;
1263           clip_rectangle.height += CELL_SPACING;
1264         }
1265
1266       if (i == ctree->tree_column)
1267         {
1268
1269           if (clist_row->state == GTK_STATE_SELECTED)
1270             {
1271               gdk_gc_set_foreground (ctree->lines_gc, 
1272                                      &GTK_WIDGET (ctree)->style->
1273                                      fg[GTK_STATE_SELECTED]);
1274               gdk_gc_set_background (ctree->lines_gc, 
1275                                      &GTK_WIDGET (ctree)->style->
1276                                      bg[GTK_STATE_SELECTED]);
1277             }
1278           else
1279             {
1280               gdk_gc_set_foreground (ctree->lines_gc, 
1281                                      &GTK_WIDGET (ctree)->style->
1282                                      fg[GTK_STATE_NORMAL]);
1283               if (clist_row->bg_set)
1284                 gdk_gc_set_background (ctree->lines_gc, 
1285                                        &clist_row->background);
1286             }
1287
1288           if (ctree->line_style == GTK_CTREE_LINES_TABBED)
1289             {
1290               if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
1291                 {
1292                   xdest = clip_rectangle.x + clip_rectangle.width - 1 -
1293                     (((GtkCTreeRow *) clist_row)->level - 1) *
1294                     ctree->tree_indent;
1295
1296                   gdk_draw_line (clist->clist_window,
1297                                  ctree->lines_gc, 
1298                                  -1,
1299                                  row_rectangle.y - 1,
1300                                  MAX (xdest - TAB_SIZE, clip_rectangle.x - 1),
1301                                  row_rectangle.y - 1);
1302
1303                   if (clist_row == clist->row_list_end->data)
1304                     gdk_draw_line
1305                       (clist->clist_window,
1306                        ctree->lines_gc, 
1307                        -1,
1308                        row_rectangle.y + clist->row_height,
1309                        MAX (clip_rectangle.x + clip_rectangle.width -
1310                             TAB_SIZE - 1 -
1311                             (((GtkCTreeRow *) clist_row)->level > 1) *
1312                             MIN (ctree->tree_indent / 2, TAB_SIZE),
1313                             clip_rectangle.x - 1),
1314                        row_rectangle.y + clist->row_height);
1315
1316                   if (clist_row->state != GTK_STATE_SELECTED)
1317                     gdk_draw_rectangle
1318                       (clist->clist_window,
1319                        widget->style->bg_gc[GTK_STATE_PRELIGHT],
1320                        TRUE,
1321                        clip_rectangle.x + clip_rectangle.width,
1322                        row_rectangle.y,
1323                        CELL_SPACING + COLUMN_INSET,
1324                        row_rectangle.height);
1325                 }
1326               else
1327                 {
1328                   xdest = clip_rectangle.x +
1329                     (((GtkCTreeRow *) clist_row)->level - 1) *
1330                     ctree->tree_indent;
1331                   
1332                   gdk_draw_line (clist->clist_window,
1333                                  ctree->lines_gc, 
1334                                  MIN (xdest + TAB_SIZE,
1335                                       clip_rectangle.x + clip_rectangle.width),
1336                                  row_rectangle.y - 1,
1337                                  clist->clist_window_width,
1338                                  row_rectangle.y - 1);
1339
1340                   if (clist_row == clist->row_list_end->data)
1341                     gdk_draw_line
1342                       (clist->clist_window, ctree->lines_gc, 
1343                        MIN (clip_rectangle.x + TAB_SIZE +
1344                             (((GtkCTreeRow *) clist_row)->level > 1) *
1345                             MIN (ctree->tree_indent / 2, TAB_SIZE),
1346                             clip_rectangle.x + clip_rectangle.width),
1347                        row_rectangle.y + clist->row_height,
1348                        clist->clist_window_width,
1349                        row_rectangle.y + clist->row_height);
1350
1351                   if (clist_row->state != GTK_STATE_SELECTED)
1352                     gdk_draw_rectangle
1353                       (clist->clist_window,
1354                        widget->style->bg_gc[GTK_STATE_PRELIGHT],
1355                        TRUE,
1356                        clip_rectangle.x - CELL_SPACING - COLUMN_INSET,
1357                        row_rectangle.y,
1358                        CELL_SPACING + COLUMN_INSET,
1359                        row_rectangle.height);
1360                 }
1361             }
1362         }
1363
1364       if (!area)
1365         {
1366           rect = &clip_rectangle;
1367         }
1368       else
1369         {
1370
1371           if (!gdk_rectangle_intersect (area, &clip_rectangle, 
1372                                         &intersect_rectangle))
1373             continue;
1374           rect = &intersect_rectangle;
1375         }
1376
1377       /* calculate real width for column justification */
1378       switch (clist_row->cell[i].type)
1379         {
1380         case GTK_CELL_EMPTY:
1381           continue;
1382           break;
1383
1384         case GTK_CELL_TEXT:
1385           width = gdk_string_width (GTK_WIDGET (clist)->style->font,
1386                                     GTK_CELL_TEXT (clist_row->cell[i])->text);
1387           break;
1388
1389         case GTK_CELL_PIXMAP:
1390           gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, 
1391                                &width, &height);
1392           pixmap_width = width;
1393           break;
1394
1395         case GTK_CELL_PIXTEXT:
1396           if (i == ctree->tree_column)
1397             {
1398               string_width = 0;
1399               width = 0;
1400
1401               if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap)
1402                 gdk_window_get_size (GTK_CELL_PIXTEXT 
1403                                      (clist_row->cell[i])->pixmap, 
1404                                      &width, &height);
1405
1406               pixmap_width = width;
1407               width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1408
1409               if (GTK_CELL_PIXTEXT (clist_row->cell[i])->text)
1410                 string_width += gdk_string_width 
1411                   (GTK_WIDGET (clist)->style->font,
1412                    GTK_CELL_PIXTEXT(clist_row->cell[i])->text);
1413               
1414               width += string_width + 
1415                 ((GtkCTreeRow *)clist_row)->level * ctree->tree_indent;
1416             }
1417           else
1418             {
1419               gdk_window_get_size (GTK_CELL_PIXTEXT 
1420                                    (clist_row->cell[i])->pixmap, 
1421                                    &width, &height);
1422               pixmap_width = width;
1423               width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1424               width += gdk_string_width (GTK_WIDGET (clist)->style->font,
1425                                          GTK_CELL_PIXTEXT 
1426                                          (clist_row->cell[i])->text);
1427             }
1428           break;
1429
1430         case GTK_CELL_WIDGET:
1431           /* unimplemented */
1432           continue;
1433           break;
1434
1435         default:
1436           continue;
1437           break;
1438         }
1439
1440       switch (clist->column[i].justification)
1441         {
1442         case GTK_JUSTIFY_LEFT:
1443           offset = clip_rectangle.x;
1444           break;
1445
1446         case GTK_JUSTIFY_RIGHT:
1447           offset = (clip_rectangle.x + clip_rectangle.width) - width;
1448           break;
1449
1450         case GTK_JUSTIFY_CENTER:
1451           offset = (clip_rectangle.x + (clip_rectangle.width / 2)) 
1452             - (width / 2);
1453           break;
1454
1455         case GTK_JUSTIFY_FILL:
1456           offset = (clip_rectangle.x + (clip_rectangle.width / 2)) 
1457             - (width / 2);
1458           break;
1459
1460         default:
1461           offset = 0;
1462           break;
1463         };
1464
1465       if (i == ctree->tree_column)
1466         {
1467           GdkGC *cgc;
1468           GdkGC *tgc;
1469           GdkGC *mbg_gc;
1470           GtkCTreeNode *work;
1471           GtkCTreeNode *work2;
1472           gint xoffset;
1473           gint yoffset;
1474           gint xcenter;
1475           gint ycenter;
1476           gint offset_x;
1477           gint offset_y = 0; 
1478           gint next_level;
1479           gint in;
1480           GdkPoint points[6];
1481
1482           xsrc = 0;
1483           ysrc = 0;
1484
1485           yoffset = (clip_rectangle.height - PM_SIZE) / 2;
1486           xoffset = (ctree->tree_indent - PM_SIZE) / 2;
1487           ycenter = clip_rectangle.y + (clip_rectangle.height / 2);
1488           ydest = ycenter - height / 2 + clist_row->cell[i].vertical;
1489
1490           gdk_gc_set_clip_origin (fg_gc, 0, 0);
1491           gdk_gc_set_clip_rectangle (fg_gc, rect);
1492           if (ctree->line_style != GTK_CTREE_LINES_NONE)
1493             {
1494               gdk_gc_set_clip_origin (ctree->lines_gc, 0, 0);
1495               gdk_gc_set_clip_rectangle (ctree->lines_gc, rect);
1496             }
1497
1498           switch (clist->column[i].justification)
1499             {
1500             case GTK_JUSTIFY_CENTER:
1501             case GTK_JUSTIFY_FILL:
1502               offset = clip_rectangle.x;
1503             case GTK_JUSTIFY_LEFT:
1504               offset_x = 1;
1505               xdest = clip_rectangle.x - xoffset +
1506                 (((GtkCTreeRow *) clist_row)->level - 1) * ctree->tree_indent;
1507               xcenter = xdest + (ctree->tree_indent / 2);
1508           
1509               switch (ctree->line_style)
1510                 {
1511                 case GTK_CTREE_LINES_NONE:
1512                   break;
1513                 case GTK_CTREE_LINES_TABBED:
1514                   xdest = clip_rectangle.x +
1515                     (((GtkCTreeRow *) clist_row)->level - 1) *
1516                     ctree->tree_indent;
1517                   xcenter = xdest + TAB_SIZE;
1518
1519                   gdk_gc_set_clip_origin (clist->bg_gc, 0, 0);
1520                   gdk_gc_set_clip_rectangle (clist->bg_gc, rect);
1521
1522                   gdk_gc_set_clip_origin 
1523                     (widget->style->bg_gc[GTK_STATE_PRELIGHT], 0, 0);
1524                   gdk_gc_set_clip_rectangle 
1525                     (widget->style->bg_gc[GTK_STATE_PRELIGHT], rect);
1526
1527                   work = ((GtkCTreeRow *)clist_row)->parent;
1528                   next_level = ((GtkCTreeRow *)clist_row)->level;
1529
1530                   if (!(((GtkCTreeRow *)clist_row)->sibling ||
1531                         (((GtkCTreeRow *)clist_row)->children &&
1532                          ((GtkCTreeRow *)clist_row)->expanded)))
1533                     {
1534                       work2 = gtk_ctree_find_glist_ptr
1535                         (ctree, (GtkCTreeRow *) clist_row);
1536
1537                       if (GTK_CTREE_NODE_NEXT (work2))
1538                         next_level =
1539                           GTK_CTREE_ROW (GTK_CTREE_NODE_NEXT (work2))->level;
1540                       else
1541                         next_level = 0;
1542                     }
1543
1544                   while (work)
1545                     {
1546                       xcenter -= ctree->tree_indent;
1547
1548                       if (GTK_CTREE_ROW(work)->row.bg_set)
1549                         {
1550                           gdk_gc_set_foreground
1551                             (clist->bg_gc,
1552                              &(GTK_CTREE_ROW(work)->row.background));
1553                           mbg_gc = clist->bg_gc;
1554                         }
1555                       else
1556                         mbg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
1557
1558                       if (clist_row->state != GTK_STATE_SELECTED)
1559                         gdk_draw_rectangle (clist->clist_window, mbg_gc, TRUE,
1560                                             xcenter, rect->y,
1561                                             ctree->tree_indent, rect->height);
1562
1563                       if (next_level > GTK_CTREE_ROW (work)->level)
1564                         gdk_draw_line 
1565                           (clist->clist_window, ctree->lines_gc, 
1566                            xcenter, rect->y,
1567                            xcenter, rect->y + rect->height);
1568                       else
1569                         {
1570                           gdk_draw_line (clist->clist_window, ctree->lines_gc, 
1571                                          xcenter, clip_rectangle.y,
1572                                          xcenter, ycenter);
1573
1574                           in = MIN (ctree->tree_indent, 2 * TAB_SIZE);
1575
1576                           if (clist_row->state != GTK_STATE_SELECTED)
1577                             {
1578                               work2 = GTK_CTREE_ROW (work)->parent;
1579
1580                               if (work2 && GTK_CTREE_ROW (work2)->row.bg_set)
1581                                 {
1582                                   gdk_gc_set_foreground
1583                                     (clist->bg_gc,
1584                                      &(GTK_CTREE_ROW (work2)->row.background));
1585                                   
1586                                   gdk_draw_rectangle 
1587                                     (clist->clist_window, clist->bg_gc, TRUE,
1588                                      xcenter,
1589                                      ycenter,
1590                                      in / 2 + in % 2,
1591                                      row_rectangle.height / 2 + 1);
1592
1593                                   if (GTK_CTREE_ROW (work)->row.bg_set)
1594                                     gdk_gc_set_foreground
1595                                       (clist->bg_gc,
1596                                        &(GTK_CTREE_ROW (work)->row.background));
1597                                 }
1598                               else 
1599                                 gdk_draw_rectangle 
1600                                   (clist->clist_window,
1601                                    widget->style->bg_gc[GTK_STATE_PRELIGHT],
1602                                    TRUE,
1603                                    xcenter,
1604                                    ycenter,
1605                                    in / 2 + in % 2,
1606                                    row_rectangle.height / 2 + 1);
1607
1608                               gdk_draw_arc (clist->clist_window, mbg_gc,
1609                                             TRUE,
1610                                             xcenter, clip_rectangle.y,
1611                                             in, clist->row_height,
1612                                             180 * 64, 90 * 64);
1613                             }
1614
1615                           gdk_draw_arc (clist->clist_window, ctree->lines_gc,
1616                                         FALSE,
1617                                         xcenter, clip_rectangle.y,
1618                                         in, clist->row_height,
1619                                         180 * 64, 90 * 64);
1620                         }
1621                       work = GTK_CTREE_ROW (work)->parent;
1622                     }
1623
1624                   if (clist_row->state != GTK_STATE_SELECTED)
1625                     gdk_draw_rectangle
1626                       (clist->clist_window,
1627                        widget->style->bg_gc[GTK_STATE_PRELIGHT], TRUE,
1628                        clip_rectangle.x, row_rectangle.y,
1629                        TAB_SIZE, row_rectangle.height);
1630
1631                   xcenter = xdest + (ctree->tree_indent / 2);
1632                   
1633                   if (clist_row->bg_set)
1634                     gdk_gc_set_foreground 
1635                       (clist->bg_gc, &clist_row->background);
1636                   
1637                   if (((GtkCTreeRow *)clist_row)->is_leaf)
1638                     {
1639                       points[0].x = xdest + TAB_SIZE;
1640                       points[0].y = row_rectangle.y - 1;
1641                       
1642                       points[1].x = points[0].x - 4;
1643                       points[1].y = points[0].y;
1644                       
1645                       points[2].x = points[1].x - 2;
1646                       points[2].y = points[1].y + 3;
1647
1648                       points[3].x = points[2].x;
1649                       points[3].y = points[2].y + clist->row_height - 5;
1650
1651                       points[4].x = points[3].x + 2;
1652                       points[4].y = points[3].y + 3;
1653
1654                       points[5].x = points[4].x + 4;
1655                       points[5].y = points[4].y;
1656
1657                       if (clist_row->state != GTK_STATE_SELECTED)
1658                         gdk_draw_polygon (clist->clist_window, bg_gc, TRUE,
1659                                           points, 6);
1660
1661                       gdk_draw_lines (clist->clist_window, ctree->lines_gc,
1662                                       points, 6);
1663                     }
1664                   else 
1665                     {
1666                       if (clist_row->state != GTK_STATE_SELECTED)
1667                         gdk_draw_arc (clist->clist_window, bg_gc, TRUE,
1668                                       xdest, row_rectangle.y - 1,
1669                                       2 * TAB_SIZE, clist->row_height,
1670                                       90 * 64, 180 * 64);
1671
1672                       gdk_draw_arc (clist->clist_window, ctree->lines_gc,
1673                                     FALSE,
1674                                     xdest, row_rectangle.y - 1,
1675                                     2 * TAB_SIZE, clist->row_height,
1676                                     90 * 64, 180 * 64);
1677
1678                     }
1679
1680                   gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
1681                   gdk_gc_set_clip_rectangle (clist->bg_gc, NULL);
1682                   gdk_gc_set_clip_rectangle 
1683                     (widget->style->bg_gc[GTK_STATE_PRELIGHT], NULL);
1684                   
1685                   break;
1686                 default:
1687                   xcenter = xdest + (ctree->tree_indent / 2);
1688                   if (ctree->line_style == GTK_CTREE_LINES_DOTTED)
1689                     {
1690                       offset_x += abs ((clip_rectangle.x + clist->hoffset) %
1691                                        2); 
1692                       offset_y = abs ((clip_rectangle.y + clist->voffset) % 2);
1693                     }
1694                   
1695                   gdk_draw_line (clist->clist_window, ctree->lines_gc, 
1696                                  xcenter, clip_rectangle.y + offset_y, xcenter,
1697                                  (((GtkCTreeRow *)clist_row)->sibling) ?
1698                                  rect->y + rect->height : ycenter);     
1699                   
1700                   gdk_draw_line (clist->clist_window, ctree->lines_gc,
1701                                  xcenter + offset_x, ycenter,
1702                                  xcenter + PM_SIZE / 2 + 2, ycenter);
1703                   
1704                   work = ((GtkCTreeRow *)clist_row)->parent;
1705                   while (work)
1706                     {
1707                       xcenter -= ctree->tree_indent;
1708                       if (GTK_CTREE_ROW (work)->sibling)
1709                         gdk_draw_line (clist->clist_window, ctree->lines_gc, 
1710                                        xcenter, clip_rectangle.y + offset_y,
1711                                        xcenter, rect->y + rect->height);
1712                       work = GTK_CTREE_ROW (work)->parent;
1713                     }
1714                   gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
1715                   break;
1716                 }
1717           
1718               if (((GtkCTreeRow *)clist_row)->children)
1719                 {
1720                   if (clist_row->state == GTK_STATE_SELECTED)
1721                     {
1722                       if (clist_row->fg_set)
1723                         tgc = clist->fg_gc;
1724                       else
1725                         tgc = widget->style->fg_gc[GTK_STATE_NORMAL];
1726                       cgc = tgc;
1727                     }
1728                   else 
1729                     {
1730                       cgc = GTK_WIDGET 
1731                         (clist)->style->fg_gc[GTK_STATE_SELECTED];
1732                       tgc = fg_gc;
1733                     }
1734               
1735                   gdk_gc_set_clip_rectangle (cgc, rect);
1736
1737                   switch (ctree->line_style)
1738                     {
1739                     case GTK_CTREE_LINES_NONE:
1740                       if (!((GtkCTreeRow *)clist_row)->expanded)
1741                         {
1742                           points[0].x = xdest + xoffset + (PM_SIZE+2) / 6 + 2;
1743                           points[0].y = clip_rectangle.y + yoffset - 1;
1744                           points[1].x = points[0].x;
1745                           points[1].y = points[0].y + (PM_SIZE+2);
1746                           points[2].x = points[0].x + 2 * (PM_SIZE+2) / 3 - 1;
1747                           points[2].y = points[0].y + (PM_SIZE+2) / 2;
1748                         }
1749                       else
1750                         {
1751                           points[0].x = xdest + xoffset;
1752                           points[0].y = clip_rectangle.y + yoffset 
1753                             + (PM_SIZE+2) / 6;
1754                           points[1].x = points[0].x + (PM_SIZE+2);
1755                           points[1].y = points[0].y;
1756                           points[2].x = points[0].x + (PM_SIZE+2) / 2;
1757                           points[2].y = clip_rectangle.y + yoffset +
1758                             2 * (PM_SIZE+2) / 3;
1759                         }
1760
1761                       gdk_draw_polygon (clist->clist_window,
1762                                         GTK_WIDGET (clist)->style->
1763                                         fg_gc[GTK_STATE_SELECTED],
1764                                         TRUE, points, 3);
1765                       gdk_draw_polygon (clist->clist_window, tgc, FALSE, 
1766                                         points, 3);
1767                       break;
1768                     case GTK_CTREE_LINES_TABBED:
1769                       xcenter = xdest + PM_SIZE + 2;
1770                       gdk_draw_arc (clist->clist_window,
1771                                     GTK_WIDGET (clist)->style->
1772                                     fg_gc[GTK_STATE_SELECTED],
1773                                     TRUE,
1774                                     xcenter - PM_SIZE/2,
1775                                     ycenter - PM_SIZE/2,
1776                                     PM_SIZE, PM_SIZE, 0, 360 * 64);
1777
1778                       gdk_draw_line (clist->clist_window, tgc, 
1779                                      xcenter - 2,
1780                                      ycenter,
1781                                      xcenter + 2,
1782                                      ycenter);
1783                 
1784                       if (!((GtkCTreeRow *)clist_row)->expanded)
1785                         gdk_draw_line (clist->clist_window, tgc,
1786                                        xcenter, clip_rectangle.y + yoffset + 2,
1787                                        xcenter,
1788                                        clip_rectangle.y + yoffset + PM_SIZE-2);
1789                       break;
1790                     default:
1791                       gdk_draw_rectangle 
1792                         (clist->clist_window,
1793                          GTK_WIDGET (clist)->style->fg_gc[GTK_STATE_SELECTED],
1794                          TRUE,
1795                          xdest + xoffset, 
1796                          clip_rectangle.y + yoffset,
1797                          PM_SIZE, PM_SIZE);
1798                 
1799                       gdk_draw_rectangle (clist->clist_window, tgc, FALSE,
1800                                           xdest + xoffset, 
1801                                           clip_rectangle.y + yoffset,
1802                                           PM_SIZE, PM_SIZE);
1803                 
1804                       gdk_draw_line (clist->clist_window, tgc, 
1805                                      xdest + xoffset + 2, ycenter, 
1806                                      xdest + xoffset + PM_SIZE - 2, ycenter);
1807                 
1808                       if (!((GtkCTreeRow *)clist_row)->expanded)
1809                         {
1810                           xcenter = xdest + (ctree->tree_indent / 2);
1811                           gdk_draw_line (clist->clist_window, tgc,
1812                                          xcenter,
1813                                          clip_rectangle.y + yoffset + 2,
1814                                          xcenter,
1815                                          clip_rectangle.y + yoffset +
1816                                          PM_SIZE - 2);
1817                         }
1818                       break;
1819                     }
1820                   
1821                   gdk_gc_set_clip_rectangle (cgc, NULL);
1822                 }
1823           
1824               xdest += offset - clip_rectangle.x + ctree->tree_indent +
1825                 clist_row->cell[i].horizontal;
1826
1827               if (pixmap_width && xdest + pixmap_width >= rect->x && 
1828                   xdest <= rect->x + rect->width)
1829                 draw_pixmap = TRUE;
1830
1831               break;
1832
1833             case  GTK_JUSTIFY_RIGHT:
1834               offset_x = 0;
1835           
1836               xdest = clip_rectangle.x + clip_rectangle.width + xoffset - 1 -
1837                 (((GtkCTreeRow *) clist_row)->level - 1) * ctree->tree_indent;
1838             
1839               switch (ctree->line_style)
1840                 {
1841                 case  GTK_CTREE_LINES_NONE:
1842                   break;
1843                 case GTK_CTREE_LINES_TABBED:
1844                   xdest = clip_rectangle.x + clip_rectangle.width - 1
1845                     - (((GtkCTreeRow *) clist_row)->level - 1)
1846                     * ctree->tree_indent;
1847                   xcenter = xdest - TAB_SIZE;
1848
1849                   gdk_gc_set_clip_origin (clist->bg_gc, 0, 0);
1850                   gdk_gc_set_clip_rectangle (clist->bg_gc, rect);
1851
1852                   gdk_gc_set_clip_origin 
1853                     (widget->style->bg_gc[GTK_STATE_PRELIGHT], 0, 0);
1854                   gdk_gc_set_clip_rectangle 
1855                     (widget->style->bg_gc[GTK_STATE_PRELIGHT], rect);
1856
1857                   work = ((GtkCTreeRow *)clist_row)->parent;
1858                   next_level = ((GtkCTreeRow *)clist_row)->level;
1859
1860                   if (!(((GtkCTreeRow *)clist_row)->sibling ||
1861                         (((GtkCTreeRow *)clist_row)->children &&
1862                          ((GtkCTreeRow *)clist_row)->expanded)))
1863                     {
1864                       work2 = gtk_ctree_find_glist_ptr
1865                         (ctree, (GtkCTreeRow *) clist_row);
1866
1867                       if (GTK_CTREE_NODE_NEXT (work2))
1868                         next_level =
1869                           GTK_CTREE_ROW (GTK_CTREE_NODE_NEXT (work2))->level;
1870                       else
1871                         next_level = 0;
1872                     }
1873
1874                   while (work)
1875                     {
1876                       xcenter += ctree->tree_indent;
1877
1878                       if (GTK_CTREE_ROW(work)->row.bg_set)
1879                         {
1880                           gdk_gc_set_foreground
1881                             (clist->bg_gc,
1882                              &(GTK_CTREE_ROW (work)->row.background));
1883                           mbg_gc = clist->bg_gc;
1884                         }
1885                       else
1886                         mbg_gc = widget->style->bg_gc[GTK_STATE_PRELIGHT];
1887
1888                       if (clist_row->state != GTK_STATE_SELECTED)
1889                         gdk_draw_rectangle (clist->clist_window,
1890                                             mbg_gc, TRUE,
1891                                             xcenter - ctree->tree_indent + 1,
1892                                             rect->y,
1893                                             ctree->tree_indent,
1894                                             rect->height);
1895
1896                       if (next_level > GTK_CTREE_ROW (work)->level)
1897                         gdk_draw_line 
1898                           (clist->clist_window, ctree->lines_gc, 
1899                            xcenter, rect->y,
1900                            xcenter, rect->y + rect->height);
1901                       else
1902                         {
1903                           gdk_draw_line (clist->clist_window, ctree->lines_gc, 
1904                                          xcenter, clip_rectangle.y,
1905                                          xcenter, ycenter);
1906
1907                           in = MIN (ctree->tree_indent, 2 * TAB_SIZE);
1908
1909                           if (clist_row->state != GTK_STATE_SELECTED)
1910                             {
1911                               work2 = GTK_CTREE_ROW (work)->parent;
1912
1913                               if (work2 && GTK_CTREE_ROW (work2)->row.bg_set)
1914                                 {
1915                                   gdk_gc_set_foreground
1916                                     (clist->bg_gc,
1917                                      &(GTK_CTREE_ROW (work2)->row.background));
1918                                   
1919                                   gdk_draw_rectangle 
1920                                     (clist->clist_window, clist->bg_gc, TRUE,
1921                                      xcenter + 1 - in / 2 - in % 2,
1922                                      ycenter,
1923                                      in / 2 + in % 2,
1924                                      row_rectangle.height / 2 + 1);
1925
1926                                   if (GTK_CTREE_ROW (work)->row.bg_set)
1927                                     gdk_gc_set_foreground
1928                                       (clist->bg_gc,
1929                                        &(GTK_CTREE_ROW(work)->row.background));
1930                                 }
1931                               else 
1932                                 gdk_draw_rectangle 
1933                                   (clist->clist_window,
1934                                    widget->style->bg_gc[GTK_STATE_PRELIGHT],
1935                                    TRUE,
1936                                    xcenter + 1 - in / 2 - in % 2,
1937                                    ycenter,
1938                                    in / 2 + in % 2,
1939                                    row_rectangle.height / 2 + 1);
1940
1941                               gdk_draw_arc (clist->clist_window, mbg_gc, TRUE,
1942                                             xcenter - in, clip_rectangle.y,
1943                                             in, clist->row_height,
1944                                             270 * 64, 90 * 64);
1945                             }
1946
1947                           gdk_draw_arc (clist->clist_window, ctree->lines_gc,
1948                                         FALSE,
1949                                         xcenter - in, clip_rectangle.y,
1950                                         in, clist->row_height,
1951                                         270 * 64, 90 * 64);
1952                         }
1953
1954                       work = GTK_CTREE_ROW (work)->parent;
1955                     }
1956
1957                   if (clist_row->state != GTK_STATE_SELECTED)
1958                     gdk_draw_rectangle
1959                       (clist->clist_window,
1960                        widget->style->bg_gc[GTK_STATE_PRELIGHT], TRUE,
1961                        xcenter + 1, row_rectangle.y,
1962                        TAB_SIZE, row_rectangle.height);
1963
1964                   xcenter = xdest - (ctree->tree_indent / 2);
1965                   
1966                   if (clist_row->bg_set)
1967                     gdk_gc_set_foreground 
1968                       (clist->bg_gc, &clist_row->background);
1969                   
1970                   if (((GtkCTreeRow *)clist_row)->is_leaf)
1971                     {
1972                       points[0].x = xdest - TAB_SIZE;
1973                       points[0].y = row_rectangle.y - 1;
1974                       
1975                       points[1].x = points[0].x + 4;
1976                       points[1].y = points[0].y;
1977                       
1978                       points[2].x = points[1].x + 2;
1979                       points[2].y = points[1].y + 3;
1980
1981                       points[3].x = points[2].x;
1982                       points[3].y = points[2].y + clist->row_height - 5;
1983
1984                       points[4].x = points[3].x - 2;
1985                       points[4].y = points[3].y + 3;
1986
1987                       points[5].x = points[4].x - 4;
1988                       points[5].y = points[4].y;
1989
1990                       if (clist_row->state != GTK_STATE_SELECTED)
1991                         gdk_draw_polygon (clist->clist_window, bg_gc, TRUE,
1992                                           points, 6);
1993
1994                       gdk_draw_lines (clist->clist_window, ctree->lines_gc,
1995                                       points, 6);
1996                     }
1997                   else 
1998                     {
1999                       if (clist_row->state != GTK_STATE_SELECTED)
2000                         gdk_draw_arc (clist->clist_window, bg_gc, TRUE,
2001                                       xdest - 2 * TAB_SIZE,
2002                                       row_rectangle.y - 1,
2003                                       2 * TAB_SIZE, clist->row_height,
2004                                       270 * 64, 180 * 64);
2005
2006                       gdk_draw_arc (clist->clist_window, ctree->lines_gc,
2007                                     FALSE,
2008                                     xdest - 2 * TAB_SIZE,
2009                                     row_rectangle.y - 1,
2010                                     2 * TAB_SIZE, clist->row_height,
2011                                     270 * 64, 180 * 64);
2012                     }
2013
2014                   gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
2015                   gdk_gc_set_clip_rectangle (clist->bg_gc, NULL);
2016                   gdk_gc_set_clip_rectangle 
2017                     (widget->style->bg_gc[GTK_STATE_PRELIGHT], NULL);
2018                   
2019                   break;
2020                 default:
2021                   xcenter = xdest - (ctree->tree_indent / 2);
2022                   if (ctree->line_style == GTK_CTREE_LINES_DOTTED)
2023                     {
2024                       offset_x += abs ((clip_rectangle.x + clist->hoffset) % 
2025                                        2); 
2026                       offset_y = abs ((clip_rectangle.y + clist->voffset) % 2);
2027                     }
2028                   
2029                   gdk_draw_line (clist->clist_window, ctree->lines_gc, 
2030                                  xcenter,  clip_rectangle.y + offset_y,
2031                                  xcenter,
2032                                  (((GtkCTreeRow *)clist_row)->sibling) ?
2033                                  rect->y + rect->height : ycenter);
2034                   
2035                   gdk_draw_line (clist->clist_window, ctree->lines_gc, 
2036                                  xcenter - offset_x, ycenter, 
2037                                  xcenter - PM_SIZE / 2 - 2, ycenter);
2038                   
2039                   work = ((GtkCTreeRow *)clist_row)->parent;
2040                   while (work)
2041                     {
2042                       xcenter += ctree->tree_indent;
2043                       if (GTK_CTREE_ROW (work)->sibling)
2044                         gdk_draw_line (clist->clist_window, ctree->lines_gc,
2045                                        xcenter, clip_rectangle.y - offset_y,
2046                                        xcenter, rect->y + rect->height);
2047                       work = GTK_CTREE_ROW (work)->parent;
2048                     }
2049                   gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
2050                 }
2051
2052           
2053               if (((GtkCTreeRow *)clist_row)->children)
2054                 {
2055                   if (clist_row->state == GTK_STATE_SELECTED)
2056                     {
2057                       if (clist_row->fg_set)
2058                         tgc = clist->fg_gc;
2059                       else
2060                         tgc = widget->style->fg_gc[GTK_STATE_NORMAL];
2061                       cgc = tgc;
2062                     }
2063                   else 
2064                     {
2065                       cgc = 
2066                         GTK_WIDGET(clist)->style->fg_gc[GTK_STATE_SELECTED];
2067                       tgc = fg_gc;
2068                     }
2069               
2070                   gdk_gc_set_clip_rectangle (cgc, rect);
2071               
2072                   switch (ctree->line_style)
2073                     {
2074                     case GTK_CTREE_LINES_NONE:
2075                       if (!((GtkCTreeRow *)clist_row)->expanded)
2076                         {
2077                           points[0].x = xdest - xoffset - (PM_SIZE+2) / 6 - 2;
2078                           points[0].y = clip_rectangle.y + yoffset - 1;
2079                           points[1].x = points[0].x;
2080                           points[1].y = points[0].y + (PM_SIZE+2);
2081                           points[2].x = points[0].x - 2 * (PM_SIZE+2) / 3 + 1;
2082                           points[2].y = points[0].y + (PM_SIZE+2) / 2;
2083                         }
2084                       else
2085                         {
2086                           points[0].x = xdest - xoffset;
2087                           points[0].y = clip_rectangle.y + yoffset + 
2088                             (PM_SIZE+2) / 6;
2089                           points[1].x = points[0].x - (PM_SIZE+2);
2090                           points[1].y = points[0].y;
2091                           points[2].x = points[0].x - (PM_SIZE+2) / 2;
2092                           points[2].y = clip_rectangle.y + yoffset +
2093                             2 * (PM_SIZE+2) / 3;
2094                         }
2095
2096                       gdk_draw_polygon (clist->clist_window,
2097                                         GTK_WIDGET (clist)->style->
2098                                         fg_gc[GTK_STATE_SELECTED],
2099                                         TRUE, points, 3);
2100                       gdk_draw_polygon (clist->clist_window, tgc, FALSE, 
2101                                         points, 3);
2102                       break;
2103                     case GTK_CTREE_LINES_TABBED:
2104                       xcenter = xdest - PM_SIZE - 2;
2105
2106                       gdk_draw_arc (clist->clist_window,
2107                                     GTK_WIDGET (clist)->style->
2108                                     fg_gc[GTK_STATE_SELECTED],
2109                                     TRUE,
2110                                     xcenter - PM_SIZE/2,
2111                                     ycenter - PM_SIZE/2,
2112                                     PM_SIZE, PM_SIZE, 0, 360 * 64);
2113
2114                       gdk_draw_line (clist->clist_window, tgc, 
2115                                      xcenter - 2,
2116                                      ycenter,
2117                                      xcenter + 2,
2118                                      ycenter);
2119                 
2120                       if (!((GtkCTreeRow *)clist_row)->expanded)
2121                         {
2122                           gdk_draw_line (clist->clist_window, tgc, xcenter,
2123                                          clip_rectangle.y + yoffset + 2,
2124                                          xcenter, clip_rectangle.y + yoffset
2125                                          + PM_SIZE - 2);
2126                         }
2127                       break;
2128                     default:
2129                       gdk_draw_rectangle (clist->clist_window, 
2130                                           GTK_WIDGET(clist)->style->
2131                                           fg_gc[GTK_STATE_SELECTED], TRUE, 
2132                                           xdest - xoffset - PM_SIZE, 
2133                                           clip_rectangle.y + yoffset,
2134                                           PM_SIZE, PM_SIZE);
2135                       
2136                       gdk_draw_rectangle (clist->clist_window, tgc, FALSE,
2137                                           xdest - xoffset - PM_SIZE, 
2138                                           clip_rectangle.y + yoffset,
2139                                           PM_SIZE, PM_SIZE);
2140                   
2141                       gdk_draw_line (clist->clist_window, tgc, 
2142                                      xdest - xoffset - 2, ycenter,
2143                                      xdest - xoffset - PM_SIZE + 2, ycenter);
2144                 
2145                       if (!((GtkCTreeRow *)clist_row)->expanded)
2146                         {
2147                           xcenter = xdest - (ctree->tree_indent / 2);
2148                           gdk_draw_line (clist->clist_window, tgc, xcenter, 
2149                                          clip_rectangle.y + yoffset + 2,
2150                                          xcenter, clip_rectangle.y + yoffset
2151                                          + PM_SIZE - 2);
2152                         }
2153                     }
2154                   gdk_gc_set_clip_rectangle (cgc, NULL);
2155                 }
2156               
2157               xdest -=  (ctree->tree_indent + pixmap_width 
2158                          + clist_row->cell[i].horizontal);
2159
2160               if (pixmap_width && xdest + pixmap_width >= rect->x && 
2161                   xdest <= rect->x + rect->width)
2162                 draw_pixmap = TRUE;
2163               break;
2164             default :
2165               break;
2166             }
2167
2168           if (draw_pixmap)
2169             {
2170               if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
2171                 {
2172                   gdk_gc_set_clip_mask 
2173                     (fg_gc, GTK_CELL_PIXTEXT (clist_row->cell[i])->mask);
2174                   gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2175                 }
2176               
2177               if (xdest < clip_rectangle.x)
2178                 {
2179                   xsrc = clip_rectangle.x - xdest;
2180                   pixmap_width -= xsrc;
2181                   xdest = clip_rectangle.x;
2182                 }
2183               
2184               if (xdest + pixmap_width >
2185                   clip_rectangle.x + clip_rectangle.width)
2186                 pixmap_width =
2187                   (clip_rectangle.x + clip_rectangle.width) - xdest;
2188               
2189               if (ydest < clip_rectangle.y)
2190                 {
2191                   ysrc = clip_rectangle.y - ydest;
2192                   height -= ysrc;
2193                   ydest = clip_rectangle.y;
2194                 }
2195                   
2196               if (ydest + height > clip_rectangle.y + clip_rectangle.height)
2197                 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
2198
2199               gdk_draw_pixmap (clist->clist_window, fg_gc,
2200                                GTK_CELL_PIXTEXT 
2201                                (clist_row->cell[i])->pixmap,
2202                                xsrc, ysrc, xdest, ydest, 
2203                                pixmap_width, height);
2204             }
2205
2206           if (string_width)
2207             { 
2208               gint delta;
2209                   
2210               if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
2211                 xdest -= (GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing +
2212                           string_width);
2213               else
2214                 xdest += (GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing +
2215                           pixmap_width);
2216
2217               delta = CELL_SPACING - (rect->y - clip_rectangle.y);
2218               if (delta > 0)
2219                 {
2220                   rect->y += delta;
2221                   rect->height -= delta;
2222                 }
2223                   
2224               gdk_gc_set_clip_rectangle (fg_gc, rect);
2225               
2226               gdk_draw_string 
2227                 (clist->clist_window, widget->style->font, fg_gc, xdest,
2228                  row_rectangle.y + clist->row_center_offset +
2229                  clist_row->cell[i].vertical,
2230                  GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2231             }
2232           gdk_gc_set_clip_rectangle (fg_gc, NULL);
2233         }
2234       else
2235         {
2236           switch (clist_row->cell[i].type)
2237             {
2238             case GTK_CELL_EMPTY:
2239               continue;
2240               break;
2241               
2242             case GTK_CELL_TEXT:
2243               gdk_gc_set_clip_rectangle (fg_gc, rect);
2244               
2245               gdk_draw_string (clist->clist_window, 
2246                                widget->style->font,
2247                                fg_gc,
2248                                offset + clist_row->cell[i].horizontal,
2249                                row_rectangle.y + clist->row_center_offset + 
2250                                clist_row->cell[i].vertical,
2251                                GTK_CELL_TEXT (clist_row->cell[i])->text);
2252               
2253               gdk_gc_set_clip_rectangle (fg_gc, NULL);
2254               break;
2255
2256             case GTK_CELL_PIXMAP:
2257               xsrc = 0;
2258               ysrc = 0;
2259               xdest = offset + clist_row->cell[i].horizontal;
2260               ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) 
2261                 - height / 2 + clist_row->cell[i].vertical;
2262
2263               if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
2264                 {
2265                   gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXMAP 
2266                                         (clist_row->cell[i])->mask);
2267                   gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2268                 }
2269
2270               if (xdest < clip_rectangle.x)
2271                 {
2272                   xsrc = clip_rectangle.x - xdest;
2273                   pixmap_width -= xsrc;
2274                   xdest = clip_rectangle.x;
2275                 }
2276               
2277               if (xdest + pixmap_width > 
2278                   clip_rectangle.x + clip_rectangle.width)
2279                 pixmap_width = (clip_rectangle.x + clip_rectangle.width) -
2280                   xdest;
2281               
2282               if (ydest < clip_rectangle.y)
2283                 {
2284                   ysrc = clip_rectangle.y - ydest;
2285                   height -= ysrc;
2286                   ydest = clip_rectangle.y;
2287                 }
2288
2289               if (ydest + height > clip_rectangle.y + clip_rectangle.height)
2290                 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
2291
2292               gdk_draw_pixmap (clist->clist_window, fg_gc,
2293                                GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
2294                                xsrc, ysrc, xdest, ydest, pixmap_width, height);
2295
2296               if (GTK_CELL_PIXMAP (clist_row->cell[i])->mask)
2297                 {
2298                   gdk_gc_set_clip_origin (fg_gc, 0, 0);
2299                   gdk_gc_set_clip_mask (fg_gc, NULL);
2300                 }
2301               break;
2302
2303             case GTK_CELL_PIXTEXT:
2304               /* draw the pixmap */
2305               xsrc = 0;
2306               ysrc = 0;
2307               xdest = offset + clist_row->cell[i].horizontal;
2308               ydest = (clip_rectangle.y + (clip_rectangle.height / 2)) 
2309                 - height / 2 + clist_row->cell[i].vertical;
2310               
2311               if (GTK_CELL_PIXTEXT (clist_row->cell[i])->mask)
2312                 {
2313                   gdk_gc_set_clip_mask (fg_gc, GTK_CELL_PIXTEXT
2314                                         (clist_row->cell[i])->mask);
2315                   gdk_gc_set_clip_origin (fg_gc, xdest, ydest);
2316                 }
2317
2318               if (xdest < clip_rectangle.x)
2319                 {
2320                   xsrc = clip_rectangle.x - xdest;
2321                   pixmap_width -= xsrc;
2322                   xdest = clip_rectangle.x;
2323                 }
2324
2325               if (xdest + pixmap_width >
2326                   clip_rectangle.x + clip_rectangle.width)
2327                 pixmap_width = (clip_rectangle.x + clip_rectangle.width)
2328                   - xdest;
2329
2330               if (ydest < clip_rectangle.y)
2331                 {
2332                   ysrc = clip_rectangle.y - ydest;
2333                   height -= ysrc;
2334                   ydest = clip_rectangle.y;
2335                 }
2336
2337               if (ydest + height > clip_rectangle.y + clip_rectangle.height)
2338                 height = (clip_rectangle.y + clip_rectangle.height) - ydest;
2339
2340               gdk_draw_pixmap (clist->clist_window, fg_gc,
2341                                GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
2342                                xsrc, ysrc, xdest, ydest, pixmap_width, height);
2343               
2344               gdk_gc_set_clip_origin (fg_gc, 0, 0);
2345               
2346               xdest += pixmap_width + GTK_CELL_PIXTEXT
2347                 (clist_row->cell[i])->spacing;
2348           
2349               /* draw the string */
2350               gdk_gc_set_clip_rectangle (fg_gc, rect);
2351
2352               gdk_draw_string (clist->clist_window, widget->style->font, fg_gc,
2353                                xdest, 
2354                                row_rectangle.y + clist->row_center_offset + 
2355                                clist_row->cell[i].vertical,
2356                                GTK_CELL_PIXTEXT (clist_row->cell[i])->text);
2357               
2358               gdk_gc_set_clip_rectangle (fg_gc, NULL);
2359               
2360               break;
2361
2362             case GTK_CELL_WIDGET:
2363               /* unimplemented */
2364               continue;
2365               break;
2366
2367             default:
2368               continue;
2369               break;
2370             }
2371         }
2372     }
2373   if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget))
2374     {
2375       if (area)
2376         {
2377           if (gdk_rectangle_intersect (area, &row_rectangle,
2378                                        &intersect_rectangle))
2379             {
2380               gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
2381               gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
2382                                   row_rectangle.x, row_rectangle.y,
2383                                   row_rectangle.width - 1,
2384                                   row_rectangle.height - 1);
2385               gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
2386             }
2387         }
2388       else
2389         gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
2390                             row_rectangle.x, row_rectangle.y,
2391                             row_rectangle.width - 1, row_rectangle.height - 1);
2392     }
2393 }
2394
2395 static void
2396 tree_draw_node (GtkCTree     *ctree, 
2397                 GtkCTreeNode *node)
2398 {
2399   GtkCList *clist;
2400   
2401   clist = GTK_CLIST (ctree);
2402
2403   if (!GTK_CLIST_FROZEN (clist) && gtk_ctree_is_visible (ctree, node))
2404     {
2405       GtkCTreeNode *work;
2406       gint num = 0;
2407       
2408       work = GTK_CTREE_NODE (clist->row_list);
2409       while (work != node)
2410         {
2411           work = GTK_CTREE_NODE_NEXT (work);
2412           num++;
2413         }
2414       if (gtk_clist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2415         GTK_CLIST_CLASS_FW (clist)->draw_row
2416           (clist, NULL, num, GTK_CLIST_ROW ((GList *) node));
2417     }
2418 }
2419
2420 static GtkCTreeNode *
2421 gtk_ctree_last_visible (GtkCTree     *ctree,
2422                         GtkCTreeNode *node)
2423 {
2424   GtkCTreeNode *work;
2425   
2426   if (!node)
2427     return NULL;
2428
2429   work = GTK_CTREE_ROW (node)->children;
2430
2431   if (!work || !GTK_CTREE_ROW (node)->expanded)
2432     return node;
2433
2434   while (GTK_CTREE_ROW (work)->sibling)
2435     work = GTK_CTREE_ROW (work)->sibling;
2436
2437   return gtk_ctree_last_visible (ctree, work);
2438 }
2439
2440 static void
2441 gtk_ctree_link (GtkCTree     *ctree,
2442                 GtkCTreeNode *node,
2443                 GtkCTreeNode *parent,
2444                 GtkCTreeNode *sibling,
2445                 gboolean      update_focus_row)
2446 {
2447   GtkCList *clist;
2448   GtkCTreeNode *list_end;
2449   gboolean visible = FALSE;
2450   gint rows = 0;
2451   
2452   g_return_if_fail (!sibling || GTK_CTREE_ROW (sibling)->parent == parent);
2453   g_return_if_fail (node != NULL);
2454   g_return_if_fail (node != sibling);
2455   g_return_if_fail (node != parent);
2456
2457   clist = GTK_CLIST (ctree);
2458
2459   if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED)
2460     {
2461       if (clist->anchor != -1)
2462         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2463       
2464       g_list_free (clist->undo_selection);
2465       g_list_free (clist->undo_unselection);
2466       clist->undo_selection = NULL;
2467       clist->undo_unselection = NULL;
2468     }
2469
2470   for (rows = 1, list_end = node; GTK_CTREE_NODE_NEXT (list_end);
2471        list_end = GTK_CTREE_NODE_NEXT (list_end))
2472     rows++;
2473
2474   GTK_CTREE_ROW (node)->parent = parent;
2475   GTK_CTREE_ROW (node)->sibling = sibling;
2476
2477   if (!parent || (parent && (gtk_ctree_is_visible (ctree, parent) &&
2478                              GTK_CTREE_ROW (parent)->expanded)))
2479     {
2480       visible = TRUE;
2481       clist->rows += rows;
2482     }
2483       
2484
2485   if (sibling)
2486     {
2487       GtkCTreeNode *work;
2488
2489       if (parent)
2490         work = GTK_CTREE_ROW (parent)->children;
2491       else
2492         work = GTK_CTREE_NODE (clist->row_list);
2493       if (work != sibling)
2494         {
2495           while (GTK_CTREE_ROW (work)->sibling != sibling)
2496             work = GTK_CTREE_ROW (work)->sibling;
2497           GTK_CTREE_ROW (work)->sibling = node;
2498         }
2499
2500       if (sibling == GTK_CTREE_NODE (clist->row_list))
2501         GTK_CTREE_NODE (clist->row_list) = node;
2502       if (GTK_CTREE_NODE_PREV (sibling) &&
2503           GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling)
2504         GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) = node;
2505       
2506       GTK_CTREE_NODE_PREV (node) = GTK_CTREE_NODE_PREV (sibling);
2507       GTK_CTREE_NODE_NEXT (list_end) = sibling;
2508       GTK_CTREE_NODE_PREV (sibling) = list_end;
2509       if (parent && GTK_CTREE_ROW (parent)->children == sibling)
2510         GTK_CTREE_ROW (parent)->children = node;
2511     }
2512   else
2513     {
2514       GtkCTreeNode *work;
2515
2516       if (parent)
2517         work = GTK_CTREE_ROW (parent)->children;
2518       else
2519         work = GTK_CTREE_NODE (clist->row_list);
2520
2521       if (work)
2522         {
2523           /* find sibling */
2524           while (GTK_CTREE_ROW (work)->sibling)
2525             work = GTK_CTREE_ROW (work)->sibling;
2526           GTK_CTREE_ROW (work)->sibling = node;
2527           
2528           /* find last visible child of sibling */
2529           work = gtk_ctree_last_visible (ctree, work);
2530           
2531           GTK_CTREE_NODE_NEXT (list_end) = GTK_CTREE_NODE_NEXT (work);
2532           if (GTK_CTREE_NODE_NEXT (work))
2533             GTK_CTREE_NODE_PREV (GTK_CTREE_NODE_NEXT (work)) = list_end;
2534           GTK_CTREE_NODE_NEXT (work) = node;
2535           GTK_CTREE_NODE_PREV (node) = work;
2536         }
2537       else
2538         {
2539           if (parent)
2540             {
2541               GTK_CTREE_ROW (parent)->children = node;
2542               GTK_CTREE_NODE_PREV (node) = parent;
2543               if (GTK_CTREE_ROW (parent)->expanded)
2544                 {
2545                   GTK_CTREE_NODE_NEXT (list_end)= GTK_CTREE_NODE_NEXT (parent);
2546                   if (GTK_CTREE_NODE_NEXT(parent))
2547                     GTK_CTREE_NODE_PREV (GTK_CTREE_NODE_NEXT (parent)) =
2548                       list_end;
2549                   GTK_CTREE_NODE_NEXT (parent) = node;
2550                 }
2551               else
2552                 GTK_CTREE_NODE_NEXT (list_end) = NULL;
2553             }
2554           else
2555             {
2556               GTK_CTREE_NODE (clist->row_list) = node;
2557               GTK_CTREE_NODE_PREV (node) = NULL;
2558               GTK_CTREE_NODE_NEXT (list_end) = NULL;
2559             }
2560         }
2561     }
2562
2563   gtk_ctree_pre_recursive (ctree, node, tree_update_level, NULL); 
2564
2565   if (clist->row_list_end == NULL ||
2566       GTK_CTREE_NODE (clist->row_list_end->next) == node)
2567     GTK_CTREE_NODE (clist->row_list_end) = list_end;
2568
2569   if (visible && update_focus_row)
2570     {
2571       gint pos;
2572           
2573       pos = g_list_position (clist->row_list, (GList *)node);
2574   
2575       if (pos <= clist->focus_row)
2576         {
2577           clist->focus_row += rows;
2578           clist->undo_anchor = clist->focus_row;
2579         }
2580     }
2581 }
2582
2583 static void
2584 gtk_ctree_unlink (GtkCTree     *ctree, 
2585                   GtkCTreeNode *node,
2586                   gboolean      update_focus_row)
2587 {
2588   GtkCList *clist;
2589   gint rows;
2590   gint level;
2591   gint visible;
2592   GtkCTreeNode *work;
2593   GtkCTreeNode *parent;
2594
2595   g_return_if_fail (ctree != NULL);
2596   g_return_if_fail (GTK_IS_CTREE (ctree));
2597   g_return_if_fail (node != NULL);
2598
2599   clist = GTK_CLIST (ctree);
2600   
2601   if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED)
2602     {
2603       if (clist->anchor != -1)
2604         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2605       
2606       g_list_free (clist->undo_selection);
2607       g_list_free (clist->undo_unselection);
2608       clist->undo_selection = NULL;
2609       clist->undo_unselection = NULL;
2610     }
2611
2612   visible = gtk_ctree_is_visible (ctree, node);
2613
2614   /* clist->row_list_end unlinked ? */
2615   if (visible &&
2616       (GTK_CTREE_NODE_NEXT (node) == NULL ||
2617        (GTK_CTREE_ROW (node)->children &&
2618         gtk_ctree_is_ancestor (ctree, node,
2619                                GTK_CTREE_NODE (clist->row_list_end)))))
2620     GTK_CTREE_NODE (clist->row_list_end) = GTK_CTREE_NODE_PREV (node);
2621
2622   /* update list */
2623   rows = 0;
2624   level = GTK_CTREE_ROW (node)->level;
2625   work = GTK_CTREE_NODE_NEXT (node);
2626   while (work && GTK_CTREE_ROW (work)->level > level)
2627     {
2628       work = GTK_CTREE_NODE_NEXT (work);
2629       rows++;
2630     }
2631
2632   if (visible)
2633     {
2634       clist->rows -= (rows + 1);
2635
2636       if (update_focus_row)
2637         {
2638           gint pos;
2639           
2640           pos = g_list_position (clist->row_list, (GList *)node);
2641           if (pos + rows + 1 < clist->focus_row)
2642             clist->focus_row -= (rows + 1);
2643           else if (pos <= clist->focus_row)
2644             clist->focus_row = pos - 1;
2645           clist->undo_anchor = clist->focus_row;
2646         }
2647     }
2648
2649   if (work)
2650     {
2651       GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (work)) = NULL;
2652       GTK_CTREE_NODE_PREV (work) = GTK_CTREE_NODE_PREV (node);
2653     }
2654
2655   if (GTK_CTREE_NODE_PREV (node) &&
2656       GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node)
2657     GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) = work;
2658
2659   /* update tree */
2660   parent = GTK_CTREE_ROW (node)->parent;
2661   if (parent)
2662     {
2663       if (GTK_CTREE_ROW (parent)->children == node)
2664         {
2665           GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
2666           if (!GTK_CTREE_ROW (parent)->children && 
2667               GTK_CTREE_ROW (parent)->pixmap_closed)
2668             {
2669               GTK_CTREE_ROW (parent)->expanded = FALSE;
2670               GTK_CELL_PIXTEXT 
2671                 (GTK_CTREE_ROW(parent)->row.cell[ctree->tree_column])->pixmap =
2672                 GTK_CTREE_ROW (parent)->pixmap_closed;
2673               GTK_CELL_PIXTEXT 
2674                 (GTK_CTREE_ROW (parent)->row.cell[ctree->tree_column])->mask = 
2675                 GTK_CTREE_ROW (parent)->mask_closed;
2676             }
2677         }
2678       else
2679         {
2680           GtkCTreeNode *sibling;
2681
2682           sibling = GTK_CTREE_ROW (parent)->children;
2683           while (GTK_CTREE_ROW (sibling)->sibling != node)
2684             sibling = GTK_CTREE_ROW (sibling)->sibling;
2685           GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
2686         }
2687     }
2688   else
2689     {
2690       if (GTK_CTREE_NODE (clist->row_list) == node)
2691         GTK_CTREE_NODE (clist->row_list) = GTK_CTREE_ROW (node)->sibling;
2692       else
2693         {
2694           GtkCTreeNode *sibling;
2695
2696           sibling = GTK_CTREE_NODE (clist->row_list);
2697           while (GTK_CTREE_ROW (sibling)->sibling != node)
2698             sibling = GTK_CTREE_ROW (sibling)->sibling;
2699           GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
2700         }
2701     }
2702 }
2703
2704 static void
2705 real_tree_move (GtkCTree     *ctree,
2706                 GtkCTreeNode *node,
2707                 GtkCTreeNode *new_parent, 
2708                 GtkCTreeNode *new_sibling)
2709 {
2710   GtkCList *clist;
2711   GtkCTreeNode *work;
2712   gboolean thaw = FALSE;
2713
2714   g_return_if_fail (ctree != NULL);
2715   g_return_if_fail (node != NULL);
2716   g_return_if_fail (!new_sibling || 
2717                     GTK_CTREE_ROW (new_sibling)->parent == new_parent);
2718
2719   if (new_parent && GTK_CTREE_ROW (new_parent)->is_leaf)
2720     return;
2721
2722   /* new_parent != child of child */
2723   for (work = new_parent; work; work = GTK_CTREE_ROW (work)->parent)
2724     if (work == node)
2725       return;
2726
2727   clist = GTK_CLIST (ctree);
2728
2729   if (clist->selection_mode == GTK_SELECTION_EXTENDED)
2730     {
2731       if (clist->anchor != -1)
2732         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2733       
2734       g_list_free (clist->undo_selection);
2735       g_list_free (clist->undo_unselection);
2736       clist->undo_selection = NULL;
2737       clist->undo_unselection = NULL;
2738     }
2739
2740   if (GTK_CLIST_AUTO_SORT (clist))
2741     {
2742       if (new_parent == GTK_CTREE_ROW (node)->parent)
2743         return;
2744       
2745       if (new_parent)
2746         new_sibling = GTK_CTREE_ROW (new_parent)->children;
2747       else
2748         new_sibling = GTK_CTREE_NODE (clist->row_list);
2749
2750       while (new_sibling && clist->compare (clist, node, new_sibling) > 0)
2751         new_sibling = GTK_CTREE_ROW (new_sibling)->sibling;
2752     }
2753
2754   if (new_parent == GTK_CTREE_ROW (node)->parent && 
2755       new_sibling == GTK_CTREE_ROW (node)->sibling)
2756     return;
2757
2758   if (!GTK_CLIST_FROZEN (clist))
2759     {
2760       gtk_clist_freeze (clist);
2761       thaw = TRUE;
2762     }
2763
2764   work = NULL;
2765   if (gtk_ctree_is_visible (ctree, node) ||
2766       gtk_ctree_is_visible (ctree, new_sibling))
2767     work = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
2768       
2769   gtk_ctree_unlink (ctree, node, FALSE);
2770   gtk_ctree_link (ctree, node, new_parent, new_sibling, FALSE);
2771   
2772   if (work)
2773     {
2774       while (work &&  !gtk_ctree_is_visible (ctree, work))
2775         work = GTK_CTREE_ROW (work)->parent;
2776       clist->focus_row = g_list_position (clist->row_list, (GList *)work);
2777       clist->undo_anchor = clist->focus_row;
2778     }
2779
2780   if (thaw)
2781     gtk_clist_thaw (clist);
2782 }
2783
2784 static void
2785 change_focus_row_expansion (GtkCTree          *ctree,
2786                             GtkCTreeExpansionType action)
2787 {
2788   GtkCList *clist;
2789   GtkCTreeNode *node;
2790
2791   g_return_if_fail (ctree != NULL);
2792   g_return_if_fail (GTK_IS_CTREE (ctree));
2793
2794   clist = GTK_CLIST (ctree);
2795
2796   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (ctree))
2797     return;
2798   
2799   if (!(node =
2800         GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
2801       GTK_CTREE_ROW (node)->is_leaf || !(GTK_CTREE_ROW (node)->children))
2802     return;
2803
2804   switch (action)
2805     {
2806     case GTK_CTREE_EXPANSION_EXPAND:
2807       gtk_ctree_expand (ctree, node);
2808       break;
2809     case GTK_CTREE_EXPANSION_EXPAND_RECURSIVE:
2810       gtk_ctree_expand_recursive (ctree, node);
2811       break;
2812     case GTK_CTREE_EXPANSION_COLLAPSE:
2813       gtk_ctree_collapse (ctree, node);
2814       break;
2815     case GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE:
2816       gtk_ctree_collapse_recursive (ctree, node);
2817       break;
2818     case GTK_CTREE_EXPANSION_TOGGLE:
2819       gtk_ctree_toggle_expansion (ctree, node);
2820       break;
2821     case GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE:
2822       gtk_ctree_toggle_expansion_recursive (ctree, node);
2823       break;
2824     }
2825 }
2826
2827 static void 
2828 real_tree_expand (GtkCTree     *ctree,
2829                   GtkCTreeNode *node)
2830 {
2831   GtkCList *clist;
2832   GtkCTreeNode *work;
2833   gint level;
2834
2835   g_return_if_fail (ctree != NULL);
2836   g_return_if_fail (GTK_IS_CTREE (ctree));
2837
2838   if (!node || GTK_CTREE_ROW (node)->expanded)
2839     return;
2840
2841   clist = GTK_CLIST (ctree);
2842   
2843   if (clist->selection_mode == GTK_SELECTION_EXTENDED && clist->anchor >= 0)
2844     GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2845
2846   GTK_CTREE_ROW (node)->expanded = TRUE;
2847   level = GTK_CTREE_ROW (node)->level;
2848
2849   if (GTK_CTREE_ROW (node)->pixmap_opened)
2850     {
2851       GTK_CELL_PIXTEXT 
2852         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = 
2853         GTK_CTREE_ROW (node)->pixmap_opened;
2854       GTK_CELL_PIXTEXT 
2855         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = 
2856         GTK_CTREE_ROW (node)->mask_opened;
2857     }
2858
2859   work = GTK_CTREE_ROW (node)->children;
2860   if (work)
2861     {
2862       GtkCList *clist;
2863       gint tmp = 0;
2864       gint row;
2865
2866       clist = GTK_CLIST (ctree);
2867
2868       while (GTK_CTREE_NODE_NEXT (work))
2869         {
2870           work = GTK_CTREE_NODE_NEXT (work);
2871           tmp++;
2872         }
2873
2874       GTK_CTREE_NODE_NEXT (work) = GTK_CTREE_NODE_NEXT (node);
2875
2876       if (GTK_CTREE_NODE_NEXT (node))
2877         GTK_CTREE_NODE_PREV (GTK_CTREE_NODE_NEXT (node)) = work;
2878       else
2879         GTK_CTREE_NODE (clist->row_list_end) = work;
2880
2881       GTK_CTREE_NODE_NEXT (node) = GTK_CTREE_ROW (node)->children;
2882       
2883       if (gtk_ctree_is_visible (ctree, node))
2884         {
2885           row = g_list_position (clist->row_list, (GList *)node);
2886           if (row < clist->focus_row)
2887             clist->focus_row += tmp + 1;
2888           clist->rows += tmp + 1;
2889           if (!GTK_CLIST_FROZEN (ctree))
2890             gtk_clist_thaw (clist);
2891         }
2892     }
2893 }
2894
2895 static void 
2896 real_tree_collapse (GtkCTree     *ctree,
2897                     GtkCTreeNode *node)
2898 {
2899   GtkCList *clist;
2900   GtkCTreeNode *work;
2901   gint level;
2902
2903   g_return_if_fail (ctree != NULL);
2904   g_return_if_fail (GTK_IS_CTREE (ctree));
2905
2906   if (!node || !GTK_CTREE_ROW (node)->expanded)
2907     return;
2908
2909   clist = GTK_CLIST (ctree);
2910
2911   if (clist->selection_mode == GTK_SELECTION_EXTENDED && clist->anchor >= 0)
2912     GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
2913   
2914   GTK_CTREE_ROW (node)->expanded = FALSE;
2915   level = GTK_CTREE_ROW (node)->level;
2916
2917   if (GTK_CTREE_ROW (node)->pixmap_closed)
2918     {
2919       GTK_CELL_PIXTEXT 
2920         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = 
2921         GTK_CTREE_ROW (node)->pixmap_closed;
2922       GTK_CELL_PIXTEXT 
2923         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = 
2924         GTK_CTREE_ROW (node)->mask_closed;
2925     }
2926
2927   work = GTK_CTREE_ROW (node)->children;
2928   if (work)
2929     {
2930       GtkCList *clist;
2931       gint tmp = 0;
2932       gint row;
2933
2934       clist = GTK_CLIST (ctree);
2935
2936       while (work && GTK_CTREE_ROW (work)->level > level)
2937         {
2938           work = GTK_CTREE_NODE_NEXT (work);
2939           tmp++;
2940         }
2941
2942       if (work)
2943         {
2944           GTK_CTREE_NODE_NEXT (node) = work;
2945           GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (work)) = NULL;
2946           GTK_CTREE_NODE_PREV (work) = node;
2947         }
2948       else
2949         {
2950           GTK_CTREE_NODE_NEXT (node) = NULL;
2951           GTK_CTREE_NODE (clist->row_list_end) = node;
2952         }
2953
2954       if (gtk_ctree_is_visible (ctree, node))
2955         {
2956           row = g_list_position (clist->row_list, (GList *)node);
2957           if (row < clist->focus_row)
2958             clist->focus_row -= tmp;
2959           clist->rows -= tmp;
2960           if (!GTK_CLIST_FROZEN (ctree))
2961             gtk_clist_thaw (clist);
2962         }
2963     }
2964 }
2965
2966 static void
2967 cell_set_text (GtkCList    *clist,
2968                GtkCListRow *clist_row,
2969                gint         column,
2970                gchar       *text)
2971 {
2972   cell_empty (clist, clist_row, column);
2973
2974   if (text)
2975     {
2976       clist_row->cell[column].type = GTK_CELL_TEXT;
2977       GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2978     }
2979 }
2980
2981 static void
2982 cell_set_pixmap (GtkCList    *clist,
2983                  GtkCListRow *clist_row,
2984                  gint         column,
2985                  GdkPixmap   *pixmap,
2986                  GdkBitmap   *mask)
2987 {
2988   cell_empty (clist, clist_row, column);
2989
2990   if (pixmap)
2991     {
2992       clist_row->cell[column].type = GTK_CELL_PIXMAP;
2993       GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
2994       GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
2995     }
2996 }
2997
2998 static void
2999 cell_set_pixtext (GtkCList    *clist,
3000                   GtkCListRow *clist_row,
3001                   gint         column,
3002                   gchar       *text,
3003                   guint8       spacing,
3004                   GdkPixmap   *pixmap,
3005                   GdkBitmap   *mask)
3006 {
3007   cell_empty (clist, clist_row, column);
3008
3009   if (text && pixmap)
3010     {
3011       clist_row->cell[column].type = GTK_CELL_PIXTEXT;
3012       GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3013       GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3014       GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3015       GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3016     }
3017 }
3018
3019 static void 
3020 set_node_info (GtkCTree     *ctree,
3021                GtkCTreeNode *node,
3022                gchar        *text,
3023                guint8        spacing,
3024                GdkPixmap    *pixmap_closed,
3025                GdkBitmap    *mask_closed,
3026                GdkPixmap    *pixmap_opened,
3027                GdkBitmap    *mask_opened,
3028                gboolean      is_leaf,
3029                gboolean      expanded)
3030 {
3031   GtkCellPixText *tree_cell;
3032
3033   if (GTK_CTREE_ROW (node)->pixmap_opened)
3034     {
3035       gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_opened);
3036       if (GTK_CTREE_ROW (node)->mask_opened) 
3037         gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_opened);
3038     }
3039   if (GTK_CTREE_ROW (node)->pixmap_closed)
3040     {
3041       gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_closed);
3042       if (GTK_CTREE_ROW (node)->mask_closed) 
3043         gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_closed);
3044     }
3045
3046   GTK_CTREE_ROW (node)->pixmap_opened = NULL;
3047   GTK_CTREE_ROW (node)->mask_opened   = NULL;
3048   GTK_CTREE_ROW (node)->pixmap_closed = NULL;
3049   GTK_CTREE_ROW (node)->mask_closed   = NULL;
3050
3051   if (pixmap_closed)
3052     {
3053       GTK_CTREE_ROW (node)->pixmap_closed = gdk_pixmap_ref (pixmap_closed);
3054       if (mask_closed) 
3055         GTK_CTREE_ROW (node)->mask_closed = gdk_bitmap_ref (mask_closed);
3056     }
3057   if (pixmap_opened)
3058     {
3059       GTK_CTREE_ROW (node)->pixmap_opened = gdk_pixmap_ref (pixmap_opened);
3060       if (mask_opened) 
3061         GTK_CTREE_ROW (node)->mask_opened = gdk_bitmap_ref (mask_opened);
3062     }
3063
3064   GTK_CTREE_ROW (node)->is_leaf  = is_leaf;
3065   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
3066
3067   GTK_CTREE_ROW (node)->row.cell[ctree->tree_column].type = GTK_CELL_PIXTEXT;
3068
3069   tree_cell = GTK_CELL_PIXTEXT (GTK_CTREE_ROW 
3070                                 (node)->row.cell[ctree->tree_column]);
3071
3072   if (tree_cell->text)
3073     g_free (tree_cell->text);
3074
3075   tree_cell->text = g_strdup (text);
3076   tree_cell->spacing = spacing;
3077
3078   if (GTK_CTREE_ROW (node)->expanded)
3079     {
3080       tree_cell->pixmap = pixmap_opened;
3081       tree_cell->mask   = mask_opened;
3082     }
3083   else 
3084     {
3085       tree_cell->pixmap = pixmap_closed;
3086       tree_cell->mask   = mask_closed;
3087     }
3088 }
3089
3090 static void
3091 tree_delete (GtkCTree     *ctree, 
3092              GtkCTreeNode *node, 
3093              gpointer      data)
3094 {
3095   GtkCList *clist;
3096   
3097   clist = GTK_CLIST (ctree);
3098   
3099   if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3100     {
3101       GList *work;
3102
3103       work = g_list_find (clist->selection, node);
3104       if (work)
3105         {
3106           if (clist->selection_end && clist->selection_end == work)
3107             clist->selection_end = clist->selection_end->prev;
3108           clist->selection = g_list_remove (clist->selection, node);
3109         }
3110     }
3111
3112   row_delete (ctree, GTK_CTREE_ROW (node));
3113   g_list_free_1 ((GList *)node);
3114 }
3115
3116 static void
3117 tree_delete_row (GtkCTree     *ctree, 
3118                  GtkCTreeNode *node, 
3119                  gpointer      data)
3120 {
3121   row_delete (ctree, GTK_CTREE_ROW (node));
3122   g_list_free_1 ((GList *)node);
3123 }
3124
3125 static void
3126 tree_update_level (GtkCTree     *ctree, 
3127                    GtkCTreeNode *node, 
3128                    gpointer      data)
3129 {
3130   if (!node)
3131     return;
3132
3133   if (GTK_CTREE_ROW (node)->parent)
3134       GTK_CTREE_ROW (node)->level = 
3135         GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
3136   else
3137       GTK_CTREE_ROW (node)->level = 1;
3138 }
3139
3140 static void
3141 tree_select (GtkCTree     *ctree, 
3142              GtkCTreeNode *node, 
3143              gpointer      data)
3144 {
3145   if (node && GTK_CTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
3146     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW],
3147                      node, -1);
3148 }
3149
3150 static void
3151 tree_unselect (GtkCTree     *ctree, 
3152                GtkCTreeNode *node, 
3153                gpointer      data)
3154 {
3155   if (node && GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3156     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 
3157                      node, -1);
3158 }
3159
3160 static void
3161 tree_expand (GtkCTree     *ctree, 
3162              GtkCTreeNode *node, 
3163              gpointer      data)
3164 {
3165   if (node && !GTK_CTREE_ROW (node)->expanded)
3166     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node);
3167 }
3168
3169 static void
3170 tree_collapse (GtkCTree     *ctree, 
3171                GtkCTreeNode *node, 
3172                gpointer      data)
3173 {
3174   if (node && GTK_CTREE_ROW (node)->expanded)
3175     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node);
3176 }
3177
3178 static void
3179 tree_collapse_to_depth (GtkCTree     *ctree, 
3180                         GtkCTreeNode *node, 
3181                         gint          depth)
3182 {
3183   if (node && GTK_CTREE_ROW (node)->level == depth)
3184     gtk_ctree_collapse_recursive (ctree, node);
3185 }
3186
3187 static void
3188 tree_toggle_expansion (GtkCTree     *ctree,
3189                        GtkCTreeNode *node,
3190                        gpointer      data)
3191 {
3192   if (!node)
3193     return;
3194
3195   if (GTK_CTREE_ROW (node)->expanded)
3196     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node);
3197   else
3198     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node);
3199 }
3200
3201 static GtkCTreeRow *
3202 row_new (GtkCTree *ctree)
3203 {
3204   GtkCList *clist;
3205   GtkCTreeRow *ctree_row;
3206   int i;
3207
3208   clist = GTK_CLIST (ctree);
3209   ctree_row = g_chunk_new (GtkCTreeRow, clist->row_mem_chunk);
3210   ctree_row->row.cell = g_chunk_new (GtkCell, clist->cell_mem_chunk);
3211
3212   for (i = 0; i < clist->columns; i++)
3213     {
3214       ctree_row->row.cell[i].type = GTK_CELL_EMPTY;
3215       ctree_row->row.cell[i].vertical = 0;
3216       ctree_row->row.cell[i].horizontal = 0;
3217     }
3218
3219   GTK_CELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
3220
3221   ctree_row->row.fg_set  = FALSE;
3222   ctree_row->row.bg_set  = FALSE;
3223   ctree_row->row.state   = GTK_STATE_NORMAL;
3224   ctree_row->row.data    = NULL;
3225   ctree_row->row.destroy = NULL;
3226
3227   ctree_row->level         = 0;
3228   ctree_row->expanded      = FALSE;
3229   ctree_row->parent        = NULL;
3230   ctree_row->sibling       = NULL;
3231   ctree_row->children      = NULL;
3232   ctree_row->pixmap_closed = NULL;
3233   ctree_row->mask_closed   = NULL;
3234   ctree_row->pixmap_opened = NULL;
3235   ctree_row->mask_opened   = NULL;
3236   
3237   return ctree_row;
3238 }
3239
3240 static void
3241 row_delete (GtkCTree    *ctree,
3242             GtkCTreeRow *ctree_row)
3243 {
3244   GtkCList *clist;
3245   gint i;
3246
3247   clist = GTK_CLIST (ctree);
3248
3249   for (i = 0; i < clist->columns; i++)
3250     cell_empty (clist, &(ctree_row->row), i);
3251
3252   if (ctree_row->pixmap_closed)
3253     {
3254       gdk_pixmap_unref (ctree_row->pixmap_closed);
3255       if (ctree_row->mask_closed)
3256         gdk_bitmap_unref (ctree_row->mask_closed);
3257     }
3258
3259   if (ctree_row->pixmap_opened)
3260     {
3261       gdk_pixmap_unref (ctree_row->pixmap_opened);
3262       if (ctree_row->mask_opened)
3263         gdk_bitmap_unref (ctree_row->mask_opened);
3264     }
3265
3266   if (ctree_row->row.destroy)
3267     ctree_row->row.destroy (ctree_row->row.data);
3268
3269   g_mem_chunk_free (clist->cell_mem_chunk, ctree_row->row.cell);
3270   g_mem_chunk_free (clist->row_mem_chunk, ctree_row);
3271 }
3272
3273 static void
3274 cell_empty (GtkCList    *clist,
3275             GtkCListRow *clist_row,
3276             gint         column)
3277 {
3278   switch (clist_row->cell[column].type)
3279     {
3280     case GTK_CELL_EMPTY:
3281       break;
3282       
3283     case GTK_CELL_TEXT:
3284       g_free (GTK_CELL_TEXT (clist_row->cell[column])->text);
3285       break;
3286       
3287     case GTK_CELL_PIXMAP:
3288       gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap);
3289       if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask)
3290           gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask);
3291       break;
3292       
3293     case GTK_CELL_PIXTEXT:
3294       if (GTK_CTREE (clist)->tree_column == column)
3295         {
3296           if (GTK_CELL_PIXTEXT (clist_row->cell[column])->text)
3297             g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
3298           break;
3299         }
3300       g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text);
3301       gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap);
3302       if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask)
3303         gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask);
3304       break;
3305
3306     case GTK_CELL_WIDGET:
3307       /* unimplemented */
3308       break;
3309       
3310     default:
3311       break;
3312     }
3313
3314   clist_row->cell[column].type = GTK_CELL_EMPTY;
3315 }
3316
3317 static void
3318 real_select_row (GtkCList *clist,
3319                  gint      row,
3320                  gint      column,
3321                  GdkEvent *event)
3322 {
3323   GList *node;
3324
3325   g_return_if_fail (clist != NULL);
3326   g_return_if_fail (GTK_IS_CTREE (clist));
3327   
3328   if ((node = g_list_nth (clist->row_list, row)))
3329     gtk_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],
3330                      node, column);
3331 }
3332
3333 static void
3334 real_unselect_row (GtkCList *clist,
3335                    gint      row,
3336                    gint      column,
3337                    GdkEvent *event)
3338 {
3339   GList *node;
3340
3341   g_return_if_fail (clist != NULL);
3342   g_return_if_fail (GTK_IS_CTREE (clist));
3343
3344   if ((node = g_list_nth (clist->row_list, row)))
3345     gtk_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],
3346                      node, column);
3347 }
3348
3349 static void
3350 real_tree_select (GtkCTree     *ctree,
3351                   GtkCTreeNode *node,
3352                   gint          column)
3353 {
3354   GtkCList *clist;
3355   GList *list;
3356   GtkCTreeNode *sel_row;
3357   gboolean node_selected;
3358
3359   g_return_if_fail (ctree != NULL);
3360   g_return_if_fail (GTK_IS_CTREE (ctree));
3361
3362   if (!node || GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3363     return;
3364
3365   clist = GTK_CLIST (ctree);
3366
3367   switch (clist->selection_mode)
3368     {
3369     case GTK_SELECTION_SINGLE:
3370     case GTK_SELECTION_BROWSE:
3371
3372       node_selected = FALSE;
3373       list = clist->selection;
3374
3375       while (list)
3376         {
3377           sel_row = list->data;
3378           list = list->next;
3379           
3380           if (node == sel_row)
3381             node_selected = TRUE;
3382           else
3383             gtk_signal_emit (GTK_OBJECT (ctree),
3384                              ctree_signals[TREE_UNSELECT_ROW], sel_row, column);
3385         }
3386
3387       if (node_selected)
3388         return;
3389
3390     default:
3391       break;
3392     }
3393
3394   GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
3395
3396   if (!clist->selection)
3397     {
3398       clist->selection = g_list_append (clist->selection, node);
3399       clist->selection_end = clist->selection;
3400     }
3401   else
3402     clist->selection_end = g_list_append (clist->selection_end, node)->next;
3403
3404   tree_draw_node (ctree, node);
3405 }
3406
3407 static void
3408 real_tree_unselect (GtkCTree     *ctree,
3409                     GtkCTreeNode *node,
3410                     gint          column)
3411 {
3412   GtkCList *clist;
3413
3414   g_return_if_fail (ctree != NULL);
3415   g_return_if_fail (GTK_IS_CTREE (ctree));
3416
3417   if (!node || GTK_CTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
3418     return;
3419
3420   clist = GTK_CLIST (ctree);
3421
3422   if (clist->selection_end && clist->selection_end->data == node)
3423     clist->selection_end = clist->selection_end->prev;
3424
3425   clist->selection = g_list_remove (clist->selection, node);
3426   
3427   GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
3428
3429   tree_draw_node (ctree, node);
3430 }
3431
3432 static void
3433 tree_toggle_selection (GtkCTree     *ctree,
3434                        GtkCTreeNode *node,
3435                        gint          column)
3436 {
3437   GtkCList *clist;
3438   
3439   g_return_if_fail (ctree != NULL);
3440   g_return_if_fail (GTK_IS_CTREE (ctree));
3441
3442   clist = GTK_CLIST (ctree);
3443
3444   switch (clist->selection_mode)
3445     {
3446     case GTK_SELECTION_SINGLE:
3447     case GTK_SELECTION_MULTIPLE:
3448       if (node && GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3449         gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 
3450                          node, column);
3451       else if (node)
3452         gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 
3453                          node, column);
3454       break;
3455
3456     case GTK_SELECTION_BROWSE:
3457       if (node && GTK_CTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
3458         gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 
3459                          node, column);
3460       break;
3461
3462     case GTK_SELECTION_EXTENDED:
3463       break;
3464     }
3465 }
3466
3467 static void
3468 select_row_recursive (GtkCTree     *ctree, 
3469                       GtkCTreeNode *node, 
3470                       gpointer      data)
3471 {
3472   if (!node || GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3473     return;
3474
3475   GTK_CLIST (ctree)->undo_unselection = 
3476     g_list_prepend (GTK_CLIST (ctree)->undo_unselection, node);
3477   gtk_ctree_select (ctree, node);
3478 }
3479
3480 static void
3481 real_select_all (GtkCList *clist)
3482 {
3483   GtkCTree *ctree;
3484   GtkCTreeNode *node;
3485   gboolean thaw = FALSE;
3486   
3487   g_return_if_fail (clist != NULL);
3488   g_return_if_fail (GTK_IS_CTREE (clist));
3489
3490   ctree = GTK_CTREE (clist);
3491
3492   switch (clist->selection_mode)
3493     {
3494     case GTK_SELECTION_SINGLE:
3495     case GTK_SELECTION_BROWSE:
3496       return;
3497
3498     case GTK_SELECTION_EXTENDED:
3499
3500       if (!GTK_CLIST_FROZEN (clist))
3501         {
3502           gtk_clist_freeze (clist);
3503           thaw = TRUE;
3504         }
3505
3506       g_list_free (clist->undo_selection);
3507       g_list_free (clist->undo_unselection);
3508       clist->undo_selection = NULL;
3509       clist->undo_unselection = NULL;
3510           
3511       clist->anchor_state = GTK_STATE_SELECTED;
3512       clist->anchor = -1;
3513       clist->drag_pos = -1;
3514       clist->undo_anchor = clist->focus_row;
3515
3516       for (node = GTK_CTREE_NODE (clist->row_list); node;
3517            node = GTK_CTREE_NODE_NEXT (node))
3518         gtk_ctree_pre_recursive (ctree, node, select_row_recursive, NULL);
3519
3520       if (thaw)
3521         gtk_clist_thaw (clist);
3522       break;
3523
3524     case GTK_SELECTION_MULTIPLE:
3525       gtk_ctree_select_recursive (ctree, NULL);
3526       break;;
3527     }
3528 }
3529
3530 static void
3531 real_unselect_all (GtkCList *clist)
3532 {
3533   GtkCTree *ctree;
3534   GtkCTreeNode *node;
3535   GList *list;
3536  
3537   g_return_if_fail (clist != NULL);
3538   g_return_if_fail (GTK_IS_CTREE (clist));
3539   
3540   ctree = GTK_CTREE (clist);
3541
3542   switch (clist->selection_mode)
3543     {
3544     case GTK_SELECTION_BROWSE:
3545       if (clist->focus_row >= 0)
3546         {
3547           gtk_ctree_select
3548             (ctree,
3549              GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
3550           return;
3551         }
3552       break;
3553
3554     case GTK_SELECTION_EXTENDED:
3555       g_list_free (clist->undo_selection);
3556       g_list_free (clist->undo_unselection);
3557       clist->undo_selection = NULL;
3558       clist->undo_unselection = NULL;
3559
3560       clist->anchor = -1;
3561       clist->drag_pos = -1;
3562       clist->undo_anchor = clist->focus_row;
3563       break;
3564
3565     default:
3566       break;
3567     }
3568
3569   list = clist->selection;
3570
3571   while (list)
3572     {
3573       node = list->data;
3574       list = list->next;
3575       gtk_ctree_unselect (ctree, node);
3576     }
3577 }
3578
3579 static gboolean
3580 ctree_is_hot_spot (GtkCTree     *ctree, 
3581                    GtkCTreeNode *node,
3582                    gint          row, 
3583                    gint          x, 
3584                    gint          y)
3585 {
3586   GtkCTreeRow *tree_row;
3587   GtkCList *clist;
3588   GtkCellPixText *cell;
3589   gint xl;
3590   gint yu;
3591   
3592   g_return_val_if_fail (ctree != NULL, FALSE);
3593   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
3594   g_return_val_if_fail (node != NULL, FALSE);
3595
3596   tree_row = GTK_CTREE_ROW (node);
3597   clist = GTK_CLIST (ctree);
3598
3599   cell = GTK_CELL_PIXTEXT(tree_row->row.cell[ctree->tree_column]);
3600
3601   yu = ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2;
3602
3603   if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
3604     {
3605       xl = clist->column[ctree->tree_column].area.x 
3606         + clist->column[ctree->tree_column].area.width + clist->hoffset 
3607         /*+ cell->horizontal +*/
3608         - (tree_row->level - 1) * ctree->tree_indent 
3609         - PM_SIZE - 1 -
3610         (ctree->line_style == GTK_CTREE_LINES_TABBED) * ((PM_SIZE / 2) + 1);
3611     }
3612   else
3613     {
3614       xl = clist->column[ctree->tree_column].area.x + clist->hoffset 
3615         + cell->horizontal + (tree_row->level - 1) * ctree->tree_indent +
3616         (ctree->line_style == GTK_CTREE_LINES_TABBED) * ((PM_SIZE / 2) + 2);
3617     }
3618
3619   return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE);
3620 }
3621
3622 static gint
3623 default_compare (GtkCList     *clist,
3624                  gconstpointer ptr1,
3625                  gconstpointer ptr2)
3626 {
3627   GtkCTreeNode *node1 = (GtkCTreeNode *) ptr1;
3628   GtkCTreeNode *node2 = (GtkCTreeNode *) ptr2;
3629   char *text1;
3630   char *text2;
3631
3632   text1 = GTK_CELL_PIXTEXT (GTK_CTREE_ROW
3633                             (node1)->row.cell[clist->sort_column])->text;
3634   text2 = GTK_CELL_PIXTEXT (GTK_CTREE_ROW
3635                             (node2)->row.cell[clist->sort_column])->text;
3636
3637   return strcmp (text1, text2);
3638 }
3639
3640 /***********************************************************
3641  ***********************************************************
3642  ***                  Public interface                   ***
3643  ***********************************************************
3644  ***********************************************************/
3645
3646
3647 /***********************************************************
3648  *           Creation, insertion, deletion                 *
3649  ***********************************************************/
3650
3651 void
3652 gtk_ctree_construct (GtkCTree *ctree,
3653                      gint      columns, 
3654                      gint      tree_column,
3655                      gchar    *titles[])
3656 {
3657   GtkCList *clist;
3658
3659   g_return_if_fail (ctree != NULL);
3660   g_return_if_fail (GTK_IS_CTREE (ctree));
3661   g_return_if_fail (GTK_CLIST_CONSTRUCTED (ctree) == FALSE);
3662
3663   clist = GTK_CLIST (ctree);
3664
3665   clist->row_mem_chunk = g_mem_chunk_new ("ctree row mem chunk",
3666                                           sizeof (GtkCTreeRow),
3667                                           sizeof (GtkCTreeRow)
3668                                           * CLIST_OPTIMUM_SIZE, 
3669                                           G_ALLOC_AND_FREE);
3670
3671   clist->cell_mem_chunk = g_mem_chunk_new ("ctree cell mem chunk",
3672                                            sizeof (GtkCell) * columns,
3673                                            sizeof (GtkCell) * columns
3674                                            * CLIST_OPTIMUM_SIZE, 
3675                                            G_ALLOC_AND_FREE);
3676
3677   ctree->tree_column = tree_column;
3678
3679   gtk_clist_construct (clist, columns, titles);
3680 }
3681
3682 GtkWidget *
3683 gtk_ctree_new_with_titles (gint   columns, 
3684                            gint   tree_column,
3685                            gchar *titles[])
3686 {
3687   GtkWidget *widget;
3688
3689   g_return_val_if_fail (columns > 0, NULL);
3690   g_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
3691
3692   widget = gtk_type_new (GTK_TYPE_CTREE);
3693   gtk_ctree_construct (GTK_CTREE (widget), columns, tree_column, titles);
3694   return widget;
3695 }
3696
3697 GtkWidget *
3698 gtk_ctree_new (gint columns, 
3699                gint tree_column)
3700 {
3701   return gtk_ctree_new_with_titles (columns, tree_column, NULL);
3702 }
3703
3704 GtkCTreeNode * 
3705 gtk_ctree_insert (GtkCTree     *ctree,
3706                   GtkCTreeNode *parent, 
3707                   GtkCTreeNode *sibling,
3708                   gchar     *text[],
3709                   guint8     spacing,
3710                   GdkPixmap *pixmap_closed,
3711                   GdkBitmap *mask_closed,
3712                   GdkPixmap *pixmap_opened,
3713                   GdkBitmap *mask_opened,
3714                   gboolean   is_leaf,
3715                   gboolean   expanded)
3716 {
3717   GtkCList *clist;
3718   GtkCTreeRow *new_row;
3719   GtkCTreeNode *node;
3720   gint i;
3721
3722   g_return_val_if_fail (ctree != NULL, NULL);
3723   g_return_val_if_fail (!sibling || GTK_CTREE_ROW (sibling)->parent == parent,
3724                         NULL);
3725
3726   if (parent && GTK_CTREE_ROW (parent)->is_leaf)
3727     return NULL;
3728
3729   clist = GTK_CLIST (ctree);
3730
3731   /* create the row */
3732   new_row = row_new (ctree);
3733   node = GTK_CTREE_NODE (g_list_alloc ());
3734   GTK_CTREE_ROW (node) = new_row;
3735
3736   if (text)
3737     for (i = 0; i < clist->columns; i++)
3738       if (text[i] && i != ctree->tree_column)
3739         cell_set_text (clist, &(new_row->row), i, text[i]);
3740
3741   set_node_info (ctree, node, text[ctree->tree_column], spacing, pixmap_closed,
3742                  mask_closed, pixmap_opened, mask_opened, is_leaf, expanded);
3743
3744   /* sorted insertion */
3745   if (GTK_CLIST_AUTO_SORT (clist))
3746     {
3747       if (parent)
3748         sibling = GTK_CTREE_ROW (parent)->children;
3749       else
3750         sibling = GTK_CTREE_NODE (clist->row_list);
3751
3752       while (sibling && clist->compare (clist, node, sibling) > 0)
3753         sibling = GTK_CTREE_ROW (sibling)->sibling;
3754     }
3755
3756   gtk_ctree_link (ctree, node, parent, sibling, TRUE);
3757
3758   if (!GTK_CLIST_FROZEN (clist))
3759     gtk_clist_thaw (clist);
3760
3761   return node;
3762 }
3763
3764 GtkCTreeNode *
3765 gtk_ctree_insert_gnode (GtkCTree          *ctree,
3766                         GtkCTreeNode      *parent,
3767                         GtkCTreeNode      *sibling,
3768                         GNode             *gnode,
3769                         GtkCTreeGNodeFunc  func,
3770                         gpointer           data)
3771 {
3772   GtkCList *clist;
3773   GtkCTreeNode *cnode = NULL;
3774   GtkCTreeNode *child = NULL;
3775   GtkCTreeNode *new_child;
3776   GtkCTreeRow *new_row;
3777   gboolean thaw;
3778   GNode *work;
3779   guint depth = 1;
3780
3781   g_return_val_if_fail (ctree != NULL, NULL);
3782   g_return_val_if_fail (gnode != NULL, NULL);
3783   g_return_val_if_fail (func != NULL, NULL);
3784   if (sibling)
3785     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
3786   
3787   clist = GTK_CLIST (ctree);
3788
3789   if (parent)
3790     depth = GTK_CTREE_ROW (parent)->level + 1;
3791
3792   if (!(new_row = row_new (ctree)))
3793     return NULL;
3794   if (!(cnode = GTK_CTREE_NODE (g_list_alloc ())))
3795     return NULL;
3796   GTK_CTREE_ROW (cnode) = new_row;
3797
3798   set_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE);
3799
3800   if (!func (ctree, depth, gnode, cnode, data))
3801     {
3802       tree_delete_row (ctree, cnode, NULL);
3803       return NULL;
3804     }
3805
3806   if ((thaw = !GTK_CLIST_FROZEN (clist)))
3807     gtk_clist_freeze (clist);
3808
3809   if (GTK_CLIST_AUTO_SORT (clist))
3810     {
3811       if (parent)
3812         sibling = GTK_CTREE_ROW (parent)->children;
3813       else
3814         sibling = GTK_CTREE_NODE (clist->row_list);
3815
3816       while (sibling && clist->compare (clist, cnode, sibling) > 0)
3817         sibling = GTK_CTREE_ROW (sibling)->sibling;
3818     }
3819
3820   gtk_ctree_link (ctree, cnode, parent, sibling, TRUE);
3821
3822   for (work = g_node_last_child (gnode); work; work = work->prev)
3823     {
3824       new_child = gtk_ctree_insert_gnode (ctree, cnode, child,
3825                                           work, func, data);
3826       if (new_child)
3827         child = new_child;
3828     }   
3829   
3830   if (thaw) 
3831     gtk_clist_thaw (clist);
3832
3833   return cnode;
3834 }
3835
3836 void
3837 gtk_ctree_remove (GtkCTree     *ctree, 
3838                   GtkCTreeNode *node)
3839 {
3840   GtkCList *clist;
3841   gboolean thaw = FALSE;
3842
3843   g_return_if_fail (ctree != NULL);
3844   g_return_if_fail (GTK_IS_CTREE (ctree));
3845
3846   clist = GTK_CLIST (ctree);
3847
3848   if (!GTK_CLIST_FROZEN (clist))
3849     {
3850       gtk_clist_freeze (clist);
3851       thaw = TRUE;
3852     }
3853
3854   if (node)
3855     {
3856       gtk_ctree_unlink (ctree, node, TRUE);
3857       gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_delete),
3858                                 NULL);
3859     }
3860   else
3861     gtk_clist_clear (clist);
3862
3863   if (thaw)
3864     gtk_clist_thaw (clist);
3865 }
3866
3867 static void
3868 real_clear (GtkCList *clist)
3869 {
3870   GtkCTree *ctree;
3871   GtkCTreeNode *work;
3872   GtkCTreeNode *ptr;
3873
3874   g_return_if_fail (clist != NULL);
3875   g_return_if_fail (GTK_IS_CTREE (clist));
3876
3877   ctree = GTK_CTREE (clist);
3878
3879   ctree->drag_row       = -1;
3880   ctree->drag_rect      = FALSE;
3881   ctree->in_drag        = FALSE;
3882   ctree->drag_source    = NULL;
3883   ctree->drag_target    = NULL;
3884   ctree->drag_icon      = NULL;
3885
3886   /* remove all the rows */
3887   work = GTK_CTREE_NODE (clist->row_list);
3888   clist->row_list = NULL;
3889   clist->row_list_end = NULL;
3890
3891   while (work)
3892     {
3893       ptr = work;
3894       work = GTK_CTREE_ROW (work)->sibling;
3895       gtk_ctree_post_recursive (ctree, ptr, GTK_CTREE_FUNC (tree_delete_row), 
3896                                 NULL);
3897     }
3898
3899   (parent_class->clear) (clist);
3900 }
3901
3902
3903 /***********************************************************
3904  *  Generic recursive functions, querying / finding tree   *
3905  *  information                                            *
3906  ***********************************************************/
3907
3908
3909 void
3910 gtk_ctree_post_recursive (GtkCTree     *ctree, 
3911                           GtkCTreeNode *node,
3912                           GtkCTreeFunc  func,
3913                           gpointer      data)
3914 {
3915   GtkCTreeNode *work;
3916   GtkCTreeNode *tmp;
3917
3918   g_return_if_fail (ctree != NULL);
3919   g_return_if_fail (GTK_IS_CTREE (ctree));
3920   g_return_if_fail (func != NULL);
3921
3922   if (node)
3923     work = GTK_CTREE_ROW (node)->children;
3924   else
3925     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
3926
3927   while (work)
3928     {
3929       tmp = GTK_CTREE_ROW (work)->sibling;
3930       gtk_ctree_post_recursive (ctree, work, func, data);
3931       work = tmp;
3932     }
3933
3934   if (node)
3935     func (ctree, node, data);
3936 }
3937
3938 void
3939 gtk_ctree_post_recursive_to_depth (GtkCTree     *ctree, 
3940                                    GtkCTreeNode *node,
3941                                    gint          depth,
3942                                    GtkCTreeFunc  func,
3943                                    gpointer      data)
3944 {
3945   GtkCTreeNode *work;
3946   GtkCTreeNode *tmp;
3947
3948   g_return_if_fail (ctree != NULL);
3949   g_return_if_fail (GTK_IS_CTREE (ctree));
3950   g_return_if_fail (func != NULL);
3951
3952   if (depth < 0)
3953     {
3954       gtk_ctree_post_recursive (ctree, node, func, data);
3955       return;
3956     }
3957
3958   if (node)
3959     work = GTK_CTREE_ROW (node)->children;
3960   else
3961     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
3962
3963   if (work && GTK_CTREE_ROW (work)->level <= depth)
3964     {
3965       while (work)
3966         {
3967           tmp = GTK_CTREE_ROW (work)->sibling;
3968           gtk_ctree_post_recursive_to_depth (ctree, work, depth, func, data);
3969           work = tmp;
3970         }
3971     }
3972
3973   if (node && GTK_CTREE_ROW (node)->level <= depth)
3974     func (ctree, node, data);
3975 }
3976
3977 void
3978 gtk_ctree_pre_recursive (GtkCTree     *ctree, 
3979                          GtkCTreeNode *node,
3980                          GtkCTreeFunc  func,
3981                          gpointer      data)
3982 {
3983   GtkCTreeNode *work;
3984   GtkCTreeNode *tmp;
3985
3986   g_return_if_fail (ctree != NULL);
3987   g_return_if_fail (GTK_IS_CTREE (ctree));
3988   g_return_if_fail (func != NULL);
3989
3990   if (node)
3991     {
3992       work = GTK_CTREE_ROW (node)->children;
3993       func (ctree, node, data);
3994     }
3995   else
3996     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
3997
3998   while (work)
3999     {
4000       tmp = GTK_CTREE_ROW (work)->sibling;
4001       gtk_ctree_pre_recursive (ctree, work, func, data);
4002       work = tmp;
4003     }
4004 }
4005
4006 void
4007 gtk_ctree_pre_recursive_to_depth (GtkCTree     *ctree, 
4008                                   GtkCTreeNode *node,
4009                                   gint          depth, 
4010                                   GtkCTreeFunc  func,
4011                                   gpointer      data)
4012 {
4013   GtkCTreeNode *work;
4014   GtkCTreeNode *tmp;
4015
4016   g_return_if_fail (ctree != NULL);
4017   g_return_if_fail (GTK_IS_CTREE (ctree));
4018   g_return_if_fail (func != NULL);
4019
4020   if (depth < 0)
4021     {
4022       gtk_ctree_pre_recursive (ctree, node, func, data);
4023       return;
4024     }
4025
4026   if (node)
4027     {
4028       work = GTK_CTREE_ROW (node)->children;
4029       if (GTK_CTREE_ROW (node)->level <= depth)
4030         func (ctree, node, data);
4031     }
4032   else
4033     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4034
4035   if (work && GTK_CTREE_ROW (work)->level <= depth)
4036     {
4037       while (work)
4038         {
4039           tmp = GTK_CTREE_ROW (work)->sibling;
4040           gtk_ctree_pre_recursive_to_depth (ctree, work, depth, func, data);
4041           work = tmp;
4042         }
4043     }
4044 }
4045
4046 gboolean
4047 gtk_ctree_is_visible (GtkCTree     *ctree, 
4048                       GtkCTreeNode *node)
4049
4050   GtkCTreeRow *work;
4051
4052   g_return_val_if_fail (ctree != NULL, FALSE);
4053   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4054   g_return_val_if_fail (node != NULL, FALSE);
4055
4056   work = GTK_CTREE_ROW (node);
4057
4058   while (work->parent && GTK_CTREE_ROW (work->parent)->expanded)
4059     work = GTK_CTREE_ROW (work->parent);
4060
4061   if (!work->parent)
4062     return TRUE;
4063
4064   return FALSE;
4065 }
4066
4067 GtkCTreeNode * 
4068 gtk_ctree_last (GtkCTree     *ctree,
4069                 GtkCTreeNode *node)
4070 {
4071   g_return_val_if_fail (ctree != NULL, NULL);
4072   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4073
4074   if (!node) 
4075     return NULL;
4076
4077   while (GTK_CTREE_ROW (node)->sibling)
4078     node = GTK_CTREE_ROW (node)->sibling;
4079   
4080   if (GTK_CTREE_ROW (node)->children)
4081     return gtk_ctree_last (ctree, GTK_CTREE_ROW (node)->children);
4082   
4083   return node;
4084 }
4085
4086 GtkCTreeNode *
4087 gtk_ctree_find_glist_ptr (GtkCTree    *ctree,
4088                           GtkCTreeRow *ctree_row)
4089 {
4090   GtkCTreeNode *node;
4091   
4092   g_return_val_if_fail (ctree != NULL, FALSE);
4093   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4094   g_return_val_if_fail (ctree_row != NULL, FALSE);
4095   
4096   if (ctree_row->parent)
4097     node = GTK_CTREE_ROW(ctree_row->parent)->children;
4098   else
4099     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4100
4101   while (GTK_CTREE_ROW (node) != ctree_row)
4102     node = GTK_CTREE_ROW (node)->sibling;
4103   
4104   return node;
4105 }
4106
4107 gboolean
4108 gtk_ctree_find (GtkCTree     *ctree,
4109                 GtkCTreeNode *node,
4110                 GtkCTreeNode *child)
4111 {
4112   if (!child)
4113     return FALSE;
4114
4115   if (!node)
4116     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4117
4118   while (node)
4119     {
4120       if (node == child) 
4121         return TRUE;
4122       if (GTK_CTREE_ROW (node)->children)
4123         {
4124           if (gtk_ctree_find (ctree, GTK_CTREE_ROW (node)->children, child))
4125             return TRUE;
4126         }
4127       node = GTK_CTREE_ROW (node)->sibling;
4128     }
4129   return FALSE;
4130 }
4131
4132 gboolean
4133 gtk_ctree_is_ancestor (GtkCTree     *ctree,
4134                        GtkCTreeNode *node,
4135                        GtkCTreeNode *child)
4136 {
4137   g_return_val_if_fail (node != NULL, FALSE);
4138
4139   return gtk_ctree_find (ctree, GTK_CTREE_ROW (node)->children, child);
4140 }
4141
4142 GtkCTreeNode *
4143 gtk_ctree_find_by_row_data (GtkCTree     *ctree,
4144                             GtkCTreeNode *node,
4145                             gpointer      data)
4146 {
4147   GtkCTreeNode *work;
4148   
4149   if (!node)
4150     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4151   
4152   while (node)
4153     {
4154       if (GTK_CTREE_ROW (node)->row.data == data) 
4155         return node;
4156       if (GTK_CTREE_ROW (node)->children &&
4157           (work = gtk_ctree_find_by_row_data 
4158            (ctree, GTK_CTREE_ROW (node)->children, data)))
4159         return work;
4160       node = GTK_CTREE_ROW (node)->sibling;
4161     }
4162   return NULL;
4163 }
4164
4165 GtkCTreeNode *
4166 gtk_ctree_find_by_row_data_custom (GtkCTree     *ctree,
4167                                    GtkCTreeNode *node,
4168                                    gpointer      data,
4169                                    GCompareFunc  func)
4170 {
4171   GtkCTreeNode *work;
4172
4173   g_return_val_if_fail (func != NULL, NULL);
4174
4175   if (!node)
4176     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4177
4178   while (node)
4179     {
4180       if (!func (GTK_CTREE_ROW (node)->row.data, data))
4181         return node;
4182       if (GTK_CTREE_ROW (node)->children &&
4183           (work = gtk_ctree_find_by_row_data_custom
4184            (ctree, GTK_CTREE_ROW (node)->children, data, func)))
4185         return work;
4186       node = GTK_CTREE_ROW (node)->sibling;
4187     }
4188   return NULL;
4189 }
4190
4191 gboolean
4192 gtk_ctree_is_hot_spot (GtkCTree *ctree, 
4193                        gint      x, 
4194                        gint      y)
4195 {
4196   GtkCTreeNode *node;
4197   gint column;
4198   gint row;
4199   
4200   g_return_val_if_fail (ctree != NULL, FALSE);
4201   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4202
4203   if (gtk_clist_get_selection_info (GTK_CLIST (ctree), x, y, &row, &column))
4204     if ((node = GTK_CTREE_NODE(g_list_nth (GTK_CLIST (ctree)->row_list, row))))
4205       return ctree_is_hot_spot (ctree, node, row, x, y);
4206
4207   return FALSE;
4208 }
4209
4210
4211 /***********************************************************
4212  *   Tree signals : move, expand, collapse, (un)select     *
4213  ***********************************************************/
4214
4215
4216 void
4217 gtk_ctree_move (GtkCTree     *ctree,
4218                 GtkCTreeNode *node,
4219                 GtkCTreeNode *new_parent, 
4220                 GtkCTreeNode *new_sibling)
4221 {
4222   g_return_if_fail (ctree != NULL);
4223   g_return_if_fail (GTK_IS_CTREE (ctree));
4224   g_return_if_fail (node != NULL);
4225   
4226   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_MOVE], node,
4227                    new_parent, new_sibling);
4228 }
4229
4230 void
4231 gtk_ctree_expand (GtkCTree     *ctree,
4232                   GtkCTreeNode *node)
4233 {
4234   g_return_if_fail (ctree != NULL);
4235   g_return_if_fail (GTK_IS_CTREE (ctree));
4236   g_return_if_fail (node != NULL);
4237   
4238   if (GTK_CTREE_ROW (node)->is_leaf)
4239     return;
4240
4241   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node);
4242 }
4243
4244 void 
4245 gtk_ctree_expand_recursive (GtkCTree     *ctree,
4246                             GtkCTreeNode *node)
4247 {
4248   GtkCList *clist;
4249   gboolean thaw = FALSE;
4250
4251   g_return_if_fail (ctree != NULL);
4252   g_return_if_fail (GTK_IS_CTREE (ctree));
4253
4254   clist = GTK_CLIST (ctree);
4255
4256   if (node && GTK_CTREE_ROW (node)->is_leaf)
4257     return;
4258
4259   if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && 
4260       !GTK_CLIST_FROZEN (clist))
4261     {
4262       gtk_clist_freeze (clist);
4263       thaw = TRUE;
4264     }
4265
4266   gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_expand), NULL);
4267
4268   if (thaw)
4269     gtk_clist_thaw (clist);
4270 }
4271
4272 void 
4273 gtk_ctree_expand_to_depth (GtkCTree     *ctree,
4274                            GtkCTreeNode *node,
4275                            gint          depth)
4276 {
4277   GtkCList *clist;
4278   gboolean thaw = FALSE;
4279
4280   g_return_if_fail (ctree != NULL);
4281   g_return_if_fail (GTK_IS_CTREE (ctree));
4282
4283   clist = GTK_CLIST (ctree);
4284
4285   if (node && GTK_CTREE_ROW (node)->is_leaf)
4286     return;
4287
4288   if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && 
4289       !GTK_CLIST_FROZEN (clist))
4290     {
4291       gtk_clist_freeze (clist);
4292       thaw = TRUE;
4293     }
4294
4295   gtk_ctree_post_recursive_to_depth (ctree, node, depth,
4296                                      GTK_CTREE_FUNC (tree_expand), NULL);
4297
4298   if (thaw)
4299     gtk_clist_thaw (clist);
4300 }
4301
4302 void
4303 gtk_ctree_collapse (GtkCTree     *ctree,
4304                     GtkCTreeNode *node)
4305 {
4306   g_return_if_fail (ctree != NULL);
4307   g_return_if_fail (GTK_IS_CTREE (ctree));
4308   g_return_if_fail (node != NULL);
4309   
4310   if (GTK_CTREE_ROW (node)->is_leaf)
4311     return;
4312
4313   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node);
4314 }
4315
4316 void 
4317 gtk_ctree_collapse_recursive (GtkCTree     *ctree,
4318                               GtkCTreeNode *node)
4319 {
4320   GtkCList *clist;
4321   gboolean thaw = FALSE;
4322
4323   g_return_if_fail (ctree != NULL);
4324   g_return_if_fail (GTK_IS_CTREE (ctree));
4325
4326   if (node && GTK_CTREE_ROW (node)->is_leaf)
4327     return;
4328
4329   clist = GTK_CLIST (ctree);
4330
4331   if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && 
4332       !GTK_CLIST_FROZEN (clist))
4333     {
4334       gtk_clist_freeze (clist);
4335       thaw = TRUE;
4336     }
4337
4338   gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_collapse), NULL);
4339
4340   if (thaw)
4341     gtk_clist_thaw (clist);
4342 }
4343
4344 void 
4345 gtk_ctree_collapse_to_depth (GtkCTree     *ctree,
4346                              GtkCTreeNode *node,
4347                              gint          depth)
4348 {
4349   GtkCList *clist;
4350   gboolean thaw = FALSE;
4351
4352   g_return_if_fail (ctree != NULL);
4353   g_return_if_fail (GTK_IS_CTREE (ctree));
4354
4355   if (node && GTK_CTREE_ROW (node)->is_leaf)
4356     return;
4357
4358   clist = GTK_CLIST (ctree);
4359
4360   if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && 
4361       !GTK_CLIST_FROZEN (clist))
4362     {
4363       gtk_clist_freeze (clist);
4364       thaw = TRUE;
4365     }
4366
4367   gtk_ctree_post_recursive_to_depth (ctree, node, depth,
4368                                      GTK_CTREE_FUNC (tree_collapse_to_depth),
4369                                      GINT_TO_POINTER (depth));
4370
4371   if (thaw)
4372     gtk_clist_thaw (clist);
4373 }
4374
4375 void
4376 gtk_ctree_toggle_expansion (GtkCTree     *ctree,
4377                             GtkCTreeNode *node)
4378 {
4379   g_return_if_fail (ctree != NULL);
4380   g_return_if_fail (GTK_IS_CTREE (ctree));
4381   g_return_if_fail (node != NULL);
4382   
4383   if (GTK_CTREE_ROW (node)->is_leaf)
4384     return;
4385
4386   tree_toggle_expansion (ctree, node, NULL);
4387 }
4388
4389 void 
4390 gtk_ctree_toggle_expansion_recursive (GtkCTree     *ctree,
4391                                       GtkCTreeNode *node)
4392 {
4393   GtkCList *clist;
4394   gboolean thaw = FALSE;
4395
4396   g_return_if_fail (ctree != NULL);
4397   g_return_if_fail (GTK_IS_CTREE (ctree));
4398   
4399   if (node && GTK_CTREE_ROW (node)->is_leaf)
4400     return;
4401
4402   clist = GTK_CLIST (ctree);
4403
4404   if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && 
4405       !GTK_CLIST_FROZEN (clist))
4406     {
4407       gtk_clist_freeze (clist);
4408       thaw = TRUE;
4409     }
4410   
4411   gtk_ctree_post_recursive (ctree, node,
4412                             GTK_CTREE_FUNC (tree_toggle_expansion), NULL);
4413
4414   if (thaw)
4415     gtk_clist_thaw (clist);
4416 }
4417
4418 void
4419 gtk_ctree_select (GtkCTree     *ctree, 
4420                   GtkCTreeNode *node)
4421 {
4422   g_return_if_fail (ctree != NULL);
4423   g_return_if_fail (GTK_IS_CTREE (ctree));
4424   g_return_if_fail (node != NULL);
4425
4426   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW],
4427                    node, -1);
4428 }
4429
4430 void
4431 gtk_ctree_unselect (GtkCTree     *ctree, 
4432                     GtkCTreeNode *node)
4433 {
4434   g_return_if_fail (ctree != NULL);
4435   g_return_if_fail (GTK_IS_CTREE (ctree));
4436   g_return_if_fail (node != NULL);
4437
4438   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW],
4439                    node, -1);
4440 }
4441
4442 void
4443 gtk_ctree_select_recursive (GtkCTree     *ctree, 
4444                             GtkCTreeNode *node)
4445 {
4446   gtk_ctree_real_select_recursive (ctree, node, TRUE);
4447 }
4448
4449 void
4450 gtk_ctree_unselect_recursive (GtkCTree     *ctree, 
4451                               GtkCTreeNode *node)
4452 {
4453   gtk_ctree_real_select_recursive (ctree, node, FALSE);
4454 }
4455
4456 void
4457 gtk_ctree_real_select_recursive (GtkCTree     *ctree, 
4458                                  GtkCTreeNode *node, 
4459                                  gint          state)
4460 {
4461   GtkCList *clist;
4462   gboolean thaw = FALSE;
4463
4464   g_return_if_fail (ctree != NULL);
4465   g_return_if_fail (GTK_IS_CTREE (ctree));
4466
4467   clist = GTK_CLIST (ctree);
4468
4469   if ((state && 
4470        (clist->selection_mode ==  GTK_SELECTION_BROWSE ||
4471         clist->selection_mode == GTK_SELECTION_SINGLE)) ||
4472       (!state && clist->selection_mode ==  GTK_SELECTION_BROWSE))
4473     return;
4474
4475   if (((node && gtk_ctree_is_visible (ctree, node)) || !node) && 
4476       !GTK_CLIST_FROZEN (clist))
4477     {
4478       gtk_clist_freeze (clist);
4479       thaw = TRUE;
4480     }
4481
4482   if (clist->selection_mode == GTK_SELECTION_EXTENDED)
4483     {
4484       if (clist->anchor != -1)
4485         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
4486       
4487       g_list_free (clist->undo_selection);
4488       g_list_free (clist->undo_unselection);
4489       clist->undo_selection = NULL;
4490       clist->undo_unselection = NULL;
4491     }
4492
4493   if (state)
4494     gtk_ctree_post_recursive (ctree, node,
4495                               GTK_CTREE_FUNC (tree_select), NULL);
4496   else 
4497     gtk_ctree_post_recursive (ctree, node,
4498                               GTK_CTREE_FUNC (tree_unselect), NULL);
4499   
4500   if (thaw)
4501     gtk_clist_thaw (clist);
4502 }
4503
4504
4505 /***********************************************************
4506  *           Analogons of GtkCList functions               *
4507  ***********************************************************/
4508
4509
4510 void 
4511 gtk_ctree_set_text (GtkCTree     *ctree,
4512                     GtkCTreeNode *node,
4513                     gint          column,
4514                     gchar        *text)
4515 {
4516   g_return_if_fail (ctree != NULL);
4517   g_return_if_fail (GTK_IS_CTREE (ctree));
4518   g_return_if_fail (node != NULL);
4519   g_return_if_fail (ctree->tree_column != column);
4520
4521   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4522     return;
4523
4524   cell_set_text (GTK_CLIST (ctree), &(GTK_CTREE_ROW(node)->row), column, text);
4525   tree_draw_node (ctree, node);
4526 }
4527
4528 void 
4529 gtk_ctree_set_pixmap (GtkCTree     *ctree,
4530                       GtkCTreeNode *node,
4531                       gint          column,
4532                       GdkPixmap    *pixmap,
4533                       GdkBitmap    *mask)
4534 {
4535   g_return_if_fail (ctree != NULL);
4536   g_return_if_fail (GTK_IS_CTREE (ctree));
4537   g_return_if_fail (node != NULL);
4538   g_return_if_fail (pixmap != NULL);
4539   g_return_if_fail (ctree->tree_column != column);
4540
4541   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4542     return;
4543
4544   gdk_pixmap_ref (pixmap);
4545   if (mask) 
4546     gdk_pixmap_ref (mask);
4547
4548   cell_set_pixmap (GTK_CLIST (ctree), &(GTK_CTREE_ROW (node)->row), column, 
4549                    pixmap, mask);
4550   tree_draw_node (ctree, node);
4551 }
4552
4553 void 
4554 gtk_ctree_set_pixtext (GtkCTree     *ctree,
4555                        GtkCTreeNode *node,
4556                        gint          column,
4557                        gchar        *text,
4558                        guint8        spacing,
4559                        GdkPixmap    *pixmap,
4560                        GdkBitmap    *mask)
4561 {
4562   g_return_if_fail (ctree != NULL);
4563   g_return_if_fail (GTK_IS_CTREE (ctree));
4564   g_return_if_fail (node != NULL);
4565   g_return_if_fail (pixmap != NULL);
4566   g_return_if_fail (ctree->tree_column != column);
4567
4568   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4569     return;
4570
4571   gdk_pixmap_ref (pixmap);
4572   if (mask) 
4573     gdk_pixmap_ref (mask);
4574
4575   cell_set_pixtext (GTK_CLIST (ctree), &(GTK_CTREE_ROW (node)->row), column,
4576                     text, spacing, pixmap, mask);
4577   tree_draw_node (ctree, node);
4578 }
4579
4580 void 
4581 gtk_ctree_set_node_info (GtkCTree     *ctree,
4582                          GtkCTreeNode *node,
4583                          gchar        *text,
4584                          guint8        spacing,
4585                          GdkPixmap    *pixmap_closed,
4586                          GdkBitmap    *mask_closed,
4587                          GdkPixmap    *pixmap_opened,
4588                          GdkBitmap    *mask_opened,
4589                          gboolean      is_leaf,
4590                          gboolean      expanded)
4591 {
4592   gboolean old_leaf;
4593   gboolean old_expanded;
4594  
4595   g_return_if_fail (ctree != NULL);
4596   g_return_if_fail (GTK_IS_CTREE (ctree));
4597   g_return_if_fail (node != NULL);
4598
4599   old_leaf = GTK_CTREE_ROW (node)->is_leaf;
4600   old_expanded = GTK_CTREE_ROW (node)->expanded;
4601
4602   if (is_leaf && GTK_CTREE_ROW (node)->children)
4603     {
4604       GtkCTreeNode *work;
4605       GtkCTreeNode *ptr;
4606       
4607       work = GTK_CTREE_ROW (node)->children;
4608       while (work)
4609         {
4610           ptr = work;
4611           work = GTK_CTREE_ROW(work)->sibling;
4612           gtk_ctree_remove (ctree, ptr);
4613         }
4614     }
4615
4616   set_node_info (ctree, node, text, spacing, pixmap_closed, mask_closed,
4617                  pixmap_opened, mask_opened, is_leaf, expanded);
4618
4619   if (!is_leaf && !old_leaf)
4620     {
4621       GTK_CTREE_ROW (node)->expanded = old_expanded;
4622       if (expanded && !old_expanded)
4623         gtk_ctree_expand (ctree, node);
4624       else if (!expanded && old_expanded)
4625         gtk_ctree_collapse (ctree, node);
4626     }
4627
4628   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4629   
4630   tree_draw_node (ctree, node);
4631 }
4632
4633 void
4634 gtk_ctree_set_shift (GtkCTree     *ctree,
4635                      GtkCTreeNode *node,
4636                      gint          column,
4637                      gint          vertical,
4638                      gint          horizontal)
4639 {
4640   g_return_if_fail (ctree != NULL);
4641   g_return_if_fail (GTK_IS_CTREE (ctree));
4642   g_return_if_fail (node != NULL);
4643
4644   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4645     return;
4646
4647   GTK_CTREE_ROW (node)->row.cell[column].vertical   = vertical;
4648   GTK_CTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4649
4650   tree_draw_node (ctree, node);
4651 }
4652
4653 GtkCellType 
4654 gtk_ctree_get_cell_type (GtkCTree     *ctree,
4655                          GtkCTreeNode *node,
4656                          gint          column)
4657 {
4658   g_return_val_if_fail (ctree != NULL, -1);
4659   g_return_val_if_fail (GTK_IS_CTREE (ctree), -1);
4660   g_return_val_if_fail (node != NULL, -1);
4661
4662   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4663     return -1;
4664
4665   return GTK_CTREE_ROW (node)->row.cell[column].type;
4666 }
4667
4668 gint
4669 gtk_ctree_get_text (GtkCTree      *ctree,
4670                     GtkCTreeNode  *node,
4671                     gint           column,
4672                     gchar        **text)
4673 {
4674   g_return_val_if_fail (ctree != NULL, 0);
4675   g_return_val_if_fail (GTK_IS_CTREE (ctree), 0);
4676   g_return_val_if_fail (node != NULL, 0);
4677
4678   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4679     return 0;
4680
4681   if (GTK_CTREE_ROW (node)->row.cell[column].type != GTK_CELL_TEXT)
4682     return 0;
4683
4684   if (text)
4685     *text = GTK_CELL_TEXT (GTK_CTREE_ROW (node)->row.cell[column])->text;
4686
4687   return 1;
4688 }
4689
4690 gint
4691 gtk_ctree_get_pixmap (GtkCTree     *ctree,
4692                       GtkCTreeNode *node,
4693                       gint          column,
4694                       GdkPixmap   **pixmap,
4695                       GdkBitmap   **mask)
4696 {
4697   g_return_val_if_fail (ctree != NULL, 0);
4698   g_return_val_if_fail (GTK_IS_CTREE (ctree), 0);
4699   g_return_val_if_fail (node != NULL, 0);
4700
4701   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4702     return 0;
4703
4704   if (GTK_CTREE_ROW (node)->row.cell[column].type != GTK_CELL_PIXMAP)
4705     return 0;
4706
4707   if (pixmap)
4708     *pixmap = GTK_CELL_PIXMAP (GTK_CTREE_ROW(node)->row.cell[column])->pixmap;
4709   if (mask)
4710     *mask = GTK_CELL_PIXMAP (GTK_CTREE_ROW (node)->row.cell[column])->mask;
4711
4712   return 1;
4713 }
4714
4715 gint
4716 gtk_ctree_get_pixtext (GtkCTree      *ctree,
4717                        GtkCTreeNode  *node,
4718                        gint           column,
4719                        gchar        **text,
4720                        guint8        *spacing,
4721                        GdkPixmap    **pixmap,
4722                        GdkBitmap    **mask)
4723 {
4724   g_return_val_if_fail (ctree != NULL, 0);
4725   g_return_val_if_fail (GTK_IS_CTREE (ctree), 0);
4726   g_return_val_if_fail (node != NULL, 0);
4727   
4728   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4729     return 0;
4730   
4731   if (GTK_CTREE_ROW (node)->row.cell[column].type != GTK_CELL_PIXTEXT)
4732     return 0;
4733   
4734   if (text)
4735     *text = GTK_CELL_PIXTEXT (GTK_CTREE_ROW (node)->row.cell[column])->text;
4736   if (spacing)
4737     *spacing = GTK_CELL_PIXTEXT (GTK_CTREE_ROW 
4738                                  (node)->row.cell[column])->spacing;
4739   if (pixmap)
4740     *pixmap = GTK_CELL_PIXTEXT (GTK_CTREE_ROW 
4741                                 (node)->row.cell[column])->pixmap;
4742   if (mask)
4743     *mask = GTK_CELL_PIXTEXT (GTK_CTREE_ROW (node)->row.cell[column])->mask;
4744   
4745   return 1;
4746 }
4747
4748 gint
4749 gtk_ctree_get_node_info (GtkCTree      *ctree,
4750                          GtkCTreeNode  *node,
4751                          gchar        **text,
4752                          guint8        *spacing,
4753                          GdkPixmap    **pixmap_closed,
4754                          GdkBitmap    **mask_closed,
4755                          GdkPixmap    **pixmap_opened,
4756                          GdkBitmap    **mask_opened,
4757                          gboolean      *is_leaf,
4758                          gboolean      *expanded)
4759 {
4760   g_return_val_if_fail (ctree != NULL, 0);
4761   g_return_val_if_fail (GTK_IS_CTREE (ctree), 0);
4762   g_return_val_if_fail (node != NULL, 0);
4763   
4764   if (text)
4765     *text = GTK_CELL_PIXTEXT 
4766       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->text;
4767   if (spacing)
4768     *spacing = GTK_CELL_PIXTEXT 
4769       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
4770   if (pixmap_closed)
4771     *pixmap_closed = GTK_CTREE_ROW (node)->pixmap_closed;
4772   if (mask_closed)
4773     *mask_closed = GTK_CTREE_ROW (node)->mask_closed;
4774   if (pixmap_opened)
4775     *pixmap_opened = GTK_CTREE_ROW (node)->pixmap_opened;
4776   if (mask_opened)
4777     *mask_opened = GTK_CTREE_ROW (node)->mask_opened;
4778   if (is_leaf)
4779     *is_leaf = GTK_CTREE_ROW (node)->is_leaf;
4780   if (expanded)
4781     *expanded = GTK_CTREE_ROW (node)->expanded;
4782   
4783   return 1;
4784 }
4785
4786 void
4787 gtk_ctree_set_foreground (GtkCTree     *ctree,
4788                           GtkCTreeNode *node,
4789                           GdkColor     *color)
4790 {
4791   g_return_if_fail (ctree != NULL);
4792   g_return_if_fail (GTK_IS_CTREE (ctree));
4793   g_return_if_fail (node != NULL);
4794
4795   if (color)
4796     {
4797       GTK_CTREE_ROW (node)->row.foreground = *color;
4798       GTK_CTREE_ROW (node)->row.fg_set = TRUE;
4799     }
4800   else
4801     GTK_CTREE_ROW (node)->row.fg_set = FALSE;
4802
4803   tree_draw_node (ctree, node);
4804 }
4805
4806 void
4807 gtk_ctree_set_background (GtkCTree     *ctree,
4808                           GtkCTreeNode *node,
4809                           GdkColor     *color)
4810 {
4811   g_return_if_fail (ctree != NULL);
4812   g_return_if_fail (GTK_IS_CTREE (ctree));
4813   g_return_if_fail (node != NULL);
4814
4815   if (color)
4816     {
4817       GTK_CTREE_ROW (node)->row.background = *color;
4818       GTK_CTREE_ROW (node)->row.bg_set = TRUE;
4819     }
4820   else
4821     GTK_CTREE_ROW (node)->row.bg_set = FALSE;
4822
4823   tree_draw_node (ctree, node);
4824 }
4825
4826 void
4827 gtk_ctree_set_row_data (GtkCTree     *ctree,
4828                         GtkCTreeNode *node,
4829                         gpointer      data)
4830 {
4831   gtk_ctree_set_row_data_full (ctree, node, data, NULL);
4832 }
4833
4834 void
4835 gtk_ctree_set_row_data_full (GtkCTree         *ctree,
4836                              GtkCTreeNode     *node,
4837                              gpointer          data,
4838                              GtkDestroyNotify  destroy)
4839 {
4840   g_return_if_fail (ctree != NULL);
4841   g_return_if_fail (GTK_IS_CTREE (ctree));
4842
4843   GTK_CTREE_ROW (node)->row.data = data;
4844   GTK_CTREE_ROW (node)->row.destroy = destroy;
4845 }
4846
4847 gpointer
4848 gtk_ctree_get_row_data (GtkCTree     *ctree,
4849                         GtkCTreeNode *node)
4850 {
4851   g_return_val_if_fail (ctree != NULL, NULL);
4852   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4853
4854   return node ? GTK_CTREE_ROW (node)->row.data : NULL;
4855 }
4856
4857 void
4858 gtk_ctree_moveto (GtkCTree     *ctree,
4859                   GtkCTreeNode *node,
4860                   gint          column,
4861                   gfloat        row_align,
4862                   gfloat        col_align)
4863 {
4864   gint row = -1;
4865   GtkCList *clist;
4866
4867   g_return_if_fail (ctree != NULL);
4868   g_return_if_fail (GTK_IS_CTREE (ctree));
4869
4870   clist = GTK_CLIST (ctree);
4871
4872   while (node && !gtk_ctree_is_visible (ctree, node))
4873     node = GTK_CTREE_ROW (node)->parent;
4874
4875   if (node)
4876     row = g_list_position (clist->row_list, (GList *)node);
4877   
4878   gtk_clist_moveto (clist, row, column, row_align, col_align);
4879 }
4880
4881
4882 /***********************************************************
4883  *             GtkCTree specific functions                 *
4884  ***********************************************************/
4885
4886
4887 void
4888 gtk_ctree_set_indent (GtkCTree *ctree, 
4889                       gint      indent)
4890 {
4891   g_return_if_fail (ctree != NULL);
4892   g_return_if_fail (GTK_IS_CTREE (ctree));
4893   g_return_if_fail (indent >= 0);
4894
4895   if (indent != ctree->tree_indent)
4896     {
4897       ctree->tree_indent = indent;
4898       if (!GTK_CLIST_FROZEN (ctree))
4899         gtk_clist_thaw (GTK_CLIST (ctree));
4900     }
4901 }
4902
4903 void
4904 gtk_ctree_set_reorderable (GtkCTree *ctree, 
4905                            gboolean  reorderable)
4906 {
4907   g_return_if_fail (ctree != NULL);
4908   g_return_if_fail (GTK_IS_CTREE (ctree));
4909
4910   if (ctree->reorderable == (reorderable != 0))
4911     return;
4912
4913   ctree->reorderable = (reorderable != 0);
4914   
4915   if (GTK_WIDGET_REALIZED (ctree))
4916     {
4917       if (ctree->reorderable)
4918         create_xor_gc (ctree);
4919       else
4920         gdk_gc_destroy (ctree->xor_gc);
4921     }
4922 }
4923
4924 void
4925 gtk_ctree_set_use_drag_icons (GtkCTree *ctree,
4926                               gboolean  use_icons)
4927 {
4928   g_return_if_fail (ctree != NULL);
4929   g_return_if_fail (GTK_IS_CTREE (ctree));
4930
4931   if (ctree->use_icons == (use_icons != 0))
4932     return;
4933
4934   ctree->use_icons = (use_icons != 0);
4935 }
4936
4937 void 
4938 gtk_ctree_set_line_style (GtkCTree          *ctree, 
4939                           GtkCTreeLineStyle  line_style)
4940 {
4941   g_return_if_fail (ctree != NULL);
4942   g_return_if_fail (GTK_IS_CTREE (ctree));
4943
4944   if (line_style != ctree->line_style)
4945     {
4946       ctree->line_style = line_style;
4947
4948       if (!GTK_WIDGET_REALIZED (ctree))
4949         return;
4950
4951       switch (line_style)
4952         {
4953         case GTK_CTREE_LINES_SOLID:
4954           if (GTK_WIDGET_REALIZED (ctree))
4955             gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID, 
4956                                         None, None);
4957           break;
4958         case GTK_CTREE_LINES_DOTTED:
4959           if (GTK_WIDGET_REALIZED (ctree))
4960             gdk_gc_set_line_attributes (ctree->lines_gc, 1, 
4961                                         GDK_LINE_ON_OFF_DASH, None, None);
4962           gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2);
4963           break;
4964         case GTK_CTREE_LINES_TABBED:
4965           if (GTK_WIDGET_REALIZED (ctree))
4966             gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID, 
4967                                         None, None);
4968           break;
4969         case GTK_CTREE_LINES_NONE:
4970           break;
4971         default:
4972           return;
4973         }
4974       if (!GTK_CLIST_FROZEN (ctree))
4975         gtk_clist_thaw (GTK_CLIST (ctree));
4976     }
4977 }
4978
4979
4980 /***********************************************************
4981  *             Tree sorting functions                      *
4982  ***********************************************************/
4983
4984
4985 static void
4986 tree_sort (GtkCTree     *ctree,
4987            GtkCTreeNode *node,
4988            gpointer      data)
4989 {
4990   GtkCTreeNode *list_start;
4991   GtkCTreeNode *cmp;
4992   GtkCTreeNode *work;
4993   GtkCList *clist;
4994
4995   clist = GTK_CLIST (ctree);
4996
4997   if (node)
4998     list_start = GTK_CTREE_ROW (node)->children;
4999   else
5000     list_start = GTK_CTREE_NODE (clist->row_list);
5001
5002   while (list_start)
5003     {
5004       cmp = list_start;
5005       work = GTK_CTREE_ROW (cmp)->sibling;
5006       while (work)
5007         {
5008           if (clist->sort_type == GTK_SORT_ASCENDING)
5009             {
5010               if (clist->compare (clist, work, cmp) < 0)
5011                 cmp = work;
5012             }
5013           else
5014             {
5015               if (clist->compare (clist, work, cmp) > 0)
5016                 cmp = work;
5017             }
5018           work = GTK_CTREE_ROW (work)->sibling;
5019         }
5020       if (cmp == list_start)
5021         list_start = GTK_CTREE_ROW (cmp)->sibling;
5022       else
5023         {
5024           gtk_ctree_unlink (ctree, cmp, FALSE);
5025           gtk_ctree_link (ctree, cmp, node, list_start, FALSE);
5026         }
5027     }
5028 }
5029
5030 void
5031 gtk_ctree_sort_recursive (GtkCTree     *ctree, 
5032                           GtkCTreeNode *node)
5033 {
5034   GtkCList *clist;
5035   GtkCTreeNode *focus_node = NULL;
5036   gboolean thaw = FALSE;
5037
5038   g_return_if_fail (ctree != NULL);
5039   g_return_if_fail (GTK_IS_CTREE (ctree));
5040
5041   clist = GTK_CLIST (ctree);
5042
5043   if (!GTK_CLIST_FROZEN (clist))
5044     {
5045       gtk_clist_freeze (clist);
5046       thaw = TRUE;
5047     }
5048
5049   if (clist->selection_mode == GTK_SELECTION_EXTENDED)
5050     {
5051       if (clist->anchor != -1)
5052         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5053       
5054       g_list_free (clist->undo_selection);
5055       g_list_free (clist->undo_unselection);
5056       clist->undo_selection = NULL;
5057       clist->undo_unselection = NULL;
5058     }
5059
5060   if (!node || (node && gtk_ctree_is_visible (ctree, node)))
5061     focus_node =
5062       GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
5063       
5064   gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL);
5065
5066   if (!node)
5067     tree_sort (ctree, NULL, NULL);
5068
5069   if (focus_node)
5070     {
5071       clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5072       clist->undo_anchor = clist->focus_row;
5073     }
5074
5075   if (thaw)
5076     gtk_clist_thaw (clist);
5077 }
5078
5079 void
5080 gtk_ctree_sort (GtkCTree     *ctree, 
5081                 GtkCTreeNode *node)
5082 {
5083   GtkCList *clist;
5084   GtkCTreeNode *focus_node = NULL;
5085   gboolean thaw = FALSE;
5086
5087   g_return_if_fail (ctree != NULL);
5088   g_return_if_fail (GTK_IS_CTREE (ctree));
5089
5090   clist = GTK_CLIST (ctree);
5091
5092   if (!GTK_CLIST_FROZEN (clist))
5093     {
5094       gtk_clist_freeze (clist);
5095       thaw = TRUE;
5096     }
5097
5098   if (clist->selection_mode == GTK_SELECTION_EXTENDED)
5099     {
5100       if (clist->anchor != -1)
5101         GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
5102       
5103       g_list_free (clist->undo_selection);
5104       g_list_free (clist->undo_unselection);
5105       clist->undo_selection = NULL;
5106       clist->undo_unselection = NULL;
5107     }
5108
5109   if (!node || (node && gtk_ctree_is_visible (ctree, node)))
5110     focus_node = GTK_CTREE_NODE
5111       (g_list_nth (clist->row_list, clist->focus_row));
5112
5113   tree_sort (ctree, node, NULL);
5114
5115   if (focus_node)
5116     {
5117       clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5118       clist->undo_anchor = clist->focus_row;
5119     }
5120
5121   if (thaw)
5122     gtk_clist_thaw (clist);
5123 }
5124
5125 /************************************************************************/
5126
5127 static void
5128 fake_unselect_all (GtkCList *clist,
5129                    gint      row)
5130 {
5131   GList *list;
5132   GList *focus_node = NULL;
5133
5134   if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
5135     {
5136       if (GTK_CTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL)
5137         {
5138           GTK_CTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
5139           
5140           if (!GTK_CLIST_FROZEN (clist) &&
5141               gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5142             GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row,
5143                                                   GTK_CLIST_ROW (focus_node));
5144         }  
5145     }
5146
5147   clist->undo_selection = clist->selection;
5148   clist->selection = NULL;
5149   clist->selection_end = NULL;
5150   
5151   for (list = clist->undo_selection; list; list = list->next)
5152     {
5153       if (list->data == focus_node)
5154         continue;
5155
5156       GTK_CTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
5157       tree_draw_node (GTK_CTREE (clist), GTK_CTREE_NODE (list->data));
5158     }
5159 }
5160
5161 static GList *
5162 selection_find (GtkCList *clist,
5163                 gint      row_number,
5164                 GList    *row_list_element)
5165 {
5166   return g_list_find (clist->selection, row_list_element);
5167 }
5168
5169 static void
5170 resync_selection (GtkCList *clist, GdkEvent *event)
5171 {
5172   GtkCTree *ctree;
5173   GList *list;
5174   GtkCTreeNode *node;
5175   gint i;
5176   gint e;
5177   gint row;
5178   gboolean thaw = FALSE;
5179   gboolean unselect;
5180
5181   g_return_if_fail (clist != NULL);
5182   g_return_if_fail (GTK_IS_CTREE (clist));
5183
5184   if (clist->anchor < 0)
5185     return;
5186
5187   ctree = GTK_CTREE (clist);
5188   
5189   if (!GTK_CLIST_FROZEN (clist))
5190     {
5191       GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN);
5192       thaw = TRUE;
5193     }
5194
5195   i = MIN (clist->anchor, clist->drag_pos);
5196   e = MAX (clist->anchor, clist->drag_pos);
5197
5198   if (clist->undo_selection)
5199     {
5200       list = clist->selection;
5201       clist->selection = clist->undo_selection;
5202       clist->selection_end = g_list_last (clist->selection);
5203       clist->undo_selection = list;
5204       list = clist->selection;
5205
5206       while (list)
5207         {
5208           node = list->data;
5209           list = list->next;
5210           
5211           unselect = TRUE;
5212
5213           if (gtk_ctree_is_visible (ctree, node))
5214             {
5215               row = g_list_position (clist->row_list, (GList *)node);
5216               if (row >= i && row <= e)
5217                 unselect = FALSE;
5218             }
5219           if (unselect)
5220             {
5221               GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5222               gtk_ctree_unselect (ctree, node);
5223               clist->undo_selection = g_list_prepend (clist->undo_selection,
5224                                                       node);
5225             }
5226         }
5227     }    
5228
5229
5230   for (node = GTK_CTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
5231        i++, node = GTK_CTREE_NODE_NEXT (node))
5232     if (g_list_find (clist->selection, node))
5233       {
5234         if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5235           {
5236             GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5237             gtk_ctree_unselect (ctree, node);
5238             clist->undo_selection = g_list_prepend (clist->undo_selection,
5239                                                     node);
5240           }
5241       }
5242     else if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5243       {
5244         GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5245         clist->undo_unselection = g_list_prepend (clist->undo_unselection,
5246                                                   node);
5247       }
5248
5249   for (list = clist->undo_unselection; list; list = list->next)
5250     gtk_ctree_select (ctree, list->data);
5251
5252   clist->anchor = -1;
5253   clist->drag_pos = -1;
5254
5255   if (thaw)
5256     GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN);
5257 }
5258
5259 static void
5260 real_undo_selection (GtkCList *clist)
5261 {
5262   GtkCTree *ctree;
5263   GList *work;
5264
5265   g_return_if_fail (clist != NULL);
5266   g_return_if_fail (GTK_IS_CTREE (clist));
5267
5268   if (clist->selection_mode != GTK_SELECTION_EXTENDED)
5269     return;
5270
5271   if (!(clist->undo_selection || clist->undo_unselection))
5272     {
5273       gtk_clist_unselect_all (clist);
5274       return;
5275     }
5276
5277   ctree = GTK_CTREE (clist);
5278
5279   for (work = clist->undo_selection; work; work = work->next)
5280     gtk_ctree_select (ctree, GTK_CTREE_NODE (work->data));
5281
5282   for (work = clist->undo_unselection; work; work = work->next)
5283     gtk_ctree_unselect (ctree, GTK_CTREE_NODE (work->data));
5284
5285   if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor)
5286     {
5287       gtk_widget_draw_focus (GTK_WIDGET (clist));
5288       clist->focus_row = clist->undo_anchor;
5289       gtk_widget_draw_focus (GTK_WIDGET (clist));
5290     }
5291   else
5292     clist->focus_row = clist->undo_anchor;
5293   
5294   clist->undo_anchor = -1;
5295  
5296   g_list_free (clist->undo_selection);
5297   g_list_free (clist->undo_unselection);
5298   clist->undo_selection = NULL;
5299   clist->undo_unselection = NULL;
5300
5301   if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5302       clist->clist_window_height)
5303     gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5304   else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5305     gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5306
5307 }