2006-05-23 [colin] 2.2.0cvs48
[claws.git] / src / gtk / gtksctree.c
1 /*
2  * This program is based on gtkflist.c
3  */
4
5 #include <stdlib.h>
6
7 #include "gtksctree.h"
8 #include "sylpheed-marshal.h"
9 #include "stock_pixmap.h"
10
11 #define CLIST_UNFROZEN(clist)     (((GtkCList*) (clist))->freeze_count == 0)
12 #define CLIST_REFRESH(clist)    G_STMT_START { \
13   if (CLIST_UNFROZEN (clist)) \
14     GTK_CLIST_GET_CLASS (clist)->refresh ((GtkCList*) (clist)); \
15 } G_STMT_END
16 #define CELL_SPACING               1
17 #define CLIST_OPTIMUM_SIZE         64
18 #define COLUMN_INSET               3
19
20 enum {
21         ROW_POPUP_MENU,
22         EMPTY_POPUP_MENU,
23         OPEN_ROW,
24         START_DRAG,
25         LAST_SIGNAL
26 };
27
28 static GdkPixmap *emptyxpm = NULL;
29 static GdkBitmap *emptyxpmmask = NULL;
30
31 static void gtk_sctree_class_init (GtkSCTreeClass *class);
32 static void gtk_sctree_init (GtkSCTree *sctree);
33
34 static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event);
35 static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event);
36 static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event);
37 static void gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context);
38 static void gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context);
39 static void gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
40                                      GtkSelectionData *data, guint info, guint time);
41 static void gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time);
42 static gboolean gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
43                                        gint x, gint y, guint time);
44 static gboolean gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
45                                      gint x, gint y, guint time);
46 static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
47                                           gint x, gint y, GtkSelectionData *data,
48                                           guint info, guint time);
49
50 static void gtk_sctree_clear (GtkCList *clist);
51 static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node);
52        
53 static void stree_sort (GtkCTree *ctree, GtkCTreeNode  *node, gpointer data);
54 void gtk_sctree_sort_node (GtkCTree *ctree, GtkCTreeNode *node);
55 void gtk_sctree_sort_recursive (GtkCTree *ctree, GtkCTreeNode *node);
56
57 static void gtk_sctree_link (GtkCTree *ctree,
58                         GtkCTreeNode  *node,
59                         GtkCTreeNode  *parent,
60                         GtkCTreeNode  *sibling,
61                         gboolean       update_focus_row);
62
63 static void gtk_sctree_unlink (GtkCTree      *ctree, 
64                         GtkCTreeNode  *node,
65                         gboolean       update_focus_row);
66
67 static void stree_update_level (GtkCTree      *ctree, 
68                         GtkCTreeNode  *node, 
69                         gpointer       data);
70
71 static GtkCTreeNode * gtk_sctree_last_visible (GtkCTree     *ctree,
72                                               GtkCTreeNode *node);
73 static void gtk_sctree_real_tree_expand            (GtkCTree      *ctree,
74                                                  GtkCTreeNode  *node);
75
76 static GtkCTreeClass *parent_class;
77
78 static guint sctree_signals[LAST_SIGNAL];
79
80
81 /**
82  * gtk_sctree_get_type:
83  * @void: 
84  * 
85  * Creates the GtkSCTree class and its type information
86  * 
87  * Return value: The type ID for GtkSCTreeClass
88  **/
89 GType
90 gtk_sctree_get_type (void)
91 {
92         static GType sctree_type = 0;
93
94         if (!sctree_type) {
95                 GTypeInfo sctree_info = {
96                         sizeof (GtkSCTreeClass),
97
98                         (GBaseInitFunc) NULL,
99                         (GBaseFinalizeFunc) NULL,
100
101                         (GClassInitFunc) gtk_sctree_class_init,
102                         (GClassFinalizeFunc) NULL,
103                         NULL,   /* class_data */
104
105                         sizeof (GtkSCTree),
106                         0,      /* n_preallocs */
107                         (GInstanceInitFunc) gtk_sctree_init,
108                 };
109
110                 sctree_type = g_type_register_static (GTK_TYPE_CTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0);
111         }
112
113         return sctree_type;
114 }
115
116 /* Standard class initialization function */
117 static void
118 gtk_sctree_class_init (GtkSCTreeClass *klass)
119 {
120         GtkObjectClass *object_class;
121         GtkWidgetClass *widget_class;
122         GtkCListClass *clist_class;
123         GtkCTreeClass *ctree_class;
124
125         object_class = (GtkObjectClass *) klass;
126         widget_class = (GtkWidgetClass *) klass;
127         clist_class = (GtkCListClass *) klass;
128         ctree_class = (GtkCTreeClass *) klass;
129
130         parent_class = gtk_type_class (gtk_ctree_get_type ());
131
132         sctree_signals[ROW_POPUP_MENU] =
133                 g_signal_new ("row_popup_menu",
134                               G_TYPE_FROM_CLASS (klass),
135                               G_SIGNAL_RUN_FIRST,
136                               G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
137                               NULL, NULL,
138                               sylpheed_marshal_VOID__POINTER,
139                               G_TYPE_NONE, 1,
140                               GDK_TYPE_EVENT);
141         sctree_signals[EMPTY_POPUP_MENU] =
142                 g_signal_new ("empty_popup_menu",
143                               G_TYPE_FROM_CLASS (klass),
144                               G_SIGNAL_RUN_FIRST,
145                               G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
146                               NULL, NULL,
147                               sylpheed_marshal_VOID__POINTER,
148                               G_TYPE_NONE, 1,
149                               GDK_TYPE_EVENT);
150         sctree_signals[OPEN_ROW] =
151                 g_signal_new ("open_row",
152                               G_TYPE_FROM_CLASS (klass),
153                               G_SIGNAL_RUN_FIRST,
154                               G_STRUCT_OFFSET (GtkSCTreeClass, open_row),
155                               NULL, NULL,
156                               g_cclosure_marshal_VOID__VOID,
157                               G_TYPE_NONE, 0);
158         sctree_signals[START_DRAG] =
159                 g_signal_new ("start_drag",
160                               G_TYPE_FROM_CLASS (klass),
161                               G_SIGNAL_RUN_FIRST,
162                               G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
163                               NULL, NULL,
164                               sylpheed_marshal_VOID__INT_POINTER,
165                               G_TYPE_NONE, 2,
166                               G_TYPE_INT,
167                               GDK_TYPE_EVENT);
168
169         /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */
170
171         clist_class->clear = gtk_sctree_clear;
172         ctree_class->tree_collapse = gtk_sctree_collapse;
173         ctree_class->tree_expand = gtk_sctree_real_tree_expand;
174         
175         widget_class->button_press_event = gtk_sctree_button_press;
176         widget_class->button_release_event = gtk_sctree_button_release;
177         widget_class->motion_notify_event = gtk_sctree_motion;
178         widget_class->drag_begin = gtk_sctree_drag_begin;
179         widget_class->drag_end = gtk_sctree_drag_end;
180         widget_class->drag_data_get = gtk_sctree_drag_data_get;
181         widget_class->drag_leave = gtk_sctree_drag_leave;
182         widget_class->drag_motion = gtk_sctree_drag_motion;
183         widget_class->drag_drop = gtk_sctree_drag_drop;
184         widget_class->drag_data_received = gtk_sctree_drag_data_received;
185 }
186
187 /* Standard object initialization function */
188 static void
189 gtk_sctree_init (GtkSCTree *sctree)
190 {
191         sctree->anchor_row = NULL;
192
193         /* GtkCTree does not specify pointer motion by default */
194         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
195         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
196 }
197
198 /* Get information the specified row is selected. */
199
200 static gboolean
201 row_is_selected(GtkSCTree *sctree, gint row)
202 {
203         GtkCListRow *clist_row;
204         clist_row =  g_list_nth (GTK_CLIST(sctree)->row_list, row)->data;
205         return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE;
206 }
207
208 /* Selects the rows between the anchor to the specified row, inclusive.  */
209 static void
210 select_range (GtkSCTree *sctree, gint row)
211 {
212         gint prev_row;
213         gint min, max;
214         gint i;
215
216         if (sctree->anchor_row == NULL) {
217                 prev_row = row;
218                 sctree->anchor_row = gtk_ctree_node_nth(GTK_CTREE(sctree), row);
219         } else
220                 prev_row = g_list_position(GTK_CLIST(sctree)->row_list,
221                                            (GList *)sctree->anchor_row);
222
223         if (row < prev_row) {
224                 min = row;
225                 max = prev_row;
226                 GTK_CLIST(sctree)->focus_row = max;
227         } else {
228                 min = prev_row;
229                 max = row;
230         }
231         sctree->selecting_range = TRUE;
232         for (i = min; i < max; i++)
233                 gtk_clist_select_row (GTK_CLIST (sctree), i, -1);
234
235         sctree->selecting_range = FALSE;
236         gtk_clist_select_row (GTK_CLIST (sctree), max, -1);
237 }
238
239 /* Handles row selection according to the specified modifier state */
240 static void
241 select_row (GtkSCTree *sctree, gint row, gint col, guint state)
242 {
243         gboolean range, additive;
244         g_return_if_fail (sctree != NULL);
245         g_return_if_fail (GTK_IS_SCTREE (sctree));
246     
247         range = ((state & GDK_SHIFT_MASK) != 0) &&
248                 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
249                 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
250         additive = ((state & GDK_CONTROL_MASK) != 0) &&
251                    (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
252                    (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
253
254         gtk_clist_freeze (GTK_CLIST (sctree));
255
256         GTK_CLIST(sctree)->focus_row = row;
257
258         if (!additive) {
259                 sctree->selecting_range = TRUE;
260                 gtk_clist_unselect_all (GTK_CLIST (sctree));
261                 sctree->selecting_range = FALSE;
262         }
263
264         if (!range) {
265                 GtkCTreeNode *node;
266
267                 node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
268
269                 /*No need to manage overlapped list*/
270                 if (additive) {
271                         if (row_is_selected(sctree, row))
272                                 gtk_clist_unselect_row (GTK_CLIST (sctree), row, col);
273                         else
274                                 g_signal_emit_by_name
275                                         (G_OBJECT (sctree),
276                                          "tree_select_row", node, col);
277                 } else {
278                         g_signal_emit_by_name
279                                 (G_OBJECT (sctree),
280                                  "tree_select_row", node, col);
281                 }
282                 sctree->anchor_row = node;
283         } else
284                 select_range (sctree, row);
285         
286         gtk_clist_thaw (GTK_CLIST (sctree));
287 }
288
289 /* Our handler for button_press events.  We override all of GtkCList's broken
290  * behavior.
291  */
292 static gint
293 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
294 {
295         GtkSCTree *sctree;
296         GtkCList *clist;
297         gboolean on_row;
298         gint row;
299         gint col;
300         gint retval;
301
302         g_return_val_if_fail (widget != NULL, FALSE);
303         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
304         g_return_val_if_fail (event != NULL, FALSE);
305
306         sctree = GTK_SCTREE (widget);
307         clist = GTK_CLIST (widget);
308         retval = FALSE;
309
310         if (event->window != clist->clist_window)
311                 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
312
313         on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
314
315         if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
316                 gtk_widget_grab_focus (widget);
317
318         if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
319                 gtk_ctree_toggle_expansion
320                         (GTK_CTREE(sctree), 
321                          gtk_ctree_node_nth(GTK_CTREE(sctree), row));
322                 return TRUE;
323         }
324
325         switch (event->type) {
326         case GDK_BUTTON_PRESS:
327                 if (event->button == 1 || event->button == 2) {
328                         if (event->button == 2)
329                                 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
330                         if (on_row) {
331                                 /* Save the mouse info for DnD */
332                                 sctree->dnd_press_button = event->button;
333                                 sctree->dnd_press_x = event->x;
334                                 sctree->dnd_press_y = event->y;
335
336                                 /* Handle selection */
337                                 if ((row_is_selected (sctree, row)
338                                      && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
339                                     || ((event->state & GDK_CONTROL_MASK)
340                                         && !(event->state & GDK_SHIFT_MASK))) {
341                                         sctree->dnd_select_pending = TRUE;
342                                         sctree->dnd_select_pending_state = event->state;
343                                         sctree->dnd_select_pending_row = row;
344                                 } else
345                                         select_row (sctree, row, col, event->state);
346                         } else {
347                                 sctree->selecting_range = TRUE;
348                                 gtk_clist_unselect_all (clist);
349                                 sctree->selecting_range = FALSE;
350                         }
351
352                         retval = TRUE;
353                 } else if (event->button == 3) {
354                         /* Emit *_popup_menu signal*/
355                         if (on_row) {
356                                 if (!row_is_selected(sctree,row))
357                                         select_row (sctree, row, col, 0);
358                                 g_signal_emit (G_OBJECT (sctree),
359                                                  sctree_signals[ROW_POPUP_MENU],
360                                                  0, event);
361                         } else {
362                                 sctree->selecting_range = TRUE;
363                                 gtk_clist_unselect_all(clist);
364                                 sctree->selecting_range = FALSE;
365                                 g_signal_emit (G_OBJECT (sctree),
366                                                  sctree_signals[EMPTY_POPUP_MENU],
367                                                  0, event);
368                         }
369                         retval = TRUE;
370                 }
371
372                 break;
373
374         case GDK_2BUTTON_PRESS:
375                 if (event->button != 1)
376                         break;
377
378                 sctree->dnd_select_pending = FALSE;
379                 sctree->dnd_select_pending_state = 0;
380
381                 if (on_row)
382                         g_signal_emit (G_OBJECT (sctree),
383                                        sctree_signals[OPEN_ROW], 0);
384
385                 retval = TRUE;
386                 break;
387
388         default:
389                 break;
390         }
391
392         return retval;
393 }
394
395 /* Our handler for button_release events.  We override all of GtkCList's broken
396  * behavior.
397  */
398 static gint
399 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
400 {
401         GtkSCTree *sctree;
402         GtkCList *clist;
403         gint on_row;
404         gint row, col;
405         gint retval;
406
407         g_return_val_if_fail (widget != NULL, FALSE);
408         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
409         g_return_val_if_fail (event != NULL, FALSE);
410
411         sctree = GTK_SCTREE (widget);
412         clist = GTK_CLIST (widget);
413         retval = FALSE;
414
415         if (event->window != clist->clist_window)
416                 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
417
418         on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
419
420         if (!(event->button == 1 || event->button == 2))
421                 return FALSE;
422
423         sctree->dnd_press_button = 0;
424         sctree->dnd_press_x = 0;
425         sctree->dnd_press_y = 0;
426
427         if (on_row) {
428                 if (sctree->dnd_select_pending) {
429                         select_row (sctree, row, col, sctree->dnd_select_pending_state);
430                         sctree->dnd_select_pending = FALSE;
431                         sctree->dnd_select_pending_state = 0;
432                 }
433
434                 retval = TRUE;
435         }
436
437         return retval;
438 }
439
440 /* Our handler for motion_notify events.  We override all of GtkCList's broken
441  * behavior.
442  */
443 static gint
444 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
445 {
446         GtkSCTree *sctree;
447         GtkCList *clist;
448
449         g_return_val_if_fail (widget != NULL, FALSE);
450         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
451         g_return_val_if_fail (event != NULL, FALSE);
452
453         sctree = GTK_SCTREE (widget);
454         clist = GTK_CLIST (widget);
455
456         if (event->window != clist->clist_window)
457                 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
458
459         if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
460               || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
461                 return FALSE;
462
463         /* This is the same threshold value that is used in gtkdnd.c */
464
465         if (MAX (ABS (sctree->dnd_press_x - event->x),
466                  ABS (sctree->dnd_press_y - event->y)) <= 3)
467                 return FALSE;
468
469         /* Handle any pending selections */
470
471         if (sctree->dnd_select_pending) {
472                 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
473                         select_row (sctree,
474                                     sctree->dnd_select_pending_row,
475                                     -1,
476                                     sctree->dnd_select_pending_state);
477
478                 sctree->dnd_select_pending = FALSE;
479                 sctree->dnd_select_pending_state = 0;
480         }
481
482         g_signal_emit (G_OBJECT (sctree),
483                        sctree_signals[START_DRAG],
484                        0,
485                        sctree->dnd_press_button,
486                        event);
487         return TRUE;
488 }
489
490 /* We override the drag_begin signal to do nothing */
491 static void
492 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
493 {
494         /* nothing */
495 }
496
497 /* We override the drag_end signal to do nothing */
498 static void
499 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
500 {
501         /* nothing */
502 }
503
504 /* We override the drag_data_get signal to do nothing */
505 static void
506 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
507                                      GtkSelectionData *data, guint info, guint time)
508 {
509         /* nothing */
510 }
511
512 /* We override the drag_leave signal to do nothing */
513 static void
514 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
515 {
516         /* nothing */
517 }
518
519 /* We override the drag_motion signal to do nothing */
520 static gboolean
521 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
522                                    gint x, gint y, guint time)
523 {
524         return FALSE;
525 }
526
527 /* We override the drag_drop signal to do nothing */
528 static gboolean
529 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
530                                  gint x, gint y, guint time)
531 {
532         return FALSE;
533 }
534
535 /* We override the drag_data_received signal to do nothing */
536 static void
537 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
538                                           gint x, gint y, GtkSelectionData *data,
539                                           guint info, guint time)
540 {
541         /* nothing */
542 }
543
544 /* Our handler for the clear signal of the clist.  We have to reset the anchor
545  * to null.
546  */
547 static void
548 gtk_sctree_clear (GtkCList *clist)
549 {
550         GtkSCTree *sctree;
551
552         g_return_if_fail (clist != NULL);
553         g_return_if_fail (GTK_IS_SCTREE (clist));
554
555         sctree = GTK_SCTREE (clist);
556         sctree->anchor_row = NULL;
557
558         if (((GtkCListClass *)parent_class)->clear)
559                 (* ((GtkCListClass *)parent_class)->clear) (clist);
560 }
561
562 /* Our handler for the change_focus_row_expansion signal of the ctree.  
563  We have to set the anchor to parent visible node.
564  */
565 static void 
566 gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node)
567 {
568         g_return_if_fail (ctree != NULL);
569         g_return_if_fail (GTK_IS_SCTREE (ctree));
570
571         (* parent_class->tree_collapse) (ctree, node);
572         GTK_SCTREE(ctree)->anchor_row =
573                 gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row);
574 }
575
576 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, 
577                                        gchar *titles[])
578 {
579         GtkWidget *widget;
580                                                                                                             
581         g_return_val_if_fail (columns > 0, NULL);
582         g_return_val_if_fail (tree_column >= 0, NULL);
583                                                                                                             
584         widget = gtk_widget_new (TYPE_GTK_SCTREE,
585                                  "n_columns", columns,
586                                  "tree_column", tree_column,
587                                  NULL);
588         if (titles) {
589                 GtkCList *clist = GTK_CLIST (widget);
590                 guint i;
591
592                 for (i = 0; i < columns; i++)
593                         gtk_clist_set_column_title (clist, i, titles[i]);
594                 gtk_clist_column_titles_show (clist);
595         }
596
597         return widget;
598 }
599
600 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
601 {
602         select_row(sctree, 
603                    g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
604                    -1, 0);
605 }
606
607 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state)
608 {
609         select_row(sctree, 
610                    g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
611                    -1, state);
612 }
613
614 void gtk_sctree_unselect_all (GtkSCTree *sctree)
615 {
616         sctree->selecting_range = TRUE;
617         gtk_clist_unselect_all(GTK_CLIST(sctree));
618         sctree->selecting_range = FALSE;
619         sctree->anchor_row = NULL;
620 }
621
622 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node)
623 {
624         sctree->anchor_row = node;
625 }
626
627 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCTreeNode *node)
628 {
629         if (sctree->anchor_row == node)
630                 sctree->anchor_row = NULL;
631         gtk_ctree_remove_node(GTK_CTREE(sctree), node);
632 }
633
634 /***********************************************************
635  *             Tree sorting functions                      *
636  ***********************************************************/
637
638 static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom)
639 {
640         gint j, k ;
641         GtkCTreeNode *temp;
642
643         j = 2 * root;
644         k = j + 1;
645
646         /* find the maximum element of numbers[root],
647            numbers[2*root] and numbers[2*root+1] */
648         if (j <= bottom) {
649                 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)),
650                                     GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
651                         j = root;
652                 if (k <= bottom)
653                         if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)),
654                                             GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
655                                 j = k;
656                 /* if numbers[root] wasn't the maximum element then
657                    sink again */
658                 if (root != j) {
659                         temp = g_ptr_array_index( numbers,root);
660                         g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
661                         g_ptr_array_index( numbers, j) = temp;
662                         sink( clist, numbers, j, bottom);
663                 }
664         }
665 }
666
667 static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size)
668 {
669         gint i;
670         GtkCTreeNode *temp;
671         
672         /* build the Heap */
673         for (i = (array_size / 2); i >= 1; i--)
674                 sink( clist, numbers, i, array_size);
675         /* output the Heap */
676         for (i = array_size; i >= 2; i--) {
677                 temp = g_ptr_array_index( numbers, 1);
678                 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
679                 g_ptr_array_index( numbers, i) = temp;
680                 sink( clist, numbers, 1, i-1);
681         }
682 }
683
684 static void
685 stree_sort (GtkCTree    *ctree,
686            GtkCTreeNode *node,
687            gpointer      data)
688 {
689         GtkCTreeNode *list_start, *work, *next;
690         GPtrArray *row_array, *viewable_array;
691         GtkCList *clist;
692         gint i;
693
694         clist = GTK_CLIST (ctree);
695
696         if (node)
697                 work = GTK_CTREE_ROW (node)->children;
698         else
699                 work = GTK_CTREE_NODE (clist->row_list);
700
701         row_array = g_ptr_array_new();
702         viewable_array = g_ptr_array_new();
703
704         if (work) {
705                 g_ptr_array_add( row_array, NULL);
706                 while (work) {
707                         /* add all rows to row_array */
708                         g_ptr_array_add( row_array, work);
709                         if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work))
710                                 g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent);
711                         next = GTK_CTREE_ROW (work)->sibling;
712                         gtk_sctree_unlink( ctree, work, FALSE);
713                         work = next;
714                 }
715
716                 heap_sort( clist, row_array, (row_array->len)-1);
717
718                 if (node)
719                         list_start = GTK_CTREE_ROW (node)->children;
720                 else
721                         list_start = GTK_CTREE_NODE (clist->row_list);
722
723                 if (clist->sort_type == GTK_SORT_ASCENDING) {
724                         for (i=(row_array->len)-1; i>=1; i--) {
725                                 work = g_ptr_array_index( row_array, i);
726                                 gtk_sctree_link( ctree, work, node, list_start, FALSE);
727                                 list_start = work;
728                                 /* insert work at the beginning of the list */
729                         }
730                 } else {
731                         for (i=1; i<row_array->len; i++) {
732                                 work = g_ptr_array_index( row_array, i);
733                                 gtk_sctree_link( ctree, work, node, list_start, FALSE);
734                                 list_start = work;
735                                 /* insert work at the beginning of the list */
736                         }
737                 }
738
739                 for (i=0; i<viewable_array->len; i++) {
740                         gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i));
741                 }
742                 
743         }
744         g_ptr_array_free( row_array, TRUE);
745         g_ptr_array_free( viewable_array, TRUE);
746 }
747
748 void
749 gtk_sctree_sort_recursive (GtkCTree     *ctree, 
750                           GtkCTreeNode *node)
751 {
752         GtkCList *clist;
753         GtkCTreeNode *focus_node = NULL;
754
755         g_return_if_fail (ctree != NULL);
756         g_return_if_fail (GTK_IS_CTREE (ctree));
757
758         clist = GTK_CLIST (ctree);
759
760         gtk_clist_freeze (clist);
761
762         if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
763                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
764       
765                 g_list_free (clist->undo_selection);
766                 g_list_free (clist->undo_unselection);
767                 clist->undo_selection = NULL;
768                 clist->undo_unselection = NULL;
769         }
770
771         if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
772                 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
773       
774         GTK_SCTREE(ctree)->sorting = TRUE;
775
776         gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (stree_sort), NULL);
777
778         if (!node)
779                 stree_sort (ctree, NULL, NULL);
780
781         GTK_SCTREE(ctree)->sorting = FALSE;
782
783         if (focus_node) {
784                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
785                 clist->undo_anchor = clist->focus_row;
786         }
787
788         gtk_clist_thaw (clist);
789 }
790
791 void
792 gtk_sctree_sort_node (GtkCTree     *ctree, 
793                      GtkCTreeNode *node)
794 {
795         GtkCList *clist;
796         GtkCTreeNode *focus_node = NULL;
797
798         g_return_if_fail (ctree != NULL);
799         g_return_if_fail (GTK_IS_CTREE (ctree));
800
801         clist = GTK_CLIST (ctree);
802
803         gtk_clist_freeze (clist);
804
805         if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
806                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
807
808                 g_list_free (clist->undo_selection);
809                 g_list_free (clist->undo_unselection);
810                 clist->undo_selection = NULL;
811                 clist->undo_unselection = NULL;
812         }
813
814         if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
815                 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
816
817         GTK_SCTREE(ctree)->sorting = TRUE;
818
819         stree_sort (ctree, node, NULL);
820
821         GTK_SCTREE(ctree)->sorting = FALSE;
822
823         if (focus_node) {
824                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
825                 clist->undo_anchor = clist->focus_row;
826         }
827
828         gtk_clist_thaw (clist);
829 }
830
831 /************************************************************************/
832
833 static void
834 gtk_sctree_unlink (GtkCTree     *ctree, 
835                   GtkCTreeNode *node,
836                   gboolean      update_focus_row)
837 {
838         GtkCList *clist;
839         gint rows;
840         gint level;
841         gint visible;
842         GtkCTreeNode *work;
843         GtkCTreeNode *parent;
844         GList *list;
845
846         g_return_if_fail (ctree != NULL);
847         g_return_if_fail (GTK_IS_CTREE (ctree));
848         g_return_if_fail (node != NULL);
849
850         clist = GTK_CLIST (ctree);
851   
852         if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
853                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
854
855                 g_list_free (clist->undo_selection);
856                 g_list_free (clist->undo_unselection);
857                 clist->undo_selection = NULL;
858                 clist->undo_unselection = NULL;
859         }
860
861         visible = gtk_ctree_is_viewable (ctree, node);
862
863         /* clist->row_list_end unlinked ? */
864         if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL ||
865            (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node,
866             GTK_CTREE_NODE (clist->row_list_end)))))
867                 clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
868
869         /* update list */
870         rows = 0;
871         level = GTK_CTREE_ROW (node)->level;
872         work = GTK_CTREE_NODE_NEXT (node);
873         while (work && GTK_CTREE_ROW (work)->level > level) {
874                 work = GTK_CTREE_NODE_NEXT (work);
875                 rows++;
876         }
877
878         if (visible) {
879                 clist->rows -= (rows + 1);
880
881                 if (update_focus_row) {
882                         gint pos;
883                         pos = g_list_position (clist->row_list, (GList *)node);
884                         if (pos + rows < clist->focus_row)
885                                 clist->focus_row -= (rows + 1);
886                         else if (pos <= clist->focus_row) {
887                                 if (!GTK_CTREE_ROW (node)->sibling)
888                                         clist->focus_row = MAX (pos - 1, 0);
889                                 else
890                                         clist->focus_row = pos;
891               
892                                 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
893                         }
894                         clist->undo_anchor = clist->focus_row;
895                 }
896         }
897
898         if (work) {
899                 list = (GList *)GTK_CTREE_NODE_PREV (work);
900                 list->next = NULL;
901                 list = (GList *)work;
902                 list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
903         }
904
905         if (GTK_CTREE_NODE_PREV (node) &&
906             GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) {
907                 list = (GList *)GTK_CTREE_NODE_PREV (node);
908                 list->next = (GList *)work;
909         }
910
911         /* update tree */
912         parent = GTK_CTREE_ROW (node)->parent;
913         if (parent) {
914                 if (GTK_CTREE_ROW (parent)->children == node) {
915                         GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
916                         if (!GTK_CTREE_ROW (parent)->children)
917                                 gtk_ctree_collapse (ctree, parent);
918                 }
919                 else {
920                         GtkCTreeNode *sibling;
921
922                         sibling = GTK_CTREE_ROW (parent)->children;
923                         while (GTK_CTREE_ROW (sibling)->sibling != node)
924                                 sibling = GTK_CTREE_ROW (sibling)->sibling;
925                         GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
926                 }
927         }
928         else {
929                 if (clist->row_list == (GList *)node)
930                         clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
931                 else {
932                         GtkCTreeNode *sibling;
933
934                         sibling = GTK_CTREE_NODE (clist->row_list);
935                         while (GTK_CTREE_ROW (sibling)->sibling != node)
936                                 sibling = GTK_CTREE_ROW (sibling)->sibling;
937                         GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
938                 }
939         }
940 }
941
942 static void
943 gtk_sctree_link (GtkCTree     *ctree,
944                 GtkCTreeNode *node,
945                 GtkCTreeNode *parent,
946                 GtkCTreeNode *sibling,
947                 gboolean      update_focus_row)
948 {
949         GtkCList *clist;
950         GList *list_end;
951         GList *list;
952         GList *work;
953         gboolean visible = FALSE;
954         gint rows = 0;
955   
956         if (sibling)
957                 g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
958         g_return_if_fail (node != NULL);
959         g_return_if_fail (node != sibling);
960         g_return_if_fail (node != parent);
961
962         clist = GTK_CLIST (ctree);
963
964         if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
965                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
966
967                 g_list_free (clist->undo_selection);
968                 g_list_free (clist->undo_unselection);
969                 clist->undo_selection = NULL;
970                 clist->undo_unselection = NULL;
971         }
972
973         for (rows = 1, list_end = (GList *)node; list_end->next;
974              list_end = list_end->next)
975                 rows++;
976
977         GTK_CTREE_ROW (node)->parent = parent;
978         GTK_CTREE_ROW (node)->sibling = sibling;
979
980         if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
981             GTK_CTREE_ROW (parent)->expanded))) {
982                 visible = TRUE;
983                 clist->rows += rows;
984         }
985
986         if (parent)
987                 work = (GList *)(GTK_CTREE_ROW (parent)->children);
988         else
989                 work = clist->row_list;
990
991         if (sibling) {
992                 if (work != (GList *)sibling) {
993                         while (GTK_CTREE_ROW (work)->sibling != sibling)
994                                 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
995                         GTK_CTREE_ROW (work)->sibling = node;
996                 }
997
998                 if (sibling == GTK_CTREE_NODE (clist->row_list))
999                 clist->row_list = (GList *) node;
1000                 if (GTK_CTREE_NODE_PREV (sibling) &&
1001                     GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) {
1002                         list = (GList *)GTK_CTREE_NODE_PREV (sibling);
1003                         list->next = (GList *)node;
1004                 }
1005
1006                 list = (GList *)node;
1007                 list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
1008                 list_end->next = (GList *)sibling;
1009                 list = (GList *)sibling;
1010                 list->prev = list_end;
1011                 if (parent && GTK_CTREE_ROW (parent)->children == sibling)
1012                         GTK_CTREE_ROW (parent)->children = node;
1013         }
1014         else {
1015                 if (work) {
1016                         /* find sibling */
1017                         while (GTK_CTREE_ROW (work)->sibling)
1018                         work = (GList *)(GTK_CTREE_ROW (work)->sibling);
1019                         GTK_CTREE_ROW (work)->sibling = node;
1020
1021                         /* find last visible child of sibling */
1022                         work = (GList *) gtk_sctree_last_visible (ctree,
1023                                GTK_CTREE_NODE (work));
1024
1025                         list_end->next = work->next;
1026                         if (work->next)
1027                                 list = work->next->prev = list_end;
1028                         work->next = (GList *)node;
1029                         list = (GList *)node;
1030                         list->prev = work;
1031                 }
1032                 else {
1033                         if (parent) {
1034                                 GTK_CTREE_ROW (parent)->children = node;
1035                                 list = (GList *)node;
1036                                 list->prev = (GList *)parent;
1037                                 if (GTK_CTREE_ROW (parent)->expanded) {
1038                                         list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
1039                                         if (GTK_CTREE_NODE_NEXT(parent)) {
1040                                                 list = (GList *)GTK_CTREE_NODE_NEXT (parent);
1041                                                 list->prev = list_end;
1042                                         }
1043                                         list = (GList *)parent;
1044                                         list->next = (GList *)node;
1045                                 }
1046                                 else
1047                                         list_end->next = NULL;
1048                         }
1049                         else {
1050                                 clist->row_list = (GList *)node;
1051                                 list = (GList *)node;
1052                                 list->prev = NULL;
1053                                 list_end->next = NULL;
1054                         }
1055                 }
1056         }
1057
1058         gtk_ctree_pre_recursive (ctree, node, stree_update_level, NULL); 
1059
1060         if (clist->row_list_end == NULL ||
1061             clist->row_list_end->next == (GList *)node)
1062                 clist->row_list_end = list_end;
1063
1064         if (visible && update_focus_row) {
1065                 gint pos;
1066                 pos = g_list_position (clist->row_list, (GList *)node);
1067   
1068                 if (pos <= clist->focus_row) {
1069                         clist->focus_row += rows;
1070                         clist->undo_anchor = clist->focus_row;
1071                 }
1072         }
1073 }
1074
1075 static void
1076 stree_update_level (GtkCTree     *ctree, 
1077                    GtkCTreeNode *node, 
1078                    gpointer      data)
1079 {
1080         if (!node)
1081                 return;
1082
1083         if (GTK_CTREE_ROW (node)->parent)
1084                 GTK_CTREE_ROW (node)->level = 
1085                 GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
1086         else
1087                 GTK_CTREE_ROW (node)->level = 1;
1088 }
1089
1090 static GtkCTreeNode *
1091 gtk_sctree_last_visible (GtkCTree     *ctree,
1092                         GtkCTreeNode *node)
1093 {
1094         GtkCTreeNode *work;
1095   
1096         if (!node)
1097                 return NULL;
1098
1099         work = GTK_CTREE_ROW (node)->children;
1100
1101         if (!work || !GTK_CTREE_ROW (node)->expanded)
1102                 return node;
1103
1104         while (GTK_CTREE_ROW (work)->sibling)
1105                 work = GTK_CTREE_ROW (work)->sibling;
1106
1107         return gtk_sctree_last_visible (ctree, work);
1108 }
1109
1110 /* this wrapper simply replaces NULL pixmaps 
1111  * with a transparent, 1x1 pixmap. This works
1112  * around a memory problem deep inside gtk, 
1113  * revealed by valgrind. 
1114  */
1115 /*GtkCTreeNode* gtk_sctree_insert_node        (GtkCTree *ctree,
1116                                              GtkCTreeNode *parent,
1117                                              GtkCTreeNode *sibling,
1118                                              gchar *text[],
1119                                              guint8 spacing,
1120                                              GdkPixmap *pixmap_closed,
1121                                              GdkBitmap *mask_closed,
1122                                              GdkPixmap *pixmap_opened,
1123                                              GdkBitmap *mask_opened,
1124                                              gboolean is_leaf,
1125                                              gboolean expanded)
1126 {
1127         if (!emptyxpm) {
1128                 stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1129                          &emptyxpm, &emptyxpmmask);
1130         }
1131         if (!pixmap_closed) {
1132                 pixmap_closed = emptyxpm;
1133                 mask_closed = emptyxpmmask;
1134         }
1135         if (!pixmap_opened) {
1136                 pixmap_opened = emptyxpm;
1137                 mask_opened = emptyxpmmask;
1138         }
1139         return gtk_ctree_insert_node(ctree, parent, sibling, text,spacing,
1140                 pixmap_closed, mask_closed, pixmap_opened, mask_opened,
1141                 is_leaf, expanded);
1142 }*/
1143
1144 static void 
1145 sset_node_info (GtkCTree     *ctree,
1146                GtkCTreeNode *node,
1147                const gchar  *text,
1148                guint8        spacing,
1149                GdkPixmap    *pixmap_closed,
1150                GdkBitmap    *mask_closed,
1151                GdkPixmap    *pixmap_opened,
1152                GdkBitmap    *mask_opened,
1153                gboolean      is_leaf,
1154                gboolean      expanded)
1155 {
1156   if (GTK_CTREE_ROW (node)->pixmap_opened)
1157     {
1158       gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_opened);
1159       if (GTK_CTREE_ROW (node)->mask_opened) 
1160         gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_opened);
1161     }
1162   if (GTK_CTREE_ROW (node)->pixmap_closed)
1163     {
1164       gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_closed);
1165       if (GTK_CTREE_ROW (node)->mask_closed) 
1166         gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_closed);
1167     }
1168
1169   GTK_CTREE_ROW (node)->pixmap_opened = NULL;
1170   GTK_CTREE_ROW (node)->mask_opened   = NULL;
1171   GTK_CTREE_ROW (node)->pixmap_closed = NULL;
1172   GTK_CTREE_ROW (node)->mask_closed   = NULL;
1173
1174   if (pixmap_closed)
1175     {
1176       GTK_CTREE_ROW (node)->pixmap_closed = gdk_pixmap_ref (pixmap_closed);
1177       if (mask_closed) 
1178         GTK_CTREE_ROW (node)->mask_closed = gdk_bitmap_ref (mask_closed);
1179     }
1180   if (pixmap_opened)
1181     {
1182       GTK_CTREE_ROW (node)->pixmap_opened = gdk_pixmap_ref (pixmap_opened);
1183       if (mask_opened) 
1184         GTK_CTREE_ROW (node)->mask_opened = gdk_bitmap_ref (mask_opened);
1185     }
1186
1187   GTK_CTREE_ROW (node)->is_leaf  = is_leaf;
1188   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
1189
1190   if (GTK_CTREE_ROW (node)->expanded)
1191     gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column,
1192                                 text, spacing, pixmap_opened, mask_opened);
1193   else 
1194     gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column,
1195                                 text, spacing, pixmap_closed, mask_closed);
1196 }
1197
1198 static void
1199 stree_draw_node (GtkCTree     *ctree, 
1200                 GtkCTreeNode *node)
1201 {
1202   GtkCList *clist;
1203   
1204   clist = GTK_CLIST (ctree);
1205
1206   if (CLIST_UNFROZEN (clist) && gtk_ctree_is_viewable (ctree, node))
1207     {
1208       GtkCTreeNode *work;
1209       gint num = 0;
1210       
1211       work = GTK_CTREE_NODE (clist->row_list);
1212       while (work && work != node)
1213         {
1214           work = GTK_CTREE_NODE_NEXT (work);
1215           num++;
1216         }
1217       if (work && gtk_clist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
1218         GTK_CLIST_GET_CLASS (clist)->draw_row
1219           (clist, NULL, num, GTK_CLIST_ROW ((GList *) node));
1220     }
1221 }
1222
1223 /* this wrapper simply replaces NULL pixmaps 
1224  * with a transparent, 1x1 pixmap. This works
1225  * around a memory problem deep inside gtk, 
1226  * revealed by valgrind. 
1227  */
1228 void        gtk_sctree_set_node_info        (GtkCTree *ctree,
1229                                              GtkCTreeNode *node,
1230                                              const gchar *text,
1231                                              guint8 spacing,
1232                                              GdkPixmap *pixmap_closed,
1233                                              GdkBitmap *mask_closed,
1234                                              GdkPixmap *pixmap_opened,
1235                                              GdkBitmap *mask_opened,
1236                                              gboolean is_leaf,
1237                                              gboolean expanded)
1238 {
1239   gboolean old_leaf;
1240   gboolean old_expanded;
1241   GtkCTreeNode *work;
1242  
1243   if (!emptyxpm) {
1244           stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1245                    &emptyxpm, &emptyxpmmask);
1246   }
1247   if (!pixmap_closed) {
1248           pixmap_closed = emptyxpm;
1249           mask_closed = emptyxpmmask;
1250   }
1251   if (!pixmap_opened) {
1252           pixmap_opened = emptyxpm;
1253           mask_opened = emptyxpmmask;
1254   }
1255
1256   if (!GTK_IS_CTREE (ctree) || !node) return;
1257
1258   old_leaf = GTK_CTREE_ROW (node)->is_leaf;
1259   old_expanded = GTK_CTREE_ROW (node)->expanded;
1260
1261   if (is_leaf && (work = GTK_CTREE_ROW (node)->children) != NULL)
1262     {
1263       GtkCTreeNode *ptr;
1264       
1265       while (work)
1266         {
1267           ptr = work;
1268           work = GTK_CTREE_ROW (work)->sibling;
1269           gtk_ctree_remove_node (ctree, ptr);
1270         }
1271     }
1272
1273   sset_node_info (ctree, node, text, spacing, pixmap_closed, mask_closed,
1274                  pixmap_opened, mask_opened, is_leaf, expanded);
1275
1276   if (!is_leaf && !old_leaf)
1277     {
1278       GTK_CTREE_ROW (node)->expanded = old_expanded;
1279       if (expanded && !old_expanded)
1280         gtk_ctree_expand (ctree, node);
1281       else if (!expanded && old_expanded)
1282         gtk_ctree_collapse (ctree, node);
1283     }
1284
1285   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
1286   
1287   stree_draw_node (ctree, node);
1288 }
1289
1290 static GtkCTreeRow *
1291 srow_new (GtkCTree *ctree)
1292 {
1293   GtkCList *clist;
1294   GtkCTreeRow *ctree_row;
1295   int i;
1296
1297   clist = GTK_CLIST (ctree);
1298 #if GTK_CHECK_VERSION(2,9,0)
1299   ctree_row = g_slice_new (GtkCTreeRow);
1300   ctree_row->row.cell = g_slice_alloc (sizeof (GtkCell) * clist->columns);
1301 #else
1302   ctree_row = g_chunk_new (GtkCTreeRow, (GMemChunk *)clist->row_mem_chunk);
1303   ctree_row->row.cell = g_chunk_new (GtkCell, (GMemChunk *)clist->cell_mem_chunk);
1304 #endif
1305   for (i = 0; i < clist->columns; i++)
1306     {
1307       ctree_row->row.cell[i].type = GTK_CELL_EMPTY;
1308       ctree_row->row.cell[i].vertical = 0;
1309       ctree_row->row.cell[i].horizontal = 0;
1310       ctree_row->row.cell[i].style = NULL;
1311     }
1312
1313   GTK_CELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
1314
1315   ctree_row->row.fg_set     = FALSE;
1316   ctree_row->row.bg_set     = FALSE;
1317   ctree_row->row.style      = NULL;
1318   ctree_row->row.selectable = TRUE;
1319   ctree_row->row.state      = GTK_STATE_NORMAL;
1320   ctree_row->row.data       = NULL;
1321   ctree_row->row.destroy    = NULL;
1322
1323   ctree_row->level         = 0;
1324   ctree_row->expanded      = FALSE;
1325   ctree_row->parent        = NULL;
1326   ctree_row->sibling       = NULL;
1327   ctree_row->children      = NULL;
1328   ctree_row->pixmap_closed = NULL;
1329   ctree_row->mask_closed   = NULL;
1330   ctree_row->pixmap_opened = NULL;
1331   ctree_row->mask_opened   = NULL;
1332   
1333   return ctree_row;
1334 }
1335
1336 static void
1337 srow_delete (GtkCTree    *ctree,
1338             GtkCTreeRow *ctree_row)
1339 {
1340   GtkCList *clist;
1341   gint i;
1342
1343   clist = GTK_CLIST (ctree);
1344
1345   for (i = 0; i < clist->columns; i++)
1346     {
1347       GTK_CLIST_GET_CLASS (clist)->set_cell_contents
1348         (clist, &(ctree_row->row), i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
1349       if (ctree_row->row.cell[i].style)
1350         {
1351           if (GTK_WIDGET_REALIZED (ctree))
1352             gtk_style_detach (ctree_row->row.cell[i].style);
1353           g_object_unref (ctree_row->row.cell[i].style);
1354         }
1355     }
1356
1357   if (ctree_row->row.style)
1358     {
1359       if (GTK_WIDGET_REALIZED (ctree))
1360         gtk_style_detach (ctree_row->row.style);
1361       g_object_unref (ctree_row->row.style);
1362     }
1363
1364   if (ctree_row->pixmap_closed)
1365     {
1366       gdk_pixmap_unref (ctree_row->pixmap_closed);
1367       if (ctree_row->mask_closed)
1368         gdk_bitmap_unref (ctree_row->mask_closed);
1369     }
1370
1371   if (ctree_row->pixmap_opened)
1372     {
1373       gdk_pixmap_unref (ctree_row->pixmap_opened);
1374       if (ctree_row->mask_opened)
1375         gdk_bitmap_unref (ctree_row->mask_opened);
1376     }
1377
1378   if (ctree_row->row.destroy)
1379     {
1380       GtkDestroyNotify dnotify = ctree_row->row.destroy;
1381       gpointer ddata = ctree_row->row.data;
1382
1383       ctree_row->row.destroy = NULL;
1384       ctree_row->row.data = NULL;
1385
1386       dnotify (ddata);
1387     }
1388
1389 #if GTK_CHECK_VERSION(2,9,0)  
1390   g_slice_free1 (sizeof (GtkCell) * clist->columns, ctree_row->row.cell);
1391   g_slice_free (GtkCTreeRow, ctree_row);
1392 #else
1393   g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell);
1394   g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row);
1395 #endif
1396 }
1397
1398 static void
1399 stree_delete_row (GtkCTree     *ctree, 
1400                  GtkCTreeNode *node, 
1401                  gpointer      data)
1402 {
1403   srow_delete (ctree, GTK_CTREE_ROW (node));
1404   g_list_free_1 ((GList *)node);
1405 }
1406
1407 static void
1408 gtk_sctree_column_auto_resize (GtkCList    *clist,
1409                     GtkCListRow *clist_row,
1410                     gint         column,
1411                     gint         old_width)
1412 {
1413   /* resize column if needed for auto_resize */
1414   GtkRequisition requisition;
1415
1416   if (!clist->column[column].auto_resize ||
1417       GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1418     return;
1419
1420   if (clist_row)
1421     GTK_CLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
1422                                                    column, &requisition);
1423   else
1424     requisition.width = 0;
1425
1426   if (requisition.width > clist->column[column].width)
1427     gtk_clist_set_column_width (clist, column, requisition.width);
1428   else if (requisition.width < old_width &&
1429            old_width == clist->column[column].width)
1430     {
1431       GList *list;
1432       gint new_width;
1433
1434       /* run a "gtk_clist_optimal_column_width" but break, if
1435        * the column doesn't shrink */
1436       if (GTK_CLIST_SHOW_TITLES (clist) && clist->column[column].button)
1437         new_width = (clist->column[column].button->requisition.width -
1438                      (CELL_SPACING + (2 * COLUMN_INSET)));
1439       else
1440         new_width = 0;
1441
1442       for (list = clist->row_list; list; list = list->next)
1443         {
1444           GTK_CLIST_GET_CLASS (clist)->cell_size_request
1445             (clist, GTK_CLIST_ROW (list), column, &requisition);
1446           new_width = MAX (new_width, requisition.width);
1447           if (new_width == clist->column[column].width)
1448             break;
1449         }
1450       if (new_width < clist->column[column].width)
1451         gtk_clist_set_column_width (clist, column, new_width);
1452     }
1453 }
1454
1455
1456 static void 
1457 gtk_sctree_real_tree_expand (GtkCTree     *ctree,
1458                   GtkCTreeNode *node)
1459 {
1460   GtkCList *clist;
1461   GtkCTreeNode *work;
1462   GtkRequisition requisition;
1463   gboolean visible;
1464   gint level;
1465
1466   g_return_if_fail (GTK_IS_CTREE (ctree));
1467
1468   if (!node || GTK_CTREE_ROW (node)->expanded || GTK_CTREE_ROW (node)->is_leaf)
1469     return;
1470
1471   clist = GTK_CLIST (ctree);
1472   
1473   GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1474
1475   GTK_CTREE_ROW (node)->expanded = TRUE;
1476   level = GTK_CTREE_ROW (node)->level;
1477
1478   visible = gtk_ctree_is_viewable (ctree, node);
1479   /* get cell width if tree_column is auto resized */
1480   if (visible && clist->column[ctree->tree_column].auto_resize &&
1481       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1482     GTK_CLIST_GET_CLASS (clist)->cell_size_request
1483       (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column, &requisition);
1484
1485   /* unref/unset closed pixmap */
1486   if (GTK_CELL_PIXTEXT 
1487       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
1488     {
1489       gdk_pixmap_unref
1490         (GTK_CELL_PIXTEXT
1491          (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap);
1492       
1493       GTK_CELL_PIXTEXT
1494         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL;
1495       
1496       if (GTK_CELL_PIXTEXT 
1497           (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask)
1498         {
1499           gdk_pixmap_unref
1500             (GTK_CELL_PIXTEXT 
1501              (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask);
1502           GTK_CELL_PIXTEXT 
1503             (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL;
1504         }
1505     }
1506
1507   /* set/ref opened pixmap */
1508   if (GTK_CTREE_ROW (node)->pixmap_opened)
1509     {
1510       GTK_CELL_PIXTEXT 
1511         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = 
1512         gdk_pixmap_ref (GTK_CTREE_ROW (node)->pixmap_opened);
1513
1514       if (GTK_CTREE_ROW (node)->mask_opened) 
1515         GTK_CELL_PIXTEXT 
1516           (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = 
1517           gdk_pixmap_ref (GTK_CTREE_ROW (node)->mask_opened);
1518     }
1519
1520
1521   work = GTK_CTREE_ROW (node)->children;
1522   if (work)
1523     {
1524       GList *list = (GList *)work;
1525       gint *cell_width = NULL;
1526       gint tmp = 0;
1527       gint row;
1528       gint i;
1529       
1530       if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1531         {
1532           cell_width = g_new0 (gint, clist->columns);
1533           if (clist->column[ctree->tree_column].auto_resize)
1534               cell_width[ctree->tree_column] = requisition.width;
1535
1536           while (work)
1537             {
1538               /* search maximum cell widths of auto_resize columns */
1539               for (i = 0; i < clist->columns; i++)
1540                 if (clist->column[i].auto_resize)
1541                   {
1542                     GTK_CLIST_GET_CLASS (clist)->cell_size_request
1543                       (clist, &GTK_CTREE_ROW (work)->row, i, &requisition);
1544                     cell_width[i] = MAX (requisition.width, cell_width[i]);
1545                   }
1546
1547               list = (GList *)work;
1548               work = GTK_CTREE_NODE_NEXT (work);
1549               tmp++;
1550             }
1551         }
1552       else
1553         while (work)
1554           {
1555             list = (GList *)work;
1556             work = GTK_CTREE_NODE_NEXT (work);
1557             tmp++;
1558           }
1559
1560       list->next = (GList *)GTK_CTREE_NODE_NEXT (node);
1561
1562       if (GTK_CTREE_NODE_NEXT (node))
1563         {
1564           GList *tmp_list;
1565
1566           tmp_list = (GList *)GTK_CTREE_NODE_NEXT (node);
1567           tmp_list->prev = list;
1568         }
1569       else
1570         clist->row_list_end = list;
1571
1572       list = (GList *)node;
1573       list->next = (GList *)(GTK_CTREE_ROW (node)->children);
1574
1575       if (visible)
1576         {
1577           /* resize auto_resize columns if needed */
1578           for (i = 0; i < clist->columns; i++)
1579             if (clist->column[i].auto_resize &&
1580                 cell_width[i] > clist->column[i].width)
1581               gtk_clist_set_column_width (clist, i, cell_width[i]);
1582           g_free (cell_width);
1583         
1584           if (!GTK_SCTREE(ctree)->sorting) {
1585                   /* update focus_row position */
1586                   row = g_list_position (clist->row_list, (GList *)node);
1587                   if (row < clist->focus_row)
1588                     clist->focus_row += tmp;
1589           }
1590           clist->rows += tmp;
1591           CLIST_REFRESH (clist);
1592         }
1593     }
1594   else if (visible && clist->column[ctree->tree_column].auto_resize)
1595     /* resize tree_column if needed */
1596     gtk_sctree_column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column,
1597                         requisition.width);
1598 }
1599
1600 GtkCTreeNode * 
1601 gtk_sctree_insert_node (GtkCTree     *ctree,
1602                        GtkCTreeNode *parent, 
1603                        GtkCTreeNode *sibling,
1604                        gchar        *text[],
1605                        guint8        spacing,
1606                        GdkPixmap    *pixmap_closed,
1607                        GdkBitmap    *mask_closed,
1608                        GdkPixmap    *pixmap_opened,
1609                        GdkBitmap    *mask_opened,
1610                        gboolean      is_leaf,
1611                        gboolean      expanded)
1612 {
1613   GtkCList *clist;
1614   GtkCTreeRow *new_row;
1615   GtkCTreeNode *node;
1616   GList *list;
1617   gint i;
1618
1619   if (!emptyxpm) {
1620           stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1621                    &emptyxpm, &emptyxpmmask);
1622   }
1623   if (!pixmap_closed) {
1624           pixmap_closed = emptyxpm;
1625           mask_closed = emptyxpmmask;
1626   }
1627   if (!pixmap_opened) {
1628           pixmap_opened = emptyxpm;
1629           mask_opened = emptyxpmmask;
1630   }
1631   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
1632   if (sibling)
1633     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
1634
1635   if (parent && GTK_CTREE_ROW (parent)->is_leaf)
1636     return NULL;
1637
1638   clist = GTK_CLIST (ctree);
1639
1640   /* create the row */
1641   new_row = srow_new (ctree);
1642   list = g_list_alloc ();
1643   list->data = new_row;
1644   node = GTK_CTREE_NODE (list);
1645
1646   if (text)
1647     for (i = 0; i < clist->columns; i++)
1648       if (text[i] && i != ctree->tree_column)
1649         GTK_CLIST_GET_CLASS (clist)->set_cell_contents
1650           (clist, &(new_row->row), i, GTK_CELL_TEXT, text[i], 0, NULL, NULL);
1651
1652   sset_node_info (ctree, node, text ?
1653                  text[ctree->tree_column] : NULL, spacing, pixmap_closed,
1654                  mask_closed, pixmap_opened, mask_opened, is_leaf, expanded);
1655
1656   /* sorted insertion */
1657   if (GTK_CLIST_AUTO_SORT (clist))
1658     {
1659       if (parent)
1660         sibling = GTK_CTREE_ROW (parent)->children;
1661       else
1662         sibling = GTK_CTREE_NODE (clist->row_list);
1663
1664       while (sibling && clist->compare
1665              (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (sibling)) > 0)
1666         sibling = GTK_CTREE_ROW (sibling)->sibling;
1667     }
1668
1669   gtk_sctree_link (ctree, node, parent, sibling, FALSE);
1670
1671   if (text && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) &&
1672       gtk_ctree_is_viewable (ctree, node))
1673     {
1674       for (i = 0; i < clist->columns; i++)
1675         if (clist->column[i].auto_resize)
1676           gtk_sctree_column_auto_resize (clist, &(new_row->row), i, 0);
1677     }
1678
1679   if (clist->rows == 1)
1680     {
1681       clist->focus_row = 0;
1682       if (clist->selection_mode == GTK_SELECTION_BROWSE)
1683         gtk_sctree_select (GTK_SCTREE(ctree), node);
1684     }
1685
1686
1687   CLIST_REFRESH (clist);
1688
1689   return node;
1690 }
1691
1692 GtkCTreeNode *
1693 gtk_sctree_insert_gnode (GtkCTree          *ctree,
1694                         GtkCTreeNode      *parent,
1695                         GtkCTreeNode      *sibling,
1696                         GNode             *gnode,
1697                         GtkCTreeGNodeFunc  func,
1698                         gpointer           data)
1699 {
1700   GtkCList *clist;
1701   GtkCTreeNode *cnode = NULL;
1702   GtkCTreeNode *child = NULL;
1703   GtkCTreeNode *new_child;
1704   GList *list;
1705   GNode *work;
1706   guint depth = 1;
1707
1708   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
1709   g_return_val_if_fail (gnode != NULL, NULL);
1710   g_return_val_if_fail (func != NULL, NULL);
1711   if (sibling)
1712     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
1713   
1714   clist = GTK_CLIST (ctree);
1715
1716   if (parent)
1717     depth = GTK_CTREE_ROW (parent)->level + 1;
1718
1719   list = g_list_alloc ();
1720   list->data = srow_new (ctree);
1721   cnode = GTK_CTREE_NODE (list);
1722
1723   gtk_clist_freeze (clist);
1724
1725   sset_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE);
1726
1727   if (!func (ctree, depth, gnode, cnode, data))
1728     {
1729       stree_delete_row (ctree, cnode, NULL);
1730       gtk_clist_thaw (clist);
1731       return NULL;
1732     }
1733
1734   if (GTK_CLIST_AUTO_SORT (clist))
1735     {
1736       if (parent)
1737         sibling = GTK_CTREE_ROW (parent)->children;
1738       else
1739         sibling = GTK_CTREE_NODE (clist->row_list);
1740
1741       while (sibling && clist->compare
1742              (clist, GTK_CTREE_ROW (cnode), GTK_CTREE_ROW (sibling)) > 0)
1743         sibling = GTK_CTREE_ROW (sibling)->sibling;
1744     }
1745
1746   gtk_sctree_link (ctree, cnode, parent, sibling, FALSE);
1747
1748   for (work = g_node_last_child (gnode); work; work = work->prev)
1749     {
1750       new_child = gtk_sctree_insert_gnode (ctree, cnode, child,
1751                                           work, func, data);
1752       if (new_child)
1753         child = new_child;
1754     }   
1755   
1756   gtk_clist_thaw (clist);
1757
1758   return cnode;
1759 }
1760