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