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