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