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