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