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