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