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