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