2008-05-18 [colin] 3.4.0cvs51
[claws.git] / src / gtk / gtksctree.c
index 87f923afaaa888391237a87957a5b917e4545d79..c1aaa39802473394c3bda2968e221366b6d84140 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
  * Parts of this file:
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
  *
  * Parts of this file from gtk/gtkctree.c and gtk/gtkclist.c:
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, 
@@ -13,7 +13,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #include <stdlib.h>
 
 #include "gtksctree.h"
-#include "sylpheed-marshal.h"
+#include "claws-marshal.h"
 #include "stock_pixmap.h"
 #include "prefs_common.h"
 #include "utils.h"
@@ -84,6 +84,7 @@ static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *co
                                          guint info, guint time);
 
 static void gtk_sctree_clear (GtkCList *clist);
+static void gtk_sctree_real_unselect_all (GtkCList *clist);
 static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node);
        
 static void stree_sort (GtkCTree *ctree, GtkCTreeNode  *node, gpointer data);
@@ -288,8 +289,12 @@ gtk_sctree_draw_expander (GtkCTree     *ctree,
     justification_factor = -1;
   else
     justification_factor = 1;
-  y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
-       (clip_rectangle->height + 1) % 2);
+  if (!GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist)))
+      y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
+          (clip_rectangle->height + 1) % 2);
+  else
+      y = (clip_rectangle->y + (clip_rectangle->height/2 - PM_SIZE) / 2 -
+          (clip_rectangle->height/2 + 1) % 2);
 
   if (!ctree_row->children)
     {
@@ -776,6 +781,15 @@ gtk_sctree_draw_lines (GtkCTree     *ctree,
   return offset;
 }
 
+static gboolean filter_fg (PangoAttribute *attribute, gpointer data)
+{
+       const PangoAttrClass *klass = attribute->klass;
+       if (klass->type == PANGO_ATTR_FOREGROUND)
+               return TRUE;
+
+       return FALSE;   
+}
+
 static PangoLayout *
 sc_gtk_clist_create_cell_layout (GtkCList       *clist,
                               GtkCListRow    *clist_row,
@@ -802,11 +816,26 @@ sc_gtk_clist_create_cell_layout (GtkCList       *clist,
       if (!text)
        return NULL;
       
-      layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
-                                              ((cell->type == GTK_CELL_PIXTEXT) ?
-                                               GTK_CELL_PIXTEXT (*cell)->text :
-                                               GTK_CELL_TEXT (*cell)->text));
-      pango_layout_set_font_description (layout, style->font_desc);
+      if (!GTK_SCTREE(clist)->use_markup[column]) {
+             layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
+                                                      ((cell->type == GTK_CELL_PIXTEXT) ?
+                                                       GTK_CELL_PIXTEXT (*cell)->text :
+                                                       GTK_CELL_TEXT (*cell)->text));
+             pango_layout_set_font_description (layout, style->font_desc);
+      } else {
+             PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist));
+             layout = pango_layout_new (context);
+             pango_layout_set_markup (layout, text, -1);
+             pango_layout_set_font_description (layout, style->font_desc);
+             if (clist_row->state == GTK_STATE_SELECTED) {
+                     /* for selected row, we should remove any forced foreground color
+                      * or it looks like shit */
+                     PangoAttrList *list = pango_layout_get_attributes(layout);
+                     PangoAttrList *rem = pango_attr_list_filter(list, filter_fg, NULL);
+                     if (rem)
+                             pango_attr_list_unref(rem);
+             }
+      }
       
       return layout;
       
@@ -848,14 +877,14 @@ gtk_sctree_draw_row (GtkCList     *clist,
        }
        if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) {
                greybg.pixel = normalbg.pixel;
-               greybg.red = normalbg.red - 0x1111;
-               greybg.green = normalbg.green - 0x1111;
-               greybg.blue = normalbg.blue - 0x1111;
+               greybg.red = normalbg.red - prefs_common.stripes_color_offset;
+               greybg.green = normalbg.green - prefs_common.stripes_color_offset;
+               greybg.blue = normalbg.blue - prefs_common.stripes_color_offset;
        } else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) {
                greybg.pixel = normalbg.pixel;
-               greybg.red = normalbg.red + 0x1111;
-               greybg.green = normalbg.green + 0x1111;
-               greybg.blue = normalbg.blue + 0x1111;
+               greybg.red = normalbg.red + prefs_common.stripes_color_offset;
+               greybg.green = normalbg.green + prefs_common.stripes_color_offset;
+               greybg.blue = normalbg.blue + prefs_common.stripes_color_offset;
        } else {
                color_change = FALSE;
        }
@@ -1116,6 +1145,10 @@ gtk_sctree_draw_row (GtkCList     *clist,
 
          if (i != ctree->tree_column)
            {
+             int start_y = (clip_rectangle.height - height) / 2;
+             if (GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist)))
+                     start_y = (clip_rectangle.height/2 - height) / 2;
+
              offset += clist_row->cell[i].horizontal;
              switch (clist_row->cell[i].type)
                {
@@ -1126,7 +1159,7 @@ gtk_sctree_draw_row (GtkCList     *clist,
                     GTK_CELL_PIXMAP (clist_row->cell[i])->mask,
                     offset,
                     clip_rectangle.y + clist_row->cell[i].vertical +
-                    (clip_rectangle.height - height) / 2,
+                    start_y,
                     pixmap_width, height);
                  break;
                case GTK_CELL_PIXTEXT:
@@ -1136,7 +1169,7 @@ gtk_sctree_draw_row (GtkCList     *clist,
                     GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
                     offset,
                     clip_rectangle.y + clist_row->cell[i].vertical +
-                    (clip_rectangle.height - height) / 2,
+                    start_y,
                     pixmap_width, height);
                  offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
 
@@ -1276,7 +1309,11 @@ gtk_sctree_change_focus_row_expansion (GtkCTree          *ctree,
   switch (action)
     {
     case GTK_CTREE_EXPANSION_EXPAND:
-      gtk_ctree_expand_recursive (ctree, node);
+      if (GTK_SCTREE(ctree)->always_expand_recursively)
+             gtk_ctree_expand_recursive (ctree, node);
+      else
+             gtk_ctree_expand (ctree, node);
+
       break;
     case GTK_CTREE_EXPANSION_EXPAND_RECURSIVE:
       gtk_ctree_expand_recursive (ctree, node);
@@ -1288,7 +1325,10 @@ gtk_sctree_change_focus_row_expansion (GtkCTree          *ctree,
       gtk_ctree_collapse_recursive (ctree, node);
       break;
     case GTK_CTREE_EXPANSION_TOGGLE:
-      gtk_ctree_toggle_expansion_recursive (ctree, node);
+      if (GTK_SCTREE(ctree)->always_expand_recursively)
+             gtk_ctree_toggle_expansion_recursive (ctree, node);
+      else
+             gtk_ctree_toggle_expansion (ctree, node);
       break;
     case GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE:
       gtk_ctree_toggle_expansion_recursive (ctree, node);
@@ -1296,10 +1336,19 @@ gtk_sctree_change_focus_row_expansion (GtkCTree          *ctree,
     }
 }
 
+static void gtk_sctree_finalize(GObject *object)
+{
+       GtkSCTree *sctree = GTK_SCTREE(object);
+       g_free(sctree->use_markup);
+       sctree->use_markup = NULL;
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
 /* Standard class initialization function */
 static void
 gtk_sctree_class_init (GtkSCTreeClass *klass)
 {
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
        GtkObjectClass *object_class;
        GtkWidgetClass *widget_class;
        GtkCListClass *clist_class;
@@ -1318,7 +1367,7 @@ gtk_sctree_class_init (GtkSCTreeClass *klass)
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
                              NULL, NULL,
-                             sylpheed_marshal_VOID__POINTER,
+                             claws_marshal_VOID__POINTER,
                              G_TYPE_NONE, 1,
                              GDK_TYPE_EVENT);
        sctree_signals[EMPTY_POPUP_MENU] =
@@ -1327,7 +1376,7 @@ gtk_sctree_class_init (GtkSCTreeClass *klass)
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
                              NULL, NULL,
-                             sylpheed_marshal_VOID__POINTER,
+                             claws_marshal_VOID__POINTER,
                              G_TYPE_NONE, 1,
                              GDK_TYPE_EVENT);
        sctree_signals[OPEN_ROW] =
@@ -1344,7 +1393,7 @@ gtk_sctree_class_init (GtkSCTreeClass *klass)
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
                              NULL, NULL,
-                             sylpheed_marshal_VOID__INT_POINTER,
+                             claws_marshal_VOID__INT_POINTER,
                              G_TYPE_NONE, 2,
                              G_TYPE_INT,
                              GDK_TYPE_EVENT);
@@ -1353,11 +1402,12 @@ gtk_sctree_class_init (GtkSCTreeClass *klass)
 
        clist_class->clear = gtk_sctree_clear;
        clist_class->draw_row = gtk_sctree_draw_row;
+       clist_class->unselect_all = gtk_sctree_real_unselect_all;
         ctree_class->tree_collapse = gtk_sctree_collapse;
        ctree_class->tree_expand = gtk_sctree_real_tree_expand;
        ctree_class->tree_move = sreal_tree_move;
        ctree_class->change_focus_row_expansion = gtk_sctree_change_focus_row_expansion;
-
+       
        widget_class->button_press_event = gtk_sctree_button_press;
        widget_class->button_release_event = gtk_sctree_button_release;
        widget_class->motion_notify_event = gtk_sctree_motion;
@@ -1368,6 +1418,8 @@ gtk_sctree_class_init (GtkSCTreeClass *klass)
        widget_class->drag_motion = gtk_sctree_drag_motion;
        widget_class->drag_drop = gtk_sctree_drag_drop;
        widget_class->drag_data_received = gtk_sctree_drag_data_received;
+       
+       gobject_class->finalize = gtk_sctree_finalize;
 }
 
 /* Standard object initialization function */
@@ -1414,7 +1466,7 @@ select_range (GtkSCTree *sctree, gint row)
                min = prev_row;
                max = row;
        }
-       sctree->selecting_range = TRUE;
+       sctree->selecting_range++;
        
        if (max < min) {
                int t = min;
@@ -1437,7 +1489,7 @@ select_range (GtkSCTree *sctree, gint row)
                gtk_clist_thaw(GTK_CLIST(sctree));
 
 
-       sctree->selecting_range = FALSE;
+       sctree->selecting_range--;
        gtk_clist_select_row (GTK_CLIST (sctree), max, -1);
 }
 
@@ -1459,27 +1511,13 @@ select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCTreeNode *_n
                   (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
                   (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
 
+       if (!range && !additive && sctree->force_additive_sel)
+               additive = TRUE;
+
        GTK_CLIST(sctree)->focus_row = row;
 
        if (!additive) {
-               /* if this selection isn't additive, we have to unselect what
-                * is selected. Here, heavy GUI updates can occur if we have 
-                * a big selection. See if more than one line is selected, in
-                * which case, freeze, else don't. */
-
-               gboolean should_freeze = FALSE;
-               if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 10)) {
-                       should_freeze = TRUE;
-                       sctree->selecting_range = TRUE;
-                       gtk_clist_freeze (GTK_CLIST (sctree));
-               }
-
                gtk_clist_unselect_all (GTK_CLIST (sctree));
-
-               if (should_freeze) {
-                       gtk_clist_thaw (GTK_CLIST (sctree));
-                       sctree->selecting_range = FALSE;
-               }
        }
 
        if (!range) {
@@ -1505,6 +1543,95 @@ select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCTreeNode *_n
                select_range (sctree, row);
 }
 
+static gboolean
+sctree_is_hot_spot (GtkSCTree     *sctree, 
+                  GtkCTreeNode *node,
+                  gint          row, 
+                  gint          x, 
+                  gint          y)
+{
+  GtkCTreeRow *tree_row;
+  GtkCList *clist;
+  GtkCTree *ctree;
+  GtkCellPixText *cell;
+  gint xl, xmax;
+  gint yu;
+  
+  g_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE);
+  g_return_val_if_fail (node != NULL, FALSE);
+
+  clist = GTK_CLIST (sctree);
+  ctree = GTK_CTREE (sctree);
+
+  if (!clist->column[ctree->tree_column].visible ||
+      ctree->expander_style == GTK_CTREE_EXPANDER_NONE)
+    return FALSE;
+
+  tree_row = GTK_CTREE_ROW (node);
+
+  cell = GTK_CELL_PIXTEXT (tree_row->row.cell[ctree->tree_column]);
+
+  if (!GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist)))
+     yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
+       (clist->row_height - 1) % 2);
+  else
+     yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height/2 - PM_SIZE) / 2 -
+       (clist->row_height/2 - 1) % 2);
+
+#ifndef GENERIC_UMPC
+  if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
+    xl = (clist->column[ctree->tree_column].area.x + 
+         clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
+         (tree_row->level - 1) * ctree->tree_indent - PM_SIZE -
+         (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+  else
+    xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+         (tree_row->level - 1) * ctree->tree_indent +
+         (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+
+  xmax = xl + PM_SIZE;
+#else
+  if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) {
+    xl = (clist->column[ctree->tree_column].area.x + 
+         clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
+         (tree_row->level - 1) * ctree->tree_indent - PM_SIZE -
+         (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+    xmax = xl + PM_SIZE;
+  } else if (ctree->tree_column == 0) {
+    xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+         (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+    xmax = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+          (tree_row->level - 1) * ctree->tree_indent +
+          (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3) +
+          PM_SIZE;
+  } else {
+    xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+         (tree_row->level - 1) * ctree->tree_indent +
+         (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+    xmax = xl + PM_SIZE;
+  }
+#endif
+  return (x >= xl && x <= xmax && y >= yu && y <= yu + PM_SIZE);
+}
+
+gboolean
+gtk_sctree_is_hot_spot (GtkSCTree *ctree, 
+                      gint      x, 
+                      gint      y)
+{
+  GtkCTreeNode *node;
+  gint column;
+  gint row;
+  
+  g_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE);
+
+  if (gtk_clist_get_selection_info (GTK_CLIST (ctree), x, y, &row, &column))
+    if ((node = GTK_CTREE_NODE(g_list_nth (GTK_CLIST (ctree)->row_list, row))))
+      return sctree_is_hot_spot (ctree, node, row, x, y);
+
+  return FALSE;
+}
+
 /* Our handler for button_press events.  We override all of GtkCList's broken
  * behavior.
  */
@@ -1534,10 +1661,14 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
        if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
                gtk_widget_grab_focus (widget);
 
-       if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
-               gtk_ctree_toggle_expansion_recursive
-                       (GTK_CTREE(sctree), 
-                        gtk_ctree_node_nth(GTK_CTREE(sctree), row));
+       if (gtk_sctree_is_hot_spot (GTK_SCTREE(sctree), event->x, event->y)) {
+               GtkCTreeNode *node = gtk_ctree_node_nth(GTK_CTREE(sctree), row);
+               if (GTK_CTREE_ROW (node)->expanded)
+                       gtk_ctree_collapse(GTK_CTREE(sctree), node);
+               else if (GTK_SCTREE(sctree)->always_expand_recursively)
+                       gtk_ctree_expand_recursive (GTK_CTREE(sctree), node);
+               else
+                       gtk_ctree_expand(GTK_CTREE(sctree), node);
                return TRUE;
        }
 
@@ -1564,9 +1695,7 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
                                        select_row (sctree, row, col, event->state, NULL);
                                }
                        } else {
-                               sctree->selecting_range = TRUE;
                                gtk_clist_unselect_all (clist);
-                               sctree->selecting_range = FALSE;
                        }
 
                        retval = TRUE;
@@ -1579,9 +1708,7 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
                                                 sctree_signals[ROW_POPUP_MENU],
                                                 0, event);
                        } else {
-                               sctree->selecting_range = TRUE;
                                gtk_clist_unselect_all(clist);
-                               sctree->selecting_range = FALSE;
                                g_signal_emit (G_OBJECT (sctree),
                                                 sctree_signals[EMPTY_POPUP_MENU],
                                                 0, event);
@@ -1682,8 +1809,13 @@ gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
 
        /* This is the same threshold value that is used in gtkdnd.c */
 
+#ifndef GENERIC_UMPC
+#define THRESHOLD 3
+#else
+#define THRESHOLD 8
+#endif
        if (MAX (ABS (sctree->dnd_press_x - event->x),
-                ABS (sctree->dnd_press_y - event->y)) <= 3)
+                ABS (sctree->dnd_press_y - event->y)) <= THRESHOLD)
                return FALSE;
 
        /* Handle any pending selections */
@@ -1780,6 +1912,32 @@ gtk_sctree_clear (GtkCList *clist)
                (* ((GtkCListClass *)parent_class)->clear) (clist);
 }
 
+static void
+gtk_sctree_real_unselect_all (GtkCList *clist)
+{
+       GtkSCTree *sctree;
+       gboolean should_freeze = FALSE;
+
+       g_return_if_fail (clist != NULL);
+       g_return_if_fail (GTK_IS_SCTREE (clist));
+
+       sctree = GTK_SCTREE (clist);
+
+       if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 10)) {
+               should_freeze = TRUE;
+               sctree->selecting_range++;
+               gtk_clist_freeze (GTK_CLIST (sctree));
+       }
+
+       if (((GtkCListClass *)parent_class)->unselect_all)
+               (* ((GtkCListClass *)parent_class)->unselect_all) (clist);
+
+       if (should_freeze) {
+               gtk_clist_thaw (GTK_CLIST (sctree));
+               sctree->selecting_range--;
+       }
+}
+
 /* Our handler for the change_focus_row_expansion signal of the ctree.  
  We have to set the anchor to parent visible node.
  */
@@ -1816,10 +1974,33 @@ GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column,
        }
 
        GTK_SCTREE(widget)->show_stripes = TRUE;
+       GTK_SCTREE(widget)->always_expand_recursively = TRUE;
+       GTK_SCTREE(widget)->force_additive_sel = FALSE;
+       
+       GTK_SCTREE(widget)->use_markup = g_new0(gboolean, columns);
 
        return widget;
 }
 
+void gtk_sctree_set_use_markup             (GtkSCTree          *sctree,
+                                            int                 column,
+                                            gboolean            markup)
+{
+       gint columns = 0;
+       GValue value = { 0 };
+       
+       g_return_if_fail(GTK_IS_SCTREE(sctree));
+
+       g_value_init (&value, G_TYPE_INT);      
+       g_object_get_property (G_OBJECT (sctree), "n-columns", &value);
+       columns = g_value_get_int (&value);
+       g_value_unset (&value);
+
+       g_return_if_fail(column < columns);
+
+       sctree->use_markup[column] = markup;
+}
+
 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
 {
        select_row(sctree, 
@@ -1836,16 +2017,7 @@ void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int st
 
 void gtk_sctree_unselect_all (GtkSCTree *sctree)
 {
-       gboolean froze = FALSE;
-       sctree->selecting_range = TRUE;
-       if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 1)) {
-               gtk_clist_freeze(GTK_CLIST(sctree));
-               froze = TRUE;
-       }
        gtk_clist_unselect_all(GTK_CLIST(sctree));
-       if (froze)
-               gtk_clist_thaw(GTK_CLIST(sctree));
-       sctree->selecting_range = FALSE;
        sctree->anchor_row = NULL;
 }
 
@@ -1866,6 +2038,11 @@ void gtk_sctree_set_stripes(GtkSCTree  *sctree, gboolean show_stripes)
        sctree->show_stripes = show_stripes;
 }
 
+void gtk_sctree_set_recursive_expand(GtkSCTree  *sctree, gboolean rec_exp)
+{
+       sctree->always_expand_recursively = rec_exp;
+}
+
 /***********************************************************
  *             Tree sorting functions                      *
  ***********************************************************/
@@ -2796,6 +2973,9 @@ gtk_sctree_real_tree_expand (GtkCTree     *ctree,
        {
          GList *tmp_list;
 
+         if (clist->row_list_end == list)
+             clist->row_list_end = g_list_last(list);
+
          tmp_list = (GList *)GTK_CTREE_NODE_NEXT (node);
          tmp_list->prev = list;
        }
@@ -3076,3 +3256,16 @@ sreal_tree_move (GtkCTree     *ctree,
   gtk_clist_thaw (clist);
 }
 
+void gtk_sctree_set_column_tooltip         (GtkSCTree          *sctree,
+                                            int                 column,
+                                            const gchar        *tip)
+{
+       if (!sctree->tips)
+               sctree->tips = gtk_tooltips_new();
+               
+       gtk_tooltips_set_tip(GTK_TOOLTIPS(sctree->tips), 
+               GTK_CLIST(sctree)->column[column].button,
+                       tip, NULL);
+
+}
+