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