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