talons

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

gtkcmctree.c (144322B)


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