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