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