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