Ignore the expander "hot spots" in folderview for childless folders.
[claws.git] / src / gtk / gtksctree.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Parts of this file:
4  * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
5  *
6  * Parts of this file from gtk/gtkctree.c and gtk/gtkclist.c:
7  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, 
8  * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>  
9  *
10  * Parts of this file from gtkflist.c:
11  * Copyright (C) 1999 The Free Software Foundation
12  * Author: Federico Mena <federico@nuclecu.unam.mx>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program. If not, see <http://www.gnu.org/licenses/>.
26  * 
27  */
28
29 #include <stdlib.h>
30
31 #include "gtksctree.h"
32 #include "claws-marshal.h"
33 #include "prefs_common.h"
34 #include "utils.h"
35 #include "gtkutils.h"
36
37 #define CLIST_UNFROZEN(clist)     (((GtkCMCList*) (clist))->freeze_count == 0)
38 #define CLIST_REFRESH(clist)    G_STMT_START { \
39   if (CLIST_UNFROZEN (clist)) \
40     GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
41 } G_STMT_END
42 #define CELL_SPACING               1
43 #define CLIST_OPTIMUM_SIZE         64
44 #define COLUMN_INSET               3
45 #define PM_SIZE                    8
46 #define TAB_SIZE                   (PM_SIZE + 6)
47 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
48                                     (((row) + 1) * CELL_SPACING) + \
49                                     (clist)->voffset)
50 #define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
51                                     ((clist)->row_height + CELL_SPACING))
52 #define COLUMN_LEFT_XPIXEL(clist, col)  ((clist)->column[(col)].area.x \
53                                     + (clist)->hoffset)
54 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
55
56 enum {
57         ROW_POPUP_MENU,
58         EMPTY_POPUP_MENU,
59         OPEN_ROW,
60         START_DRAG,
61         LAST_SIGNAL
62 };
63
64 static void gtk_sctree_class_init (GtkSCTreeClass *class);
65 static void gtk_sctree_init (GtkSCTree *sctree);
66
67 static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event);
68 static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event);
69 static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event);
70 static void gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context);
71 static void gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context);
72 static void gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
73                                      GtkSelectionData *data, guint info, guint time);
74 static void gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time);
75 static gboolean gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
76                                        gint x, gint y, guint time);
77 static gboolean gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
78                                      gint x, gint y, guint time);
79 static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
80                                           gint x, gint y, GtkSelectionData *data,
81                                           guint info, guint time);
82
83 static void gtk_sctree_clear (GtkCMCList *clist);
84 static void gtk_sctree_real_unselect_all (GtkCMCList *clist);
85        
86 static void stree_sort (GtkCMCTree *ctree, GtkCMCTreeNode  *node, gpointer data);
87 void gtk_sctree_sort_node (GtkCMCTree *ctree, GtkCMCTreeNode *node);
88 void gtk_sctree_sort_recursive (GtkCMCTree *ctree, GtkCMCTreeNode *node);
89
90 static void gtk_sctree_link (GtkCMCTree *ctree,
91                         GtkCMCTreeNode  *node,
92                         GtkCMCTreeNode  *parent,
93                         GtkCMCTreeNode  *sibling,
94                         gboolean       update_focus_row);
95
96 static void gtk_sctree_unlink (GtkCMCTree      *ctree, 
97                         GtkCMCTreeNode  *node,
98                         gboolean       update_focus_row);
99
100 static void stree_update_level (GtkCMCTree      *ctree, 
101                         GtkCMCTreeNode  *node, 
102                         gpointer       data);
103
104 static GtkCMCTreeNode * gtk_sctree_last_visible (GtkCMCTree     *ctree,
105                                               GtkCMCTreeNode *node);
106 static void gtk_sctree_real_tree_expand            (GtkCMCTree      *ctree,
107                                                  GtkCMCTreeNode  *node);
108 static void gtk_sctree_real_tree_collapse          (GtkCMCTree      *ctree,
109                                                  GtkCMCTreeNode  *node);
110 static void
111 sreal_tree_move (GtkCMCTree     *ctree,
112                 GtkCMCTreeNode *node,
113                 GtkCMCTreeNode *new_parent, 
114                 GtkCMCTreeNode *new_sibling);
115
116 static GtkCMCTreeClass *parent_class;
117
118 static guint sctree_signals[LAST_SIGNAL];
119
120 /**
121  * gtk_sctree_get_type:
122  * @void: 
123  * 
124  * Creates the GtkSCTree class and its type information
125  * 
126  * Return value: The type ID for GtkSCTreeClass
127  **/
128 GType
129 gtk_sctree_get_type (void)
130 {
131         static GType sctree_type = 0;
132
133         if (!sctree_type) {
134                 GTypeInfo sctree_info = {
135                         sizeof (GtkSCTreeClass),
136
137                         (GBaseInitFunc) NULL,
138                         (GBaseFinalizeFunc) NULL,
139
140                         (GClassInitFunc) gtk_sctree_class_init,
141                         (GClassFinalizeFunc) NULL,
142                         NULL,   /* class_data */
143
144                         sizeof (GtkSCTree),
145                         0,      /* n_preallocs */
146                         (GInstanceInitFunc) gtk_sctree_init,
147                 };
148
149                 sctree_type = g_type_register_static (GTK_TYPE_CMCTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0);
150         }
151
152         return sctree_type;
153 }
154
155 static void
156 gtk_sctree_change_focus_row_expansion (GtkCMCTree          *ctree,
157                             GtkCMCTreeExpansionType action)
158 {
159   GtkCMCList *clist;
160   GtkCMCTreeNode *node;
161
162   cm_return_if_fail (GTK_IS_CMCTREE (ctree));
163
164   clist = GTK_CMCLIST (ctree);
165
166   if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) && 
167       gtk_widget_has_grab (GTK_WIDGET(ctree)))
168     return;
169   
170   if (!(node =
171         GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
172       GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
173     return;
174
175   switch (action)
176     {
177     case GTK_CMCTREE_EXPANSION_EXPAND:
178       if (GTK_SCTREE(ctree)->always_expand_recursively)
179               gtk_cmctree_expand_recursive (ctree, node);
180       else
181               gtk_cmctree_expand (ctree, node);
182
183       break;
184     case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
185       gtk_cmctree_expand_recursive (ctree, node);
186       break;
187     case GTK_CMCTREE_EXPANSION_COLLAPSE:
188       gtk_cmctree_collapse (ctree, node);
189       break;
190     case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
191       gtk_cmctree_collapse_recursive (ctree, node);
192       break;
193     case GTK_CMCTREE_EXPANSION_TOGGLE:
194       if (GTK_SCTREE(ctree)->always_expand_recursively)
195               gtk_cmctree_toggle_expansion_recursive (ctree, node);
196       else
197               gtk_cmctree_toggle_expansion (ctree, node);
198       break;
199     case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
200       gtk_cmctree_toggle_expansion_recursive (ctree, node);
201       break;
202     }
203 }
204
205 static void gtk_sctree_finalize(GObject *object)
206 {
207         GtkSCTree *sctree = GTK_SCTREE(object);
208         g_free(sctree->use_markup);
209         sctree->use_markup = NULL;
210         G_OBJECT_CLASS (parent_class)->finalize (object);
211 }
212
213 /* Standard class initialization function */
214 static void
215 gtk_sctree_class_init (GtkSCTreeClass *klass)
216 {
217         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
218         GtkWidgetClass *widget_class;
219         GtkCMCListClass *clist_class;
220         GtkCMCTreeClass *ctree_class;
221
222         widget_class = (GtkWidgetClass *) klass;
223         clist_class = (GtkCMCListClass *) klass;
224         ctree_class = (GtkCMCTreeClass *) klass;
225
226         parent_class = g_type_class_peek (gtk_cmctree_get_type ());
227
228         sctree_signals[ROW_POPUP_MENU] =
229                 g_signal_new ("row_popup_menu",
230                               G_TYPE_FROM_CLASS (klass),
231                               G_SIGNAL_RUN_FIRST,
232                               G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
233                               NULL, NULL,
234                               claws_marshal_VOID__POINTER,
235                               G_TYPE_NONE, 1,
236                               GDK_TYPE_EVENT);
237         sctree_signals[EMPTY_POPUP_MENU] =
238                 g_signal_new ("empty_popup_menu",
239                               G_TYPE_FROM_CLASS (klass),
240                               G_SIGNAL_RUN_FIRST,
241                               G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
242                               NULL, NULL,
243                               claws_marshal_VOID__POINTER,
244                               G_TYPE_NONE, 1,
245                               GDK_TYPE_EVENT);
246         sctree_signals[OPEN_ROW] =
247                 g_signal_new ("open_row",
248                               G_TYPE_FROM_CLASS (klass),
249                               G_SIGNAL_RUN_FIRST,
250                               G_STRUCT_OFFSET (GtkSCTreeClass, open_row),
251                               NULL, NULL,
252                               g_cclosure_marshal_VOID__VOID,
253                               G_TYPE_NONE, 0);
254         sctree_signals[START_DRAG] =
255                 g_signal_new ("start_drag",
256                               G_TYPE_FROM_CLASS (klass),
257                               G_SIGNAL_RUN_FIRST,
258                               G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
259                               NULL, NULL,
260                               claws_marshal_VOID__INT_POINTER,
261                               G_TYPE_NONE, 2,
262                               G_TYPE_INT,
263                               GDK_TYPE_EVENT);
264
265         /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */
266
267         clist_class->clear = gtk_sctree_clear;
268         clist_class->unselect_all = gtk_sctree_real_unselect_all;
269         ctree_class->tree_collapse = gtk_sctree_real_tree_collapse;
270         ctree_class->tree_expand = gtk_sctree_real_tree_expand;
271         ctree_class->tree_move = sreal_tree_move;
272         ctree_class->change_focus_row_expansion = gtk_sctree_change_focus_row_expansion;
273         
274         widget_class->button_press_event = gtk_sctree_button_press;
275         widget_class->button_release_event = gtk_sctree_button_release;
276         widget_class->motion_notify_event = gtk_sctree_motion;
277         widget_class->drag_begin = gtk_sctree_drag_begin;
278         widget_class->drag_end = gtk_sctree_drag_end;
279         widget_class->drag_data_get = gtk_sctree_drag_data_get;
280         widget_class->drag_leave = gtk_sctree_drag_leave;
281         widget_class->drag_motion = gtk_sctree_drag_motion;
282         widget_class->drag_drop = gtk_sctree_drag_drop;
283         widget_class->drag_data_received = gtk_sctree_drag_data_received;
284         
285         gobject_class->finalize = gtk_sctree_finalize;
286 }
287
288 /* Standard object initialization function */
289 static void
290 gtk_sctree_init (GtkSCTree *sctree)
291 {
292         sctree->anchor_row = NULL;
293
294         /* GtkCMCTree does not specify pointer motion by default */
295         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
296         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
297 }
298
299 /* Get information the specified row is selected. */
300
301 static gboolean
302 row_is_selected(GtkSCTree *sctree, gint row)
303 {
304         GtkCMCListRow *clist_row;
305         clist_row =  g_list_nth (GTK_CMCLIST(sctree)->row_list, row)->data;
306         return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE;
307 }
308
309 /* Selects the rows between the anchor to the specified row, inclusive.  */
310 static void
311 select_range (GtkSCTree *sctree, gint row)
312 {
313         gint prev_row;
314         gint min, max;
315         gint i;
316         GList *node;
317         if (sctree->anchor_row == NULL) {
318                 prev_row = row;
319                 sctree->anchor_row = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row);
320         } else
321                 prev_row = g_list_position(GTK_CMCLIST(sctree)->row_list,
322                                            (GList *)sctree->anchor_row);
323
324         if (row < prev_row) {
325                 min = row;
326                 max = prev_row;
327                 GTK_CMCLIST(sctree)->focus_row = min;
328         } else {
329                 min = prev_row;
330                 max = row;
331         }
332         sctree->selecting_range++;
333         
334         if (max < min) {
335                 int t = min;
336                 min = max;
337                 max = t;
338         }
339         
340         if (max - min > 10)
341                 gtk_cmclist_freeze(GTK_CMCLIST(sctree));
342
343         node = g_list_nth((GTK_CMCLIST(sctree))->row_list, min);
344         for (i = min; i < max; i++) {
345                 if (node && GTK_CMCTREE_ROW (node)->row.selectable) {
346                         g_signal_emit_by_name(G_OBJECT(sctree), "tree_select_row",
347                                 node, -1);
348                 }
349                 node = node->next;
350         }
351         if (max - min > 10)
352                 gtk_cmclist_thaw(GTK_CMCLIST(sctree));
353
354
355         sctree->selecting_range--;
356         gtk_cmclist_select_row (GTK_CMCLIST (sctree), max, -1);
357 }
358
359 /* Handles row selection according to the specified modifier state */
360 /* in certain cases, we arrive here from a function knowing the GtkCMCTreeNode, and having
361  * already slowly found row using g_list_position. In which case, _node will be non-NULL
362  * to avoid this function having to slowly find it with g_list_nth. */
363 static void
364 select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCMCTreeNode *_node)
365 {
366         gboolean range, additive;
367         cm_return_if_fail (sctree != NULL);
368         cm_return_if_fail (GTK_IS_SCTREE (sctree));
369     
370         range = ((state & GDK_SHIFT_MASK) != 0) &&
371                 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
372                 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
373         additive = ((state & GDK_CONTROL_MASK) != 0) &&
374                    (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
375                    (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
376
377         if (!range && !additive && sctree->force_additive_sel)
378                 additive = TRUE;
379
380         GTK_CMCLIST(sctree)->focus_row = row;
381
382         if (!additive) {
383                 gtk_cmclist_unselect_all (GTK_CMCLIST (sctree));
384         }
385
386         if (!range) {
387                 GtkCMCTreeNode *node;
388
389                 node = _node ? _node : gtk_cmctree_node_nth (GTK_CMCTREE(sctree), row);
390
391                 /*No need to manage overlapped list*/
392                 if (additive) {
393                         if (row_is_selected(sctree, row))
394                                 gtk_cmclist_unselect_row (GTK_CMCLIST (sctree), row, col);
395                         else
396                                 g_signal_emit_by_name
397                                         (G_OBJECT (sctree),
398                                          "tree_select_row", node, col);
399                 } else {
400                         g_signal_emit_by_name
401                                 (G_OBJECT (sctree),
402                                  "tree_select_row", node, col);
403                 }
404                 sctree->anchor_row = node;
405         } else
406                 select_range (sctree, row);
407 }
408
409 static gboolean
410 sctree_is_hot_spot (GtkSCTree     *sctree, 
411                    GtkCMCTreeNode *node,
412                    gint          row, 
413                    gint          x, 
414                    gint          y)
415 {
416   GtkCMCTreeRow *tree_row;
417   GtkCMCList *clist;
418   GtkCMCTree *ctree;
419   gint xl, xmax;
420   gint yu;
421   gint hotspot_size;
422   
423   cm_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE);
424   cm_return_val_if_fail (node != NULL, FALSE);
425
426   clist = GTK_CMCLIST (sctree);
427   ctree = GTK_CMCTREE (sctree);
428
429   if (!clist->column[ctree->tree_column].visible ||
430       ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
431     return FALSE;
432
433   tree_row = GTK_CMCTREE_ROW (node);
434   if (!tree_row->children)
435     return FALSE;
436
437   hotspot_size = clist->row_height-2;
438   if (hotspot_size > clist->column[ctree->tree_column].area.width - 2)
439         hotspot_size = clist->column[ctree->tree_column].area.width - 2;
440
441   if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
442      yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - hotspot_size) / 2 -
443         (clist->row_height - 1) % 2);
444   else
445      yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height/2 - hotspot_size) / 2 -
446         (clist->row_height/2 - 1) % 2);
447
448 #ifndef GENERIC_UMPC
449   if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
450     xl = clist->column[ctree->tree_column].area.x + 
451           clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
452           (tree_row->level - 1) * ctree->tree_indent - hotspot_size;
453   else
454     xl = clist->column[ctree->tree_column].area.x + clist->hoffset +
455           (tree_row->level - 1) * ctree->tree_indent;
456
457   xmax = xl + hotspot_size;
458 #else
459   if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) {
460     xl = clist->column[ctree->tree_column].area.x + 
461           clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
462           (tree_row->level - 1) * ctree->tree_indent - hotspot_size;
463     xmax = xl + hotspot_size;
464   } else if (ctree->tree_column == 0) {
465     xl = clist->column[ctree->tree_column].area.x + clist->hoffset;
466     xmax = clist->column[ctree->tree_column].area.x + clist->hoffset +
467            (tree_row->level - 1) * ctree->tree_indent +
468            hotspot_size;
469   } else {
470     xl = clist->column[ctree->tree_column].area.x + clist->hoffset +
471           (tree_row->level - 1) * ctree->tree_indent;
472     xmax = xl + hotspot_size;
473   }
474 #endif
475   return (x >= xl && x <= xmax && y >= yu && y <= yu + hotspot_size);
476 }
477
478 gboolean
479 gtk_sctree_is_hot_spot (GtkSCTree *ctree, 
480                        gint      x, 
481                        gint      y)
482 {
483   GtkCMCTreeNode *node;
484   gint column;
485   gint row;
486   
487   cm_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE);
488
489   if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
490     if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
491       return sctree_is_hot_spot (ctree, node, row, x, y);
492
493   return FALSE;
494 }
495
496 /* Our handler for button_press events.  We override all of GtkCMCList's broken
497  * behavior.
498  */
499 static gint
500 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
501 {
502         GtkSCTree *sctree;
503         GtkCMCList *clist;
504         gboolean on_row;
505         gint row;
506         gint col;
507         gint retval;
508
509         cm_return_val_if_fail (widget != NULL, FALSE);
510         cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
511         cm_return_val_if_fail (event != NULL, FALSE);
512
513         sctree = GTK_SCTREE (widget);
514         clist = GTK_CMCLIST (widget);
515         retval = FALSE;
516
517         if (event->window != clist->clist_window)
518                 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
519
520         on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col);
521
522         if (on_row && !gtk_widget_has_focus(widget))
523                 gtk_widget_grab_focus (widget);
524
525         if (gtk_sctree_is_hot_spot (GTK_SCTREE(sctree), event->x, event->y)) {
526                 GtkCMCTreeNode *node = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row);
527                 if (GTK_CMCTREE_ROW (node)->expanded)
528                         gtk_cmctree_collapse(GTK_CMCTREE(sctree), node);
529                 else if (GTK_SCTREE(sctree)->always_expand_recursively)
530                         gtk_cmctree_expand_recursive (GTK_CMCTREE(sctree), node);
531                 else
532                         gtk_cmctree_expand(GTK_CMCTREE(sctree), node);
533                 return TRUE;
534         }
535
536         switch (event->type) {
537         case GDK_BUTTON_PRESS:
538                 if (event->button == 1 || event->button == 2) {
539                         if (event->button == 2)
540                                 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
541                         if (on_row) {
542                                 /* Save the mouse info for DnD */
543                                 sctree->dnd_press_button = event->button;
544                                 sctree->dnd_press_x = event->x;
545                                 sctree->dnd_press_y = event->y;
546
547                                 /* Handle selection */
548                                 if ((row_is_selected (sctree, row)
549                                      && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
550                                     || ((event->state & GDK_CONTROL_MASK)
551                                         && !(event->state & GDK_SHIFT_MASK))) {
552                                         sctree->dnd_select_pending = TRUE;
553                                         sctree->dnd_select_pending_state = event->state;
554                                         sctree->dnd_select_pending_row = row;
555                                 } else {
556                                         select_row (sctree, row, col, event->state, NULL);
557                                 }
558                         } else {
559                                 gtk_cmclist_unselect_all (clist);
560                         }
561
562                         retval = TRUE;
563                 } else if (event->button == 3) {
564                         /* Emit *_popup_menu signal*/
565                         if (on_row) {
566                                 if (!row_is_selected(sctree,row))
567                                         select_row (sctree, row, col, 0, NULL);
568                                 g_signal_emit (G_OBJECT (sctree),
569                                                  sctree_signals[ROW_POPUP_MENU],
570                                                  0, event);
571                         } else {
572                                 gtk_cmclist_unselect_all(clist);
573                                 g_signal_emit (G_OBJECT (sctree),
574                                                  sctree_signals[EMPTY_POPUP_MENU],
575                                                  0, event);
576                         }
577                         retval = TRUE;
578                 }
579
580                 break;
581
582         case GDK_2BUTTON_PRESS:
583                 if (event->button != 1)
584                         break;
585
586                 sctree->dnd_select_pending = FALSE;
587                 sctree->dnd_select_pending_state = 0;
588
589                 if (on_row)
590                         g_signal_emit (G_OBJECT (sctree),
591                                        sctree_signals[OPEN_ROW], 0);
592
593                 retval = TRUE;
594                 break;
595
596         default:
597                 break;
598         }
599
600         return retval;
601 }
602
603 /* Our handler for button_release events.  We override all of GtkCMCList's broken
604  * behavior.
605  */
606 static gint
607 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
608 {
609         GtkSCTree *sctree;
610         GtkCMCList *clist;
611         gint on_row;
612         gint row, col;
613         gint retval;
614
615         cm_return_val_if_fail (widget != NULL, FALSE);
616         cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
617         cm_return_val_if_fail (event != NULL, FALSE);
618
619         sctree = GTK_SCTREE (widget);
620         clist = GTK_CMCLIST (widget);
621         retval = FALSE;
622
623         if (event->window != clist->clist_window)
624                 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
625
626         on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col);
627
628         if (!(event->button == 1 || event->button == 2))
629                 return FALSE;
630
631         sctree->dnd_press_button = 0;
632         sctree->dnd_press_x = 0;
633         sctree->dnd_press_y = 0;
634
635         if (on_row) {
636                 if (sctree->dnd_select_pending) {
637                         select_row (sctree, row, col, sctree->dnd_select_pending_state, NULL);
638                         sctree->dnd_select_pending = FALSE;
639                         sctree->dnd_select_pending_state = 0;
640                 }
641
642                 retval = TRUE;
643         }
644
645         return retval;
646 }
647
648 /* Our handler for motion_notify events.  We override all of GtkCMCList's broken
649  * behavior.
650  */
651 static gint
652 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
653 {
654         GtkSCTree *sctree;
655         GtkCMCList *clist;
656
657         cm_return_val_if_fail (widget != NULL, FALSE);
658         cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
659         cm_return_val_if_fail (event != NULL, FALSE);
660
661         sctree = GTK_SCTREE (widget);
662         clist = GTK_CMCLIST (widget);
663
664         if (event->window != clist->clist_window)
665                 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
666
667         if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
668               || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
669                 return FALSE;
670
671         /* This is the same threshold value that is used in gtkdnd.c */
672
673 #ifndef GENERIC_UMPC
674 #define THRESHOLD 3
675 #else
676 #define THRESHOLD 8
677 #endif
678         if (MAX (ABS (sctree->dnd_press_x - event->x),
679                  ABS (sctree->dnd_press_y - event->y)) <= THRESHOLD)
680                 return FALSE;
681
682         /* Handle any pending selections */
683
684         if (sctree->dnd_select_pending) {
685                 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
686                         select_row (sctree,
687                                     sctree->dnd_select_pending_row,
688                                     -1,
689                                     sctree->dnd_select_pending_state,
690                                     NULL);
691
692                 sctree->dnd_select_pending = FALSE;
693                 sctree->dnd_select_pending_state = 0;
694         }
695
696         g_signal_emit (G_OBJECT (sctree),
697                        sctree_signals[START_DRAG],
698                        0,
699                        sctree->dnd_press_button,
700                        event);
701         return TRUE;
702 }
703
704 /* We override the drag_begin signal to do nothing */
705 static void
706 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
707 {
708         /* nothing */
709 }
710
711 /* We override the drag_end signal to do nothing */
712 static void
713 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
714 {
715         /* nothing */
716 }
717
718 /* We override the drag_data_get signal to do nothing */
719 static void
720 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
721                                      GtkSelectionData *data, guint info, guint time)
722 {
723         /* nothing */
724 }
725
726 /* We override the drag_leave signal to do nothing */
727 static void
728 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
729 {
730         /* nothing */
731 }
732
733 /* We override the drag_motion signal to do nothing */
734 static gboolean
735 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
736                                    gint x, gint y, guint time)
737 {
738         return FALSE;
739 }
740
741 /* We override the drag_drop signal to do nothing */
742 static gboolean
743 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
744                                  gint x, gint y, guint time)
745 {
746         return FALSE;
747 }
748
749 /* We override the drag_data_received signal to do nothing */
750 static void
751 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
752                                           gint x, gint y, GtkSelectionData *data,
753                                           guint info, guint time)
754 {
755         /* nothing */
756 }
757
758 /* Our handler for the clear signal of the clist.  We have to reset the anchor
759  * to null.
760  */
761 static void
762 gtk_sctree_clear (GtkCMCList *clist)
763 {
764         GtkSCTree *sctree;
765
766         cm_return_if_fail (clist != NULL);
767         cm_return_if_fail (GTK_IS_SCTREE (clist));
768
769         sctree = GTK_SCTREE (clist);
770         sctree->anchor_row = NULL;
771
772         if (((GtkCMCListClass *)parent_class)->clear)
773                 (* ((GtkCMCListClass *)parent_class)->clear) (clist);
774 }
775
776 static void
777 gtk_sctree_real_unselect_all (GtkCMCList *clist)
778 {
779         GtkSCTree *sctree;
780         gboolean should_freeze = FALSE;
781
782         cm_return_if_fail (clist != NULL);
783         cm_return_if_fail (GTK_IS_SCTREE (clist));
784
785         sctree = GTK_SCTREE (clist);
786
787         if (sc_g_list_bigger(GTK_CMCLIST(sctree)->selection, 10)) {
788                 should_freeze = TRUE;
789                 sctree->selecting_range++;
790                 gtk_cmclist_freeze (GTK_CMCLIST (sctree));
791         }
792
793         if (((GtkCMCListClass *)parent_class)->unselect_all)
794                 (* ((GtkCMCListClass *)parent_class)->unselect_all) (clist);
795
796         if (should_freeze) {
797                 gtk_cmclist_thaw (GTK_CMCLIST (sctree));
798                 sctree->selecting_range--;
799         }
800 }
801
802 static void
803 gtk_sctree_column_auto_resize (GtkCMCList    *clist,
804                     GtkCMCListRow *clist_row,
805                     gint         column,
806                     gint         old_width)
807 {
808   /* resize column if needed for auto_resize */
809   GtkRequisition requisition;
810
811   if (!clist->column[column].auto_resize ||
812       GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
813     return;
814
815   if (clist_row)
816     GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
817                                                    column, &requisition);
818   else
819     requisition.width = 0;
820
821   if (requisition.width > clist->column[column].width)
822     gtk_cmclist_set_column_width (clist, column, requisition.width);
823   else if (requisition.width < old_width &&
824            old_width == clist->column[column].width)
825     {
826       GList *list;
827       GtkRequisition button_req;
828       gint new_width;
829
830       /* run a "gtk_cmclist_optimal_column_width" but break, if
831        * the column doesn't shrink */
832       if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
833         {
834         gtk_widget_get_requisition (clist->column[column].button, &button_req);
835         new_width = (button_req.width -
836                      (CELL_SPACING + (2 * COLUMN_INSET)));
837         }
838       else
839         new_width = 0;
840
841       for (list = clist->row_list; list; list = list->next)
842         {
843           GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
844             (clist, GTK_CMCLIST_ROW (list), column, &requisition);
845           new_width = MAX (new_width, requisition.width);
846           if (new_width == clist->column[column].width)
847             break;
848         }
849       if (new_width < clist->column[column].width)
850         gtk_cmclist_set_column_width (clist, column, new_width);
851     }
852 }
853
854 static void
855 gtk_sctree_auto_resize_columns (GtkCMCList *clist)
856 {
857   gint i;
858
859   if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
860     return;
861
862   for (i = 0; i < clist->columns; i++)
863     gtk_sctree_column_auto_resize (clist, NULL, i, clist->column[i].width);
864 }
865
866 static void 
867 gtk_sctree_real_tree_collapse (GtkCMCTree     *ctree,
868                     GtkCMCTreeNode *node)
869 {
870   GtkCMCList *clist;
871   GtkCMCTreeNode *work;
872   GtkRequisition requisition;
873   gboolean visible;
874   gint level;
875
876   cm_return_if_fail (GTK_IS_CMCTREE (ctree));
877
878   if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
879       GTK_CMCTREE_ROW (node)->is_leaf)
880     return;
881
882   clist = GTK_CMCLIST (ctree);
883
884   GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
885   
886   GTK_CMCTREE_ROW (node)->expanded = FALSE;
887   level = GTK_CMCTREE_ROW (node)->level;
888
889   visible = gtk_cmctree_is_viewable (ctree, node);
890   /* get cell width if tree_column is auto resized */
891   if (visible && clist->column[ctree->tree_column].auto_resize &&
892       !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
893     GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
894       (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
895
896   /* unref/unset opened pixbuf */
897   if (GTK_CMCELL_PIXTEXT 
898       (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
899     {
900       g_object_unref
901         (GTK_CMCELL_PIXTEXT
902          (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
903       
904       GTK_CMCELL_PIXTEXT
905         (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
906     }
907
908   /* set/ref closed pixbuf */
909   if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
910     {
911       GTK_CMCELL_PIXTEXT 
912         (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = 
913         g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
914     }
915
916   work = GTK_CMCTREE_ROW (node)->children;
917   if (work)
918     {
919       gint tmp = 0;
920       gint row;
921       GList *list;
922
923       while (work && GTK_CMCTREE_ROW (work)->level > level)
924         {
925           work = GTK_CMCTREE_NODE_NEXT (work);
926           tmp++;
927         }
928
929       if (work)
930         {
931           list = (GList *)node;
932           list->next = (GList *)work;
933           list = (GList *)GTK_CMCTREE_NODE_PREV (work);
934           list->next = NULL;
935           list = (GList *)work;
936           list->prev = (GList *)node;
937         }
938       else
939         {
940           list = (GList *)node;
941           list->next = NULL;
942           clist->row_list_end = (GList *)node;
943         }
944
945       if (visible)
946         {
947           /* resize auto_resize columns if needed */
948           gtk_sctree_auto_resize_columns (clist);
949
950           if (!GTK_SCTREE(clist)->sorting) {
951                   row = g_list_position (clist->row_list, (GList *)node);
952                   if (row < clist->focus_row)
953                     clist->focus_row -= tmp;
954           }
955           clist->rows -= tmp;
956           CLIST_REFRESH (clist);
957         }
958     }
959   else if (visible && clist->column[ctree->tree_column].auto_resize &&
960            !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
961     /* resize tree_column if needed */
962     gtk_sctree_column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column,
963                         requisition.width);
964     
965 }
966
967
968 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, 
969                                        gchar *titles[])
970 {
971         GtkWidget *widget;
972                                                                                                             
973         cm_return_val_if_fail (columns > 0, NULL);
974         cm_return_val_if_fail (tree_column >= 0, NULL);
975         
976         if (tree_column >= columns) {
977                 g_warning("Wrong tree column");
978                 tree_column = 0;
979                 print_backtrace();
980         }
981         
982         widget = gtk_widget_new (TYPE_GTK_SCTREE,
983                                  "n_columns", columns,
984                                  "tree_column", tree_column,
985                                  NULL);
986         if (titles) {
987                 GtkCMCList *clist = GTK_CMCLIST (widget);
988                 guint i;
989
990                 for (i = 0; i < columns; i++)
991                         gtk_cmclist_set_column_title (clist, i, titles[i]);
992                 gtk_cmclist_column_titles_show (clist);
993         }
994
995         GTK_SCTREE(widget)->show_stripes = TRUE;
996         GTK_SCTREE(widget)->always_expand_recursively = TRUE;
997         GTK_SCTREE(widget)->force_additive_sel = FALSE;
998         
999         GTK_SCTREE(widget)->use_markup = g_new0(gboolean, columns);
1000
1001         return widget;
1002 }
1003
1004 void gtk_sctree_set_use_markup              (GtkSCTree          *sctree,
1005                                              int                 column,
1006                                              gboolean            markup)
1007 {
1008         gint columns = 0;
1009         GValue value = { 0 };
1010         
1011         cm_return_if_fail(GTK_IS_SCTREE(sctree));
1012
1013         g_value_init (&value, G_TYPE_INT);      
1014         g_object_get_property (G_OBJECT (sctree), "n-columns", &value);
1015         columns = g_value_get_int (&value);
1016         g_value_unset (&value);
1017
1018         cm_return_if_fail(column < columns);
1019
1020         sctree->use_markup[column] = markup;
1021 }
1022
1023 void gtk_sctree_select (GtkSCTree *sctree, GtkCMCTreeNode *node)
1024 {
1025         select_row(sctree, 
1026                    g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node),
1027                    -1, 0, node);
1028 }
1029
1030 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCMCTreeNode *node, int state)
1031 {
1032         select_row(sctree, 
1033                    g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node),
1034                    -1, state, node);
1035 }
1036
1037 void gtk_sctree_unselect_all (GtkSCTree *sctree)
1038 {
1039         gtk_cmclist_unselect_all(GTK_CMCLIST(sctree));
1040         sctree->anchor_row = NULL;
1041 }
1042
1043 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCMCTreeNode *node)
1044 {
1045         sctree->anchor_row = node;
1046 }
1047
1048 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCMCTreeNode *node)
1049 {
1050         if (sctree->anchor_row == node)
1051                 sctree->anchor_row = NULL;
1052         gtk_cmctree_remove_node(GTK_CMCTREE(sctree), node);
1053 }
1054
1055 void gtk_sctree_set_stripes(GtkSCTree  *sctree, gboolean show_stripes)
1056 {
1057         sctree->show_stripes = show_stripes;
1058 }
1059
1060 void gtk_sctree_set_recursive_expand(GtkSCTree  *sctree, gboolean rec_exp)
1061 {
1062         sctree->always_expand_recursively = rec_exp;
1063 }
1064
1065 /***********************************************************
1066  *             Tree sorting functions                      *
1067  ***********************************************************/
1068
1069 static void sink(GtkCMCList *clist, GPtrArray *numbers, gint root, gint bottom)
1070 {
1071         gint j, k ;
1072         GtkCMCTreeNode *temp;
1073
1074         j = 2 * root;
1075         k = j + 1;
1076
1077         /* find the maximum element of numbers[root],
1078            numbers[2*root] and numbers[2*root+1] */
1079         if (j <= bottom) {
1080                 if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, root)),
1081                                     GTK_CMCTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
1082                         j = root;
1083                 if (k <= bottom)
1084                         if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, k)),
1085                                             GTK_CMCTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
1086                                 j = k;
1087                 /* if numbers[root] wasn't the maximum element then
1088                    sink again */
1089                 if (root != j) {
1090                         temp = g_ptr_array_index( numbers,root);
1091                         g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
1092                         g_ptr_array_index( numbers, j) = temp;
1093                         sink( clist, numbers, j, bottom);
1094                 }
1095         }
1096 }
1097
1098 static void heap_sort(GtkCMCList *clist, GPtrArray *numbers, gint array_size)
1099 {
1100         gint i;
1101         GtkCMCTreeNode *temp;
1102         
1103         /* build the Heap */
1104         for (i = (array_size / 2); i >= 1; i--)
1105                 sink( clist, numbers, i, array_size);
1106         /* output the Heap */
1107         for (i = array_size; i >= 2; i--) {
1108                 temp = g_ptr_array_index( numbers, 1);
1109                 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
1110                 g_ptr_array_index( numbers, i) = temp;
1111                 sink( clist, numbers, 1, i-1);
1112         }
1113 }
1114
1115 static void
1116 stree_sort (GtkCMCTree    *ctree,
1117            GtkCMCTreeNode *node,
1118            gpointer      data)
1119 {
1120         GtkCMCTreeNode *list_start, *work, *next;
1121         GPtrArray *row_array, *viewable_array;
1122         GtkCMCList *clist;
1123         gint i;
1124
1125         clist = GTK_CMCLIST (ctree);
1126
1127         if (node)
1128                 work = GTK_CMCTREE_ROW (node)->children;
1129         else
1130                 work = GTK_CMCTREE_NODE (clist->row_list);
1131
1132         row_array = g_ptr_array_new();
1133         viewable_array = g_ptr_array_new();
1134
1135         if (work) {
1136                 g_ptr_array_add( row_array, NULL);
1137                 while (work) {
1138                         /* add all rows to row_array */
1139                         g_ptr_array_add( row_array, work);
1140                         if (GTK_CMCTREE_ROW (work)->parent && gtk_cmctree_is_viewable( ctree, work))
1141                                 g_ptr_array_add( viewable_array, GTK_CMCTREE_ROW (work)->parent);
1142                         next = GTK_CMCTREE_ROW (work)->sibling;
1143                         gtk_sctree_unlink( ctree, work, FALSE);
1144                         work = next;
1145                 }
1146
1147                 heap_sort( clist, row_array, (row_array->len)-1);
1148
1149                 if (node)
1150                         list_start = GTK_CMCTREE_ROW (node)->children;
1151                 else
1152                         list_start = GTK_CMCTREE_NODE (clist->row_list);
1153
1154                 if (clist->sort_type == GTK_SORT_ASCENDING) {
1155                         for (i=(row_array->len)-1; i>=1; i--) {
1156                                 work = g_ptr_array_index( row_array, i);
1157                                 gtk_sctree_link( ctree, work, node, list_start, FALSE);
1158                                 list_start = work;
1159                                 /* insert work at the beginning of the list */
1160                         }
1161                 } else {
1162                         for (i=1; i<row_array->len; i++) {
1163                                 work = g_ptr_array_index( row_array, i);
1164                                 gtk_sctree_link( ctree, work, node, list_start, FALSE);
1165                                 list_start = work;
1166                                 /* insert work at the beginning of the list */
1167                         }
1168                 }
1169
1170                 for (i=0; i<viewable_array->len; i++) {
1171                         gtk_cmctree_expand( ctree, g_ptr_array_index( viewable_array, i));
1172                 }
1173                 
1174         }
1175         g_ptr_array_free( row_array, TRUE);
1176         g_ptr_array_free( viewable_array, TRUE);
1177 }
1178
1179 void
1180 gtk_sctree_sort_recursive (GtkCMCTree     *ctree, 
1181                           GtkCMCTreeNode *node)
1182 {
1183         GtkCMCList *clist;
1184         GtkCMCTreeNode *focus_node = NULL;
1185
1186         cm_return_if_fail (ctree != NULL);
1187         cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1188
1189         clist = GTK_CMCLIST (ctree);
1190
1191         gtk_cmclist_freeze (clist);
1192
1193         if (clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1194                 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1195       
1196                 g_list_free (clist->undo_selection);
1197                 g_list_free (clist->undo_unselection);
1198                 clist->undo_selection = NULL;
1199                 clist->undo_unselection = NULL;
1200         }
1201
1202         if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
1203                 focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1204       
1205         GTK_SCTREE(ctree)->sorting = TRUE;
1206
1207         gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (stree_sort), NULL);
1208
1209         if (!node)
1210                 stree_sort (ctree, NULL, NULL);
1211
1212         GTK_SCTREE(ctree)->sorting = FALSE;
1213
1214         if (focus_node) {
1215                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
1216                 clist->undo_anchor = clist->focus_row;
1217         }
1218
1219         gtk_cmclist_thaw (clist);
1220 }
1221
1222 void
1223 gtk_sctree_sort_node (GtkCMCTree     *ctree, 
1224                      GtkCMCTreeNode *node)
1225 {
1226         GtkCMCList *clist;
1227         GtkCMCTreeNode *focus_node = NULL;
1228
1229         cm_return_if_fail (ctree != NULL);
1230         cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1231
1232         clist = GTK_CMCLIST (ctree);
1233
1234         gtk_cmclist_freeze (clist);
1235
1236         if (clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1237                 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1238
1239                 g_list_free (clist->undo_selection);
1240                 g_list_free (clist->undo_unselection);
1241                 clist->undo_selection = NULL;
1242                 clist->undo_unselection = NULL;
1243         }
1244
1245         if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
1246                 focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1247
1248         GTK_SCTREE(ctree)->sorting = TRUE;
1249
1250         stree_sort (ctree, node, NULL);
1251
1252         GTK_SCTREE(ctree)->sorting = FALSE;
1253
1254         if (focus_node) {
1255                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
1256                 clist->undo_anchor = clist->focus_row;
1257         }
1258
1259         gtk_cmclist_thaw (clist);
1260 }
1261
1262 /************************************************************************/
1263
1264 static void
1265 gtk_sctree_unlink (GtkCMCTree     *ctree, 
1266                   GtkCMCTreeNode *node,
1267                   gboolean      update_focus_row)
1268 {
1269         GtkCMCList *clist;
1270         gint rows;
1271         gint level;
1272         gint visible;
1273         GtkCMCTreeNode *work;
1274         GtkCMCTreeNode *parent;
1275         GList *list;
1276
1277         cm_return_if_fail (ctree != NULL);
1278         cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1279         cm_return_if_fail (node != NULL);
1280
1281         clist = GTK_CMCLIST (ctree);
1282   
1283         if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1284                 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1285
1286                 g_list_free (clist->undo_selection);
1287                 g_list_free (clist->undo_unselection);
1288                 clist->undo_selection = NULL;
1289                 clist->undo_unselection = NULL;
1290         }
1291
1292         visible = gtk_cmctree_is_viewable (ctree, node);
1293
1294         /* clist->row_list_end unlinked ? */
1295         if (visible && (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
1296            (GTK_CMCTREE_ROW (node)->children && gtk_cmctree_is_ancestor (ctree, node,
1297             GTK_CMCTREE_NODE (clist->row_list_end)))))
1298                 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
1299
1300         /* update list */
1301         rows = 0;
1302         level = GTK_CMCTREE_ROW (node)->level;
1303         work = GTK_CMCTREE_NODE_NEXT (node);
1304         while (work && GTK_CMCTREE_ROW (work)->level > level) {
1305                 work = GTK_CMCTREE_NODE_NEXT (work);
1306                 rows++;
1307         }
1308
1309         if (visible) {
1310                 clist->rows -= (rows + 1);
1311
1312                 if (update_focus_row) {
1313                         gint pos;
1314                         pos = g_list_position (clist->row_list, (GList *)node);
1315                         if (pos + rows < clist->focus_row)
1316                                 clist->focus_row -= (rows + 1);
1317                         else if (pos <= clist->focus_row) {
1318                                 if (!GTK_CMCTREE_ROW (node)->sibling)
1319                                         clist->focus_row = MAX (pos - 1, 0);
1320                                 else
1321                                         clist->focus_row = pos;
1322               
1323                                 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1324                         }
1325                         clist->undo_anchor = clist->focus_row;
1326                 }
1327         }
1328
1329         if (work) {
1330                 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
1331                 list->next = NULL;
1332                 list = (GList *)work;
1333                 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
1334         }
1335
1336         if (GTK_CMCTREE_NODE_PREV (node) &&
1337             GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node) {
1338                 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
1339                 list->next = (GList *)work;
1340         }
1341
1342         /* update tree */
1343         parent = GTK_CMCTREE_ROW (node)->parent;
1344         if (parent) {
1345                 if (GTK_CMCTREE_ROW (parent)->children == node) {
1346                         GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
1347                 }
1348                 else {
1349                         GtkCMCTreeNode *sibling;
1350
1351                         sibling = GTK_CMCTREE_ROW (parent)->children;
1352                         while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1353                                 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1354                         GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1355                 }
1356         }
1357         else {
1358                 if (clist->row_list == (GList *)node)
1359                         clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1360                 else {
1361                         GtkCMCTreeNode *sibling;
1362
1363                         sibling = GTK_CMCTREE_NODE (clist->row_list);
1364                         while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1365                                 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1366                         GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1367                 }
1368         }
1369 }
1370
1371 static void
1372 gtk_sctree_link (GtkCMCTree     *ctree,
1373                 GtkCMCTreeNode *node,
1374                 GtkCMCTreeNode *parent,
1375                 GtkCMCTreeNode *sibling,
1376                 gboolean      update_focus_row)
1377 {
1378         GtkCMCList *clist;
1379         GList *list_end;
1380         GList *list;
1381         GList *work;
1382         gboolean visible = FALSE;
1383         gint rows = 0;
1384   
1385         if (sibling)
1386                 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
1387         cm_return_if_fail (node != NULL);
1388         cm_return_if_fail (node != sibling);
1389         cm_return_if_fail (node != parent);
1390
1391         clist = GTK_CMCLIST (ctree);
1392
1393         if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1394                 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1395
1396                 g_list_free (clist->undo_selection);
1397                 g_list_free (clist->undo_unselection);
1398                 clist->undo_selection = NULL;
1399                 clist->undo_unselection = NULL;
1400         }
1401
1402         for (rows = 1, list_end = (GList *)node; list_end->next;
1403              list_end = list_end->next)
1404                 rows++;
1405
1406         GTK_CMCTREE_ROW (node)->parent = parent;
1407         GTK_CMCTREE_ROW (node)->sibling = sibling;
1408
1409         if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1410             GTK_CMCTREE_ROW (parent)->expanded))) {
1411                 visible = TRUE;
1412                 clist->rows += rows;
1413         }
1414
1415         if (parent)
1416                 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1417         else
1418                 work = clist->row_list;
1419
1420         if (sibling) {
1421                 if (work != (GList *)sibling) {
1422                         while (GTK_CMCTREE_ROW (work)->sibling != sibling)
1423                                 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1424                         GTK_CMCTREE_ROW (work)->sibling = node;
1425                 }
1426
1427                 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
1428                 clist->row_list = (GList *) node;
1429                 if (GTK_CMCTREE_NODE_PREV (sibling) &&
1430                     GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling) {
1431                         list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1432                         list->next = (GList *)node;
1433                 }
1434
1435                 list = (GList *)node;
1436                 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1437                 list_end->next = (GList *)sibling;
1438                 list = (GList *)sibling;
1439                 list->prev = list_end;
1440                 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
1441                         GTK_CMCTREE_ROW (parent)->children = node;
1442         }
1443         else {
1444                 if (work) {
1445                         /* find sibling */
1446                         while (GTK_CMCTREE_ROW (work)->sibling)
1447                         work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1448                         GTK_CMCTREE_ROW (work)->sibling = node;
1449
1450                         /* find last visible child of sibling */
1451                         work = (GList *) gtk_sctree_last_visible (ctree,
1452                                GTK_CMCTREE_NODE (work));
1453
1454                         list_end->next = work->next;
1455                         if (work->next)
1456                                 work->next->prev = list_end;
1457                         work->next = (GList *)node;
1458                         list = (GList *)node;
1459                         list->prev = work;
1460                 }
1461                 else {
1462                         if (parent) {
1463                                 GTK_CMCTREE_ROW (parent)->children = node;
1464                                 list = (GList *)node;
1465                                 list->prev = (GList *)parent;
1466                                 if (GTK_CMCTREE_ROW (parent)->expanded) {
1467                                         list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1468                                         if (GTK_CMCTREE_NODE_NEXT(parent)) {
1469                                                 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1470                                                 list->prev = list_end;
1471                                         }
1472                                         list = (GList *)parent;
1473                                         list->next = (GList *)node;
1474                                 }
1475                                 else
1476                                         list_end->next = NULL;
1477                         }
1478                         else {
1479                                 clist->row_list = (GList *)node;
1480                                 list = (GList *)node;
1481                                 list->prev = NULL;
1482                                 list_end->next = NULL;
1483                         }
1484                 }
1485         }
1486
1487         gtk_cmctree_pre_recursive (ctree, node, stree_update_level, NULL); 
1488
1489         if (clist->row_list_end == NULL ||
1490             clist->row_list_end->next == (GList *)node)
1491                 clist->row_list_end = list_end;
1492
1493         if (visible && update_focus_row) {
1494                 gint pos;
1495                 pos = g_list_position (clist->row_list, (GList *)node);
1496   
1497                 if (pos <= clist->focus_row) {
1498                         clist->focus_row += rows;
1499                         clist->undo_anchor = clist->focus_row;
1500                 }
1501         }
1502 }
1503
1504 static void
1505 stree_update_level (GtkCMCTree     *ctree, 
1506                    GtkCMCTreeNode *node, 
1507                    gpointer      data)
1508 {
1509         if (!node)
1510                 return;
1511
1512         if (GTK_CMCTREE_ROW (node)->parent)
1513                 GTK_CMCTREE_ROW (node)->level = 
1514                 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
1515         else
1516                 GTK_CMCTREE_ROW (node)->level = 1;
1517 }
1518
1519 static GtkCMCTreeNode *
1520 gtk_sctree_last_visible (GtkCMCTree     *ctree,
1521                         GtkCMCTreeNode *node)
1522 {
1523         GtkCMCTreeNode *work;
1524   
1525         if (!node)
1526                 return NULL;
1527
1528         work = GTK_CMCTREE_ROW (node)->children;
1529
1530         if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1531                 return node;
1532
1533         while (GTK_CMCTREE_ROW (work)->sibling)
1534                 work = GTK_CMCTREE_ROW (work)->sibling;
1535
1536         return gtk_sctree_last_visible (ctree, work);
1537 }
1538
1539 static void 
1540 sset_node_info (GtkCMCTree     *ctree,
1541                GtkCMCTreeNode *node,
1542                const gchar  *text,
1543                guint8        spacing,
1544                GdkPixbuf    *pixbuf_closed,
1545                GdkPixbuf    *pixbuf_opened,
1546                gboolean      is_leaf,
1547                gboolean      expanded)
1548 {
1549   if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
1550     {
1551       g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
1552     }
1553   if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
1554     {
1555       g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
1556     }
1557
1558   GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
1559   GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
1560
1561   if (pixbuf_closed)
1562     {
1563       GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
1564     }
1565   if (pixbuf_opened)
1566     {
1567       GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
1568     }
1569
1570   GTK_CMCTREE_ROW (node)->is_leaf  = is_leaf;
1571   GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
1572
1573   if (GTK_CMCTREE_ROW (node)->expanded)
1574     gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
1575                                 text, spacing, pixbuf_opened);
1576   else 
1577     gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
1578                                 text, spacing, pixbuf_closed);
1579 }
1580
1581 static GtkCMCTreeRow *
1582 srow_new (GtkCMCTree *ctree)
1583 {
1584   GtkCMCList *clist;
1585   GtkCMCTreeRow *ctree_row;
1586   int i;
1587
1588   clist = GTK_CMCLIST (ctree);
1589   ctree_row = g_slice_new (GtkCMCTreeRow);
1590   ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
1591   for (i = 0; i < clist->columns; i++)
1592     {
1593       ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
1594       ctree_row->row.cell[i].vertical = 0;
1595       ctree_row->row.cell[i].horizontal = 0;
1596       ctree_row->row.cell[i].style = NULL;
1597     }
1598
1599   GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
1600
1601   ctree_row->row.fg_set     = FALSE;
1602   ctree_row->row.bg_set     = FALSE;
1603   ctree_row->row.style      = NULL;
1604   ctree_row->row.selectable = TRUE;
1605   ctree_row->row.state      = GTK_STATE_NORMAL;
1606   ctree_row->row.data       = NULL;
1607   ctree_row->row.destroy    = NULL;
1608
1609   ctree_row->level         = 0;
1610   ctree_row->expanded      = FALSE;
1611   ctree_row->parent        = NULL;
1612   ctree_row->sibling       = NULL;
1613   ctree_row->children      = NULL;
1614   ctree_row->pixbuf_closed = NULL;
1615   ctree_row->pixbuf_opened = NULL;
1616   
1617   return ctree_row;
1618 }
1619
1620 static void
1621 srow_delete (GtkCMCTree    *ctree,
1622             GtkCMCTreeRow *ctree_row)
1623 {
1624   GtkCMCList *clist;
1625   gint i;
1626
1627   clist = GTK_CMCLIST (ctree);
1628
1629   for (i = 0; i < clist->columns; i++)
1630     {
1631       GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
1632         (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
1633       if (ctree_row->row.cell[i].style)
1634         {
1635           if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
1636             gtk_style_detach (ctree_row->row.cell[i].style);
1637           g_object_unref (ctree_row->row.cell[i].style);
1638         }
1639     }
1640
1641   if (ctree_row->row.style)
1642     {
1643       if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
1644         gtk_style_detach (ctree_row->row.style);
1645       g_object_unref (ctree_row->row.style);
1646     }
1647
1648   if (ctree_row->pixbuf_closed)
1649     {
1650       g_object_unref (ctree_row->pixbuf_closed);
1651     }
1652
1653   if (ctree_row->pixbuf_opened)
1654     {
1655       g_object_unref (ctree_row->pixbuf_opened);
1656     }
1657
1658   if (ctree_row->row.destroy)
1659     {
1660       GDestroyNotify dnotify = ctree_row->row.destroy;
1661       gpointer ddata = ctree_row->row.data;
1662
1663       ctree_row->row.destroy = NULL;
1664       ctree_row->row.data = NULL;
1665
1666       dnotify (ddata);
1667     }
1668
1669   g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
1670   g_slice_free (GtkCMCTreeRow, ctree_row);
1671 }
1672
1673 static void
1674 stree_delete_row (GtkCMCTree     *ctree, 
1675                  GtkCMCTreeNode *node, 
1676                  gpointer      data)
1677 {
1678   srow_delete (ctree, GTK_CMCTREE_ROW (node));
1679   g_list_free_1 ((GList *)node);
1680 }
1681
1682 static void 
1683 gtk_sctree_real_tree_expand (GtkCMCTree     *ctree,
1684                   GtkCMCTreeNode *node)
1685 {
1686   GtkCMCList *clist;
1687   GtkCMCTreeNode *work;
1688   GtkRequisition requisition;
1689   gboolean visible;
1690
1691   cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1692
1693   if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
1694     return;
1695
1696   clist = GTK_CMCLIST (ctree);
1697   
1698   GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1699
1700   GTK_CMCTREE_ROW (node)->expanded = TRUE;
1701
1702   visible = gtk_cmctree_is_viewable (ctree, node);
1703   /* get cell width if tree_column is auto resized */
1704   if (visible && clist->column[ctree->tree_column].auto_resize &&
1705       !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1706     GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1707       (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
1708
1709   /* unref/unset closed pixbuf */
1710   if (GTK_CMCELL_PIXTEXT 
1711       (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
1712     {
1713       g_object_unref
1714         (GTK_CMCELL_PIXTEXT
1715          (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
1716       
1717       GTK_CMCELL_PIXTEXT
1718         (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
1719     }
1720
1721   /* set/ref opened pixbuf */
1722   if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
1723     {
1724       GTK_CMCELL_PIXTEXT 
1725         (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = 
1726         g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
1727     }
1728
1729
1730   work = GTK_CMCTREE_ROW (node)->children;
1731   if (work)
1732     {
1733       GList *list = (GList *)work;
1734       gint *cell_width = NULL;
1735       gint tmp = 0;
1736       gint row;
1737       gint i;
1738       
1739       if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1740         {
1741           cell_width = g_new0 (gint, clist->columns);
1742           if (clist->column[ctree->tree_column].auto_resize)
1743               cell_width[ctree->tree_column] = requisition.width;
1744
1745           while (work)
1746             {
1747               /* search maximum cell widths of auto_resize columns */
1748               for (i = 0; i < clist->columns; i++)
1749                 if (clist->column[i].auto_resize)
1750                   {
1751                     GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1752                       (clist, &GTK_CMCTREE_ROW (work)->row, i, &requisition);
1753                     cell_width[i] = MAX (requisition.width, cell_width[i]);
1754                   }
1755
1756               list = (GList *)work;
1757               work = GTK_CMCTREE_NODE_NEXT (work);
1758               tmp++;
1759             }
1760         }
1761       else
1762         while (work)
1763           {
1764             list = (GList *)work;
1765             work = GTK_CMCTREE_NODE_NEXT (work);
1766             tmp++;
1767           }
1768
1769       list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1770
1771       if (GTK_CMCTREE_NODE_NEXT (node))
1772         {
1773           GList *tmp_list;
1774
1775           if (clist->row_list_end == list)
1776               clist->row_list_end = g_list_last(list);
1777
1778           tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1779           tmp_list->prev = list;
1780         }
1781       else
1782         clist->row_list_end = list;
1783
1784       list = (GList *)node;
1785       list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
1786
1787       if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1788         {
1789           /* resize auto_resize columns if needed */
1790           for (i = 0; i < clist->columns; i++)
1791             if (clist->column[i].auto_resize &&
1792                 cell_width[i] > clist->column[i].width)
1793               gtk_cmclist_set_column_width (clist, i, cell_width[i]);
1794           g_free (cell_width);
1795         
1796           if (!GTK_SCTREE(ctree)->sorting) {
1797                   /* update focus_row position */
1798                   row = g_list_position (clist->row_list, (GList *)node);
1799                   if (row < clist->focus_row)
1800                     clist->focus_row += tmp;
1801           }
1802           clist->rows += tmp;
1803           CLIST_REFRESH (clist);
1804         }
1805     }
1806   else if (visible && clist->column[ctree->tree_column].auto_resize)
1807     /* resize tree_column if needed */
1808     gtk_sctree_column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column,
1809                         requisition.width);
1810
1811 }
1812
1813 GtkCMCTreeNode * 
1814 gtk_sctree_insert_node (GtkCMCTree     *ctree,
1815                        GtkCMCTreeNode *parent, 
1816                        GtkCMCTreeNode *sibling,
1817                        gchar        *text[],
1818                        guint8        spacing,
1819                        GdkPixbuf    *pixbuf_closed,
1820                        GdkPixbuf    *pixbuf_opened,
1821                        gboolean      is_leaf,
1822                        gboolean      expanded)
1823 {
1824   GtkCMCList *clist;
1825   GtkCMCTreeRow *new_row;
1826   GtkCMCTreeNode *node;
1827   GList *list;
1828   gint i;
1829
1830   cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
1831   if (sibling)
1832     cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
1833
1834   if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
1835     return NULL;
1836
1837   clist = GTK_CMCLIST (ctree);
1838
1839   /* create the row */
1840   new_row = srow_new (ctree);
1841   list = g_list_alloc ();
1842   list->data = new_row;
1843   node = GTK_CMCTREE_NODE (list);
1844
1845   if (text)
1846     for (i = 0; i < clist->columns; i++)
1847       if (text[i] && i != ctree->tree_column)
1848         GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
1849           (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL);
1850
1851   sset_node_info (ctree, node, text ?
1852                  text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
1853                  pixbuf_opened, is_leaf, expanded);
1854
1855   /* sorted insertion */
1856   if (GTK_CMCLIST_AUTO_SORT (clist))
1857     {
1858       if (parent)
1859         sibling = GTK_CMCTREE_ROW (parent)->children;
1860       else
1861         sibling = GTK_CMCTREE_NODE (clist->row_list);
1862
1863       while (sibling && clist->compare
1864              (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
1865         sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1866     }
1867
1868   gtk_sctree_link (ctree, node, parent, sibling, FALSE);
1869
1870   if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
1871       gtk_cmctree_is_viewable (ctree, node))
1872     {
1873       for (i = 0; i < clist->columns; i++)
1874         if (clist->column[i].auto_resize)
1875           gtk_sctree_column_auto_resize (clist, &(new_row->row), i, 0);
1876     }
1877
1878   if (clist->rows == 1)
1879     {
1880       clist->focus_row = 0;
1881       if (clist->selection_mode == GTK_SELECTION_BROWSE)
1882         gtk_sctree_select (GTK_SCTREE(ctree), node);
1883     }
1884
1885
1886   CLIST_REFRESH (clist);
1887
1888   return node;
1889 }
1890
1891 GtkCMCTreeNode *
1892 gtk_sctree_insert_gnode (GtkCMCTree          *ctree,
1893                         GtkCMCTreeNode      *parent,
1894                         GtkCMCTreeNode      *sibling,
1895                         GNode             *gnode,
1896                         GtkCMCTreeGNodeFunc  func,
1897                         gpointer           data)
1898 {
1899   GtkCMCList *clist;
1900   GtkCMCTreeNode *cnode = NULL;
1901   GtkCMCTreeNode *child = NULL;
1902   GtkCMCTreeNode *new_child;
1903   GList *list;
1904   GNode *work;
1905   guint depth = 1;
1906
1907   cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
1908   cm_return_val_if_fail (gnode != NULL, NULL);
1909   cm_return_val_if_fail (func != NULL, NULL);
1910   if (sibling)
1911     cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
1912   
1913   clist = GTK_CMCLIST (ctree);
1914
1915   if (parent)
1916     depth = GTK_CMCTREE_ROW (parent)->level + 1;
1917
1918   list = g_list_alloc ();
1919   list->data = srow_new (ctree);
1920   cnode = GTK_CMCTREE_NODE (list);
1921
1922   gtk_cmclist_freeze (clist);
1923
1924   sset_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
1925
1926   if (!func (ctree, depth, gnode, cnode, data))
1927     {
1928       stree_delete_row (ctree, cnode, NULL);
1929       gtk_cmclist_thaw (clist);
1930       return NULL;
1931     }
1932
1933   if (GTK_CMCLIST_AUTO_SORT (clist))
1934     {
1935       if (parent)
1936         sibling = GTK_CMCTREE_ROW (parent)->children;
1937       else
1938         sibling = GTK_CMCTREE_NODE (clist->row_list);
1939
1940       while (sibling && clist->compare
1941              (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
1942         sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1943     }
1944
1945   gtk_sctree_link (ctree, cnode, parent, sibling, FALSE);
1946
1947   for (work = g_node_last_child (gnode); work; work = work->prev)
1948     {
1949       new_child = gtk_sctree_insert_gnode (ctree, cnode, child,
1950                                           work, func, data);
1951       if (new_child)
1952         child = new_child;
1953     }   
1954   
1955   gtk_cmclist_thaw (clist);
1956
1957   return cnode;
1958 }
1959
1960 static void
1961 sreal_tree_move (GtkCMCTree     *ctree,
1962                 GtkCMCTreeNode *node,
1963                 GtkCMCTreeNode *new_parent, 
1964                 GtkCMCTreeNode *new_sibling)
1965 {
1966   GtkCMCList *clist;
1967   GtkCMCTreeNode *work;
1968   gboolean visible = FALSE;
1969
1970   cm_return_if_fail (ctree != NULL);
1971   cm_return_if_fail (node != NULL);
1972   cm_return_if_fail (!new_sibling || 
1973                     GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
1974
1975   if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
1976     return;
1977
1978   /* new_parent != child of child */
1979   for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
1980     if (work == node)
1981       return;
1982
1983   clist = GTK_CMCLIST (ctree);
1984
1985   visible = gtk_cmctree_is_viewable (ctree, node);
1986
1987   if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1988     {
1989       GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1990       
1991       g_list_free (clist->undo_selection);
1992       g_list_free (clist->undo_unselection);
1993       clist->undo_selection = NULL;
1994       clist->undo_unselection = NULL;
1995     }
1996
1997   if (GTK_CMCLIST_AUTO_SORT (clist))
1998     {
1999       if (new_parent == GTK_CMCTREE_ROW (node)->parent)
2000         return;
2001       
2002       if (new_parent)
2003         new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
2004       else
2005         new_sibling = GTK_CMCTREE_NODE (clist->row_list);
2006
2007       while (new_sibling && clist->compare
2008              (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
2009         new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
2010     }
2011
2012   if (new_parent == GTK_CMCTREE_ROW (node)->parent && 
2013       new_sibling == GTK_CMCTREE_ROW (node)->sibling)
2014     return;
2015
2016   gtk_cmclist_freeze (clist);
2017
2018   work = NULL;
2019
2020   if (!GTK_SCTREE(ctree)->sorting && gtk_cmctree_is_viewable (ctree, node))
2021     work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
2022       
2023   gtk_sctree_unlink (ctree, node, FALSE);
2024   gtk_sctree_link (ctree, node, new_parent, new_sibling, FALSE);
2025   
2026   if (!GTK_SCTREE(ctree)->sorting && work)
2027     {
2028       while (work &&  !gtk_cmctree_is_viewable (ctree, work))
2029         work = GTK_CMCTREE_ROW (work)->parent;
2030       clist->focus_row = g_list_position (clist->row_list, (GList *)work);
2031       clist->undo_anchor = clist->focus_row;
2032     }
2033
2034   if (clist->column[ctree->tree_column].auto_resize &&
2035       !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
2036       (visible || gtk_cmctree_is_viewable (ctree, node)))
2037     gtk_cmclist_set_column_width
2038       (clist, ctree->tree_column,
2039        gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
2040
2041   gtk_cmclist_thaw (clist);
2042 }
2043
2044 void gtk_sctree_set_column_tooltip          (GtkSCTree          *sctree,
2045                                              int                 column,
2046                                              const gchar        *tip)
2047 {
2048         CLAWS_SET_TIP(GTK_CMCLIST(sctree)->column[column].button,
2049                         tip);
2050 }
2051