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