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