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