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