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