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