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