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