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