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