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