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