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