]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktreeview.c
Make parameter naming consistent.
[~andy/gtk] / gtk / gtktreeview.c
index 3949bc481d90fa3a2b8e69b10ea7f5b95ee5452e..74f4b027574fd3a62d635bcd11644cc61824424f 100644 (file)
@@ -29,6 +29,7 @@
 #include "gtkcellrenderer.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
+#include "gtkbuildable.h"
 #include "gtkbutton.h"
 #include "gtkalignment.h"
 #include "gtklabel.h"
 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
 
+/* Translate from bin_window coordinates to rbtree (tree coordinates) and
+ * vice versa.
+ */
 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
 
-/* This is in Window coordinates */
+/* This is in bin_window coordinates */
 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
 
@@ -133,12 +137,14 @@ enum {
   PROP_SEARCH_COLUMN,
   PROP_FIXED_HEIGHT_MODE,
   PROP_HOVER_SELECTION,
-  PROP_HOVER_EXPAND
+  PROP_HOVER_EXPAND,
+  PROP_SHOW_EXPANDERS,
+  PROP_LEVEL_INDENTATION,
+  PROP_RUBBER_BANDING,
+  PROP_ENABLE_GRID_LINES,
+  PROP_ENABLE_TREE_LINES
 };
 
-static void     gtk_tree_view_class_init           (GtkTreeViewClass *klass);
-static void     gtk_tree_view_init                 (GtkTreeView      *tree_view);
-
 /* object signals */
 static void     gtk_tree_view_finalize             (GObject          *object);
 static void     gtk_tree_view_set_property         (GObject         *object,
@@ -293,6 +299,9 @@ static gboolean validate_rows            (GtkTreeView *tree_view);
 static gboolean presize_handler_callback (gpointer     data);
 static void     install_presize_handler  (GtkTreeView *tree_view);
 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
+static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
+                                            GtkTreePath *path,
+                                            gint         offset);
 static void    gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
@@ -347,7 +356,8 @@ static void     gtk_tree_view_clamp_node_visible             (GtkTreeView
                                                              GtkRBTree         *tree,
                                                              GtkRBNode         *node);
 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView       *tree_view,
-                                                             GtkTreeViewColumn *column);
+                                                             GtkTreeViewColumn *column,
+                                                             gboolean           focus_to_cell);
 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView       *tree_view,
                                                              GdkEventMotion    *event);
 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView       *tree_view);
@@ -380,6 +390,7 @@ static void     column_sizing_notify                         (GObject
                                                               gpointer           data);
 static gboolean expand_collapse_timeout                      (gpointer           data);
 static gboolean do_expand_collapse                           (GtkTreeView       *tree_view);
+static void     gtk_tree_view_stop_rubber_band                (GtkTreeView       *tree_view);
 
 /* interactive search */
 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
@@ -410,7 +421,7 @@ static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry
 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
                                                         GdkEventKey      *event,
                                                         GtkTreeView      *tree_view);
-static void     gtk_tree_view_search_move               (GtkWidget        *window,
+static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
                                                         GtkTreeView      *tree_view,
                                                         gboolean          up);
 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
@@ -450,14 +461,18 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree
                                                         GtkTreeViewColumn *column,
                                                         gint               drop_position);
 
-static void gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
-                                                     gint         wx,
-                                                     gint         wy,
-                                                     gint        *tx,
-                                                     gint        *ty);
+/* GtkBuildable */
+static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
+                                              GtkBuilder  *builder,
+                                              GObject     *child,
+                                              const gchar *type);
+static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
+
 
+static gboolean scroll_row_timeout                   (gpointer     data);
+static void     add_scroll_timeout                   (GtkTreeView *tree_view);
+static void     remove_scroll_timeout                (GtkTreeView *tree_view);
 
-static GtkContainerClass *parent_class = NULL;
 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
 
 \f
@@ -465,33 +480,9 @@ static guint tree_view_signals [LAST_SIGNAL] = { 0 };
 /* GType Methods
  */
 
-GType
-gtk_tree_view_get_type (void)
-{
-  static GType tree_view_type = 0;
-
-  if (!tree_view_type)
-    {
-      static const GTypeInfo tree_view_info =
-      {
-        sizeof (GtkTreeViewClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-        (GClassInitFunc) gtk_tree_view_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-        sizeof (GtkTreeView),
-       0,              /* n_preallocs */
-        (GInstanceInitFunc) gtk_tree_view_init
-      };
-
-      tree_view_type =
-       g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkTreeView"),
-                               &tree_view_info, 0);
-    }
-
-  return tree_view_type;
-}
+G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+                                               gtk_tree_view_buildable_init))
 
 static void
 gtk_tree_view_class_init (GtkTreeViewClass *class)
@@ -502,7 +493,6 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
   GtkContainerClass *container_class;
   GtkBindingSet *binding_set;
 
-  parent_class = g_type_class_peek_parent (class);
   binding_set = gtk_binding_set_by_class (class);
 
   o_class = (GObjectClass *) class;
@@ -708,6 +698,63 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                            FALSE,
                                                            GTK_PARAM_READWRITE));
 
+    /**
+     * GtkTreeView:show-expanders:
+     *
+     * %TRUE if the view has expanders.
+     *
+     * Since: 2.12
+     */
+    g_object_class_install_property (o_class,
+                                    PROP_SHOW_EXPANDERS,
+                                    g_param_spec_boolean ("show-expanders",
+                                                          P_("Show Expanders"),
+                                                          P_("View has expanders"),
+                                                          TRUE,
+                                                          GTK_PARAM_READWRITE));
+
+    /**
+     * GtkTreeView:level-indentation:
+     *
+     * Extra indentation for each level.
+     *
+     * Since: 2.12
+     */
+    g_object_class_install_property (o_class,
+                                    PROP_LEVEL_INDENTATION,
+                                    g_param_spec_int ("level-indentation",
+                                                      P_("Level Indentation"),
+                                                      P_("Extra indentation for each level"),
+                                                      0,
+                                                      G_MAXINT,
+                                                      0,
+                                                      GTK_PARAM_READWRITE));
+
+    g_object_class_install_property (o_class,
+                                     PROP_RUBBER_BANDING,
+                                     g_param_spec_boolean ("rubber-banding",
+                                                           P_("Rubber Banding"),
+                                                           P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
+                                                           FALSE,
+                                                           GTK_PARAM_READWRITE));
+
+    g_object_class_install_property (o_class,
+                                     PROP_ENABLE_GRID_LINES,
+                                     g_param_spec_enum ("enable-grid-lines",
+                                                       P_("Enable Grid Lines"),
+                                                       P_("Whether grid lines should be drawn in the tree view"),
+                                                       GTK_TYPE_TREE_VIEW_GRID_LINES,
+                                                       GTK_TREE_VIEW_GRID_LINES_NONE,
+                                                       GTK_PARAM_READWRITE));
+
+    g_object_class_install_property (o_class,
+                                     PROP_ENABLE_TREE_LINES,
+                                     g_param_spec_boolean ("enable-tree-lines",
+                                                           P_("Enable Tree Lines"),
+                                                           P_("Whether tree lines should be drawn in the tree view"),
+                                                           FALSE,
+                                                           GTK_PARAM_READWRITE));
+
   /* Style properties */
 #define _TREE_VIEW_EXPANDER_SIZE 12
 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
@@ -768,6 +815,41 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                               GDK_TYPE_COLOR,
                                                               GTK_PARAM_READABLE));
 
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("row-ending-details",
+                                                                P_("Row Ending details"),
+                                                                P_("Enable extended row background theming"),
+                                                                FALSE,
+                                                                GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("grid-line-width",
+                                                            P_("Grid line width"),
+                                                            P_("Width, in pixels, of the tree view grid lines"),
+                                                            0, G_MAXINT, 1,
+                                                            GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("tree-line-width",
+                                                            P_("Tree line width"),
+                                                            P_("Width, in pixels, of the tree view lines"),
+                                                            0, G_MAXINT, 1,
+                                                            GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_string ("grid-line-pattern",
+                                                               P_("Grid line pattern"),
+                                                               P_("Dash pattern used to draw the tree view grid lines"),
+                                                               "\1\1",
+                                                               GTK_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_string ("tree-line-pattern",
+                                                               P_("Tree line pattern"),
+                                                               P_("Dash pattern used to draw the tree view lines"),
+                                                               "\1\1",
+                                                               GTK_PARAM_READABLE));
+
   /* Signals */
   widget_class->set_scroll_adjustments_signal =
     g_signal_new (I_("set_scroll_adjustments"),
@@ -806,8 +888,19 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_PATH,
                  GTK_TYPE_TREE_VIEW_COLUMN);
 
+  /**
+   * GtkTreeView::test-expand-row:
+   * @tree_view: the object on which the signal is emitted
+   * @iter: the tree iter of the row to expand
+   * @path: a tree path that points to the row 
+   * 
+   * The given row is about to be expanded (show its children nodes). Use this
+   * signal if you need to control the expandability of individual rows.
+   *
+   * Returns: %TRUE to allow expansion, %FALSE to reject
+   */
   tree_view_signals[TEST_EXPAND_ROW] =
-    g_signal_new (I_("test_expand_row"),
+    g_signal_new (I_("test-expand-row"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
@@ -817,8 +910,19 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_ITER,
                  GTK_TYPE_TREE_PATH);
 
+  /**
+   * GtkTreeView::test-collapse-row:
+   * @tree_view: the object on which the signal is emitted
+   * @iter: the tree iter of the row to collapse
+   * @path: a tree path that points to the row 
+   * 
+   * The given row is about to be collapsed (hide its children nodes). Use this
+   * signal if you need to control the collapsibility of individual rows.
+   *
+   * Returns: %TRUE to allow expansion, %FALSE to reject
+   */
   tree_view_signals[TEST_COLLAPSE_ROW] =
-    g_signal_new (I_("test_collapse_row"),
+    g_signal_new (I_("test-collapse-row"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
@@ -828,8 +932,16 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_ITER,
                  GTK_TYPE_TREE_PATH);
 
+  /**
+   * GtkTreeView::row-expanded:
+   * @tree_view: the object on which the signal is emitted
+   * @iter: the tree iter of the expanded row
+   * @path: a tree path that points to the row 
+   * 
+   * The given row has been expanded (child nodes are shown).
+   */
   tree_view_signals[ROW_EXPANDED] =
-    g_signal_new (I_("row_expanded"),
+    g_signal_new (I_("row-expanded"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
@@ -839,8 +951,16 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_ITER,
                  GTK_TYPE_TREE_PATH);
 
+  /**
+   * GtkTreeView::row-collapsed:
+   * @tree_view: the object on which the signal is emitted
+   * @iter: the tree iter of the collapsed row
+   * @path: a tree path that points to the row 
+   * 
+   * The given row has been collapsed (child nodes are hidden).
+   */
   tree_view_signals[ROW_COLLAPSED] =
-    g_signal_new (I_("row_collapsed"),
+    g_signal_new (I_("row-collapsed"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
@@ -850,8 +970,14 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_ITER,
                  GTK_TYPE_TREE_PATH);
 
+  /**
+   * GtkTreeView::columns-changed:
+   * @tree_view: the object on which the signal is emitted 
+   * 
+   * The number of columns of the treeview has changed.
+   */
   tree_view_signals[COLUMNS_CHANGED] =
-    g_signal_new (I_("columns_changed"),
+    g_signal_new (I_("columns-changed"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
@@ -859,8 +985,14 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  _gtk_marshal_NONE__NONE,
                  G_TYPE_NONE, 0);
 
+  /**
+   * GtkTreeView::cursor-changed:
+   * @tree_view: the object on which the signal is emitted
+   * 
+   * The position of the cursor (focused cell) has changed.
+   */
   tree_view_signals[CURSOR_CHANGED] =
-    g_signal_new (I_("cursor_changed"),
+    g_signal_new (I_("cursor-changed"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
@@ -984,22 +1116,6 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                  GTK_MOVEMENT_PAGES, 1);
 
 
-  gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, 1);
-
-  gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, -1);
-
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move_cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, 1);
-
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move_cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, -1);
-
   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
                                 "move_cursor", 2,
                                G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
@@ -1046,6 +1162,17 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, FALSE);
 
+  gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "expand_collapse_cursor_row", 3,
+                               G_TYPE_BOOLEAN, TRUE,
+                               G_TYPE_BOOLEAN, TRUE,
+                               G_TYPE_BOOLEAN, FALSE);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "expand_collapse_cursor_row", 3,
+                               G_TYPE_BOOLEAN, TRUE,
+                               G_TYPE_BOOLEAN, TRUE,
+                               G_TYPE_BOOLEAN, FALSE);
+
+
   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
                                 "expand_collapse_cursor_row", 3,
                                 G_TYPE_BOOLEAN, TRUE,
@@ -1112,6 +1239,10 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, FALSE);
+  gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "expand_collapse_cursor_row", 3,
+                               G_TYPE_BOOLEAN, TRUE,
+                               G_TYPE_BOOLEAN, FALSE,
+                               G_TYPE_BOOLEAN, FALSE);
   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, FALSE,
@@ -1120,6 +1251,10 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, FALSE);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "expand_collapse_cursor_row", 3,
+                               G_TYPE_BOOLEAN, TRUE,
+                               G_TYPE_BOOLEAN, FALSE,
+                               G_TYPE_BOOLEAN, FALSE);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, FALSE,
@@ -1157,6 +1292,12 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
 }
 
+static void
+gtk_tree_view_buildable_init (GtkBuildableIface *iface)
+{
+  iface->add_child = gtk_tree_view_buildable_add_child;
+}
+
 static void
 gtk_tree_view_init (GtkTreeView *tree_view)
 {
@@ -1172,6 +1313,7 @@ gtk_tree_view_init (GtkTreeView *tree_view)
 
   /* We need some padding */
   tree_view->priv->dy = 0;
+  tree_view->priv->cursor_offset = 0;
   tree_view->priv->n_columns = 0;
   tree_view->priv->header_height = 1;
   tree_view->priv->x_drag = 0;
@@ -1199,6 +1341,13 @@ gtk_tree_view_init (GtkTreeView *tree_view)
           
   tree_view->priv->hover_selection = FALSE;
   tree_view->priv->hover_expand = FALSE;
+
+  tree_view->priv->level_indentation = 0;
+
+  tree_view->priv->rubber_banding_enable = FALSE;
+
+  tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
+  tree_view->priv->tree_lines_enabled = FALSE;
 }
 
 \f
@@ -1257,6 +1406,21 @@ gtk_tree_view_set_property (GObject         *object,
     case PROP_HOVER_EXPAND:
       tree_view->priv->hover_expand = g_value_get_boolean (value);
       break;
+    case PROP_SHOW_EXPANDERS:
+      gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
+      break;
+    case PROP_LEVEL_INDENTATION:
+      tree_view->priv->level_indentation = g_value_get_int (value);
+      break;
+    case PROP_RUBBER_BANDING:
+      tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
+      break;
+    case PROP_ENABLE_GRID_LINES:
+      gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
+      break;
+    case PROP_ENABLE_TREE_LINES:
+      gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
+      break;
     default:
       break;
     }
@@ -1313,6 +1477,21 @@ gtk_tree_view_get_property (GObject    *object,
     case PROP_HOVER_EXPAND:
       g_value_set_boolean (value, tree_view->priv->hover_expand);
       break;
+    case PROP_SHOW_EXPANDERS:
+      g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
+      break;
+    case PROP_LEVEL_INDENTATION:
+      g_value_set_int (value, tree_view->priv->level_indentation);
+      break;
+    case PROP_RUBBER_BANDING:
+      g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
+      break;
+    case PROP_ENABLE_GRID_LINES:
+      g_value_set_enum (value, tree_view->priv->grid_lines);
+      break;
+    case PROP_ENABLE_TREE_LINES:
+      g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1322,11 +1501,20 @@ gtk_tree_view_get_property (GObject    *object,
 static void
 gtk_tree_view_finalize (GObject *object)
 {
-  (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+  (* G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize) (object);
 }
 
 \f
 
+static void
+gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
+                                  GtkBuilder  *builder,
+                                  GObject     *child,
+                                  const gchar *type)
+{
+  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
+}
+
 /* GtkObject Methods
  */
 
@@ -1473,8 +1661,8 @@ gtk_tree_view_destroy (GtkObject *object)
       tree_view->priv->vadjustment = NULL;
     }
 
-  if (GTK_OBJECT_CLASS (parent_class)->destroy)
-    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+  if (GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy) (object);
 }
 
 \f
@@ -1583,7 +1771,7 @@ gtk_tree_view_realize (GtkWidget *widget)
   /* Make the window for the tree */
   attributes.x = 0;
   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
-  attributes.width = tree_view->priv->width;
+  attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
   attributes.height = widget->allocation.height;
   attributes.event_mask = GDK_EXPOSURE_MASK |
     GDK_SCROLL_MASK |
@@ -1617,7 +1805,7 @@ gtk_tree_view_realize (GtkWidget *widget)
 
   /* Add them all up. */
   widget->style = gtk_style_attach (widget->style, widget->window);
-  gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+  gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
 
@@ -1633,6 +1821,10 @@ gtk_tree_view_realize (GtkWidget *widget)
   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
 
+  /* Need to call those here, since they create GCs */
+  gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
+  gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
+
   install_presize_handler (tree_view); 
 }
 
@@ -1640,82 +1832,102 @@ static void
 gtk_tree_view_unrealize (GtkWidget *widget)
 {
   GtkTreeView *tree_view;
+  GtkTreeViewPrivate *priv;
   GList *list;
 
   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
 
   tree_view = GTK_TREE_VIEW (widget);
+  priv = tree_view->priv;
 
-  if (tree_view->priv->scroll_timeout != 0)
+  if (priv->scroll_timeout != 0)
     {
-      g_source_remove (tree_view->priv->scroll_timeout);
-      tree_view->priv->scroll_timeout = 0;
+      g_source_remove (priv->scroll_timeout);
+      priv->scroll_timeout = 0;
     }
 
-  if (tree_view->priv->open_dest_timeout != 0)
+  if (priv->auto_expand_timeout != 0)
     {
-      g_source_remove (tree_view->priv->open_dest_timeout);
-      tree_view->priv->open_dest_timeout = 0;
+      g_source_remove (priv->auto_expand_timeout);
+      priv->auto_expand_timeout = 0;
     }
 
-  if (tree_view->priv->expand_collapse_timeout != 0)
+  if (priv->open_dest_timeout != 0)
     {
-      g_source_remove (tree_view->priv->expand_collapse_timeout);
-      tree_view->priv->expand_collapse_timeout = 0;
+      g_source_remove (priv->open_dest_timeout);
+      priv->open_dest_timeout = 0;
+    }
+
+  if (priv->expand_collapse_timeout != 0)
+    {
+      g_source_remove (priv->expand_collapse_timeout);
+      priv->expand_collapse_timeout = 0;
     }
   
-  if (tree_view->priv->presize_handler_timer != 0)
+  if (priv->presize_handler_timer != 0)
     {
-      g_source_remove (tree_view->priv->presize_handler_timer);
-      tree_view->priv->presize_handler_timer = 0;
+      g_source_remove (priv->presize_handler_timer);
+      priv->presize_handler_timer = 0;
     }
 
-  if (tree_view->priv->validate_rows_timer != 0)
+  if (priv->validate_rows_timer != 0)
     {
-      g_source_remove (tree_view->priv->validate_rows_timer);
-      tree_view->priv->validate_rows_timer = 0;
+      g_source_remove (priv->validate_rows_timer);
+      priv->validate_rows_timer = 0;
     }
 
-  if (tree_view->priv->scroll_sync_timer != 0)
+  if (priv->scroll_sync_timer != 0)
     {
-      g_source_remove (tree_view->priv->scroll_sync_timer);
-      tree_view->priv->scroll_sync_timer = 0;
+      g_source_remove (priv->scroll_sync_timer);
+      priv->scroll_sync_timer = 0;
     }
 
-  if (tree_view->priv->typeselect_flush_timeout)
+  if (priv->typeselect_flush_timeout)
     {
-      g_source_remove (tree_view->priv->typeselect_flush_timeout);
-      tree_view->priv->typeselect_flush_timeout = 0;
+      g_source_remove (priv->typeselect_flush_timeout);
+      priv->typeselect_flush_timeout = 0;
     }
   
-  for (list = tree_view->priv->columns; list; list = list->next)
+  for (list = priv->columns; list; list = list->next)
     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
 
-  gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
-  gdk_window_destroy (tree_view->priv->bin_window);
-  tree_view->priv->bin_window = NULL;
+  gdk_window_set_user_data (priv->bin_window, NULL);
+  gdk_window_destroy (priv->bin_window);
+  priv->bin_window = NULL;
 
-  gdk_window_set_user_data (tree_view->priv->header_window, NULL);
-  gdk_window_destroy (tree_view->priv->header_window);
-  tree_view->priv->header_window = NULL;
+  gdk_window_set_user_data (priv->header_window, NULL);
+  gdk_window_destroy (priv->header_window);
+  priv->header_window = NULL;
 
-  if (tree_view->priv->drag_window)
+  if (priv->drag_window)
     {
-      gdk_window_set_user_data (tree_view->priv->drag_window, NULL);
-      gdk_window_destroy (tree_view->priv->drag_window);
-      tree_view->priv->drag_window = NULL;
+      gdk_window_set_user_data (priv->drag_window, NULL);
+      gdk_window_destroy (priv->drag_window);
+      priv->drag_window = NULL;
     }
 
-  if (tree_view->priv->drag_highlight_window)
+  if (priv->drag_highlight_window)
+    {
+      gdk_window_set_user_data (priv->drag_highlight_window, NULL);
+      gdk_window_destroy (priv->drag_highlight_window);
+      priv->drag_highlight_window = NULL;
+    }
+
+  if (priv->tree_line_gc)
     {
-      gdk_window_set_user_data (tree_view->priv->drag_highlight_window, NULL);
-      gdk_window_destroy (tree_view->priv->drag_highlight_window);
-      tree_view->priv->drag_highlight_window = NULL;
+      g_object_unref (priv->tree_line_gc);
+      priv->tree_line_gc = NULL;
+    }
+
+  if (priv->grid_line_gc)
+    {
+      g_object_unref (priv->grid_line_gc);
+      priv->grid_line_gc = NULL;
     }
 
   /* GtkWidget::unrealize destroys children and widget->window */
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+  if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize) (widget);
 }
 
 /* GtkWidget::size_request helper */
@@ -2247,6 +2459,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
       gint column_handled_click = FALSE;
       gboolean row_double_click = FALSE;
       gboolean rtl;
+      gboolean node_selected;
 
       /* Empty tree? */
       if (tree_view->priv->tree == NULL)
@@ -2257,7 +2470,8 @@ gtk_tree_view_button_press (GtkWidget      *widget,
 
       /* are we in an arrow? */
       if (tree_view->priv->prelight_node &&
-          GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
+          GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
+         TREE_VIEW_DRAW_EXPANDERS (tree_view))
        {
          if (event->button == 1)
            {
@@ -2321,11 +2535,18 @@ gtk_tree_view_button_press (GtkWidget      *widget,
          cell_area.height -= vertical_separator;
          cell_area.x += horizontal_separator/2;
          cell_area.y += vertical_separator/2;
-         if (gtk_tree_view_is_expander_column (tree_view, column) &&
-              TREE_VIEW_DRAW_EXPANDERS(tree_view))
+         if (gtk_tree_view_is_expander_column (tree_view, column))
            {
-             cell_area.x += depth * tree_view->priv->expander_size;
-             cell_area.width -= depth * tree_view->priv->expander_size;
+             if (!rtl)
+               cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
+             cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
+
+              if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+               {
+                 if (!rtl)
+                   cell_area.x += depth * tree_view->priv->expander_size;
+                 cell_area.width -= depth * tree_view->priv->expander_size;
+               }
            }
          break;
        }
@@ -2407,6 +2628,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
        }
 
       /* select */
+      node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
       pre_val = tree_view->priv->vadjustment->value;
 
       /* we only handle selection modifications on the first button press
@@ -2454,11 +2676,27 @@ gtk_tree_view_button_press (GtkWidget      *widget,
       /* Save press to possibly begin a drag
        */
       if (!column_handled_click &&
+         !tree_view->priv->in_grab &&
          tree_view->priv->pressed_button < 0)
         {
           tree_view->priv->pressed_button = event->button;
           tree_view->priv->press_start_x = event->x;
           tree_view->priv->press_start_y = event->y;
+
+         if (tree_view->priv->rubber_banding_enable
+             && !node_selected
+             && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+           {
+             tree_view->priv->press_start_y += tree_view->priv->dy;
+             tree_view->priv->rubber_band_x = event->x;
+             tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
+             tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
+
+             if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+               tree_view->priv->rubber_band_ctrl = TRUE;
+             if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+               tree_view->priv->rubber_band_shift = TRUE;
+           }
         }
 
       /* Test if a double click happened on the same row. */
@@ -2674,6 +2912,9 @@ gtk_tree_view_button_release (GtkWidget      *widget,
   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
     return gtk_tree_view_button_release_drag_column (widget, event);
 
+  if (tree_view->priv->rubber_band_status)
+    gtk_tree_view_stop_rubber_band (tree_view);
+
   if (tree_view->priv->pressed_button == event->button)
     tree_view->priv->pressed_button = -1;
 
@@ -2755,7 +2996,7 @@ static gboolean
 coords_are_over_arrow (GtkTreeView *tree_view,
                        GtkRBTree   *tree,
                        GtkRBNode   *node,
-                       /* these are in window coords */
+                       /* these are in bin window coords */
                        gint         x,
                        gint         y)
 {
@@ -2788,8 +3029,6 @@ auto_expand_timeout (gpointer data)
   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
   GtkTreePath *path;
 
-  GDK_THREADS_ENTER ();
-
   if (tree_view->priv->prelight_node)
     {
       path = _gtk_tree_view_find_path (tree_view,
@@ -2806,8 +3045,6 @@ auto_expand_timeout (gpointer data)
 
   tree_view->priv->auto_expand_timeout = 0;
 
-  GDK_THREADS_LEAVE ();
-
   return FALSE;
 }
 
@@ -2825,7 +3062,7 @@ static void
 do_prelight (GtkTreeView *tree_view,
              GtkRBTree   *tree,
              GtkRBNode   *node,
-            /* these are in tree_window coords */
+            /* these are in bin_window coords */
              gint         x,
              gint         y)
 {
@@ -2835,7 +3072,7 @@ do_prelight (GtkTreeView *tree_view,
       /*  We are still on the same node,
          but we might need to take care of the arrow  */
 
-      if (tree && node)
+      if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
        {
          gboolean over_arrow;
          gboolean flag_set;
@@ -2867,7 +3104,8 @@ do_prelight (GtkTreeView *tree_view,
       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
                             GTK_RBNODE_IS_PRELIT);
 
-      if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
+      if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
+         && TREE_VIEW_DRAW_EXPANDERS (tree_view))
        {
          GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
          
@@ -2897,7 +3135,8 @@ do_prelight (GtkTreeView *tree_view,
 
   /*  Prelight the new node and arrow  */
 
-  if (coords_are_over_arrow (tree_view, tree, node, x, y))
+  if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
+      && coords_are_over_arrow (tree_view, tree, node, x, y))
     {
       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
 
@@ -2911,7 +3150,7 @@ do_prelight (GtkTreeView *tree_view,
   if (tree_view->priv->hover_expand)
     {
       tree_view->priv->auto_expand_timeout = 
-       g_timeout_add (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
+       gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
     }
 }
 
@@ -2919,7 +3158,7 @@ static void
 prelight_or_select (GtkTreeView *tree_view,
                    GtkRBTree   *tree,
                    GtkRBNode   *node,
-                   /* these are in tree_window coords */
+                   /* these are in bin_window coords */
                    gint         x,
                    gint         y)
 {
@@ -3370,73 +3609,417 @@ gtk_tree_view_motion_drag_column (GtkWidget      *widget,
   return TRUE;
 }
 
-static gboolean
-gtk_tree_view_motion_bin_window (GtkWidget      *widget,
-                                GdkEventMotion *event)
+static void
+gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
 {
-  GtkTreeView *tree_view;
-  GtkRBTree *tree;
-  GtkRBNode *node;
-  gint new_y;
+  remove_scroll_timeout (tree_view);
+  gtk_grab_remove (GTK_WIDGET (tree_view));
 
-  tree_view = (GtkTreeView *) widget;
+  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
 
-  if (tree_view->priv->tree == NULL)
-    return FALSE;
+  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+    {
+      GtkTreePath *tmp_path;
 
-  /* only check for an initiated drag when a button is pressed */
-  if (tree_view->priv->pressed_button >= 0)
-    gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
+      /* The anchor path should be set to the start path */
+      tmp_path = _gtk_tree_view_find_path (tree_view,
+                                          tree_view->priv->rubber_band_start_tree,
+                                          tree_view->priv->rubber_band_start_node);
 
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
-  if (new_y < 0)
-    new_y = 0;
+      if (tree_view->priv->anchor)
+       gtk_tree_row_reference_free (tree_view->priv->anchor);
 
-  _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
+      tree_view->priv->anchor =
+       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+                                         tree_view->priv->model,
+                                         tmp_path);
 
-  /* If we are currently pressing down a button, we don't want to prelight anything else. */
-  if ((tree_view->priv->button_pressed_node != NULL) &&
-      (tree_view->priv->button_pressed_node != node))
-    node = NULL;
+      gtk_tree_path_free (tmp_path);
 
-  prelight_or_select (tree_view, tree, node, event->x, event->y);
+      /* ... and the cursor to the end path */
+      tmp_path = _gtk_tree_view_find_path (tree_view,
+                                          tree_view->priv->rubber_band_end_tree,
+                                          tree_view->priv->rubber_band_end_node);
+      gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
+      gtk_tree_path_free (tmp_path);
 
-  return TRUE;
+      _gtk_tree_selection_emit_changed (tree_view->priv->selection);
+    }
+
+  /* Clear status variables */
+  tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
+  tree_view->priv->rubber_band_shift = 0;
+  tree_view->priv->rubber_band_ctrl = 0;
+
+  tree_view->priv->rubber_band_start_node = NULL;
+  tree_view->priv->rubber_band_start_tree = NULL;
+  tree_view->priv->rubber_band_end_node = NULL;
+  tree_view->priv->rubber_band_end_tree = NULL;
 }
 
-static gboolean
-gtk_tree_view_motion (GtkWidget      *widget,
-                     GdkEventMotion *event)
-{
-  GtkTreeView *tree_view;
+static void
+gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
+                                                GtkRBTree   *start_tree,
+                                                GtkRBNode   *start_node,
+                                                GtkRBTree   *end_tree,
+                                                GtkRBNode   *end_node,
+                                                gboolean     select,
+                                                gboolean     skip_start,
+                                                gboolean     skip_end)
+{
+  if (start_node == end_node)
+    return;
 
-  tree_view = (GtkTreeView *) widget;
+  /* We skip the first node and jump inside the loop */
+  if (skip_start)
+    goto skip_first;
 
-  /* Resizing a column */
-  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
-    return gtk_tree_view_motion_resize_column (widget, event);
+  do
+    {
+      if (select)
+        {
+         if (tree_view->priv->rubber_band_shift)
+           GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+         else if (tree_view->priv->rubber_band_ctrl)
+           {
+             /* Toggle the selection state */
+             if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+               GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+             else
+               GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+           }
+         else
+           GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+       }
+      else
+        {
+         /* Mirror the above */
+         if (tree_view->priv->rubber_band_shift)
+           GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+         else if (tree_view->priv->rubber_band_ctrl)
+           {
+             /* Toggle the selection state */
+             if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+               GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+             else
+               GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+           }
+         else
+           GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+       }
 
-  /* Drag column */
-  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
-    return gtk_tree_view_motion_drag_column (widget, event);
+      _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
 
-  /* Sanity check it */
-  if (event->window == tree_view->priv->bin_window)
-    return gtk_tree_view_motion_bin_window (widget, event);
+      if (start_node == end_node)
+       break;
 
-  return FALSE;
+skip_first:
+
+      if (start_node->children)
+        {
+         start_tree = start_node->children;
+         start_node = start_tree->root;
+         while (start_node->left != start_tree->nil)
+           start_node = start_node->left;
+       }
+      else
+        {
+         _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
+
+         if (!start_tree)
+           /* Ran out of tree */
+           break;
+       }
+
+      if (skip_end && start_node == end_node)
+       break;
+    }
+  while (TRUE);
 }
 
-/* Invalidate the focus rectangle near the edge of the bin_window; used when
- * the tree is empty.
- */
 static void
-invalidate_empty_focus (GtkTreeView *tree_view)
+gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
+{
+  GtkRBTree *start_tree, *end_tree;
+  GtkRBNode *start_node, *end_node;
+
+  _gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node);
+  _gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node);
+
+  /* Handle the start area first */
+  if (!tree_view->priv->rubber_band_start_node)
+    {
+      gtk_tree_view_update_rubber_band_selection_range (tree_view,
+                                                      start_tree,
+                                                      start_node,
+                                                      end_tree,
+                                                      end_node,
+                                                      TRUE,
+                                                      FALSE,
+                                                      FALSE);
+    }
+  else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
+           _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
+    {
+      /* New node is above the old one; selection became bigger */
+      gtk_tree_view_update_rubber_band_selection_range (tree_view,
+                                                      start_tree,
+                                                      start_node,
+                                                      tree_view->priv->rubber_band_start_tree,
+                                                      tree_view->priv->rubber_band_start_node,
+                                                      TRUE,
+                                                      FALSE,
+                                                      TRUE);
+    }
+  else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
+           _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
+    {
+      /* New node is below the old one; selection became smaller */
+      gtk_tree_view_update_rubber_band_selection_range (tree_view,
+                                                      tree_view->priv->rubber_band_start_tree,
+                                                      tree_view->priv->rubber_band_start_node,
+                                                      start_tree,
+                                                      start_node,
+                                                      FALSE,
+                                                      FALSE,
+                                                      TRUE);
+    }
+
+  tree_view->priv->rubber_band_start_tree = start_tree;
+  tree_view->priv->rubber_band_start_node = start_node;
+
+  /* Next, handle the end area */
+  if (!tree_view->priv->rubber_band_end_node)
+    {
+      /* In the event this happens, start_node was also NULL; this case is
+       * handled above.
+       */
+    }
+  else if (!end_node)
+    {
+      /* Find the last node in the tree */
+      _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
+                              &end_tree, &end_node);
+
+      /* Selection reached end of the tree */
+      gtk_tree_view_update_rubber_band_selection_range (tree_view,
+                                                      tree_view->priv->rubber_band_end_tree,
+                                                      tree_view->priv->rubber_band_end_node,
+                                                      end_tree,
+                                                      end_node,
+                                                      TRUE,
+                                                      TRUE,
+                                                      FALSE);
+    }
+  else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
+           _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
+    {
+      /* New node is below the old one; selection became bigger */
+      gtk_tree_view_update_rubber_band_selection_range (tree_view,
+                                                      tree_view->priv->rubber_band_end_tree,
+                                                      tree_view->priv->rubber_band_end_node,
+                                                      end_tree,
+                                                      end_node,
+                                                      TRUE,
+                                                      TRUE,
+                                                      FALSE);
+    }
+  else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
+           _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
+    {
+      /* New node is above the old one; selection became smaller */
+      gtk_tree_view_update_rubber_band_selection_range (tree_view,
+                                                      end_tree,
+                                                      end_node,
+                                                      tree_view->priv->rubber_band_end_tree,
+                                                      tree_view->priv->rubber_band_end_node,
+                                                      FALSE,
+                                                      TRUE,
+                                                      FALSE);
+    }
+
+  tree_view->priv->rubber_band_end_tree = end_tree;
+  tree_view->priv->rubber_band_end_node = end_node;
+}
+
+static void
+gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
 {
-  GdkRectangle area;
+  gint x, y;
+  GdkRectangle old_area;
+  GdkRectangle new_area;
+  GdkRectangle common;
+  GdkRegion *invalid_region;
 
-  if (!GTK_WIDGET_HAS_FOCUS (tree_view))
-    return;
+  old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
+  old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
+  old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
+  old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
+
+  gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
+
+  x = MAX (x, 0);
+  y = MAX (y, 0) + tree_view->priv->dy;
+
+  new_area.x = MIN (tree_view->priv->press_start_x, x);
+  new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
+  new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
+  new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
+
+  invalid_region = gdk_region_rectangle (&old_area);
+  gdk_region_union_with_rect (invalid_region, &new_area);
+
+  gdk_rectangle_intersect (&old_area, &new_area, &common);
+  if (common.width > 2 && common.height > 2)
+    {
+      GdkRegion *common_region;
+
+      /* make sure the border is invalidated */
+      common.x += 1;
+      common.y += 1;
+      common.width -= 2;
+      common.height -= 2;
+
+      common_region = gdk_region_rectangle (&common);
+
+      gdk_region_subtract (invalid_region, common_region);
+      gdk_region_destroy (common_region);
+    }
+
+  gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
+
+  gdk_region_destroy (invalid_region);
+
+  tree_view->priv->rubber_band_x = x;
+  tree_view->priv->rubber_band_y = y;
+
+  gtk_tree_view_update_rubber_band_selection (tree_view);
+}
+
+static void
+gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
+                               GdkRectangle *area)
+{
+  cairo_t *cr;
+  GdkRectangle rect;
+  GdkRectangle rubber_rect;
+
+  rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
+  rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
+  rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
+  rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
+
+  if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
+    return;
+
+  cr = gdk_cairo_create (tree_view->priv->bin_window);
+  cairo_set_line_width (cr, 1.0);
+
+  cairo_set_source_rgba (cr,
+                        GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
+                        GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
+                        GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
+                        .25);
+
+  gdk_cairo_rectangle (cr, &rect);
+  cairo_clip (cr);
+  cairo_paint (cr);
+
+  cairo_set_source_rgb (cr,
+                       GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
+                       GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
+                       GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
+
+  cairo_rectangle (cr,
+                  rubber_rect.x + 0.5, rubber_rect.y + 0.5,
+                  rubber_rect.width - 1, rubber_rect.height - 1);
+  cairo_stroke (cr);
+
+  cairo_destroy (cr);
+}
+
+static gboolean
+gtk_tree_view_motion_bin_window (GtkWidget      *widget,
+                                GdkEventMotion *event)
+{
+  GtkTreeView *tree_view;
+  GtkRBTree *tree;
+  GtkRBNode *node;
+  gint new_y;
+
+  tree_view = (GtkTreeView *) widget;
+
+  if (tree_view->priv->tree == NULL)
+    return FALSE;
+
+  if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
+    {
+      gtk_grab_add (GTK_WIDGET (tree_view));
+      gtk_tree_view_update_rubber_band (tree_view);
+
+      tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
+    }
+  else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+    {
+      gtk_tree_view_update_rubber_band (tree_view);
+
+      add_scroll_timeout (tree_view);
+    }
+
+  /* only check for an initiated drag when a button is pressed */
+  if (tree_view->priv->pressed_button >= 0
+      && !tree_view->priv->rubber_band_status)
+    gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
+
+  new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
+  if (new_y < 0)
+    new_y = 0;
+
+  _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
+
+  /* If we are currently pressing down a button, we don't want to prelight anything else. */
+  if ((tree_view->priv->button_pressed_node != NULL) &&
+      (tree_view->priv->button_pressed_node != node))
+    node = NULL;
+
+  prelight_or_select (tree_view, tree, node, event->x, event->y);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_view_motion (GtkWidget      *widget,
+                     GdkEventMotion *event)
+{
+  GtkTreeView *tree_view;
+
+  tree_view = (GtkTreeView *) widget;
+
+  /* Resizing a column */
+  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
+    return gtk_tree_view_motion_resize_column (widget, event);
+
+  /* Drag column */
+  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
+    return gtk_tree_view_motion_drag_column (widget, event);
+
+  /* Sanity check it */
+  if (event->window == tree_view->priv->bin_window)
+    return gtk_tree_view_motion_bin_window (widget, event);
+
+  return FALSE;
+}
+
+/* Invalidate the focus rectangle near the edge of the bin_window; used when
+ * the tree is empty.
+ */
+static void
+invalidate_empty_focus (GtkTreeView *tree_view)
+{
+  GdkRectangle area;
+
+  if (!GTK_WIDGET_HAS_FOCUS (tree_view))
+    return;
 
   area.x = 0;
   area.y = 0;
@@ -3470,6 +4053,40 @@ draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
                     1, 1, w, h);
 }
 
+static void
+gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
+                              GdkEventExpose *event,
+                              gint            n_visible_columns)
+{
+  GList *list = tree_view->priv->columns;
+  gint i = 0;
+  gint current_x = 0;
+
+  if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
+      && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
+    return;
+
+  /* Only draw the lines for visible rows and columns */
+  for (list = tree_view->priv->columns; list; list = list->next, i++)
+    {
+      GtkTreeViewColumn *column = list->data;
+
+      /* We don't want a line for the last column */
+      if (i == n_visible_columns - 1)
+       break;
+
+      if (! column->visible)
+       continue;
+
+      current_x += column->width;
+
+      gdk_draw_line (event->window,
+                    tree_view->priv->grid_line_gc,
+                    current_x - 1, 0,
+                    current_x - 1, tree_view->priv->height);
+    }
+}
+
 /* Warning: Very scary function.
  * Modify at your own risk
  *
@@ -3503,7 +4120,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   gint bin_window_height;
   GtkTreePath *cursor_path;
   GtkTreePath *drag_dest_path;
-  GList *last_column;
+  GList *first_column, *last_column;
   gint vertical_separator;
   gint horizontal_separator;
   gint focus_line_width;
@@ -3512,7 +4129,10 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   gboolean rtl;
   gint n_visible_columns;
   gint pointer_x, pointer_y;
+  gint grid_line_width;
   gboolean got_pointer = FALSE;
+  gboolean row_ending_details;
+  gboolean draw_vgrid_lines, draw_hgrid_lines;
 
   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
 
@@ -3525,6 +4145,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                        "vertical-separator", &vertical_separator,
                        "allow-rules", &allow_rules,
                        "focus-line-width", &focus_line_width,
+                       "row-ending-details", &row_ending_details,
                        NULL);
 
   if (tree_view->priv->tree == NULL)
@@ -3557,7 +4178,8 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                           widget,
                           "cell_even",
                           0, tree_view->priv->height,
-                          bin_window_width, bin_window_height);
+                          bin_window_width,
+                          bin_window_height - tree_view->priv->height);
     }
 
   if (node == NULL)
@@ -3590,6 +4212,15 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
     _gtk_tree_view_find_node (tree_view, drag_dest_path,
                               &drag_highlight_tree, &drag_highlight);
 
+  draw_vgrid_lines =
+    tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
+    || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
+  draw_hgrid_lines =
+    tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
+    || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
+
+  if (draw_vgrid_lines || draw_hgrid_lines)
+    gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
   
   n_visible_columns = 0;
   for (list = tree_view->priv->columns; list; list = list->next)
@@ -3600,11 +4231,15 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
     }
 
   /* Find the last column */
-  for (last_column = rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns);
-       last_column &&
-        !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
-        GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
-       last_column = rtl ? last_column->next : last_column->prev)
+  for (last_column = g_list_last (tree_view->priv->columns);
+       last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
+       last_column = last_column->prev)
+    ;
+
+  /* and the first */
+  for (first_column = g_list_first (tree_view->priv->columns);
+       first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
+       first_column = first_column->next)
     ;
 
   /* Actually process the expose event.  To do this, we want to
@@ -3616,6 +4251,8 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
     {
       gboolean parity;
       gboolean is_separator = FALSE;
+      gboolean is_first = FALSE;
+      gboolean is_last = FALSE;
       
       if (tree_view->priv->row_separator_func)
        {
@@ -3698,6 +4335,30 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
           cell_area.height -= vertical_separator;
          cell_area.width -= horizontal_separator;
 
+         if (draw_vgrid_lines)
+           {
+             if (list == first_column)
+               {
+                 cell_area.width -= grid_line_width / 2;
+               }
+             else if (list == last_column)
+               {
+                 cell_area.x += grid_line_width / 2;
+                 cell_area.width -= grid_line_width / 2;
+               }
+             else
+               {
+                 cell_area.x += grid_line_width / 2;
+                 cell_area.width -= grid_line_width;
+               }
+           }
+
+         if (draw_hgrid_lines)
+           {
+             cell_area.y += grid_line_width / 2;
+             cell_area.height -= grid_line_width;
+           }
+
          if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
            {
              cell_offset += column->width;
@@ -3761,24 +4422,144 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
            state = GTK_STATE_NORMAL;
 
          /* Draw background */
-          gtk_paint_flat_box (widget->style,
-                              event->window,
-                             state,
-                              GTK_SHADOW_NONE,
-                              &event->area,
-                              widget,
-                              detail,
-                              background_area.x,
-                              background_area.y,
-                              background_area.width,
-                              background_area.height);
+         if (row_ending_details)
+           {
+             char new_detail[128];
+
+             is_first = (rtl ? !list->next : !list->prev);
+             is_last = (rtl ? !list->prev : !list->next);
+
+             /* (I don't like the snprintfs either, but couldn't find a
+              * less messy way).
+              */
+             if (is_first && is_last)
+               g_snprintf (new_detail, 127, "%s", detail);
+             else if (is_first)
+               g_snprintf (new_detail, 127, "%s_start", detail);
+             else if (is_last)
+               g_snprintf (new_detail, 127, "%s_end", detail);
+             else
+               g_snprintf (new_detail, 128, "%s_middle", detail);
+
+             gtk_paint_flat_box (widget->style,
+                                 event->window,
+                                 state,
+                                 GTK_SHADOW_NONE,
+                                 &event->area,
+                                 widget,
+                                 new_detail,
+                                 background_area.x,
+                                 background_area.y,
+                                 background_area.width,
+                                 background_area.height);
+           }
+         else
+           {
+             gtk_paint_flat_box (widget->style,
+                                 event->window,
+                                 state,
+                                 GTK_SHADOW_NONE,
+                                 &event->area,
+                                 widget,
+                                 detail,
+                                 background_area.x,
+                                 background_area.y,
+                                 background_area.width,
+                                 background_area.height);
+           }
+
+         if (draw_hgrid_lines)
+           {
+             if (background_area.y > 0)
+               gdk_draw_line (event->window,
+                              tree_view->priv->grid_line_gc,
+                              background_area.x, background_area.y,
+                              background_area.x + background_area.width,
+                              background_area.y);
+
+             if (y_offset + max_height >= event->area.height)
+               gdk_draw_line (event->window,
+                              tree_view->priv->grid_line_gc,
+                              background_area.x, background_area.y + max_height,
+                              background_area.x + background_area.width,
+                              background_area.y + max_height);
+           }
 
          if (gtk_tree_view_is_expander_column (tree_view, column) &&
-              TREE_VIEW_DRAW_EXPANDERS(tree_view))
+             tree_view->priv->tree_lines_enabled)
+           {
+             if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
+                 && depth > 1)
+               {
+                 gdk_draw_line (event->window,
+                                tree_view->priv->tree_line_gc,
+                                background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                background_area.y + background_area.height / 2,
+                                background_area.x + tree_view->priv->expander_size * (depth - 1.1),
+                                background_area.y + background_area.height / 2);
+               }
+             else if (depth > 1)
+               {
+                 gdk_draw_line (event->window,
+                                tree_view->priv->tree_line_gc,
+                                background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                background_area.y + background_area.height / 2,
+                                background_area.x + tree_view->priv->expander_size * (depth - 0.5),
+                                background_area.y + background_area.height / 2);
+               }
+
+             if (depth > 1)
+               {
+                 gint i;
+                 GtkRBNode *tmp_node;
+                 GtkRBTree *tmp_tree;
+
+                 if (!_gtk_rbtree_next (tree, node))
+                   gdk_draw_line (event->window,
+                                  tree_view->priv->tree_line_gc,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y + background_area.height / 2);
+                 else
+                   gdk_draw_line (event->window,
+                                  tree_view->priv->tree_line_gc,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y,
+                                  background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+                                  background_area.y + background_area.height);
+
+                 tmp_node = tree->parent_node;
+                 tmp_tree = tree->parent_tree;
+
+                 for (i = depth - 2; i > 0; i--)
+                   {
+                     if (_gtk_rbtree_next (tmp_tree, tmp_node))
+                       gdk_draw_line (event->window,
+                                      tree_view->priv->tree_line_gc,
+                                      background_area.x + tree_view->priv->expander_size * (i - 0.5),
+                                      background_area.y,
+                                      background_area.x + tree_view->priv->expander_size * (i - 0.5),
+                                      background_area.y + background_area.height);
+
+                     tmp_node = tmp_tree->parent_node;
+                     tmp_tree = tmp_tree->parent_tree;
+                   }
+               }
+           }
+
+         if (gtk_tree_view_is_expander_column (tree_view, column))
            {
              if (!rtl)
-               cell_area.x += depth * tree_view->priv->expander_size;
-             cell_area.width -= depth * tree_view->priv->expander_size;
+               cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
+             cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
+
+              if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
+               {
+                 if (!rtl)
+                   cell_area.x += depth * tree_view->priv->expander_size;
+                 cell_area.width -= depth * tree_view->priv->expander_size;
+               }
 
               /* If we have an expander column, the highlight underline
                * starts with that column, so that it indicates which
@@ -3804,7 +4585,8 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                                                   &cell_area,
                                                   &event->area,
                                                   flags);
-             if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
+             if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
+                 && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
                {
                  if (!got_pointer)
                    {
@@ -3884,16 +4666,31 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                break;
              gdk_drawable_get_size (tree_view->priv->bin_window,
                                     &width, NULL);
-             gtk_paint_focus (widget->style,
-                              tree_view->priv->bin_window,
-                              GTK_WIDGET_STATE (widget),
-                              NULL,
-                              widget,
-                              "treeview-drop-indicator",
-                              0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
-                              - focus_line_width / 2,
-                              width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
+
+             if (row_ending_details)
+               gtk_paint_focus (widget->style,
+                                tree_view->priv->bin_window,
+                                GTK_WIDGET_STATE (widget),
+                                &event->area,
+                                widget,
+                                (is_first
+                                 ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
+                                 : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
+                                0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
+                                - focus_line_width / 2,
+                                width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
                               - focus_line_width + 1);
+             else
+               gtk_paint_focus (widget->style,
+                                tree_view->priv->bin_window,
+                                GTK_WIDGET_STATE (widget),
+                                &event->area,
+                                widget,
+                                "treeview-drop-indicator",
+                                0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
+                                - focus_line_width / 2,
+                                width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
+                                - focus_line_width + 1);
               break;
             }
 
@@ -3913,6 +4710,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
          GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
          GTK_WIDGET_HAS_FOCUS (widget))
         {
+         gint tmp_y, tmp_height;
          gint width;
          GtkStateType focus_rect_state;
 
@@ -3924,16 +4722,38 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
 
          gdk_drawable_get_size (tree_view->priv->bin_window,
                                 &width, NULL);
-         gtk_paint_focus (widget->style,
-                          tree_view->priv->bin_window,
-                          focus_rect_state,
-                          NULL,
-                          widget,
-                          "treeview",
-                          0,
-                          BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
-                          width,
-                          ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)));
+         
+         if (draw_hgrid_lines)
+           {
+             tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
+             tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
+           }
+         else
+           {
+             tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
+             tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
+           }
+
+         if (row_ending_details)
+           gtk_paint_focus (widget->style,
+                            tree_view->priv->bin_window,
+                            focus_rect_state,
+                            &event->area,
+                            widget,
+                            (is_first
+                             ? (is_last ? "treeview" : "treeview-left" )
+                             : (is_last ? "treeview-right" : "treeview-middle" )),
+                            0, tmp_y,
+                            width, tmp_height);
+         else
+           gtk_paint_focus (widget->style,
+                            tree_view->priv->bin_window,
+                            focus_rect_state,
+                            &event->area,
+                            widget,
+                            "treeview",
+                            0, tmp_y,
+                            width, tmp_height);
        }
 
       y_offset += max_height;
@@ -3960,6 +4780,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
       else
        {
          gboolean done = FALSE;
+
          do
            {
              node = _gtk_rbtree_next (tree, node);
@@ -3995,7 +4816,24 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
     }
   while (y_offset < event->area.height);
 
- done:
+done:
+  gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
+
+ if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+   {
+     GdkRectangle *rectangles;
+     gint n_rectangles;
+
+     gdk_region_get_rectangles (event->region,
+                               &rectangles,
+                               &n_rectangles);
+
+     while (n_rectangles--)
+       gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
+
+     g_free (rectangles);
+   }
+
   if (cursor_path)
     gtk_tree_path_free (cursor_path);
 
@@ -4279,10 +5117,14 @@ gtk_tree_view_key_press (GtkWidget   *widget,
                         GdkEventKey *event)
 {
   GtkTreeView *tree_view = (GtkTreeView *) widget;
-  GList *list;
-  gboolean rtl;
 
-  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
+  if (tree_view->priv->rubber_band_status)
+    {
+      if (event->keyval == GDK_Escape)
+       gtk_tree_view_stop_rubber_band (tree_view);
+
+      return TRUE;
+    }
 
   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
     {
@@ -4294,172 +5136,145 @@ gtk_tree_view_key_press (GtkWidget   *widget,
       return TRUE;
     }
 
-  if (tree_view->priv->columns && 
-      (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
-      (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
-       || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
+  if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
     {
-      list = tree_view->priv->columns;
-      while (list)
+      GList *focus_column;
+      gboolean rtl;
+
+      rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
+
+      for (focus_column = tree_view->priv->columns;
+           focus_column;
+           focus_column = focus_column->next)
         {
-         GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
-         if (GTK_WIDGET_HAS_FOCUS (column->button))
-           {
-             if (!column->resizable)
-               return TRUE;
+          GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
 
-             if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left)
-               {
-                 column->resized_width = MAX (column->resized_width,
-                                              column->width);
-                 column->resized_width -= 2;
-                 if (column->resized_width < 0)
-                   column->resized_width = 0;
-
-                 if (column->min_width == -1)
-                   column->resized_width = MAX (column->button->requisition.width, column->resized_width);
-                 else
-                   column->resized_width = MAX (column->min_width, column->resized_width);
+          if (GTK_WIDGET_HAS_FOCUS (column->button))
+            break;
+        }
 
-                 if (column->max_width != -1)
-                   column->resized_width = MIN (column->resized_width, column->max_width);
+      if (focus_column &&
+          (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
+          (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
+           || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
+        {
+          GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
 
-                 column->use_resized_width = TRUE;
-                 gtk_widget_queue_resize (widget);
-                 return TRUE;
-               }
-             else if (event->keyval == GDK_Right
-                       || event->keyval == GDK_KP_Right)
-               {
-                 column->resized_width = MAX (column->resized_width,
-                                              column->width);
-                 column->resized_width += 2;
+          if (!column->resizable)
+            {
+              gtk_widget_error_bell (widget);
+              return TRUE;
+            }
 
-                 if (column->max_width != -1)
-                   column->resized_width = MIN (column->resized_width, column->max_width);
+          if (event->keyval == (rtl ? GDK_Right : GDK_Left)
+              || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
+            {
+              gint old_width = column->resized_width;
 
-                 column->use_resized_width = TRUE;
-                 gtk_widget_queue_resize (widget);
-                 return TRUE;
-               }
-           }
-         list = list->next;
-       }
-    }
+              column->resized_width = MAX (column->resized_width,
+                                           column->width);
+              column->resized_width -= 2;
+              if (column->resized_width < 0)
+                column->resized_width = 0;
 
-  if (tree_view->priv->columns && (event->state & GDK_MOD1_MASK) &&
-      (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
-       || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
-       || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
-       || event->keyval == GDK_End || event->keyval == GDK_KP_End))
-    {
-      list = tree_view->priv->columns;
-      while (list)
-        {
-         GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
-         if (GTK_WIDGET_HAS_FOCUS (column->button))
-           {
-             if (event->keyval == (rtl ? GDK_Right : GDK_Left)
-                  || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
-               {
-                 GtkTreeViewColumn *col;
-                 col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
-                 if (col != (GtkTreeViewColumn *)0x1)
-                   gtk_tree_view_move_column_after (tree_view, column, col);
-                 return TRUE;
-               }
-             else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
-                       || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
-               {
-                 GtkTreeViewColumn *col;
-                 col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
-                 if (col != (GtkTreeViewColumn *)0x1)
-                   gtk_tree_view_move_column_after (tree_view, column, col);
-                 return TRUE;
-               }
-             else if (event->keyval == GDK_Home
-                       || event->keyval == GDK_KP_Home)
-               {
-                 GtkTreeViewColumn *col;
-                 col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
-                 if (col != (GtkTreeViewColumn *)0x1)
-                   gtk_tree_view_move_column_after (tree_view, column, col);
-                 return TRUE;
-               }
-             else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
-               {
-                 GtkTreeViewColumn *col;
-                 col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
-                 if (col != (GtkTreeViewColumn *)0x1)
-                   gtk_tree_view_move_column_after (tree_view, column, col);
-                 return TRUE;
-               }
-           }
-         list = list->next;
-       }
-    }
+              if (column->min_width == -1)
+                column->resized_width = MAX (column->button->requisition.width,
+                                             column->resized_width);
+              else
+                column->resized_width = MAX (column->min_width,
+                                             column->resized_width);
 
-  if (tree_view->priv->columns &&
-      GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) &&
-      (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
-       || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
-    {
-      gint width = 0;
-      list = tree_view->priv->columns;
-      while (list)
-       {
-         GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
-         if (GTK_WIDGET_HAS_FOCUS (column->button))
-           {
-             if ((event->keyval == (rtl ? GDK_Right : GDK_Left)
-                   || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
-                  && list->prev)
-               {
-                 GList *tmp;
+              if (column->max_width != -1)
+                column->resized_width = MIN (column->resized_width,
+                                             column->max_width);
 
-                 for (tmp = list->prev; tmp; tmp = tmp->prev)
-                   if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
-                     break;
+              column->use_resized_width = TRUE;
 
-                 if (!tmp)
-                   return FALSE;
+              if (column->resized_width != old_width)
+                gtk_widget_queue_resize (widget);
+              else
+                gtk_widget_error_bell (widget);
+            }
+          else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
+                   || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
+            {
+              gint old_width = column->resized_width;
 
-                 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
-                 gtk_widget_grab_focus (tree_view->priv->focus_column->button);
-                 width -= tree_view->priv->focus_column->width;
-                 gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (width, tree_view->priv->hadjustment->lower, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
-                 return TRUE;
-               }
-             else if ((event->keyval == (rtl ? GDK_Left : GDK_Right)
-                        || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
-                       && list->next)
-               {
-                 GList *tmp;
+              column->resized_width = MAX (column->resized_width,
+                                           column->width);
+              column->resized_width += 2;
 
-                 for (tmp = list->next; tmp; tmp = tmp->next)
-                   if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
-                     break;
+              if (column->max_width != -1)
+                column->resized_width = MIN (column->resized_width,
+                                             column->max_width);
 
-                 if (!tmp)
-                   return FALSE;
+              column->use_resized_width = TRUE;
 
-                 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
+              if (column->resized_width != old_width)
+                gtk_widget_queue_resize (widget);
+              else
+                gtk_widget_error_bell (widget);
+            }
 
-                 gtk_widget_grab_focus (tree_view->priv->focus_column->button);
-                 width += tree_view->priv->focus_column->width;
-                 gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (width, tree_view->priv->hadjustment->lower, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
-                 return TRUE;
-               }
-           }
-         width += GTK_TREE_VIEW_COLUMN (list->data)->width;
-         list = list->next;
-       }
+          return TRUE;
+        }
+
+      if (focus_column &&
+          (event->state & GDK_MOD1_MASK) &&
+          (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
+           || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
+           || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
+           || event->keyval == GDK_End || event->keyval == GDK_KP_End))
+        {
+          GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
+
+          if (event->keyval == (rtl ? GDK_Right : GDK_Left)
+              || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
+            {
+              GtkTreeViewColumn *col;
+              col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
+              if (col != (GtkTreeViewColumn *)0x1)
+                gtk_tree_view_move_column_after (tree_view, column, col);
+              else
+                gtk_widget_error_bell (widget);
+            }
+          else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
+                   || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
+            {
+              GtkTreeViewColumn *col;
+              col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
+              if (col != (GtkTreeViewColumn *)0x1)
+                gtk_tree_view_move_column_after (tree_view, column, col);
+              else
+                gtk_widget_error_bell (widget);
+            }
+          else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
+            {
+              GtkTreeViewColumn *col;
+              col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
+              if (col != (GtkTreeViewColumn *)0x1)
+                gtk_tree_view_move_column_after (tree_view, column, col);
+              else
+                gtk_widget_error_bell (widget);
+            }
+          else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
+            {
+              GtkTreeViewColumn *col;
+              col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
+              if (col != (GtkTreeViewColumn *)0x1)
+                gtk_tree_view_move_column_after (tree_view, column, col);
+              else
+                gtk_widget_error_bell (widget);
+            }
+
+          return TRUE;
+        }
     }
 
   /* Chain up to the parent class.  It handles the keybindings. */
-  if ((* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event))
+  if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
     return TRUE;
-                                                           
+
   /* We pass the event to the search_entry.  If its text changes, then we start
    * the typeahead find capabilities. */
   if (tree_view->priv->enable_search
@@ -4531,7 +5346,12 @@ static gboolean
 gtk_tree_view_key_release (GtkWidget   *widget,
                           GdkEventKey *event)
 {
-  return (* GTK_WIDGET_CLASS (parent_class)->key_release_event) (widget, event);
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+  if (tree_view->priv->rubber_band_status)
+    return TRUE;
+
+  return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
 }
 
 /* FIXME Is this function necessary? Can I get an enter_notify event
@@ -4576,12 +5396,11 @@ gtk_tree_view_leave_notify (GtkWidget        *widget,
 {
   GtkTreeView *tree_view;
 
-  tree_view = GTK_TREE_VIEW (widget);
-  tree_view->priv->pressed_button = -1;
-
   if (event->mode == GDK_CROSSING_GRAB)
     return TRUE;
 
+  tree_view = GTK_TREE_VIEW (widget);
+
   if (tree_view->priv->prelight_node)
     _gtk_tree_view_queue_draw_node (tree_view,
                                    tree_view->priv->prelight_tree,
@@ -4634,6 +5453,25 @@ gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
                              GTK_RBNODE_GET_HEIGHT (node));
 }
 
+static gboolean
+node_is_visible (GtkTreeView *tree_view,
+                GtkRBTree   *tree,
+                GtkRBNode   *node)
+{
+  int y;
+  int height;
+
+  y = _gtk_rbtree_node_find_offset (tree, node);
+  height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
+
+  if (y >= tree_view->priv->vadjustment->value &&
+      y + height <= (tree_view->priv->vadjustment->value
+                    + tree_view->priv->vadjustment->page_size))
+    return TRUE;
+
+  return FALSE;
+}
+
 /* Returns TRUE if it updated the size
  */
 static gboolean
@@ -4644,7 +5482,7 @@ validate_row (GtkTreeView *tree_view,
              GtkTreePath *path)
 {
   GtkTreeViewColumn *column;
-  GList *list;
+  GList *list, *first_column, *last_column;
   gint height = 0;
   gint horizontal_separator;
   gint vertical_separator;
@@ -4652,7 +5490,9 @@ validate_row (GtkTreeView *tree_view,
   gint depth = gtk_tree_path_get_depth (path);
   gboolean retval = FALSE;
   gboolean is_separator = FALSE;
+  gboolean draw_vgrid_lines, draw_hgrid_lines;
   gint focus_pad;
+  gint grid_line_width;
 
   /* double check the row needs validating */
   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
@@ -4671,8 +5511,26 @@ validate_row (GtkTreeView *tree_view,
                        "focus-line-width", &focus_line_width,
                        "horizontal-separator", &horizontal_separator,
                        "vertical-separator", &vertical_separator,
+                       "grid-line-width", &grid_line_width,
                        NULL);
   
+  draw_vgrid_lines =
+    tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
+    || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
+  draw_hgrid_lines =
+    tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
+    || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
+
+  for (last_column = g_list_last (tree_view->priv->columns);
+       last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
+       last_column = last_column->prev)
+    ;
+
+  for (first_column = g_list_first (tree_view->priv->columns);
+       first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
+       first_column = first_column->next)
+    ;
+
   for (list = tree_view->priv->columns; list; list = list->next)
     {
       gint tmp_width;
@@ -4702,13 +5560,24 @@ validate_row (GtkTreeView *tree_view,
       else
        height = 2 + 2 * focus_pad;
 
-      if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
+      if (gtk_tree_view_is_expander_column (tree_view, column))
         {
-         tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size);
+         tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
+
+         if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+           tmp_width += depth * tree_view->priv->expander_size;
        }
       else
        tmp_width = tmp_width + horizontal_separator;
 
+      if (draw_vgrid_lines)
+        {
+         if (list->data == first_column || list->data == last_column)
+           tmp_width += grid_line_width / 2.0;
+         else
+           tmp_width += grid_line_width;
+       }
+
       if (tmp_width > column->requested_width)
        {
          retval = TRUE;
@@ -4716,6 +5585,9 @@ validate_row (GtkTreeView *tree_view,
        }
     }
 
+  if (draw_hgrid_lines)
+    height += grid_line_width;
+
   if (height != GTK_RBNODE_GET_HEIGHT (node))
     {
       retval = TRUE;
@@ -4737,7 +5609,6 @@ validate_visible_area (GtkTreeView *tree_view)
   GtkRBNode *node = NULL;
   gboolean need_redraw = FALSE;
   gboolean size_changed = FALSE;
-  gboolean update_dy = FALSE;
   gint total_height;
   gint area_above = 0;
   gint area_below = 0;
@@ -4762,13 +5633,11 @@ validate_visible_area (GtkTreeView *tree_view)
       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
        {
           /* we are going to scroll, and will update dy */
-         update_dy = TRUE;
-
          gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
          if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
              GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
            {
-             need_redraw = TRUE;
+             _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
              if (validate_row (tree_view, tree, node, &iter, path))
                size_changed = TRUE;
            }
@@ -4806,9 +5675,8 @@ validate_visible_area (GtkTreeView *tree_view)
              else
                {
                  /* row not visible */
-                  update_dy = TRUE;
-
-                 if (dy >= 0 && dy <= tree_view->priv->vadjustment->page_size)
+                 if (dy >= 0
+                     && dy + height <= tree_view->priv->vadjustment->page_size)
                    {
                      /* row at the beginning -- fixed */
                      area_above = dy;
@@ -4816,8 +5684,7 @@ validate_visible_area (GtkTreeView *tree_view)
                                   - area_above - height;
                    }
                  else if (dy >= (tree_view->priv->vadjustment->upper -
-                                 tree_view->priv->vadjustment->page_size)
-                          && dy <= tree_view->priv->vadjustment->upper)
+                                 tree_view->priv->vadjustment->page_size))
                    {
                      /* row at the end -- fixed */
                      area_above = dy - (tree_view->priv->vadjustment->upper -
@@ -4827,7 +5694,7 @@ validate_visible_area (GtkTreeView *tree_view)
 
                       if (area_below < 0)
                         {
-                          area_above += area_below;
+                         area_above = tree_view->priv->vadjustment->page_size - height;
                           area_below = 0;
                         }
                    }
@@ -4883,7 +5750,7 @@ validate_visible_area (GtkTreeView *tree_view)
       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
          GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
        {
-         need_redraw = TRUE;
+         _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
          if (validate_row (tree_view, tree, node, &iter, path))
            size_changed = TRUE;
        }
@@ -4901,32 +5768,30 @@ validate_visible_area (GtkTreeView *tree_view)
    */
   if (area_above == 0)
     {
-      GtkRBTree *tree;
-      GtkRBNode *node;
-      GtkTreePath *tmppath;
-      GtkTreeIter iter;
-
-      _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
+      GtkRBTree *tmptree;
+      GtkRBNode *tmpnode;
 
-      tmppath = gtk_tree_path_copy (above_path);
+      _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
+      _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
 
-      _gtk_rbtree_prev_full (tree, node, &tree, &node);
-      if (! gtk_tree_path_prev (tmppath) && node != NULL)
+      if (tmpnode)
         {
-          gtk_tree_path_free (tmppath);
-          tmppath = _gtk_tree_view_find_path (tree_view, tree, node);
-        }
-      gtk_tree_model_get_iter (tree_view->priv->model, &iter, tmppath);
+         GtkTreePath *tmppath;
+         GtkTreeIter tmpiter;
 
-      if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
-          GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
-        {
-          need_redraw = TRUE;
-          if (validate_row (tree_view, tree, node, &iter, path))
-            size_changed = TRUE;
-        }
+         tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
+         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
 
-      gtk_tree_path_free (tmppath);
+         if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
+             GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
+           {
+             _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
+             if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
+               size_changed = TRUE;
+           }
+
+         gtk_tree_path_free (tmppath);
+       }
     }
 
   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
@@ -4936,8 +5801,6 @@ validate_visible_area (GtkTreeView *tree_view)
    */
   while (node && area_below > 0)
     {
-      gint new_height;
-
       if (node->children)
        {
          GtkTreeIter parent = iter;
@@ -4995,24 +5858,15 @@ validate_visible_area (GtkTreeView *tree_view)
       if (!node)
         break;
 
-      new_height = GTK_RBNODE_GET_HEIGHT (node);
-
       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
          GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
        {
-          gint old_height = new_height;
-
-         need_redraw = TRUE;
+         _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
          if (validate_row (tree_view, tree, node, &iter, path))
-            {
-              new_height = GTK_RBNODE_GET_HEIGHT (node);
              size_changed = TRUE;
-
-              area_below -= new_height - old_height;
-            }
        }
 
-      area_below -= ROW_HEIGHT (tree_view, new_height);
+      area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
     }
   gtk_tree_path_free (path);
 
@@ -5026,8 +5880,6 @@ validate_visible_area (GtkTreeView *tree_view)
   /* We walk backwards */
   while (area_above > 0)
     {
-      gint new_height;
-
       _gtk_rbtree_prev_full (tree, node, &tree, &node);
       if (! gtk_tree_path_prev (above_path) && node != NULL)
        {
@@ -5039,24 +5891,14 @@ validate_visible_area (GtkTreeView *tree_view)
       if (node == NULL)
        break;
 
-      new_height = GTK_RBNODE_GET_HEIGHT (node);
-
       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
          GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
        {
-          gint old_height = new_height;
-
-         need_redraw = TRUE;
+         _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
          if (validate_row (tree_view, tree, node, &iter, above_path))
-            {
-              new_height = GTK_RBNODE_GET_HEIGHT (node);
-             size_changed = TRUE;
-
-              area_above -= new_height - old_height;
-            }
+           size_changed = TRUE;
        }
-      area_above -= ROW_HEIGHT (tree_view, new_height);
-      update_dy = TRUE;
+      area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
     }
 
   /* if we scrolled to a path, we need to set the dy here,
@@ -5064,15 +5906,8 @@ validate_visible_area (GtkTreeView *tree_view)
    */
   if (tree_view->priv->scroll_to_path)
     {
-      gint dy;
-
-      if (node != NULL)
-       dy = _gtk_rbtree_node_find_offset (tree, node) - area_above;
-      else
-       dy = 0;
-
-      gtk_adjustment_set_value (tree_view->priv->vadjustment, dy);
-      gtk_tree_view_dy_to_top_row (tree_view);
+      gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
+      gtk_tree_view_top_row_to_dy (tree_view);
 
       need_redraw = TRUE;
     }
@@ -5292,7 +6127,7 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
       gtk_adjustment_changed (tree_view->priv->vadjustment);
 
       if (queue_resize)
-        gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+        gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
     }
 
   if (path) gtk_tree_path_free (path);
@@ -5321,8 +6156,6 @@ validate_rows_handler (GtkTreeView *tree_view)
 {
   gboolean retval;
 
-  GDK_THREADS_ENTER ();
-
   retval = do_validate_rows (tree_view, TRUE);
   if (! retval && tree_view->priv->validate_rows_timer)
     {
@@ -5330,8 +6163,6 @@ validate_rows_handler (GtkTreeView *tree_view)
       tree_view->priv->validate_rows_timer = 0;
     }
 
-  GDK_THREADS_LEAVE ();
-
   return retval;
 }
 
@@ -5366,12 +6197,8 @@ do_presize_handler (GtkTreeView *tree_view)
 static gboolean
 presize_handler_callback (gpointer data)
 {
-  GDK_THREADS_ENTER ();
-
   do_presize_handler (GTK_TREE_VIEW (data));
                   
-  GDK_THREADS_LEAVE ();
-
   return FALSE;
 }
 
@@ -5384,21 +6211,18 @@ install_presize_handler (GtkTreeView *tree_view)
   if (! tree_view->priv->presize_handler_timer)
     {
       tree_view->priv->presize_handler_timer =
-       g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
+       gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
     }
   if (! tree_view->priv->validate_rows_timer)
     {
       tree_view->priv->validate_rows_timer =
-       g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
+       gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
     }
 }
 
 static gboolean
 scroll_sync_handler (GtkTreeView *tree_view)
 {
-
-  GDK_THREADS_ENTER ();
-
   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
@@ -5408,8 +6232,6 @@ scroll_sync_handler (GtkTreeView *tree_view)
 
   tree_view->priv->scroll_sync_timer = 0;
 
-  GDK_THREADS_LEAVE ();
-
   return FALSE;
 }
 
@@ -5422,7 +6244,26 @@ install_scroll_sync_handler (GtkTreeView *tree_view)
   if (!tree_view->priv->scroll_sync_timer)
     {
       tree_view->priv->scroll_sync_timer =
-       g_idle_add_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
+       gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
+    }
+}
+
+static void
+gtk_tree_view_set_top_row (GtkTreeView *tree_view,
+                          GtkTreePath *path,
+                          gint         offset)
+{
+  gtk_tree_row_reference_free (tree_view->priv->top_row);
+
+  if (!path)
+    {
+      tree_view->priv->top_row = NULL;
+      tree_view->priv->top_row_dy = 0;
+    }
+  else
+    {
+      tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
+      tree_view->priv->top_row_dy = offset;
     }
 }
 
@@ -5432,27 +6273,33 @@ install_scroll_sync_handler (GtkTreeView *tree_view)
 static void
 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
 {
+  gint offset;
   GtkTreePath *path;
   GtkRBTree *tree;
   GtkRBNode *node;
 
-  gtk_tree_row_reference_free (tree_view->priv->top_row);
   if (tree_view->priv->tree == NULL)
-    tree = NULL;
+    {
+      gtk_tree_view_set_top_row (tree_view, NULL, 0);
+    }
   else
-    tree_view->priv->top_row_dy = _gtk_rbtree_find_offset (tree_view->priv->tree,
-                                                          tree_view->priv->dy,
-                                                          &tree, &node);
-  if (tree == NULL)
     {
-      tree_view->priv->top_row = NULL;
-      tree_view->priv->top_row_dy = 0;
-      return;
+      offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
+                                       tree_view->priv->dy,
+                                       &tree, &node);
+
+      if (tree == NULL)
+        {
+         tree_view->priv->top_row = NULL;
+         tree_view->priv->top_row_dy = 0;
+       }
+      else
+        {
+         path = _gtk_tree_view_find_path (tree_view, tree, node);
+         gtk_tree_view_set_top_row (tree_view, path, offset);
+         gtk_tree_path_free (path);
+       }
     }
-      
-  path = _gtk_tree_view_find_path (tree_view, tree, node);
-  tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
-  gtk_tree_path_free (path);
 }
 
 static void
@@ -5496,6 +6343,12 @@ gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
 
   tree_view->priv->dy = _gtk_rbtree_node_find_offset (tree, node);
   tree_view->priv->dy += tree_view->priv->top_row_dy;
+
+  if (tree_view->priv->dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+    tree_view->priv->dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
+
+  tree_view->priv->dy = MAX (0, tree_view->priv->dy);
+
   gtk_adjustment_set_value (tree_view->priv->vadjustment,
                            (gdouble)tree_view->priv->dy);
 }
@@ -5763,6 +6616,16 @@ drag_scan_timeout (gpointer data)
 }
 #endif /* 0 */
 
+static void
+add_scroll_timeout (GtkTreeView *tree_view)
+{
+  if (tree_view->priv->scroll_timeout == 0)
+    {
+      tree_view->priv->scroll_timeout =
+       gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
+    }
+}
+
 static void
 remove_scroll_timeout (GtkTreeView *tree_view)
 {
@@ -5772,6 +6635,7 @@ remove_scroll_timeout (GtkTreeView *tree_view)
       tree_view->priv->scroll_timeout = 0;
     }
 }
+
 static gboolean
 check_model_dnd (GtkTreeModel *model,
                  GType         required_iface,
@@ -5815,8 +6679,6 @@ open_row_timeout (gpointer data)
   GtkTreeViewDropPosition pos;
   gboolean result = FALSE;
 
-  GDK_THREADS_ENTER ();
-
   gtk_tree_view_get_drag_dest_row (tree_view,
                                    &dest_path,
                                    &pos);
@@ -5838,21 +6700,18 @@ open_row_timeout (gpointer data)
       result = TRUE;
     }
 
-  GDK_THREADS_LEAVE ();
-
   return result;
 }
 
-static gint
+static gboolean
 scroll_row_timeout (gpointer data)
 {
   GtkTreeView *tree_view = data;
 
-  GDK_THREADS_ENTER ();
-
   gtk_tree_view_vertical_autoscroll (tree_view);
 
-  GDK_THREADS_LEAVE ();
+  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+    gtk_tree_view_update_rubber_band (tree_view);
 
   return TRUE;
 }
@@ -5861,6 +6720,7 @@ scroll_row_timeout (gpointer data)
 static gboolean
 set_destination_row (GtkTreeView    *tree_view,
                      GdkDragContext *context,
+                     /* coordinates relative to the widget */
                      gint            x,
                      gint            y,
                      GdkDragAction  *suggested_action,
@@ -6123,11 +6983,14 @@ gtk_tree_view_drag_begin (GtkWidget      *widget,
   GtkTreePath *path = NULL;
   gint cell_x, cell_y;
   GdkPixmap *row_pix;
+  TreeViewDragInfo *di;
 
   tree_view = GTK_TREE_VIEW (widget);
 
-  /* if the user uses a custom DnD impl, we don't set the icon here */
-  if (!get_info (tree_view))
+  /* if the user uses a custom DND source impl, we don't set the icon here */
+  di = get_info (tree_view);
+
+  if (di == NULL || !di->source_set)
     return;
 
   gtk_tree_view_get_path_at_pos (tree_view,
@@ -6267,6 +7130,7 @@ gtk_tree_view_drag_leave (GtkWidget      *widget,
 static gboolean
 gtk_tree_view_drag_motion (GtkWidget        *widget,
                            GdkDragContext   *context,
+                          /* coordinates relative to the widget */
                            gint              x,
                            gint              y,
                            guint             time)
@@ -6300,12 +7164,11 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
         {
           tree_view->priv->open_dest_timeout =
-            g_timeout_add (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
+            gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
         }
-      else if (tree_view->priv->scroll_timeout == 0)
+      else
         {
-         tree_view->priv->scroll_timeout =
-           g_timeout_add (150, scroll_row_timeout, tree_view);
+         add_scroll_timeout (tree_view);
        }
 
       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
@@ -6333,6 +7196,7 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
 static gboolean
 gtk_tree_view_drag_drop (GtkWidget        *widget,
                          GdkDragContext   *context,
+                        /* coordinates relative to the widget */
                          gint              x,
                          gint              y,
                          guint             time)
@@ -6397,6 +7261,7 @@ gtk_tree_view_drag_drop (GtkWidget        *widget,
 static void
 gtk_tree_view_drag_data_received (GtkWidget        *widget,
                                   GdkDragContext   *context,
+                                 /* coordinates relative to the widget */
                                   gint              x,
                                   gint              y,
                                   GtkSelectionData *selection_data,
@@ -6715,7 +7580,8 @@ gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
  */
 static gboolean
 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
-                           GtkDirectionType  dir)
+                           GtkDirectionType  dir,
+                           gboolean          clamp_column_visible)
 {
   GtkWidget *focus_child;
 
@@ -6756,12 +7622,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
     }
 
 
-   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-   if (rtl) {
-     GList *temp = first_column;
-     first_column = last_column;
-     last_column = temp;
-   }
+  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
 
   switch (dir)
     {
@@ -6806,16 +7667,10 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
        if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
          break;
 
-      if (tmp_list == first_column && dir == GTK_DIR_LEFT)
-       {
-         focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
-         gtk_widget_grab_focus (focus_child);
-         break;
-       }
-      else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
-       {
-         focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
-         gtk_widget_grab_focus (focus_child);
+      if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
+         || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
+        {
+         gtk_widget_error_bell (GTK_WIDGET (tree_view));
          break;
        }
 
@@ -6823,7 +7678,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
        {
          GtkTreeViewColumn *column;
 
-         if (dir == GTK_DIR_RIGHT)
+         if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
            tmp_list = tmp_list->next;
          else
            tmp_list = tmp_list->prev;
@@ -6854,25 +7709,17 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
   if (focus_child)
     {
       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
-       if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
-         break;
-
-      tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
+       if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
+         {
+           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
+           break;
+         }
 
-      /* If the following isn't true, then the view is smaller then the scrollpane.
-       */
-      if ((focus_child->allocation.x + focus_child->allocation.width) <=
-         (tree_view->priv->hadjustment->upper))
-       {
-         /* Scroll to the button, if needed */
-         if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
-             (focus_child->allocation.x + focus_child->allocation.width))
-           gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                     focus_child->allocation.x + focus_child->allocation.width -
-                                     tree_view->priv->hadjustment->page_size);
-         else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
-           gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                     focus_child->allocation.x);
+      if (clamp_column_visible)
+        {
+         gtk_tree_view_clamp_column_visible (tree_view,
+                                             tree_view->priv->focus_column,
+                                             FALSE);
        }
     }
 
@@ -6906,7 +7753,7 @@ gtk_tree_view_focus (GtkWidget        *widget,
        {
        case GTK_DIR_LEFT:
        case GTK_DIR_RIGHT:
-         gtk_tree_view_header_focus (tree_view, direction);
+         gtk_tree_view_header_focus (tree_view, direction, TRUE);
          return TRUE;
        case GTK_DIR_TAB_BACKWARD:
        case GTK_DIR_UP:
@@ -6924,14 +7771,14 @@ gtk_tree_view_focus (GtkWidget        *widget,
   /* Case 2. We don't have focus at all. */
   if (!GTK_WIDGET_HAS_FOCUS (container))
     {
-      if (!gtk_tree_view_header_focus (tree_view, direction))
+      if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
        gtk_widget_grab_focus (widget);
       return TRUE;
     }
 
   /* Case 3. We have focus already. */
   if (direction == GTK_DIR_TAB_BACKWARD)
-    return (gtk_tree_view_header_focus (tree_view, direction));
+    return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
   else if (direction == GTK_DIR_TAB_FORWARD)
     return FALSE;
 
@@ -6943,7 +7790,7 @@ gtk_tree_view_focus (GtkWidget        *widget,
 static void
 gtk_tree_view_grab_focus (GtkWidget *widget)
 {
-  (* GTK_WIDGET_CLASS (parent_class)->grab_focus) (widget);
+  (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus) (widget);
 
   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
 }
@@ -6962,8 +7809,12 @@ gtk_tree_view_style_set (GtkWidget *widget,
 
   if (GTK_WIDGET_REALIZED (widget))
     {
-      gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+      gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
+      gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
+
+      gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
+      gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
     }
 
   gtk_widget_style_get (widget,
@@ -7000,7 +7851,7 @@ gtk_tree_view_set_focus_child (GtkContainer *container,
        }
     }
 
-  (* parent_class->set_focus_child) (container, child);
+  GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
 }
 
 static void
@@ -7125,6 +7976,7 @@ gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
 static void
 gtk_tree_view_put (GtkTreeView *tree_view,
                   GtkWidget   *child_widget,
+                  /* in tree coordinates */
                   gint         x,
                   gint         y,
                   gint         width,
@@ -7154,6 +8006,7 @@ gtk_tree_view_put (GtkTreeView *tree_view,
 void
 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
                                  GtkWidget   *widget,
+                                 /* in tree coordinates */
                                  gint         x,
                                  gint         y,
                                  gint         width,
@@ -7200,17 +8053,11 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   GtkRBTree *tree;
   GtkRBNode *node;
   gboolean free_path = FALSE;
-  gint vertical_separator;
   GList *list;
   GtkTreePath *cursor_path;
 
   g_return_if_fail (path != NULL || iter != NULL);
 
-  if (!GTK_WIDGET_REALIZED (tree_view))
-    /* We can just ignore ::changed signals if we aren't realized, as we don't care about sizes
-     */
-    return;
-
   if (tree_view->priv->cursor != NULL)
     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
   else
@@ -7223,8 +8070,6 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   if (cursor_path != NULL)
     gtk_tree_path_free (cursor_path);
 
-  gtk_widget_style_get (GTK_WIDGET (data), "vertical-separator", &vertical_separator, NULL);
-
   if (path == NULL)
     {
       path = gtk_tree_model_get_path (model, iter);
@@ -7243,16 +8088,12 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   if (tree == NULL)
     goto done;
 
-  /* Check if the node became insensitive, and if so, unselect it */
-  if (!_gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
-                                             node, path))
-    gtk_tree_selection_unselect_path (tree_view->priv->selection, path);
-
   if (tree_view->priv->fixed_height_mode
       && tree_view->priv->fixed_height >= 0)
     {
       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
-      gtk_tree_view_node_queue_redraw (tree_view, tree, node);
+      if (GTK_WIDGET_REALIZED (tree_view))
+       gtk_tree_view_node_queue_redraw (tree_view, tree, node);
     }
   else
     {
@@ -7273,7 +8114,7 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
     }
 
  done:
-  if (!tree_view->priv->fixed_height_mode)
+  if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
     install_presize_handler (tree_view);
   if (free_path)
     gtk_tree_path_free (path);
@@ -7293,6 +8134,7 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
   gint i = 0;
   gint height;
   gboolean free_path = FALSE;
+  gboolean node_visible = TRUE;
 
   g_return_if_fail (path != NULL || iter != NULL);
 
@@ -7326,6 +8168,7 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
       if (tmptree == NULL)
        {
          /* We aren't showing the node */
+         node_visible = FALSE;
           goto done;
        }
 
@@ -7357,19 +8200,22 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
     }
 
   if (tree == NULL)
-    goto done;
+    {
+      node_visible = FALSE;
+      goto done;
+    }
 
   /* ref the node */
   gtk_tree_model_ref_node (tree_view->priv->model, iter);
   if (indices[depth - 1] == 0)
     {
       tmpnode = _gtk_rbtree_find_count (tree, 1);
-      _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
+      tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
     }
   else
     {
       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
-      _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
+      tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
     }
 
  done:
@@ -7377,7 +8223,11 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
     {
       if (tree)
         _gtk_rbtree_node_mark_valid (tree, tmpnode);
-      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+
+      if (node_visible && node_is_visible (tree_view, tree, tmpnode))
+       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+      else
+       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
     }
   else
     install_presize_handler (tree_view);
@@ -7749,6 +8599,7 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
                          gboolean     recurse)
 {
   GtkRBNode *temp = NULL;
+  GtkTreePath *path = NULL;
   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
 
   do
@@ -7772,14 +8623,28 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
        {
          GtkTreeIter child;
 
+         if (!path)
+           path = gtk_tree_model_get_path (tree_view->priv->model, iter);
+         else
+           gtk_tree_path_next (path);
+
          if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
            {
-             temp->children = _gtk_rbtree_new ();
-             temp->children->parent_tree = tree;
-             temp->children->parent_node = temp;
-             gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
+             gboolean expand;
+
+             g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
+
+             if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
+                 && !expand)
+               {
+                 temp->children = _gtk_rbtree_new ();
+                 temp->children->parent_tree = tree;
+                 temp->children->parent_node = temp;
+                 gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
+               }
            }
        }
+
       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
        {
          if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
@@ -7787,6 +8652,9 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
        }
     }
   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
+
+  if (path)
+    gtk_tree_path_free (path);
 }
 
 /* If height is non-NULL, then we set it to be the new height.  if it's all
@@ -7841,10 +8709,15 @@ gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
                                              &width, NULL);
        }
 
-      if (gtk_tree_view_is_expander_column (tree_view, column) &&
-          TREE_VIEW_DRAW_EXPANDERS (tree_view))
+      if (gtk_tree_view_is_expander_column (tree_view, column))
        {
-         if (depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width)
+         int tmp = 0;
+
+         tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
+         if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+           tmp += depth * tree_view->priv->expander_size;
+
+         if (tmp > column->requested_width)
            {
              _gtk_tree_view_column_cell_set_dirty (column, TRUE);
              retval = TRUE;
@@ -7945,18 +8818,76 @@ gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
 
 static void
 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
-                                   GtkTreeViewColumn *column)
+                                   GtkTreeViewColumn *column,
+                                   gboolean           focus_to_cell)
 {
+  gint x, width;
+
   if (column == NULL)
     return;
-  if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
-      (column->button->allocation.x + column->button->allocation.width))
-    gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                             column->button->allocation.x + column->button->allocation.width -
-                             tree_view->priv->hadjustment->page_size);
-  else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
-    gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                             column->button->allocation.x);
+
+  x = column->button->allocation.x;
+  width = column->button->allocation.width;
+
+  if (width > tree_view->priv->hadjustment->page_size)
+    {
+      /* The column is larger than the horizontal page size.  If the
+       * column has cells which can be focussed individually, then we make
+       * sure the cell which gets focus is fully visible (if even the
+       * focus cell is bigger than the page size, we make sure the
+       * left-hand side of the cell is visible).
+       *
+       * If the column does not have those so-called special cells, we
+       * make sure the left-hand side of the column is visible.
+       */
+
+      if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
+        {
+         GtkTreePath *cursor_path;
+         GdkRectangle background_area, cell_area, focus_area;
+
+         cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+
+         gtk_tree_view_get_cell_area (tree_view,
+                                      cursor_path, column, &cell_area);
+         gtk_tree_view_get_background_area (tree_view,
+                                            cursor_path, column,
+                                            &background_area);
+
+         gtk_tree_path_free (cursor_path);
+
+         _gtk_tree_view_column_get_focus_area (column,
+                                               &background_area,
+                                               &cell_area,
+                                               &focus_area);
+
+         x = focus_area.x;
+         width = focus_area.width;
+
+         if (width < tree_view->priv->hadjustment->page_size)
+           {
+             if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
+               gtk_adjustment_set_value (tree_view->priv->hadjustment,
+                                         x + width - tree_view->priv->hadjustment->page_size);
+             else if (tree_view->priv->hadjustment->value > x)
+               gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
+           }
+       }
+
+      gtk_adjustment_set_value (tree_view->priv->hadjustment,
+                               CLAMP (x,
+                                      tree_view->priv->hadjustment->lower,
+                                      tree_view->priv->hadjustment->upper
+                                      - tree_view->priv->hadjustment->page_size));
+    }
+  else
+    {
+      if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
+         gtk_adjustment_set_value (tree_view->priv->hadjustment,
+                                   x + width - tree_view->priv->hadjustment->page_size);
+      else if (tree_view->priv->hadjustment->value > x)
+       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
+  }
 }
 
 /* This function could be more efficient.  I'll optimize it if profiling seems
@@ -8240,9 +9171,10 @@ gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
 
   /* We know there are always 2 slots possbile, as you can always return column. */
   /* If that's all there is, return */
-  if (tree_view->priv->column_drag_info->next->next == NULL &&
-      ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
-      ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
+  if (tree_view->priv->column_drag_info->next == NULL || 
+      (tree_view->priv->column_drag_info->next->next == NULL &&
+       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
+       ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
     {
       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
        g_free (tmp_list->data);
@@ -8393,7 +9325,7 @@ gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
     return;
 
   rect.x = 0;
-  rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width);
+  rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
 
   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
@@ -8463,6 +9395,7 @@ static void
 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
                           GtkRBTree   *tree,
                          GtkRBNode   *node,
+                         /* in bin_window coordinates */
                          gint         x,
                          gint         y)
 {
@@ -8596,11 +9529,13 @@ static void
 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
                                   gint         count)
 {
+  gint selection_count;
   GtkRBTree *cursor_tree = NULL;
   GtkRBNode *cursor_node = NULL;
   GtkRBTree *new_cursor_tree = NULL;
   GtkRBNode *new_cursor_node = NULL;
   GtkTreePath *cursor_path = NULL;
+  gboolean grab_focus = TRUE;
 
   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
     return;
@@ -8618,12 +9553,26 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
   if (cursor_tree == NULL)
     /* FIXME: we lost the cursor; should we get the first? */
     return;
-  if (count == -1)
-    _gtk_rbtree_prev_full (cursor_tree, cursor_node,
-                          &new_cursor_tree, &new_cursor_node);
+
+  selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
+
+  if (selection_count == 0
+      && tree_view->priv->selection->type != GTK_SELECTION_NONE
+      && !tree_view->priv->ctrl_pressed)
+    {
+      /* Don't move the cursor, but just select the current node */
+      new_cursor_tree = cursor_tree;
+      new_cursor_node = cursor_node;
+    }
   else
-    _gtk_rbtree_next_full (cursor_tree, cursor_node,
-                          &new_cursor_tree, &new_cursor_node);
+    {
+      if (count == -1)
+       _gtk_rbtree_prev_full (cursor_tree, cursor_node,
+                              &new_cursor_tree, &new_cursor_node);
+      else
+       _gtk_rbtree_next_full (cursor_tree, cursor_node,
+                              &new_cursor_tree, &new_cursor_node);
+    }
 
   /*
    * If the list has only one item and multi-selection is set then select
@@ -8659,9 +9608,32 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
   else
     {
       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
+
+      if (!tree_view->priv->shift_pressed)
+        {
+          if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
+                                          count < 0 ?
+                                          GTK_DIR_UP : GTK_DIR_DOWN))
+            {
+              GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
+
+              if (toplevel)
+                gtk_widget_child_focus (toplevel,
+                                        count < 0 ?
+                                        GTK_DIR_TAB_BACKWARD :
+                                        GTK_DIR_TAB_FORWARD);
+
+              grab_focus = FALSE;
+            }
+        }
+      else
+        {
+          gtk_widget_error_bell (GTK_WIDGET (tree_view));
+        }
     }
 
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+  if (grab_focus)
+    gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 }
 
 static void
@@ -8670,6 +9642,7 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
 {
   GtkRBTree *cursor_tree = NULL;
   GtkRBNode *cursor_node = NULL;
+  GtkTreePath *old_cursor_path = NULL;
   GtkTreePath *cursor_path = NULL;
   gint y;
   gint window_y;
@@ -8679,38 +9652,57 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
     return;
 
   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
-    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+    old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
   else
     /* This is sorta weird.  Focus in should give us a cursor */
     return;
 
   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
-  _gtk_tree_view_find_node (tree_view, cursor_path,
+  _gtk_tree_view_find_node (tree_view, old_cursor_path,
                            &cursor_tree, &cursor_node);
 
-  gtk_tree_path_free (cursor_path);
-
   if (cursor_tree == NULL)
-    /* FIXME: we lost the cursor.  Should we try to get one? */
-    return;
+    {
+      /* FIXME: we lost the cursor.  Should we try to get one? */
+      gtk_tree_path_free (old_cursor_path);
+      return;
+    }
   g_return_if_fail (cursor_node != NULL);
 
   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
+  y += tree_view->priv->cursor_offset;
   y += count * (int)tree_view->priv->vadjustment->page_increment;
   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
 
   if (y >= tree_view->priv->height)
     y = tree_view->priv->height - 1;
 
-  y -= _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
+  tree_view->priv->cursor_offset =
+    _gtk_rbtree_find_offset (tree_view->priv->tree, y,
+                            &cursor_tree, &cursor_node);
+
+  if (tree_view->priv->cursor_offset >= BACKGROUND_HEIGHT (cursor_node))
+    {
+      _gtk_rbtree_next_full (cursor_tree, cursor_node,
+                            &cursor_tree, &cursor_node);
+      tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
+    }
+
+  y -= tree_view->priv->cursor_offset;
   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
   g_return_if_fail (cursor_path != NULL);
   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
-  gtk_tree_path_free (cursor_path);
 
   y -= window_y;
   gtk_tree_view_scroll_to_point (tree_view, -1, y);
+  _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
+
+  if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
+    gtk_widget_error_bell (GTK_WIDGET (tree_view));
+
+  gtk_tree_path_free (old_cursor_path);
+  gtk_tree_path_free (cursor_path);
 }
 
 static void
@@ -8746,10 +9738,10 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
     }
   gtk_tree_path_free (cursor_path);
 
-  list = tree_view->priv->columns;
+  list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
   if (tree_view->priv->focus_column)
     {
-      for (list = tree_view->priv->columns; list; list = list->next)
+      for (; list; list = (rtl ? list->prev : list->next))
        {
          if (list->data == tree_view->priv->focus_column)
            break;
@@ -8758,6 +9750,8 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
 
   while (list)
     {
+      gboolean left, right;
+
       column = list->data;
       if (column->visible == FALSE)
        goto loop_end;
@@ -8767,9 +9761,19 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
                                               &iter,
                                               GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
                                               cursor_node->children?TRUE:FALSE);
-      if (_gtk_tree_view_column_cell_focus (column, count,
-                                           list->prev?TRUE:FALSE,
-                                           list->next?TRUE:FALSE))
+
+      if (rtl)
+        {
+         right = list->prev ? TRUE : FALSE;
+         left = list->next ? TRUE : FALSE;
+       }
+      else
+        {
+         left = list->prev ? TRUE : FALSE;
+         right = list->next ? TRUE : FALSE;
+        }
+
+      if (_gtk_tree_view_column_cell_focus (column, count, left, right))
        {
          tree_view->priv->focus_column = column;
          found_column = TRUE;
@@ -8791,7 +9795,13 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
                                        NULL);
       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
     }
-  gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
+  else
+    {
+      gtk_widget_error_bell (GTK_WIDGET (tree_view));
+    }
+
+  gtk_tree_view_clamp_column_visible (tree_view,
+                                     tree_view->priv->focus_column, TRUE);
 }
 
 static void
@@ -8801,23 +9811,25 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
   GtkRBTree *cursor_tree;
   GtkRBNode *cursor_node;
   GtkTreePath *path;
+  GtkTreePath *old_path;
 
   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
     return;
 
   g_return_if_fail (tree_view->priv->tree != NULL);
 
+  gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
+
+  cursor_tree = tree_view->priv->tree;
+  cursor_node = cursor_tree->root;
+
   if (count == -1)
     {
-      cursor_tree = tree_view->priv->tree;
-      cursor_node = cursor_tree->root;
       while (cursor_node && cursor_node->left != cursor_tree->nil)
        cursor_node = cursor_node->left;
     }
   else
     {
-      cursor_tree = tree_view->priv->tree;
-      cursor_node = cursor_tree->root;
       do
        {
          while (cursor_node && cursor_node->right != cursor_tree->nil)
@@ -8832,7 +9844,17 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
     }
 
   path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
-  gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+
+  if (gtk_tree_path_compare (old_path, path))
+    {
+      gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+    }
+  else
+    {
+      gtk_widget_error_bell (GTK_WIDGET (tree_view));
+    }
+
+  gtk_tree_path_free (old_path);
   gtk_tree_path_free (path);
 }
 
@@ -9062,17 +10084,12 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
 
   return TRUE;
 }
-
 static gboolean
 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
 {
-  GDK_THREADS_ENTER ();
-
   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
   tree_view->priv->typeselect_flush_timeout = 0;
 
-  GDK_THREADS_LEAVE ();
-
   return FALSE;
 }
 
@@ -9163,7 +10180,7 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
                    "activate", G_CALLBACK (gtk_tree_view_search_activate),
                    tree_view);
   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
-                   "preedit-changed",
+                   "preedit_changed",
                    G_CALLBACK (gtk_tree_view_search_preedit_changed),
                    tree_view);
   gtk_container_add (GTK_CONTAINER (vbox),
@@ -9238,7 +10255,7 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
     }
 
   tree_view->priv->typeselect_flush_timeout =
-    g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+    gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
                   (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
                   tree_view);
 
@@ -9410,9 +10427,12 @@ gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
        }
       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
 
-      /* update our dy and top_row */
-      tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
-      gtk_tree_view_dy_to_top_row (tree_view);
+      if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
+        {
+          /* update our dy and top_row */
+          tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
+          gtk_tree_view_dy_to_top_row (tree_view);
+       }
     }
 }
 
@@ -9502,6 +10522,12 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
       gtk_tree_view_stop_editing (tree_view, TRUE);
 
+      if (tree_view->priv->expand_collapse_timeout)
+        {
+          g_source_remove (tree_view->priv->expand_collapse_timeout);
+          tree_view->priv->expand_collapse_timeout = 0;
+       }
+
       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
                                            gtk_tree_view_row_changed,
                                            tree_view);
@@ -9852,6 +10878,8 @@ gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
  * gtk_tree_view_get_headers_clickable:
  * @tree_view: A #GtkTreeView.
  *
+ * Returns whether all header columns are clickable.
+ *
  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
  *
  * Since: 2.10
@@ -10087,7 +11115,7 @@ gtk_tree_view_insert_column (GtkTreeView       *tree_view,
  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
  * @position.  If @position is -1, then the newly created column is inserted at
  * the end.  The column is initialized with the attributes given. If @tree_view
- * has "fixed_height" mode enabled, then @column must have its sizing
+ * has "fixed_height" mode enabled, then the new column will have its sizing
  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
  *
  * Return value: The number of columns in @tree_view after insertion.
@@ -10107,6 +11135,8 @@ gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
 
   column = gtk_tree_view_column_new ();
+  if (tree_view->priv->fixed_height_mode)
+    gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
 
   gtk_tree_view_column_set_title (column, title);
   gtk_tree_view_column_pack_start (column, cell, TRUE);
@@ -10143,7 +11173,7 @@ gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
  * attributes (normally using data from the model). See also
  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
- * If @tree_view has "fixed_height" mode enabled, then @column must have its
+ * If @tree_view has "fixed_height" mode enabled, then the new column will have its
  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
  *
  * Return value: number of columns in the tree view post-insert
@@ -10162,6 +11192,8 @@ gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_vie
   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
 
   column = gtk_tree_view_column_new ();
+  if (tree_view->priv->fixed_height_mode)
+    gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
 
   gtk_tree_view_column_set_title (column, title);
   gtk_tree_view_column_pack_start (column, cell, TRUE);
@@ -10373,7 +11405,7 @@ gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
  *
  * Scrolls the tree view such that the top-left corner of the visible
  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
- * in tree window coordinates.  The @tree_view must be realized before
+ * in tree coordinates.  The @tree_view must be realized before
  * this function is called.  If it isn't, you probably want to be
  * using gtk_tree_view_scroll_to_cell().
  *
@@ -10479,10 +11511,11 @@ gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
       GdkRectangle vis_rect;
       gint dest_x, dest_y;
 
-      gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
-      gtk_tree_view_tree_window_to_tree_coords (tree_view, cell_rect.x, cell_rect.y, &(cell_rect.x), &(cell_rect.y));
+      gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
 
+      cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
+
       dest_x = vis_rect.x;
       dest_y = vis_rect.y;
 
@@ -10603,15 +11636,7 @@ gtk_tree_view_expand_all (GtkTreeView *tree_view)
 static gboolean
 expand_collapse_timeout (gpointer data)
 {
-  gboolean retval;
-
-  GDK_THREADS_ENTER ();
-
-  retval = do_expand_collapse (data);
-
-  GDK_THREADS_LEAVE ();
-
-  return retval;
+  return do_expand_collapse (data);
 }
 
 static gboolean
@@ -10818,6 +11843,9 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
 
   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
 
+  if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
+    return FALSE;
+
   if (expand)
     return FALSE;
 
@@ -10849,7 +11877,7 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
 
   if (animate)
     {
-      tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
+      tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
       tree_view->priv->expanded_collapsed_node = node;
       tree_view->priv->expanded_collapsed_tree = tree;
 
@@ -10859,7 +11887,7 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
   install_presize_handler (tree_view);
 
   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
-  if (open_all)
+  if (open_all && node->children)
     {
       _gtk_rbtree_traverse (node->children,
                             node->children->root,
@@ -11053,7 +12081,7 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
   
   if (animate)
     {
-      tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
+      tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
       tree_view->priv->expanded_collapsed_node = node;
       tree_view->priv->expanded_collapsed_tree = tree;
 
@@ -11493,23 +12521,29 @@ gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
 /**
  * gtk_tree_view_get_path_at_pos:
  * @tree_view: A #GtkTreeView.
- * @x: The x position to be identified.
- * @y: The y position to be identified.
+ * @x: The x position to be identified (relative to bin_window).
+ * @y: The y position to be identified (relative to bin_window).
  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
  *
- * Finds the path at the point (@x, @y), relative to widget coordinates.  That
- * is, @x and @y are relative to an events coordinates. @x and @y must come
- * from an event on the @tree_view only where <literal>event->window ==
- * gtk_tree_view_get_bin (<!-- -->)</literal>. It is primarily for things 
- * like popup menus. If @path is non-%NULL, then it will be filled with the 
- * #GtkTreePath at that point.  This path should be freed with gtk_tree_path_free().  
- * If @column is non-%NULL, then it will be filled with the column at that point.
- * @cell_x and @cell_y return the coordinates relative to the cell background
- * (i.e. the @background_area passed to gtk_cell_renderer_render()).  This
- * function is only meaningful if @tree_view is realized.
+ * Finds the path at the point (@x, @y), relative to bin_window coordinates
+ * (please see gtk_tree_view_get_bin_window()).
+ * That is, @x and @y are relative to an events coordinates. @x and @y must
+ * come from an event on the @tree_view only where <literal>event->window ==
+ * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
+ * things like popup menus. If @path is non-%NULL, then it will be filled
+ * with the #GtkTreePath at that point.  This path should be freed with
+ * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
+ * with the column at that point.  @cell_x and @cell_y return the coordinates
+ * relative to the cell background (i.e. the @background_area passed to
+ * gtk_cell_renderer_render()).  This function is only meaningful if
+ * @tree_view is realized.
+ *
+ * For converting widget coordinates (eg. the ones you get from
+ * GtkWidget::query-tooltip), please see
+ * gtk_tree_view_convert_widget_to_bin_window_coords().
  *
  * Return value: %TRUE if a row exists at that coordinate.
  **/
@@ -11622,7 +12656,7 @@ gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
  * @rect: rectangle to fill with cell rect
  *
- * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * Fills the bounding rectangle in bin_window coordinates for the cell at the
  * row specified by @path and the column specified by @column.  If @path is
  * %NULL, or points to a path not currently displayed, the @y and @height fields
  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
@@ -11677,13 +12711,24 @@ gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
 
       if (column &&
-         gtk_tree_view_is_expander_column (tree_view, column) &&
-         TREE_VIEW_DRAW_EXPANDERS (tree_view))
+         gtk_tree_view_is_expander_column (tree_view, column))
        {
-         gint depth = gtk_tree_path_get_depth (path) - 1;
+         gint depth = gtk_tree_path_get_depth (path);
+         gboolean rtl;
+
+         rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
+
+         if (!rtl)
+           rect->x += (depth - 1) * tree_view->priv->level_indentation;
+         rect->width -= (depth - 1) * tree_view->priv->level_indentation;
+
+         if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+           {
+             if (!rtl)
+               rect->x += depth * tree_view->priv->expander_size;
+             rect->width -= depth * tree_view->priv->expander_size;
+           }
 
-         rect->x += depth * tree_view->priv->expander_size;
-         rect->width -= depth * tree_view->priv->expander_size;
          rect->width = MAX (rect->width, 0);
        }
     }
@@ -11696,16 +12741,15 @@ gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
  * @rect: rectangle to fill with cell background rect
  *
- * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * Fills the bounding rectangle in bin_window coordinates for the cell at the
  * row specified by @path and the column specified by @column.  If @path is
  * %NULL, or points to a node not found in the tree, the @y and @height fields of
  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
  * fields will be filled with 0.  The returned rectangle is equivalent to the
  * @background_area passed to gtk_cell_renderer_render().  These background
- * areas tile to cover the entire tree window (except for the area used for
- * header buttons). Contrast with the @cell_area, returned by
- * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
- * surrounding borders and the tree expander area.
+ * areas tile to cover the entire bin window.  Contrast with the @cell_area,
+ * returned by gtk_tree_view_get_cell_area(), which returns only the cell
+ * itself, excluding surrounding borders and the tree expander area.
  *
  **/
 void
@@ -11754,10 +12798,10 @@ gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
  * @visible_rect: rectangle to fill
  *
  * Fills @visible_rect with the currently-visible region of the
- * buffer, in tree coordinates. Convert to widget coordinates with
- * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
- * 0,0 for row 0 of the tree, and cover the entire scrollable area of
- * the tree.
+ * buffer, in tree coordinates. Convert to bin_window coordinates with
+ * gtk_tree_view_convert_tree_to_bin_window_coords().
+ * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
+ * scrollable area of the tree.
  **/
 void
 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
@@ -11781,13 +12825,18 @@ gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
 /**
  * gtk_tree_view_widget_to_tree_coords:
  * @tree_view: a #GtkTreeView
- * @wx: widget X coordinate
- * @wy: widget Y coordinate
+ * @wx: X coordinate relative to bin_window
+ * @wy: Y coordinate relative to bin_window
  * @tx: return location for tree X coordinate
  * @ty: return location for tree Y coordinate
  *
- * Converts widget coordinates to coordinates for the
- * tree window (the full scrollable area of the tree).
+ * Converts bin_window coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Deprecated: 2.12: Due to historial reasons the name of this function is
+ * incorrect.  For converting coordinates relative to the widget to
+ * bin_window coordinates, please see
+ * gtk_tree_view_convert_widget_to_bin_window_coords().
  *
  **/
 void
@@ -11805,31 +12854,21 @@ gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
     *ty = wy + tree_view->priv->dy;
 }
 
-static void
-gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
-                                         gint         wx,
-                                         gint         wy,
-                                         gint        *tx,
-                                         gint        *ty)
-{
-  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-
-  if (tx)
-    *tx = wx;
-  if (ty)
-    *ty = wy + tree_view->priv->dy;
-}
-
 /**
  * gtk_tree_view_tree_to_widget_coords:
  * @tree_view: a #GtkTreeView
  * @tx: tree X coordinate
  * @ty: tree Y coordinate
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
+ * @wx: return location for X coordinate relative to bin_window
+ * @wy: return location for Y coordinate relative to bin_window
  *
  * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to widget coordinates.
+ * to bin_window coordinates.
+ *
+ * Deprecated: 2.12: Due to historial reasons the name of this function is
+ * incorrect.  For converting bin_window coordinates to coordinates relative
+ * to bin_window, please see
+ * gtk_tree_view_convert_bin_window_to_widget_coords().
  *
  **/
 void
@@ -11847,6 +12886,185 @@ gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
     *wy = ty - tree_view->priv->dy;
 }
 
+
+/**
+ * gtk_tree_view_convert_widget_to_tree_coords:
+ * @tree_view: a #GtkTreeView
+ * @wx: X coordinate relative to the widget
+ * @wy: Y coordinate relative to the widget
+ * @tx: return location for tree X coordinate
+ * @ty: return location for tree Y coordinate
+ *
+ * Converts widget coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
+                                             gint         wx,
+                                             gint         wy,
+                                             gint        *tx,
+                                             gint        *ty)
+{
+  gint x, y;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
+                                                    wx, wy,
+                                                    &x, &y);
+  gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
+                                                  x, y,
+                                                  tx, ty);
+}
+
+/**
+ * gtk_tree_view_convert_tree_to_widget_coords:
+ * @tree_view: a #GtkTreeView
+ * @tx: X coordinate relative to the tree
+ * @ty: Y coordinate relative to the tree
+ * @wx: return location for widget X coordinate
+ * @wy: return location for widget Y coordinate
+ *
+ * Converts tree coordinates (coordinates in full scrollable area of the tree)
+ * to widget coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
+                                             gint         tx,
+                                             gint         ty,
+                                             gint        *wx,
+                                             gint        *wy)
+{
+  gint x, y;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
+                                                  tx, ty,
+                                                  &x, &y);
+  gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+                                                    x, y,
+                                                    wx, wy);
+}
+
+/**
+ * gtk_tree_view_convert_widget_to_bin_window_coords:
+ * @tree_view: a #GtkTreeView
+ * @wx: X coordinate relative to the widget
+ * @wy: Y coordinate relative to the widget
+ * @bx: return location for bin_window X coordinate
+ * @by: return location for bin_window Y coordinate
+ *
+ * Converts widget coordinates to coordinates for the bin_window
+ * (see gtk_tree_view_get_bin_window()).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
+                                                   gint         wx,
+                                                   gint         wy,
+                                                   gint        *bx,
+                                                   gint        *by)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (bx)
+    *bx = wx + tree_view->priv->hadjustment->value;
+  if (by)
+    *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
+}
+
+/**
+ * gtk_tree_view_convert_bin_window_to_widget_coords:
+ * @tree_view: a #GtkTreeView
+ * @bx: bin_window X coordinate
+ * @by: bin_window Y coordinate
+ * @wx: return location for widget X coordinate
+ * @wy: return location for widget Y coordinate
+ *
+ * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
+ * to widget relative coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
+                                                   gint         bx,
+                                                   gint         by,
+                                                   gint        *wx,
+                                                   gint        *wy)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (wx)
+    *wx = bx - tree_view->priv->hadjustment->value;
+  if (wy)
+    *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
+}
+
+/**
+ * gtk_tree_view_convert_tree_to_bin_window_coords:
+ * @tree_view: a #GtkTreeView
+ * @tx: tree X coordinate
+ * @ty: tree Y coordinate
+ * @bx: return location for X coordinate relative to bin_window
+ * @by: return location for Y coordinate relative to bin_window
+ *
+ * Converts tree coordinates (coordinates in full scrollable area of the tree)
+ * to bin_window coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
+                                                 gint         tx,
+                                                 gint         ty,
+                                                 gint        *bx,
+                                                 gint        *by)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (bx)
+    *bx = tx;
+  if (by)
+    *by = ty - tree_view->priv->dy;
+}
+
+/**
+ * gtk_tree_view_convert_bin_window_to_tree_coords:
+ * @tree_view: a #GtkTreeView
+ * @bx: X coordinate relative to bin_window
+ * @by: Y coordinate relative to bin_window
+ * @tx: return location for tree X coordinate
+ * @ty: return location for tree Y coordinate
+ *
+ * Converts bin_window coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
+                                                 gint         bx,
+                                                 gint         by,
+                                                 gint        *tx,
+                                                 gint        *ty)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (tx)
+    *tx = bx;
+  if (ty)
+    *ty = by + tree_view->priv->dy;
+}
+
+
+
 /**
  * gtk_tree_view_get_visible_range:
  * @tree_view: A #GtkTreeView
@@ -12166,7 +13384,8 @@ gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
  * @path: Return location for the path of the highlighted row, or %NULL.
  * @pos: Return location for the drop position, or %NULL
  * 
- * Determines the destination row for a given position.
+ * Determines the destination row for a given position.  @drag_x and
+ * @drag_y are expected to be in widget coordinates.
  * 
  * Return value: whether there is a row at the given position.
  **/
@@ -12178,6 +13397,7 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
                                    GtkTreeViewDropPosition *pos)
 {
   gint cell_y;
+  gint bin_x, bin_y;
   gdouble offset_into_row;
   gdouble third;
   GdkRectangle cell;
@@ -12204,10 +13424,12 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
    * in the bottom third, drop after that row; if in the middle,
    * and the row has children, drop into the row.
    */
+  gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
+                                                    &bin_x, &bin_y);
 
   if (!gtk_tree_view_get_path_at_pos (tree_view,
-                                      drag_x,
-                                     drag_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
+                                     bin_x,
+                                     bin_y,
                                       &tmp_path,
                                       &column,
                                       NULL,
@@ -12282,6 +13504,7 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
   GdkDrawable *drawable;
   gint bin_window_width;
   gboolean is_separator = FALSE;
+  gboolean rtl;
 
   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
   g_return_val_if_fail (path != NULL, NULL);
@@ -12338,7 +13561,11 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
                       bin_window_width + 2,
                       background_area.height + 2);
 
-  for (list = tree_view->priv->columns; list; list = list->next)
+  rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
+
+  for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+      list;
+      list = (rtl ? list->prev : list->next))
     {
       GtkTreeViewColumn *column = list->data;
       GdkRectangle cell_area;
@@ -12354,17 +13581,27 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
       background_area.x = cell_offset;
       background_area.width = column->width;
 
+      gtk_widget_style_get (widget,
+                           "vertical-separator", &vertical_separator,
+                           NULL);
+
       cell_area = background_area;
 
-      gtk_widget_style_get (widget, "vertical-separator", &vertical_separator, NULL);
       cell_area.y += vertical_separator / 2;
       cell_area.height -= vertical_separator;
 
-      if (gtk_tree_view_is_expander_column (tree_view, column) &&
-          TREE_VIEW_DRAW_EXPANDERS(tree_view))
+      if (gtk_tree_view_is_expander_column (tree_view, column))
         {
-          cell_area.x += depth * tree_view->priv->expander_size;
-          cell_area.width -= depth * tree_view->priv->expander_size;
+         if (!rtl)
+           cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
+         cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
+
+          if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
+           {
+             if (!rtl)
+               cell_area.x += depth * tree_view->priv->expander_size;
+             cell_area.width -= depth * tree_view->priv->expander_size;
+           }
         }
 
       if (gtk_tree_view_column_cell_is_visible (column))
@@ -12556,7 +13793,7 @@ gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
                                     GtkDestroyNotify            search_destroy)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-  g_return_if_fail (search_equal_func !=NULL);
+  g_return_if_fail (search_equal_func != NULL);
 
   if (tree_view->priv->search_destroy)
     (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
@@ -12662,9 +13899,10 @@ gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
 /**
  * gtk_tree_view_set_search_position_func:
  * @tree_view: A #GtkTreeView
- * @search_position_func: the function to use to position the search dialog
- * @ser_data: user data to pass to @search_position_func, or %NULL
- * @destroy: Destroy notifier for @search_position_data, or %NULL
+ * @func: the function to use to position the search dialog, or %NULL
+ *    to use the default search position function
+ * @data: user data to pass to @func, or %NULL
+ * @destroy: Destroy notifier for @data, or %NULL
  *
  * Sets the function to use when positioning the seach dialog.
  *
@@ -12677,7 +13915,6 @@ gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view
                                        GDestroyNotify                 destroy)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-  g_return_if_fail (func !=NULL);
 
   if (tree_view->priv->search_position_destroy)
     (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
@@ -12727,10 +13964,14 @@ gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
       tree_view->priv->typeselect_flush_timeout = 0;
     }
        
-  /* send focus-in event */
-  send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
-  gtk_widget_hide (search_dialog);
-  gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+  if (GTK_WIDGET_VISIBLE (search_dialog))
+    {
+      /* send focus-in event */
+      send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
+      gtk_widget_hide (search_dialog);
+      gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+      send_focus_change (GTK_WIDGET (tree_view), TRUE);
+    }
 }
 
 static void
@@ -12799,7 +14040,7 @@ gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
     {
       g_source_remove (tree_view->priv->typeselect_flush_timeout);
       tree_view->priv->typeselect_flush_timeout =
-       g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+       gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
                       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
                       tree_view);
     }
@@ -12837,12 +14078,8 @@ gtk_tree_view_real_search_enable_popdown (gpointer data)
 {
   GtkTreeView *tree_view = (GtkTreeView *)data;
 
-  GDK_THREADS_ENTER ();
-
   tree_view->priv->disable_popdown = 0;
 
-  GDK_THREADS_LEAVE ();
-
   return FALSE;
 }
 
@@ -12850,7 +14087,7 @@ static void
 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
                                     gpointer   data)
 {
-  g_timeout_add (200, gtk_tree_view_real_search_enable_popdown, data);
+  gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
 }
 
 static gboolean
@@ -12898,6 +14135,17 @@ gtk_tree_view_search_scroll_event (GtkWidget *widget,
       retval = TRUE;
     }
 
+  /* renew the flush timeout */
+  if (retval && tree_view->priv->typeselect_flush_timeout
+      && !tree_view->priv->search_custom_entry_set)
+    {
+      g_source_remove (tree_view->priv->typeselect_flush_timeout);
+      tree_view->priv->typeselect_flush_timeout =
+       gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+                      (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
+                      tree_view);
+    }
+
   return retval;
 }
 
@@ -12925,28 +14173,36 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
   /* select previous matching iter */
   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
     {
-      gtk_tree_view_search_move (widget, tree_view, TRUE);
+      if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
+        gtk_widget_error_bell (widget);
+
       retval = TRUE;
     }
 
   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
       && (event->keyval == GDK_g || event->keyval == GDK_G))
     {
-      gtk_tree_view_search_move (widget, tree_view, TRUE);
+      if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
+        gtk_widget_error_bell (widget);
+
       retval = TRUE;
     }
 
   /* select next matching iter */
   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
     {
-      gtk_tree_view_search_move (widget, tree_view, FALSE);
+      if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
+        gtk_widget_error_bell (widget);
+
       retval = TRUE;
     }
 
   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
       && (event->keyval == GDK_g || event->keyval == GDK_G))
     {
-      gtk_tree_view_search_move (widget, tree_view, FALSE);
+      if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
+        gtk_widget_error_bell (widget);
+
       retval = TRUE;
     }
 
@@ -12956,7 +14212,7 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
     {
       g_source_remove (tree_view->priv->typeselect_flush_timeout);
       tree_view->priv->typeselect_flush_timeout =
-       g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+       gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
                       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
                       tree_view);
     }
@@ -12964,7 +14220,10 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
   return retval;
 }
 
-static void
+/*  this function returns FALSE if there is a search string but
+ *  nothing was found, and TRUE otherwise.
+ */
+static gboolean
 gtk_tree_view_search_move (GtkWidget   *window,
                           GtkTreeView *tree_view,
                           gboolean     up)
@@ -12979,15 +14238,17 @@ gtk_tree_view_search_move (GtkWidget   *window,
 
   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
 
-  g_return_if_fail (text != NULL);
+  g_return_val_if_fail (text != NULL, FALSE);
+
+  len = strlen (text);
 
   if (up && tree_view->priv->selected_iter == 1)
-    return;
+    return strlen (text) < 1;
 
   len = strlen (text);
 
   if (len < 1)
-    return;
+    return TRUE;
 
   model = gtk_tree_view_get_model (tree_view);
   selection = gtk_tree_view_get_selection (tree_view);
@@ -12995,7 +14256,7 @@ gtk_tree_view_search_move (GtkWidget   *window,
   /* search */
   gtk_tree_selection_unselect_all (selection);
   if (!gtk_tree_model_get_iter_first (model, &iter))
-    return;
+    return TRUE;
 
   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
                                   &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
@@ -13004,6 +14265,7 @@ gtk_tree_view_search_move (GtkWidget   *window,
     {
       /* found */
       tree_view->priv->selected_iter += up?(-1):(1);
+      return TRUE;
     }
   else
     {
@@ -13013,6 +14275,7 @@ gtk_tree_view_search_move (GtkWidget   *window,
       gtk_tree_view_search_iter (model, selection,
                                 &iter, text,
                                 &count, tree_view->priv->selected_iter);
+      return FALSE;
     }
 }
 
@@ -13203,11 +14466,11 @@ gtk_tree_view_search_init (GtkWidget   *entry,
   /* search */
   gtk_tree_selection_unselect_all (selection);
   if (tree_view->priv->typeselect_flush_timeout
-      && tree_view->priv->search_custom_entry_set)
+      && !tree_view->priv->search_custom_entry_set)
     {
       g_source_remove (tree_view->priv->typeselect_flush_timeout);
       tree_view->priv->typeselect_flush_timeout =
-       g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+       gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
                       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
                       tree_view);
     }
@@ -13292,12 +14555,6 @@ gtk_tree_view_start_editing (GtkTreeView *tree_view,
                               tree_view->priv->focus_column,
                               &cell_area);
 
-  if (gtk_tree_view_is_expander_column (tree_view, tree_view->priv->focus_column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
-    {
-      cell_area.x += tree_view->priv->expander_size;
-      cell_area.width -= tree_view->priv->expander_size;
-    }
-
   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
                                        &editable_widget,
                                        NULL,
@@ -13315,6 +14572,7 @@ gtk_tree_view_start_editing (GtkTreeView *tree_view,
 
          area = cell_area;
          cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
+
          _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
 
          area.x += left;
@@ -13344,6 +14602,7 @@ gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
                                  guint              flags)
 {
   gint pre_val = tree_view->priv->vadjustment->value;
+  GtkRequisition requisition;
 
   tree_view->priv->edited_column = column;
   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
@@ -13352,12 +14611,29 @@ gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
 
   cell_area->y += pre_val - tree_view->priv->vadjustment->value;
 
+  gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
+
   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
-  gtk_tree_view_put (tree_view,
-                    GTK_WIDGET (cell_editable),
-                    cell_area->x, cell_area->y, cell_area->width, cell_area->height);
+
+  if (requisition.height < cell_area->height)
+    {
+      gint diff = cell_area->height - requisition.height;
+      gtk_tree_view_put (tree_view,
+                        GTK_WIDGET (cell_editable),
+                        cell_area->x, cell_area->y + diff/2,
+                        cell_area->width, requisition.height);
+    }
+  else
+    {
+      gtk_tree_view_put (tree_view,
+                        GTK_WIDGET (cell_editable),
+                        cell_area->x, cell_area->y,
+                        cell_area->width, cell_area->height);
+    }
+
   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
                                   (GdkEvent *)event);
+
   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
   g_signal_connect (cell_editable, "remove_widget",
                    G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
@@ -13481,6 +14757,73 @@ gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
   return tree_view->priv->hover_expand;
 }
 
+/**
+ * gtk_tree_view_set_rubber_banding:
+ * @tree_view: a #GtkTreeView
+ * @enable: %TRUE to enable rubber banding
+ *
+ * Enables or disables rubber banding in @tree_view.  If the selection mode
+ * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
+ * multiple rows by dragging the mouse.
+ * 
+ * Since: 2.10
+ **/
+void
+gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
+                                 gboolean     enable)
+{
+  enable = enable != FALSE;
+
+  if (enable != tree_view->priv->rubber_banding_enable)
+    {
+      tree_view->priv->rubber_banding_enable = enable;
+
+      g_object_notify (G_OBJECT (tree_view), "rubber-banding");
+    }
+}
+
+/**
+ * gtk_tree_view_get_rubber_banding:
+ * @tree_view: a #GtkTreeView
+ * 
+ * Returns whether rubber banding is turned on for @tree_view.  If the
+ * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
+ * user to select multiple rows by dragging the mouse.
+ * 
+ * Return value: %TRUE if rubber banding in @tree_view is enabled.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
+{
+  return tree_view->priv->rubber_banding_enable;
+}
+
+/**
+ * gtk_tree_view_is_rubber_banding_active:
+ * @tree_view: a #GtkTreeView
+ * 
+ * Returns whether a rubber banding operation is currently being done
+ * in @tree_view.
+ *
+ * Return value: %TRUE if a rubber banding operation is currently being
+ * done in @tree_view.
+ *
+ * Since: 2.12
+ **/
+gboolean
+gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+  if (tree_view->priv->rubber_banding_enable
+      && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+    return TRUE;
+
+  return FALSE;
+}
+
 /**
  * gtk_tree_view_get_row_separator_func:
  * @tree_view: a #GtkTreeView
@@ -13535,8 +14878,15 @@ gtk_tree_view_grab_notify (GtkWidget *widget,
 {
   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
 
+  tree_view->priv->in_grab = !was_grabbed;
+
   if (!was_grabbed)
-    tree_view->priv->pressed_button = -1;
+    {
+      tree_view->priv->pressed_button = -1;
+
+      if (tree_view->priv->rubber_band_status)
+       gtk_tree_view_stop_rubber_band (tree_view);
+    }
 }
 
 static void
@@ -13547,12 +14897,279 @@ gtk_tree_view_state_changed (GtkWidget      *widget,
 
   if (GTK_WIDGET_REALIZED (widget))
     {
-      gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+      gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
     }
 
   gtk_widget_queue_draw (widget);
 }
 
+/**
+ * gtk_tree_view_get_grid_lines:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns which grid lines are enabled in @tree_view.
+ *
+ * Return value: a #GtkTreeViewGridLines value indicating which grid lines
+ * are enabled.
+ *
+ * Since: 2.10
+ */
+GtkTreeViewGridLines
+gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+  return tree_view->priv->grid_lines;
+}
+
+/**
+ * gtk_tree_view_set_grid_lines:
+ * @tree_view: a #GtkTreeView
+ * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
+ * enable.
+ *
+ * Sets which grid lines to draw in @tree_view.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
+                             GtkTreeViewGridLines   grid_lines)
+{
+  GtkTreeViewPrivate *priv;
+  GtkWidget *widget;
+  GtkTreeViewGridLines old_grid_lines;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  priv = tree_view->priv;
+  widget = GTK_WIDGET (tree_view);
+
+  old_grid_lines = priv->grid_lines;
+  priv->grid_lines = grid_lines;
+  
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
+         priv->grid_line_gc)
+       {
+         g_object_unref (priv->grid_line_gc);
+         priv->grid_line_gc = NULL;
+       }
+      
+      if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
+         !priv->grid_line_gc)
+       {
+         gint line_width;
+         guint8 *dash_list;
+
+         gtk_widget_style_get (widget,
+                               "grid-line-width", &line_width,
+                               "grid-line-pattern", (gchar *)&dash_list,
+                               NULL);
+      
+         priv->grid_line_gc = gdk_gc_new (widget->window);
+         gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
+         
+         gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
+                                     GDK_LINE_ON_OFF_DASH,
+                                     GDK_CAP_BUTT, GDK_JOIN_MITER);
+         gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
+
+         g_free (dash_list);
+       }      
+    }
+
+  if (old_grid_lines != grid_lines)
+    {
+      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+      
+      g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
+    }
+}
+
+/**
+ * gtk_tree_view_get_enable_tree_lines:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns whether or not tree lines are drawn in @tree_view.
+ *
+ * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
+ * otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+  return tree_view->priv->tree_lines_enabled;
+}
+
+/**
+ * gtk_tree_view_set_enable_tree_lines:
+ * @tree_view: a #GtkTreeView
+ * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
+ *
+ * Sets whether to draw lines interconnecting the expanders in @tree_view.
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
+                                    gboolean     enabled)
+{
+  GtkTreeViewPrivate *priv;
+  GtkWidget *widget;
+  gboolean was_enabled;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  enabled = enabled != FALSE;
+
+  priv = tree_view->priv;
+  widget = GTK_WIDGET (tree_view);
+
+  was_enabled = priv->tree_lines_enabled;
+
+  priv->tree_lines_enabled = enabled;
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      if (!enabled && priv->tree_line_gc)
+       {
+         g_object_unref (priv->tree_line_gc);
+         priv->tree_line_gc = NULL;
+       }
+      
+      if (enabled && !priv->tree_line_gc)
+       {
+         gint line_width;
+         guint8 *dash_list;
+         gtk_widget_style_get (widget,
+                               "tree-line-width", &line_width,
+                               "tree-line-pattern", (gchar *)&dash_list,
+                               NULL);
+         
+         priv->tree_line_gc = gdk_gc_new (widget->window);
+         gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
+         
+         gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
+                                     GDK_LINE_ON_OFF_DASH,
+                                     GDK_CAP_BUTT, GDK_JOIN_MITER);
+         gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
+
+         g_free (dash_list);
+       }
+    }
+
+  if (was_enabled != enabled)
+    {
+      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+
+      g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
+    }
+}
+
+
+/**
+ * gtk_tree_view_set_show_expanders:
+ * @tree_view: a #GtkTreeView
+ * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
+ *
+ * Sets whether to draw and enable expanders and indent child rows in
+ * @tree_view.  When disabled there will be no expanders visible in trees
+ * and there will be no way to expand and collapse rows by default.  Also
+ * note that hiding the expanders will disable the default indentation.  You
+ * can set a custom indentation in this case using
+ * gtk_tree_view_set_level_indentation().
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
+                                 gboolean     enabled)
+{
+  gboolean was_enabled;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  enabled = enabled != FALSE;
+  was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+
+  if (enabled)
+    GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+  else
+    GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+
+  if (was_enabled != was_enabled)
+    gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/**
+ * gtk_tree_view_get_show_expanders:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns whether or not expanders are drawn in @tree_view.
+ *
+ * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
+ * otherwise.
+ *
+ * Since: 2.12
+ */
+gboolean
+gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+  return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+}
+
+/**
+ * gtk_tree_view_set_level_indentation:
+ * @tree_view: a #GtkTreeView
+ * @indentation: the amount, in pixels, of extra indentation in @tree_view.
+ *
+ * Sets the amount of extra indentation for child levels to use in @tree_view
+ * in addition to the default indentation.  The value should be specified in
+ * pixels, a value of 0 disables this feature and in this case only the default
+ * indentation will be used.
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
+                                    gint         indentation)
+{
+  tree_view->priv->level_indentation = indentation;
+
+  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/**
+ * gtk_tree_view_get_level_indentation:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns the amount, in pixels, of extra indentation for child levels
+ * in @tree_view.
+ *
+ * Return value: the amount of extra indentation for child levels in
+ * @tree_view.  A return value of 0 means that this feature is disabled.
+ *
+ * Since: 2.12
+ */
+gint
+gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+  return tree_view->priv->level_indentation;
+}
+
 #define __GTK_TREE_VIEW_C__
 #include "gtkaliasdef.c"