talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

gtksctree.c (56122B)


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