]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktreeview.c
Merge branch 'master' into toolpalette
[~andy/gtk] / gtk / gtktreeview.c
index e47b3bfb380026637d4d5a724e86e5cc5629b004..3aad46cd4493e57ab2c0cdc433c3be7aa02c2507 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 
-#include <config.h>
+#include "config.h"
 #include <string.h>
 #include <gdk/gdkkeysyms.h>
 
@@ -48,7 +48,7 @@
 
 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
-#define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
+#define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
 #define SCROLL_EDGE_SIZE 15
 #define EXPANDER_EXTRA_PADDING 4
 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
@@ -92,10 +92,10 @@ typedef struct _TreeViewDragInfo TreeViewDragInfo;
 struct _TreeViewDragInfo
 {
   GdkModifierType start_button_mask;
-  GtkTargetList *source_target_list;
+  GtkTargetList *_unused_source_target_list;
   GdkDragAction source_actions;
 
-  GtkTargetList *dest_target_list;
+  GtkTargetList *_unused_dest_target_list;
 
   guint source_set : 1;
   guint dest_set : 1;
@@ -309,90 +309,87 @@ static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
 
 /* Internal functions */
-static gboolean gtk_tree_view_is_expander_column             (GtkTreeView       *tree_view,
-                                                             GtkTreeViewColumn *column);
-static void     gtk_tree_view_add_move_binding               (GtkBindingSet     *binding_set,
-                                                             guint              keyval,
-                                                             guint              modmask,
-                                                             gboolean           add_shifted_binding,
-                                                             GtkMovementStep    step,
-                                                             gint               count);
-static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree);
-static void     gtk_tree_view_queue_draw_path                (GtkTreeView       *tree_view,
-                                                             GtkTreePath       *path,
-                                                             GdkRectangle      *clip_rect);
-static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             GtkRBNode         *node,
-                                                             GdkRectangle      *clip_rect);
-static void     gtk_tree_view_draw_arrow                     (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             GtkRBNode         *node,
-                                                             gint               x,
-                                                             gint               y);
-static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             gint              *x1,
-                                                             gint              *x2);
-static gint     gtk_tree_view_new_column_width               (GtkTreeView       *tree_view,
-                                                             gint               i,
-                                                             gint              *x);
-static void     gtk_tree_view_adjustment_changed             (GtkAdjustment     *adjustment,
-                                                             GtkTreeView       *tree_view);
-static void     gtk_tree_view_build_tree                     (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             GtkTreeIter       *iter,
-                                                             gint               depth,
-                                                             gboolean           recurse);
-static gboolean gtk_tree_view_discover_dirty_iter            (GtkTreeView       *tree_view,
-                                                             GtkTreeIter       *iter,
-                                                             gint               depth,
-                                                             gint              *height,
-                                                             GtkRBNode         *node);
-static void     gtk_tree_view_discover_dirty                 (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             GtkTreeIter       *iter,
-                                                             gint               depth);
-static void     gtk_tree_view_clamp_node_visible             (GtkTreeView       *tree_view,
-                                                             GtkRBTree         *tree,
-                                                             GtkRBNode         *node);
-static void     gtk_tree_view_clamp_column_visible           (GtkTreeView       *tree_view,
-                                                             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);
-static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView       *tree_view,
-                                                             gint               count);
-static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView       *tree_view,
-                                                             gint               count);
-static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView       *tree_view,
-                                                             gint               count);
-static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView       *tree_view,
-                                                             gint               count);
-static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView       *tree_view,
-                                                             GtkTreePath       *path,
-                                                             GtkRBTree         *tree,
-                                                             GtkRBNode         *node,
-                                                             gboolean           animate);
-static gboolean gtk_tree_view_real_expand_row                (GtkTreeView       *tree_view,
-                                                             GtkTreePath       *path,
-                                                             GtkRBTree         *tree,
-                                                             GtkRBNode         *node,
-                                                             gboolean           open_all,
-                                                             gboolean           animate);
-static void     gtk_tree_view_real_set_cursor                (GtkTreeView       *tree_view,
-                                                             GtkTreePath       *path,
-                                                             gboolean           clear_and_select,
-                                                             gboolean           clamp_node);
-static gboolean gtk_tree_view_has_special_cell               (GtkTreeView       *tree_view);
-static void     column_sizing_notify                         (GObject           *object,
-                                                              GParamSpec        *pspec,
-                                                              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);
+static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
+                                                             GtkTreeViewColumn  *column);
+static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
+                                                             guint               keyval,
+                                                             guint               modmask,
+                                                             gboolean            add_shifted_binding,
+                                                             GtkMovementStep     step,
+                                                             gint                count);
+static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
+                                                             GtkRBTree          *tree);
+static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
+                                                             GtkTreePath        *path,
+                                                             const GdkRectangle *clip_rect);
+static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
+                                                             GtkRBTree          *tree,
+                                                             GtkRBNode          *node,
+                                                             const GdkRectangle *clip_rect);
+static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
+                                                             GtkRBTree          *tree,
+                                                             GtkRBNode          *node,
+                                                             gint                x,
+                                                             gint                y);
+static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
+                                                             GtkRBTree          *tree,
+                                                             gint               *x1,
+                                                             gint               *x2);
+static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
+                                                             gint                i,
+                                                             gint               *x);
+static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
+                                                             GtkTreeView        *tree_view);
+static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
+                                                             GtkRBTree          *tree,
+                                                             GtkTreeIter        *iter,
+                                                             gint                depth,
+                                                             gboolean            recurse);
+static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
+                                                             GtkRBTree          *tree,
+                                                             GtkRBNode          *node);
+static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
+                                                             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);
+static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
+                                                             gint                count);
+static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
+                                                             gint                count);
+static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
+                                                             gint                count);
+static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
+                                                             gint                count);
+static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
+                                                             GtkTreePath        *path,
+                                                             GtkRBTree          *tree,
+                                                             GtkRBNode          *node,
+                                                             gboolean            animate);
+static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
+                                                             GtkTreePath        *path,
+                                                             GtkRBTree          *tree,
+                                                             GtkRBNode          *node,
+                                                             gboolean            open_all,
+                                                             gboolean            animate);
+static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
+                                                             GtkTreePath        *path,
+                                                             gboolean            clear_and_select,
+                                                             gboolean            clamp_node);
+static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
+static void     column_sizing_notify                         (GObject            *object,
+                                                              GParamSpec         *pspec,
+                                                              gpointer            data);
+static gboolean expand_collapse_timeout                      (gpointer            data);
+static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
+                                                              GtkRBTree          *tree,
+                                                              GtkRBNode          *node,
+                                                              gboolean            expand);
+static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
+static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
+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);
@@ -595,7 +592,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                    g_param_spec_boolean ("headers-clickable",
                                                         P_("Headers Clickable"),
                                                         P_("Column headers respond to click events"),
-                                                        FALSE,
+                                                        TRUE,
                                                         GTK_PARAM_READWRITE));
 
   g_object_class_install_property (o_class,
@@ -634,7 +631,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                     PROP_SEARCH_COLUMN,
                                     g_param_spec_int ("search-column",
                                                       P_("Search Column"),
-                                                      P_("Model column to search through when searching through code"),
+                                                      P_("Model column to search through during interactive search"),
                                                       -1,
                                                       G_MAXINT,
                                                       -1,
@@ -667,7 +664,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
      * Currently, this works only for the selection modes 
      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
      *
-     * This mode is primarily indended for treeviews in popups, e.g.
+     * This mode is primarily intended for treeviews in popups, e.g.
      * in #GtkComboBox or #GtkEntryCompletion.
      *
      * Since: 2.6
@@ -684,10 +681,10 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
      * GtkTreeView:hover-expand:
      * 
      * Enables of disables the hover expansion mode of @tree_view.
-     * Hover expansion makes rows expand or collaps if the pointer moves 
+     * Hover expansion makes rows expand or collapse if the pointer moves 
      * over them.
      *
-     * This mode is primarily indended for treeviews in popups, e.g.
+     * This mode is primarily intended for treeviews in popups, e.g.
      * in #GtkComboBox or #GtkEntryCompletion.
      *
      * Since: 2.6
@@ -771,7 +768,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
 #define _TREE_VIEW_EXPANDER_SIZE 12
 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
-    
+
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("expander-size",
                                                             P_("Expander Size"),
@@ -863,8 +860,17 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                                GTK_PARAM_READABLE));
 
   /* Signals */
+  /**
+   * GtkTreeView::set-scroll-adjustments
+   * @horizontal: the horizontal #GtkAdjustment
+   * @vertical: the vertical #GtkAdjustment
+   *
+   * Set the scroll adjustments for the tree view. Usually scrolled containers
+   * like #GtkScrolledWindow will emit this signal to connect two instances
+   * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
+   */
   widget_class->set_scroll_adjustments_signal =
-    g_signal_new (I_("set_scroll_adjustments"),
+    g_signal_new (I_("set-scroll-adjustments"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
@@ -890,7 +896,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
    * widget conceptual overview</link> as well as #GtkTreeSelection.
    */
   tree_view_signals[ROW_ACTIVATED] =
-    g_signal_new (I_("row_activated"),
+    g_signal_new (I_("row-activated"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
@@ -994,7 +1000,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
                  NULL, NULL,
-                 _gtk_marshal_NONE__NONE,
+                 _gtk_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
 
   /**
@@ -1009,11 +1015,11 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
                  NULL, NULL,
-                 _gtk_marshal_NONE__NONE,
+                 _gtk_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
 
   tree_view_signals[MOVE_CURSOR] =
-    g_signal_new (I_("move_cursor"),
+    g_signal_new (I_("move-cursor"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
@@ -1024,25 +1030,25 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_INT);
 
   tree_view_signals[SELECT_ALL] =
-    g_signal_new (I_("select_all"),
+    g_signal_new (I_("select-all"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
                  NULL, NULL,
-                 _gtk_marshal_BOOLEAN__NONE,
+                 _gtk_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[UNSELECT_ALL] =
-    g_signal_new (I_("unselect_all"),
+    g_signal_new (I_("unselect-all"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
                  NULL, NULL,
-                 _gtk_marshal_BOOLEAN__NONE,
+                 _gtk_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[SELECT_CURSOR_ROW] =
-    g_signal_new (I_("select_cursor_row"),
+    g_signal_new (I_("select-cursor-row"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
@@ -1052,16 +1058,16 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN);
 
   tree_view_signals[TOGGLE_CURSOR_ROW] =
-    g_signal_new (I_("toggle_cursor_row"),
+    g_signal_new (I_("toggle-cursor-row"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
                  NULL, NULL,
-                 _gtk_marshal_BOOLEAN__NONE,
+                 _gtk_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
-    g_signal_new (I_("expand_collapse_cursor_row"),
+    g_signal_new (I_("expand-collapse-cursor-row"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
@@ -1073,21 +1079,21 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN);
 
   tree_view_signals[SELECT_CURSOR_PARENT] =
-    g_signal_new (I_("select_cursor_parent"),
+    g_signal_new (I_("select-cursor-parent"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
                  NULL, NULL,
-                 _gtk_marshal_BOOLEAN__NONE,
+                 _gtk_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[START_INTERACTIVE_SEARCH] =
-    g_signal_new (I_("start_interactive_search"),
+    g_signal_new (I_("start-interactive-search"),
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
                  NULL, NULL,
-                 _gtk_marshal_BOOLEAN__NONE,
+                 _gtk_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
 
   /* Key bindings */
@@ -1128,178 +1134,180 @@ 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,
+                                "move-cursor", 2,
                                G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
                                G_TYPE_INT, 1);
 
   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
-                                "move_cursor", 2,
+                                "move-cursor", 2,
                                G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
                                G_TYPE_INT, -1);
 
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
-                                "move_cursor", 2,
+                                "move-cursor", 2,
                                G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
                                G_TYPE_INT, 1);
 
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
-                                "move_cursor", 2,
+                                "move-cursor", 2,
                                G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
                                G_TYPE_INT, -1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select_all", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect_all", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect_all", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select_cursor_row", 1,
+  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
+                               G_TYPE_BOOLEAN, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
+  gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
+                               G_TYPE_BOOLEAN, TRUE);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select_cursor_row", 1,
+  gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select_cursor_row", 1,
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select_cursor_row", 1,
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
 
   /* expand and collapse rows */
-  gtk_binding_entry_add_signal (binding_set, GDK_plus, 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_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,
+  gtk_binding_entry_add_signal (binding_set, GDK_plus, 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,
+                                "expand-collapse-cursor-row", 3,
                                 G_TYPE_BOOLEAN, TRUE,
                                 G_TYPE_BOOLEAN, TRUE,
                                 G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                 G_TYPE_BOOLEAN, TRUE,
                                 G_TYPE_BOOLEAN, TRUE,
                                 G_TYPE_BOOLEAN, TRUE);
 
   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
-                                "expand_collapse_cursor_row", 3,
+                                "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_Divide, 0,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                 G_TYPE_BOOLEAN, TRUE,
                                 G_TYPE_BOOLEAN, FALSE,
                                 G_TYPE_BOOLEAN, FALSE);
 
   /* Not doable on US keyboards */
-  gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+  gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 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_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_Right,
                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE,
                                G_TYPE_BOOLEAN, TRUE);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
+  gtk_binding_entry_add_signal (binding_set, GDK_minus, 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_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,
+  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,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 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_Left, 0, "expand_collapse_cursor_row", 3,
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 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,
+  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,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_Left,
                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "expand_collapse_cursor_row", 3,
+                                "expand-collapse-cursor-row", 3,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, FALSE,
                                G_TYPE_BOOLEAN, TRUE);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select_cursor_parent", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start_interactive_search", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start_interactive_search", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
 
   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
 }
@@ -1362,6 +1370,8 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   tree_view->priv->tree_lines_enabled = FALSE;
 
   tree_view->priv->tooltip_column = -1;
+
+  tree_view->priv->post_validation_flag = FALSE;
 }
 
 \f
@@ -1439,6 +1449,7 @@ gtk_tree_view_set_property (GObject         *object,
       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
       break;
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
@@ -1510,7 +1521,7 @@ gtk_tree_view_get_property (GObject    *object,
       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
       break;
     case PROP_TOOLTIP_COLUMN:
-      g_value_set_boolean (value, tree_view->priv->tooltip_column);
+      g_value_set_int (value, tree_view->priv->tooltip_column);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1521,7 +1532,7 @@ gtk_tree_view_get_property (GObject    *object,
 static void
 gtk_tree_view_finalize (GObject *object)
 {
-  (* G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize) (object);
+  G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
 }
 
 \f
@@ -1620,14 +1631,14 @@ gtk_tree_view_destroy (GtkObject *object)
   if (tree_view->priv->column_drop_func_data &&
       tree_view->priv->column_drop_func_data_destroy)
     {
-      (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
+      tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
       tree_view->priv->column_drop_func_data = NULL;
     }
 
   if (tree_view->priv->destroy_count_destroy &&
       tree_view->priv->destroy_count_data)
     {
-      (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
+      tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
       tree_view->priv->destroy_count_data = NULL;
     }
 
@@ -1652,19 +1663,19 @@ gtk_tree_view_destroy (GtkObject *object)
 
   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
     {
-      (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
+      tree_view->priv->search_destroy (tree_view->priv->search_user_data);
       tree_view->priv->search_user_data = NULL;
     }
 
   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
     {
-      (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
+      tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
       tree_view->priv->search_position_user_data = NULL;
     }
 
   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
     {
-      (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
+      tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
       tree_view->priv->row_separator_data = NULL;
     }
   
@@ -1681,8 +1692,7 @@ gtk_tree_view_destroy (GtkObject *object)
       tree_view->priv->vadjustment = NULL;
     }
 
-  if (GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy)
-    (* GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy) (object);
+  GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
 }
 
 \f
@@ -1729,12 +1739,8 @@ gtk_tree_view_map_buttons (GtkTreeView *tree_view)
 static void
 gtk_tree_view_map (GtkWidget *widget)
 {
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GList *tmp_list;
-  GtkTreeView *tree_view;
-
-  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
-  tree_view = GTK_TREE_VIEW (widget);
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
@@ -1760,15 +1766,11 @@ gtk_tree_view_map (GtkWidget *widget)
 static void
 gtk_tree_view_realize (GtkWidget *widget)
 {
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GList *tmp_list;
-  GtkTreeView *tree_view;
   GdkWindowAttr attributes;
   gint attributes_mask;
 
-  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
-  tree_view = GTK_TREE_VIEW (widget);
-
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
   /* Make the main, clipping window */
@@ -1793,14 +1795,14 @@ gtk_tree_view_realize (GtkWidget *widget)
   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
   attributes.height = widget->allocation.height;
-  attributes.event_mask = GDK_EXPOSURE_MASK |
-    GDK_SCROLL_MASK |
-    GDK_POINTER_MOTION_MASK |
-    GDK_ENTER_NOTIFY_MASK |
-    GDK_LEAVE_NOTIFY_MASK |
-    GDK_BUTTON_PRESS_MASK |
-    GDK_BUTTON_RELEASE_MASK |
-    gtk_widget_get_events (widget);
+  attributes.event_mask = (GDK_EXPOSURE_MASK |
+                           GDK_SCROLL_MASK |
+                           GDK_POINTER_MOTION_MASK |
+                           GDK_ENTER_NOTIFY_MASK |
+                           GDK_LEAVE_NOTIFY_MASK |
+                           GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK |
+                           gtk_widget_get_events (widget));
 
   tree_view->priv->bin_window = gdk_window_new (widget->window,
                                                &attributes, attributes_mask);
@@ -1812,12 +1814,12 @@ gtk_tree_view_realize (GtkWidget *widget)
   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
   attributes.height = tree_view->priv->header_height;
   attributes.event_mask = (GDK_EXPOSURE_MASK |
-                          GDK_SCROLL_MASK |
-                          GDK_BUTTON_PRESS_MASK |
-                          GDK_BUTTON_RELEASE_MASK |
-                          GDK_KEY_PRESS_MASK |
-                          GDK_KEY_RELEASE_MASK) |
-    gtk_widget_get_events (widget);
+                           GDK_SCROLL_MASK |
+                           GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK |
+                           GDK_KEY_PRESS_MASK |
+                           GDK_KEY_RELEASE_MASK |
+                           gtk_widget_get_events (widget));
 
   tree_view->priv->header_window = gdk_window_new (widget->window,
                                                   &attributes, attributes_mask);
@@ -1851,15 +1853,10 @@ gtk_tree_view_realize (GtkWidget *widget)
 static void
 gtk_tree_view_unrealize (GtkWidget *widget)
 {
-  GtkTreeView *tree_view;
-  GtkTreeViewPrivate *priv;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+  GtkTreeViewPrivate *priv = tree_view->priv;
   GList *list;
 
-  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
-  tree_view = GTK_TREE_VIEW (widget);
-  priv = tree_view->priv;
-
   if (priv->scroll_timeout != 0)
     {
       g_source_remove (priv->scroll_timeout);
@@ -1878,11 +1875,7 @@ gtk_tree_view_unrealize (GtkWidget *widget)
       priv->open_dest_timeout = 0;
     }
 
-  if (priv->expand_collapse_timeout != 0)
-    {
-      g_source_remove (priv->expand_collapse_timeout);
-      priv->expand_collapse_timeout = 0;
-    }
+  remove_expand_collapse_timeout (tree_view);
   
   if (priv->presize_handler_timer != 0)
     {
@@ -1945,9 +1938,7 @@ gtk_tree_view_unrealize (GtkWidget *widget)
       priv->grid_line_gc = NULL;
     }
 
-  /* GtkWidget::unrealize destroys children and widget->window */
-  if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize) (widget);
+  GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
 }
 
 /* GtkWidget::size_request helper */
@@ -1996,6 +1987,7 @@ gtk_tree_view_update_size (GtkTreeView *tree_view)
 
   tree_view->priv->prev_width = tree_view->priv->width;  
   tree_view->priv->width = 0;
+
   /* keep this in sync with size_allocate below */
   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
     {
@@ -2039,16 +2031,11 @@ static void
 gtk_tree_view_size_request (GtkWidget      *widget,
                            GtkRequisition *requisition)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GList *tmp_list;
 
-  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
-  tree_view = GTK_TREE_VIEW (widget);
-
-  /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
-   * sure we have some size. In practice, with a lot of static lists, this
-   * should get a good width.
+  /* we validate some rows initially just to make sure we have some size. 
+   * In practice, with a lot of static lists, this should get a good width.
    */
   do_validate_rows (tree_view, FALSE);
   gtk_tree_view_size_request_columns (tree_view);
@@ -2162,18 +2149,20 @@ gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view
 
 /* GtkWidget::size_allocate helper */
 static void
-gtk_tree_view_size_allocate_columns (GtkWidget *widget)
+gtk_tree_view_size_allocate_columns (GtkWidget *widget,
+                                    gboolean  *width_changed)
 {
   GtkTreeView *tree_view;
   GList *list, *first_column, *last_column;
   GtkTreeViewColumn *column;
   GtkAllocation allocation;
   gint width = 0;
-  gint extra, extra_per_column;
+  gint extra, extra_per_column, extra_for_last;
   gint full_requested_width = 0;
   gint number_of_expand_columns = 0;
   gboolean column_changed = FALSE;
   gboolean rtl;
+  gboolean update_expand;
   
   tree_view = GTK_TREE_VIEW (widget);
 
@@ -2208,12 +2197,42 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget)
        number_of_expand_columns++;
     }
 
-  extra = MAX (widget->allocation.width - full_requested_width, 0);
+  /* Only update the expand value if the width of the widget has changed,
+   * or the number of expand columns has changed, or if there are no expand
+   * columns, or if we didn't have an size-allocation yet after the
+   * last validated node.
+   */
+  update_expand = (width_changed && *width_changed == TRUE)
+      || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
+      || number_of_expand_columns == 0
+      || tree_view->priv->post_validation_flag == TRUE;
+
+  tree_view->priv->post_validation_flag = FALSE;
+
+  if (!update_expand)
+    {
+      extra = tree_view->priv->last_extra_space;
+      extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
+    }
+  else
+    {
+      extra = MAX (widget->allocation.width - full_requested_width, 0);
+      extra_for_last = 0;
+
+      tree_view->priv->last_extra_space = extra;
+    }
+
   if (number_of_expand_columns > 0)
     extra_per_column = extra/number_of_expand_columns;
   else
     extra_per_column = 0;
 
+  if (update_expand)
+    {
+      tree_view->priv->last_extra_space_per_column = extra_per_column;
+      tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
+    }
+
   for (list = (rtl ? last_column : first_column); 
        list != (rtl ? first_column->prev : last_column->next);
        list = (rtl ? list->prev : list->next)) 
@@ -2269,6 +2288,12 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget)
          column->width += extra;
        }
 
+      /* In addition to expand, the last column can get even more
+       * extra space so all available space is filled up.
+       */
+      if (extra_for_last > 0 && list == last_column)
+       column->width += extra_for_last;
+
       g_object_notify (G_OBJECT (column), "width");
 
       allocation.width = column->width;
@@ -2286,6 +2311,13 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget)
                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
     }
 
+  /* We change the width here.  The user might have been resizing columns,
+   * so the total width of the tree view changes.
+   */
+  tree_view->priv->width = width;
+  if (width_changed)
+    *width_changed = TRUE;
+
   if (column_changed)
     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
 }
@@ -2295,19 +2327,15 @@ static void
 gtk_tree_view_size_allocate (GtkWidget     *widget,
                             GtkAllocation *allocation)
 {
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GList *tmp_list;
-  GtkTreeView *tree_view;
   gboolean width_changed = FALSE;
-  gint old_width = widget->allocation.width;           
-
-  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
+  gint old_width = widget->allocation.width;
 
   if (allocation->width != widget->allocation.width)
     width_changed = TRUE;
-  
-  widget->allocation = *allocation;
 
-  tree_view = GTK_TREE_VIEW (widget);
+  widget->allocation = *allocation;
 
   tmp_list = tree_view->priv->children;
 
@@ -2326,6 +2354,10 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
       gtk_widget_size_allocate (child->widget, &allocation);
     }
 
+  /* We size-allocate the columns first because the width of the
+   * tree view (used in updating the adjustments below) might change.
+   */
+  gtk_tree_view_size_allocate_columns (widget, &width_changed);
 
   tree_view->priv->hadjustment->page_size = allocation->width;
   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
@@ -2334,28 +2366,30 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
 
   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
-     {
+    {
       if (allocation->width < tree_view->priv->width)
-         {
-         if (tree_view->priv->init_hadjust_value)
-           {
-           tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
-           tree_view->priv->init_hadjust_value = FALSE;
-           }
-         else if(allocation->width != old_width)
-           tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
-         else
-           tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
-         }
+        {
+         if (tree_view->priv->init_hadjust_value)
+           {
+             tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
+             tree_view->priv->init_hadjust_value = FALSE;
+           }
+         else if (allocation->width != old_width)
+           {
+             tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
+           }
+         else
+           tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
+       }
       else
-         {
-         tree_view->priv->hadjustment->value = 0;
-         tree_view->priv->init_hadjust_value = TRUE;
-         }
-     }
+        {
+         tree_view->priv->hadjustment->value = 0;
+         tree_view->priv->init_hadjust_value = TRUE;
+       }
+    }
   else
-     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
-        tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
+    if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
+      tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
 
   gtk_adjustment_changed (tree_view->priv->hadjustment);
 
@@ -2395,8 +2429,6 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
                              allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
     }
 
-  gtk_tree_view_size_allocate_columns (widget);
-
   if (tree_view->priv->tree == NULL)
     invalidate_empty_focus (tree_view);
 
@@ -2428,16 +2460,40 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
 static void
 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
 {
-  if (!GTK_WIDGET_HAS_FOCUS (tree_view))
+  if (GTK_WIDGET_CAN_FOCUS (tree_view) && !GTK_WIDGET_HAS_FOCUS (tree_view))
     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
 }
 
+static inline gboolean
+row_is_separator (GtkTreeView *tree_view,
+                 GtkTreeIter *iter,
+                 GtkTreePath *path)
+{
+  gboolean is_separator = FALSE;
+
+  if (tree_view->priv->row_separator_func)
+    {
+      GtkTreeIter tmpiter;
+
+      if (iter)
+       tmpiter = *iter;
+      else
+       gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
+
+      is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
+                                                          &tmpiter,
+                                                          tree_view->priv->row_separator_data);
+    }
+
+  return is_separator;
+}
+
 static gboolean
 gtk_tree_view_button_press (GtkWidget      *widget,
                            GdkEventButton *event)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GList *list;
   GtkTreeViewColumn *column = NULL;
   gint i;
@@ -2445,12 +2501,9 @@ gtk_tree_view_button_press (GtkWidget      *widget,
   GdkRectangle cell_area;
   gint vertical_separator;
   gint horizontal_separator;
+  gboolean path_is_selectable;
   gboolean rtl;
 
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  tree_view = GTK_TREE_VIEW (widget);
   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
   gtk_tree_view_stop_editing (tree_view, FALSE);
   gtk_widget_style_get (widget,
@@ -2524,6 +2577,15 @@ gtk_tree_view_button_press (GtkWidget      *widget,
 
       /* Get the path and the node */
       path = _gtk_tree_view_find_path (tree_view, tree, node);
+      path_is_selectable = !row_is_separator (tree_view, NULL, path);
+
+      if (!path_is_selectable)
+       {
+         gtk_tree_path_free (path);
+         grab_focus_and_unset_draw_keyfocus (tree_view);
+         return TRUE;
+       }
+
       depth = gtk_tree_path_get_depth (path);
       background_area.y = y_offset + event->y;
       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
@@ -2806,7 +2868,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
 
          gtk_grab_add (widget);
          GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
-         column->resized_width = column->width;
+         column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
 
          /* block attached dnd signal handler */
          drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
@@ -2834,6 +2896,7 @@ gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
                                          GdkEventButton *event)
 {
   GtkTreeView *tree_view;
+  GList *l;
   gboolean rtl;
 
   tree_view = GTK_TREE_VIEW (widget);
@@ -2876,7 +2939,8 @@ gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
   tree_view->priv->drag_column = NULL;
   gdk_window_hide (tree_view->priv->drag_window);
 
-  g_list_foreach (tree_view->priv->column_drag_info, (GFunc) g_free, NULL);
+  for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
+    g_slice_free (GtkTreeViewColumnReorder, l->data);
   g_list_free (tree_view->priv->column_drag_info);
   tree_view->priv->column_drag_info = NULL;
   tree_view->priv->cur_reorder = NULL;
@@ -2922,12 +2986,7 @@ static gboolean
 gtk_tree_view_button_release (GtkWidget      *widget,
                              GdkEventButton *event)
 {
-  GtkTreeView *tree_view;
-
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  tree_view = GTK_TREE_VIEW (widget);
+  GtkTreeView *tree_view = GTK_TREE_VIEW (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);
@@ -2979,12 +3038,7 @@ static gboolean
 gtk_tree_view_grab_broken (GtkWidget          *widget,
                           GdkEventGrabBroken *event)
 {
-  GtkTreeView *tree_view;
-
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  tree_view = GTK_TREE_VIEW (widget);
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
 
   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
@@ -3301,6 +3355,10 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
 
          attributes.window_type = GDK_WINDOW_CHILD;
          attributes.wclass = GDK_INPUT_OUTPUT;
+          attributes.x = tree_view->priv->drag_column_x;
+          attributes.y = 0;
+         width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
+         height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
          attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
          attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
          attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
@@ -3308,11 +3366,6 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
          tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
          gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
 
-         width = tree_view->priv->drag_column->button->allocation.width;
-         height = tree_view->priv->drag_column->button->allocation.height;
-         gdk_window_move_resize (tree_view->priv->drag_highlight_window,
-                                 tree_view->priv->drag_column_x, 0, width, height);
-
          mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
          gc = gdk_gc_new (mask);
          col.pixel = 1;
@@ -3368,6 +3421,8 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
          attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
          attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
          attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+          attributes.x = x;
+          attributes.y = y;
          attributes.width = width;
          attributes.height = height;
          tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
@@ -3442,6 +3497,8 @@ gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
          attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
          attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
          attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+          attributes.x = x;
+          attributes.y = y;
          attributes.width = width;
          attributes.height = height;
          tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
@@ -3515,6 +3572,8 @@ gtk_tree_view_motion_resize_column (GtkWidget      *widget,
     {
       column->use_resized_width = TRUE;
       column->resized_width = new_width;
+      if (column->expand)
+       column->resized_width -= tree_view->priv->last_extra_space_per_column;
       gtk_widget_queue_resize (widget);
     }
 
@@ -3635,12 +3694,12 @@ gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
   remove_scroll_timeout (tree_view);
   gtk_grab_remove (GTK_WIDGET (tree_view));
 
-  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
     {
       GtkTreePath *tmp_path;
 
+      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+
       /* 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,
@@ -3696,6 +3755,22 @@ gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
 
   do
     {
+      /* Small optimization by assuming insensitive nodes are never
+       * selected.
+       */
+      if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+        {
+         GtkTreePath *path;
+         gboolean selectable;
+
+         path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
+         selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
+         gtk_tree_path_free (path);
+
+         if (!selectable)
+           goto node_not_selectable;
+       }
+
       if (select)
         {
          if (tree_view->priv->rubber_band_shift)
@@ -3730,6 +3805,7 @@ gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
 
       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
 
+node_not_selectable:
       if (start_node == end_node)
        break;
 
@@ -4117,7 +4193,7 @@ static gboolean
 gtk_tree_view_bin_expose (GtkWidget      *widget,
                          GdkEventExpose *event)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GtkTreePath *path;
   GtkRBTree *tree;
   GList *list;
@@ -4154,12 +4230,8 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   gboolean row_ending_details;
   gboolean draw_vgrid_lines, draw_hgrid_lines;
 
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-
   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
 
-  tree_view = GTK_TREE_VIEW (widget);
-
   gtk_widget_style_get (widget,
                        "horizontal-separator", &horizontal_separator,
                        "vertical-separator", &vertical_separator,
@@ -4274,12 +4346,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
       gboolean is_first = FALSE;
       gboolean is_last = FALSE;
       
-      if (tree_view->priv->row_separator_func)
-       {
-         is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
-                                                                 &iter,
-                                                                 tree_view->priv->row_separator_data);
-       }
+      is_separator = row_is_separator (tree_view, &iter, NULL);
 
       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
 
@@ -4505,69 +4572,6 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                               background_area.y + max_height);
            }
 
-         if (gtk_tree_view_is_expander_column (tree_view, column) &&
-             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)
@@ -4641,6 +4645,79 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                                                   &event->area,
                                                   flags);
            }
+
+         if (gtk_tree_view_is_expander_column (tree_view, column) &&
+             tree_view->priv->tree_lines_enabled)
+           {
+             gint x = background_area.x;
+             gint mult = rtl ? -1 : 1;
+             gint y0 = background_area.y;
+             gint y1 = background_area.y + background_area.height/2;
+             gint y2 = background_area.y + background_area.height;
+
+             if (rtl)
+               x += background_area.width - 1;
+
+             if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
+                 && depth > 1)
+               {
+                 gdk_draw_line (event->window,
+                                tree_view->priv->tree_line_gc,
+                                x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+                                y1,
+                                x + tree_view->priv->expander_size * (depth - 1.1) * mult,
+                                y1);
+               }
+             else if (depth > 1)
+               {
+                 gdk_draw_line (event->window,
+                                tree_view->priv->tree_line_gc,
+                                x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+                                y1,
+                                x + tree_view->priv->expander_size * (depth - 0.5) * mult,
+                                y1);
+               }
+
+             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,
+                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+                                  y0,
+                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+                                  y1);
+                 else
+                   gdk_draw_line (event->window,
+                                  tree_view->priv->tree_line_gc,
+                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+                                  y0,
+                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+                                  y2);
+
+                 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,
+                                      x + tree_view->priv->expander_size * (i - 0.5) * mult,
+                                      y0,
+                                      x + tree_view->priv->expander_size * (i - 0.5) * mult,
+                                      y2);
+
+                     tmp_node = tmp_tree->parent_node;
+                     tmp_tree = tmp_tree->parent_tree;
+                   }
+               }
+           }
+
          if (node == cursor && has_special_cell &&
              ((column == tree_view->priv->focus_column &&
                GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
@@ -4654,6 +4731,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                                                     &event->area,
                                                     flags);
            }
+
          cell_offset += column->width;
        }
 
@@ -4867,11 +4945,7 @@ static gboolean
 gtk_tree_view_expose (GtkWidget      *widget,
                      GdkEventExpose *event)
 {
-  GtkTreeView *tree_view;
-
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-
-  tree_view = GTK_TREE_VIEW (widget);
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
 
   if (event->window == tree_view->priv->bin_window)
     {
@@ -4964,7 +5038,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
            if (!tree_view->priv->column_drop_func)
              return left_column;
 
-           if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
+           if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
              {
                left_column = cur_column;
                continue;
@@ -4976,7 +5050,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
        if (!tree_view->priv->column_drop_func)
          return left_column;
 
-       if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
+       if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
          return left_column;
        else
          return (GtkTreeViewColumn *)0x1;
@@ -5015,7 +5089,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
            if (!tree_view->priv->column_drop_func)
              return left_column;
 
-           if (!(*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
+           if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
              {
                left_column = cur_column;
                continue;
@@ -5027,7 +5101,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
        if (!tree_view->priv->column_drop_func)
          return left_column;
 
-       if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
+       if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
          return left_column;
        else
          return (GtkTreeViewColumn *)0x1;
@@ -5073,7 +5147,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
            if (!tree_view->priv->column_drop_func)
              return left_column;
 
-           if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
+           if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
              return left_column;
 
            cur_column = left_column;
@@ -5083,7 +5157,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
        if (!tree_view->priv->column_drop_func)
          return NULL;
 
-       if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
+       if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
          return NULL;
        else
          return (GtkTreeViewColumn *)0x1;
@@ -5112,7 +5186,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
            if (!tree_view->priv->column_drop_func)
              return left_column;
 
-           if ((*tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
+           if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
              return left_column;
 
            cur_column = left_column;
@@ -5122,7 +5196,7 @@ gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
        if (!tree_view->priv->column_drop_func)
          return NULL;
 
-       if ((*tree_view->priv->column_drop_func) (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
+       if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
          return NULL;
        else
          return (GtkTreeViewColumn *)0x1;
@@ -5295,9 +5369,16 @@ gtk_tree_view_key_press (GtkWidget   *widget,
   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
     return TRUE;
 
+  if (tree_view->priv->search_entry_avoid_unhandled_binding)
+    {
+      tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
+      return FALSE;
+    }
+
   /* 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
+  if (GTK_WIDGET_HAS_FOCUS (tree_view)
+      && tree_view->priv->enable_search
       && !tree_view->priv->search_custom_entry_set)
     {
       GdkEvent *new_event;
@@ -5318,7 +5399,8 @@ gtk_tree_view_key_press (GtkWidget   *widget,
       gtk_widget_realize (tree_view->priv->search_window);
 
       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
-                                       "popup_menu", G_CALLBACK (gtk_true), NULL);
+                                       "popup-menu", G_CALLBACK (gtk_true),
+                                        NULL);
 
       /* Move the entry off screen */
       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
@@ -5371,7 +5453,7 @@ gtk_tree_view_key_release (GtkWidget   *widget,
   if (tree_view->priv->rubber_band_status)
     return TRUE;
 
-  return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
+  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
@@ -5381,15 +5463,11 @@ static gboolean
 gtk_tree_view_enter_notify (GtkWidget        *widget,
                            GdkEventCrossing *event)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GtkRBTree *tree;
   GtkRBNode *node;
   gint new_y;
 
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-
-  tree_view = GTK_TREE_VIEW (widget);
-
   /* Sanity check it */
   if (event->window != tree_view->priv->bin_window)
     return FALSE;
@@ -5397,6 +5475,12 @@ gtk_tree_view_enter_notify (GtkWidget        *widget,
   if (tree_view->priv->tree == NULL)
     return FALSE;
 
+  if (event->mode == GDK_CROSSING_GRAB ||
+      event->mode == GDK_CROSSING_GTK_GRAB ||
+      event->mode == GDK_CROSSING_GTK_UNGRAB ||
+      event->mode == GDK_CROSSING_STATE_CHANGED)
+    return TRUE;
+
   /* find the node internally */
   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
   if (new_y < 0)
@@ -5513,18 +5597,15 @@ validate_row (GtkTreeView *tree_view,
   gboolean draw_vgrid_lines, draw_hgrid_lines;
   gint focus_pad;
   gint grid_line_width;
+  gboolean wide_separators;
+  gint separator_height;
 
   /* double check the row needs validating */
   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
     return FALSE;
 
-  if (tree_view->priv->row_separator_func)
-    {
-      is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
-                                                             iter,
-                                                             tree_view->priv->row_separator_data);
-    }
+  is_separator = row_is_separator (tree_view, iter, NULL);
 
   gtk_widget_style_get (GTK_WIDGET (tree_view),
                        "focus-padding", &focus_pad,
@@ -5532,6 +5613,8 @@ validate_row (GtkTreeView *tree_view,
                        "horizontal-separator", &horizontal_separator,
                        "vertical-separator", &vertical_separator,
                        "grid-line-width", &grid_line_width,
+                        "wide-separators",  &wide_separators,
+                        "separator-height", &separator_height,
                        NULL);
   
   draw_vgrid_lines =
@@ -5578,7 +5661,12 @@ validate_row (GtkTreeView *tree_view,
          height = MAX (height, tree_view->priv->expander_size);
        }
       else
-       height = 2 + 2 * focus_pad;
+        {
+          if (wide_separators)
+            height = separator_height + 2 * focus_pad;
+          else
+            height = 2 + 2 * focus_pad;
+        }
 
       if (gtk_tree_view_is_expander_column (tree_view, column))
         {
@@ -5614,6 +5702,7 @@ validate_row (GtkTreeView *tree_view,
       _gtk_rbtree_node_set_height (tree, node, height);
     }
   _gtk_rbtree_node_mark_valid (tree, node);
+  tree_view->priv->post_validation_flag = TRUE;
 
   return retval;
 }
@@ -5901,16 +5990,24 @@ validate_visible_area (GtkTreeView *tree_view)
   while (area_above > 0)
     {
       _gtk_rbtree_prev_full (tree, node, &tree, &node);
-      if (! gtk_tree_path_prev (above_path) && node != NULL)
-       {
-         gtk_tree_path_free (above_path);
-         above_path = _gtk_tree_view_find_path (tree_view, tree, node);
-       }
-      gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
+
+      /* Always find the new path in the tree.  We cannot just assume
+       * a gtk_tree_path_prev() is enough here, as there might be children
+       * in between this node and the previous sibling node.  If this
+       * appears to be a performance hotspot in profiles, we can look into
+       * intrigate logic for keeping path, node and iter in sync like
+       * we do for forward walks.  (Which will be hard because of the lacking
+       * iter_prev).
+       */
 
       if (node == NULL)
        break;
 
+      gtk_tree_path_free (above_path);
+      above_path = _gtk_tree_view_find_path (tree_view, tree, node);
+
+      gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
+
       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
          GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
        {
@@ -6027,6 +6124,7 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
   gint retval = TRUE;
   GtkTreePath *path = NULL;
   GtkTreeIter iter;
+  GTimer *timer;
   gint i = 0;
 
   gint prev_height = -1;
@@ -6045,6 +6143,9 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
       return FALSE;
     }
 
+  timer = g_timer_new ();
+  g_timer_start (timer);
+
   do
     {
       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
@@ -6122,7 +6223,7 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
 
       i++;
     }
-  while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
+  while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
 
   if (!tree_view->priv->fixed_height_check)
    {
@@ -6147,10 +6248,11 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
       gtk_adjustment_changed (tree_view->priv->vadjustment);
 
       if (queue_resize)
-        gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
+        gtk_widget_queue_resize (GTK_WIDGET (tree_view));
     }
 
   if (path) gtk_tree_path_free (path);
+  g_timer_destroy (timer);
 
   return retval;
 }
@@ -6328,6 +6430,11 @@ gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
   GtkTreePath *path;
   GtkRBTree *tree;
   GtkRBNode *node;
+  int new_dy;
+
+  /* Avoid recursive calls */
+  if (tree_view->priv->in_top_row_to_dy)
+    return;
 
   if (tree_view->priv->top_row)
     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
@@ -6361,16 +6468,17 @@ gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
       return;
     }
 
-  tree_view->priv->dy = _gtk_rbtree_node_find_offset (tree, node);
-  tree_view->priv->dy += tree_view->priv->top_row_dy;
+  new_dy = _gtk_rbtree_node_find_offset (tree, node);
+  new_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;
+  if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+    new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
 
-  tree_view->priv->dy = MAX (0, tree_view->priv->dy);
+  new_dy = MAX (0, new_dy);
 
-  gtk_adjustment_set_value (tree_view->priv->vadjustment,
-                           (gdouble)tree_view->priv->dy);
+  tree_view->priv->in_top_row_to_dy = TRUE;
+  gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
+  tree_view->priv->in_top_row_to_dy = FALSE;
 }
 
 
@@ -6432,9 +6540,9 @@ get_source_row (GdkDragContext *context)
 typedef struct
 {
   GtkTreeRowReference *dest_row;
-  gboolean             path_down_mode;
-  gboolean             empty_view_drop;
-  gboolean             drop_append_mode;
+  guint                path_down_mode   : 1;
+  guint                empty_view_drop  : 1;
+  guint                drop_append_mode : 1;
 }
 DestRow;
 
@@ -6444,10 +6552,9 @@ dest_row_free (gpointer data)
   DestRow *dr = (DestRow *)data;
 
   gtk_tree_row_reference_free (dr->dest_row);
-  g_free (dr);
+  g_slice_free (DestRow, dr);
 }
 
-
 static void
 set_dest_row (GdkDragContext *context,
               GtkTreeModel   *model,
@@ -6465,12 +6572,12 @@ set_dest_row (GdkDragContext *context,
       return;
     }
 
-  dr = g_new0 (DestRow, 1);
+  dr = g_slice_new (DestRow);
 
   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
-  dr->path_down_mode = path_down_mode;
-  dr->empty_view_drop = empty_view_drop;
-  dr->drop_append_mode = drop_append_mode;
+  dr->path_down_mode = path_down_mode != FALSE;
+  dr->empty_view_drop = empty_view_drop != FALSE;
+  dr->drop_append_mode = drop_append_mode != FALSE;
 
   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
                           dr, (GDestroyNotify) dest_row_free);
@@ -6532,30 +6639,10 @@ get_info (GtkTreeView *tree_view)
   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
 }
 
-static void
-clear_source_info (TreeViewDragInfo *di)
-{
-  if (di->source_target_list)
-    gtk_target_list_unref (di->source_target_list);
-
-  di->source_target_list = NULL;
-}
-
-static void
-clear_dest_info (TreeViewDragInfo *di)
-{
-  if (di->dest_target_list)
-    gtk_target_list_unref (di->dest_target_list);
-
-  di->dest_target_list = NULL;
-}
-
 static void
 destroy_info (TreeViewDragInfo *di)
 {
-  clear_source_info (di);
-  clear_dest_info (di);
-  g_free (di);
+  g_slice_free (TreeViewDragInfo, di);
 }
 
 static TreeViewDragInfo*
@@ -6567,7 +6654,7 @@ ensure_info (GtkTreeView *tree_view)
 
   if (di == NULL)
     {
-      di = g_new0 (TreeViewDragInfo, 1);
+      di = g_slice_new0 (TreeViewDragInfo);
 
       g_object_set_data_full (G_OBJECT (tree_view),
                               I_("gtk-tree-view-drag-info"),
@@ -6777,7 +6864,8 @@ set_destination_row (GtkTreeView    *tree_view,
       return FALSE; /* no longer a drop site */
     }
 
-  *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
+  *target = gtk_drag_dest_find_target (widget, context,
+                                       gtk_drag_dest_get_target_list (widget));
   if (*target == GDK_NONE)
     {
       return FALSE;
@@ -6926,6 +7014,7 @@ static gboolean
 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
                                         GdkEventMotion   *event)
 {
+  GtkWidget *widget = GTK_WIDGET (tree_view);
   GdkDragContext *context;
   TreeViewDragInfo *di;
   GtkTreePath *path = NULL;
@@ -6942,7 +7031,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
   if (tree_view->priv->pressed_button < 0)
     goto out;
 
-  if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
+  if (!gtk_drag_check_threshold (widget,
                                  tree_view->priv->press_start_x,
                                  tree_view->priv->press_start_y,
                                  event->x, event->y))
@@ -6979,8 +7068,8 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
 
   retval = TRUE;
 
-  context = gtk_drag_begin (GTK_WIDGET (tree_view),
-                            di->source_target_list,
+  context = gtk_drag_begin (widget,
+                            gtk_drag_source_get_target_list (widget),
                             di->source_actions,
                             button,
                             (GdkEvent*)event);
@@ -7415,14 +7504,10 @@ static void
 gtk_tree_view_remove (GtkContainer *container,
                      GtkWidget    *widget)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (container);
   GtkTreeViewChild *child = NULL;
   GList *tmp_list;
 
-  g_return_if_fail (GTK_IS_TREE_VIEW (container));
-
-  tree_view = GTK_TREE_VIEW (container);
-
   tmp_list = tree_view->priv->children;
   while (tmp_list)
     {
@@ -7433,7 +7518,7 @@ gtk_tree_view_remove (GtkContainer *container,
 
          tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
          g_list_free_1 (tmp_list);
-         g_free (child);
+         g_slice_free (GtkTreeViewChild, child);
          return;
        }
 
@@ -7461,16 +7546,11 @@ gtk_tree_view_forall (GtkContainer *container,
                      GtkCallback   callback,
                      gpointer      callback_data)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (container);
   GtkTreeViewChild *child = NULL;
   GtkTreeViewColumn *column;
   GList *tmp_list;
 
-  g_return_if_fail (GTK_IS_TREE_VIEW (container));
-  g_return_if_fail (callback != NULL);
-
-  tree_view = GTK_TREE_VIEW (container);
-
   tmp_list = tree_view->priv->children;
   while (tmp_list)
     {
@@ -7652,7 +7732,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
     case GTK_DIR_DOWN:
       if (focus_child == NULL)
        {
-         if (tree_view->priv->focus_column != NULL)
+         if (tree_view->priv->focus_column != NULL && GTK_WIDGET_CAN_FOCUS (tree_view->priv->focus_column->button))
            focus_child = tree_view->priv->focus_column->button;
          else
            focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
@@ -7746,21 +7826,61 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
   return (focus_child != NULL);
 }
 
+/* This function returns in 'path' the first focusable path, if the given path
+ * is already focusable, it's the returned one.
+ */
+static gboolean
+search_first_focusable_path (GtkTreeView  *tree_view,
+                            GtkTreePath **path,
+                            gboolean      search_forward,
+                            GtkRBTree   **new_tree,
+                            GtkRBNode   **new_node)
+{
+  GtkRBTree *tree = NULL;
+  GtkRBNode *node = NULL;
+
+  if (!path || !*path)
+    return FALSE;
+
+  _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
+
+  if (!tree || !node)
+    return FALSE;
+
+  while (node && row_is_separator (tree_view, NULL, *path))
+    {
+      if (search_forward)
+       _gtk_rbtree_next_full (tree, node, &tree, &node);
+      else
+       _gtk_rbtree_prev_full (tree, node, &tree, &node);
+
+      if (*path)
+       gtk_tree_path_free (*path);
+
+      if (node)
+       *path = _gtk_tree_view_find_path (tree_view, tree, node);
+      else
+       *path = NULL;
+    }
+
+  if (new_tree)
+    *new_tree = tree;
+
+  if (new_node)
+    *new_node = node;
+
+  return (*path != NULL);
+}
+
 static gint
 gtk_tree_view_focus (GtkWidget        *widget,
                     GtkDirectionType  direction)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+  GtkContainer *container = GTK_CONTAINER (widget);
   GtkWidget *focus_child;
-  GtkContainer *container;
-
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
-  g_return_val_if_fail (GTK_WIDGET_VISIBLE (widget), FALSE);
-
-  container = GTK_CONTAINER (widget);
-  tree_view = GTK_TREE_VIEW (widget);
 
-  if (!GTK_WIDGET_IS_SENSITIVE (container))
+  if (!GTK_WIDGET_IS_SENSITIVE (container) || !GTK_WIDGET_CAN_FOCUS (widget))
     return FALSE;
 
   focus_child = container->focus_child;
@@ -7810,7 +7930,7 @@ gtk_tree_view_focus (GtkWidget        *widget,
 static void
 gtk_tree_view_grab_focus (GtkWidget *widget)
 {
-  (* GTK_WIDGET_CLASS (gtk_tree_view_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));
 }
@@ -7819,14 +7939,10 @@ static void
 gtk_tree_view_style_set (GtkWidget *widget,
                         GtkStyle *previous_style)
 {
-  GtkTreeView *tree_view;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GList *list;
   GtkTreeViewColumn *column;
 
-  g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
-  tree_view = GTK_TREE_VIEW (widget);
-
   if (GTK_WIDGET_REALIZED (widget))
     {
       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
@@ -7913,7 +8029,7 @@ gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
       tree_view->priv->hadjustment = hadj;
       g_object_ref_sink (tree_view->priv->hadjustment);
 
-      g_signal_connect (tree_view->priv->hadjustment, "value_changed",
+      g_signal_connect (tree_view->priv->hadjustment, "value-changed",
                        G_CALLBACK (gtk_tree_view_adjustment_changed),
                        tree_view);
       need_adjust = TRUE;
@@ -7924,7 +8040,7 @@ gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
       tree_view->priv->vadjustment = vadj;
       g_object_ref_sink (tree_view->priv->vadjustment);
 
-      g_signal_connect (tree_view->priv->vadjustment, "value_changed",
+      g_signal_connect (tree_view->priv->vadjustment, "value-changed",
                        G_CALLBACK (gtk_tree_view_adjustment_changed),
                        tree_view);
       need_adjust = TRUE;
@@ -7996,7 +8112,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 */
+                  /* in bin_window coordinates */
                   gint         x,
                   gint         y,
                   gint         width,
@@ -8007,7 +8123,7 @@ gtk_tree_view_put (GtkTreeView *tree_view,
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
   g_return_if_fail (GTK_IS_WIDGET (child_widget));
 
-  child = g_new (GtkTreeViewChild, 1);
+  child = g_slice_new (GtkTreeViewChild);
 
   child->widget = child_widget;
   child->x = x;
@@ -8389,23 +8505,14 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
   gtk_tree_view_stop_editing (tree_view, TRUE);
 
   /* If we have a node expanded/collapsed timeout, remove it */
-  if (tree_view->priv->expand_collapse_timeout != 0)
-    {
-      g_source_remove (tree_view->priv->expand_collapse_timeout);
-      tree_view->priv->expand_collapse_timeout = 0;
-
-      /* Reset node */
-      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
-      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
-      tree_view->priv->expanded_collapsed_node = NULL;
-    }
+  remove_expand_collapse_timeout (tree_view);
 
   if (tree_view->priv->destroy_count_func)
     {
       gint child_count = 0;
       if (node->children)
        _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
-      (* tree_view->priv->destroy_count_func) (tree_view, path, child_count, tree_view->priv->destroy_count_data);
+      tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
     }
 
   if (tree->root->count == 1)
@@ -8434,18 +8541,6 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
     g_signal_emit_by_name (tree_view->priv->selection, "changed");
 }
 
-static void
-cancel_arrow_animation (GtkTreeView *tree_view)
-{
-  if (tree_view->priv->expand_collapse_timeout)
-    {
-      while (do_expand_collapse (tree_view));
-
-      g_source_remove (tree_view->priv->expand_collapse_timeout);
-      tree_view->priv->expand_collapse_timeout = 0;
-    }
-}
-
 static void
 gtk_tree_view_rows_reordered (GtkTreeModel *model,
                              GtkTreePath  *parent,
@@ -8652,7 +8747,7 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
            {
              gboolean expand;
 
-             g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &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)
@@ -8677,133 +8772,6 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
     gtk_tree_path_free (path);
 }
 
-/* If height is non-NULL, then we set it to be the new height.  if it's all
- * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
- */
-static gboolean
-gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
-                                  GtkTreeIter *iter,
-                                  gint         depth,
-                                  gint        *height,
-                                  GtkRBNode   *node)
-{
-  GtkTreeViewColumn *column;
-  GList *list;
-  gboolean retval = FALSE;
-  gint tmpheight;
-  gint horizontal_separator;
-
-  gtk_widget_style_get (GTK_WIDGET (tree_view),
-                       "horizontal-separator", &horizontal_separator,
-                       NULL);
-
-  if (height)
-    *height = -1;
-
-  for (list = tree_view->priv->columns; list; list = list->next)
-    {
-      gint width;
-      column = list->data;
-      if (column->dirty == TRUE)
-       continue;
-      if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
-       continue;
-      if (!column->visible)
-       continue;
-
-      gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
-                                              GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
-                                              node->children?TRUE:FALSE);
-
-      if (height)
-       {
-         gtk_tree_view_column_cell_get_size (column,
-                                             NULL, NULL, NULL,
-                                             &width, &tmpheight);
-         *height = MAX (*height, tmpheight);
-       }
-      else
-       {
-         gtk_tree_view_column_cell_get_size (column,
-                                             NULL, NULL, NULL,
-                                             &width, NULL);
-       }
-
-      if (gtk_tree_view_is_expander_column (tree_view, column))
-       {
-         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;
-           }
-       }
-      else
-       {
-         if (horizontal_separator + width > column->requested_width)
-           {
-             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
-             retval = TRUE;
-           }
-       }
-    }
-
-  return retval;
-}
-
-static void
-gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
-                             GtkRBTree   *tree,
-                             GtkTreeIter *iter,
-                             gint         depth)
-{
-  GtkRBNode *temp = tree->root;
-  GtkTreeViewColumn *column;
-  GList *list;
-  GtkTreeIter child;
-  gboolean is_all_dirty;
-
-  TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
-
-  while (temp->left != tree->nil)
-    temp = temp->left;
-
-  do
-    {
-      TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
-      is_all_dirty = TRUE;
-      for (list = tree_view->priv->columns; list; list = list->next)
-       {
-         column = list->data;
-         if (column->dirty == FALSE)
-           {
-             is_all_dirty = FALSE;
-             break;
-           }
-       }
-
-      if (is_all_dirty)
-       return;
-
-      gtk_tree_view_discover_dirty_iter (tree_view,
-                                        iter,
-                                        depth,
-                                        NULL,
-                                        temp);
-      if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
-         temp->children != NULL)
-       gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
-      temp = _gtk_rbtree_next (tree, temp);
-    }
-  while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
-}
-
-
 /* Make sure the node is visible vertically */
 static void
 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
@@ -9037,13 +9005,13 @@ gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
 {
   
   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
-                                "move_cursor", 2,
+                                "move-cursor", 2,
                                 G_TYPE_ENUM, step,
                                 G_TYPE_INT, count);
 
   if (add_shifted_binding)
     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
-                                 "move_cursor", 2,
+                                 "move-cursor", 2,
                                  G_TYPE_ENUM, step,
                                  G_TYPE_INT, count);
 
@@ -9051,12 +9019,12 @@ gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
    return;
 
   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
-                                "move_cursor", 2,
+                                "move-cursor", 2,
                                 G_TYPE_ENUM, step,
                                 G_TYPE_INT, count);
 
   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
-                                "move_cursor", 2,
+                                "move-cursor", 2,
                                 G_TYPE_ENUM, step,
                                 G_TYPE_INT, count);
 }
@@ -9160,12 +9128,12 @@ gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
       /* If it's not the column moving and func tells us to skip over the column, we continue. */
       if (left_column != column && cur_column != column &&
          tree_view->priv->column_drop_func &&
-         ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
+         ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
        {
          left_column = cur_column;
          continue;
        }
-      reorder = g_new (GtkTreeViewColumnReorder, 1);
+      reorder = g_slice_new0 (GtkTreeViewColumnReorder);
       reorder->left_column = left_column;
       left_column = reorder->right_column = cur_column;
 
@@ -9175,9 +9143,9 @@ gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
   /* Add the last one */
   if (tree_view->priv->column_drop_func == NULL ||
       ((left_column != column) &&
-       (* tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
+       tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
     {
-      reorder = g_new (GtkTreeViewColumnReorder, 1);
+      reorder = g_slice_new0 (GtkTreeViewColumnReorder);
       reorder->left_column = left_column;
       reorder->right_column = NULL;
       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
@@ -9197,7 +9165,7 @@ gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
        ((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);
+       g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
       g_list_free (tree_view->priv->column_drag_info);
       tree_view->priv->column_drag_info = NULL;
       return;
@@ -9252,6 +9220,10 @@ _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
 
       attributes.window_type = GDK_WINDOW_CHILD;
       attributes.wclass = GDK_INPUT_OUTPUT;
+      attributes.x = column->button->allocation.x;
+      attributes.y = 0;
+      attributes.width = column->button->allocation.width;
+      attributes.height = column->button->allocation.height;
       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
@@ -9294,12 +9266,6 @@ _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
   gtk_propagate_event (column->button, send_event);
   gdk_event_free (send_event);
 
-  gdk_window_move_resize (tree_view->priv->drag_window,
-                         column->button->allocation.x,
-                         0,
-                         column->button->allocation.width,
-                         column->button->allocation.height);
-
   /* Kids, don't try this at home */
   g_object_ref (column->button);
   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
@@ -9334,10 +9300,10 @@ _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
 }
 
 static void
-gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
-                               GtkRBTree        *tree,
-                               GtkRBNode        *node,
-                               GdkRectangle     *clip_rect)
+gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
+                               GtkRBTree          *tree,
+                               GtkRBNode          *node,
+                               const GdkRectangle *clip_rect)
 {
   GdkRectangle rect;
 
@@ -9365,10 +9331,10 @@ gtk_tree_view_queue_draw_arrow (GtkTreeView      *tree_view,
 }
 
 void
-_gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
-                               GtkRBTree    *tree,
-                               GtkRBNode    *node,
-                               GdkRectangle *clip_rect)
+_gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
+                               GtkRBTree          *tree,
+                               GtkRBNode          *node,
+                               const GdkRectangle *clip_rect)
 {
   GdkRectangle rect;
 
@@ -9396,9 +9362,9 @@ _gtk_tree_view_queue_draw_node (GtkTreeView  *tree_view,
 }
 
 static void
-gtk_tree_view_queue_draw_path (GtkTreeView      *tree_view,
-                               GtkTreePath      *path,
-                               GdkRectangle     *clip_rect)
+gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
+                               GtkTreePath        *path,
+                               const GdkRectangle *clip_rect)
 {
   GtkRBTree *tree = NULL;
   GtkRBNode *node = NULL;
@@ -9496,21 +9462,22 @@ gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
       (! GTK_WIDGET_REALIZED (tree_view)))
     return;
 
-  GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
-
   cursor_path = NULL;
   if (tree_view->priv->cursor)
     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
 
   if (cursor_path == NULL)
     {
-      /* Consult the selection before defaulting to the first element */
+      /* Consult the selection before defaulting to the
+       * first focusable element
+       */
+      GList *selected_rows;
+      GtkTreeModel *model;
       GtkTreeSelection *selection;
-      GtkTreeModel     *model;
-      GList            *selected_rows;
 
       selection = gtk_tree_view_get_selection (tree_view);
       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
+
       if (selected_rows)
        {
           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
@@ -9518,28 +9485,41 @@ gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
          g_list_free (selected_rows);
         }
       else
-       cursor_path = gtk_tree_path_new_first ();
+       {
+         cursor_path = gtk_tree_path_new_first ();
+         search_first_focusable_path (tree_view, &cursor_path,
+                                      TRUE, NULL, NULL);
+       }
 
       gtk_tree_row_reference_free (tree_view->priv->cursor);
       tree_view->priv->cursor = NULL;
 
-      if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
-       gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
-      else
-       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
+      if (cursor_path)
+       {
+         if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+           gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
+         else
+           gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
+       }
     }
-  gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
-  gtk_tree_path_free (cursor_path);
 
-  if (tree_view->priv->focus_column == NULL)
+  if (cursor_path)
     {
-      GList *list;
-      for (list = tree_view->priv->columns; list; list = list->next)
+      GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+
+      gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+      gtk_tree_path_free (cursor_path);
+
+      if (tree_view->priv->focus_column == NULL)
        {
-         if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
+         GList *list;
+         for (list = tree_view->priv->columns; list; list = list->next)
            {
-             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
-             break;
+             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
+               {
+                 tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
+                 break;
+               }
            }
        }
     }
@@ -9556,6 +9536,7 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
   GtkRBNode *new_cursor_node = NULL;
   GtkTreePath *cursor_path = NULL;
   gboolean grab_focus = TRUE;
+  gboolean selectable;
 
   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
     return;
@@ -9568,17 +9549,20 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
   _gtk_tree_view_find_node (tree_view, cursor_path,
                            &cursor_tree, &cursor_node);
-  gtk_tree_path_free (cursor_path);
 
   if (cursor_tree == NULL)
     /* FIXME: we lost the cursor; should we get the first? */
     return;
 
   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
+  selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+                                                     cursor_node,
+                                                     cursor_path);
 
   if (selection_count == 0
       && tree_view->priv->selection->type != GTK_SELECTION_NONE
-      && !tree_view->priv->ctrl_pressed)
+      && !tree_view->priv->ctrl_pressed
+      && selectable)
     {
       /* Don't move the cursor, but just select the current node */
       new_cursor_tree = cursor_tree;
@@ -9594,9 +9578,25 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
                               &new_cursor_tree, &new_cursor_node);
     }
 
+  gtk_tree_path_free (cursor_path);
+
+  if (new_cursor_node)
+    {
+      cursor_path = _gtk_tree_view_find_path (tree_view,
+                                             new_cursor_tree, new_cursor_node);
+
+      search_first_focusable_path (tree_view, &cursor_path,
+                                  (count != -1),
+                                  &new_cursor_tree,
+                                  &new_cursor_node);
+
+      if (cursor_path)
+       gtk_tree_path_free (cursor_path);
+    }
+
   /*
    * If the list has only one item and multi-selection is set then select
-   * the row.
+   * the row (if not yet selected).
    */
   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
       new_cursor_node == NULL)
@@ -9608,7 +9608,8 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
                               &new_cursor_tree, &new_cursor_node);
 
-      if (new_cursor_node == NULL)
+      if (new_cursor_node == NULL
+         && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
         {
           new_cursor_node = cursor_node;
           new_cursor_tree = cursor_tree;
@@ -9664,6 +9665,8 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
   GtkRBNode *cursor_node = NULL;
   GtkTreePath *old_cursor_path = NULL;
   GtkTreePath *cursor_path = NULL;
+  GtkRBTree *start_cursor_tree = NULL;
+  GtkRBNode *start_cursor_node = NULL;
   gint y;
   gint window_y;
   gint vertical_separator;
@@ -9702,7 +9705,7 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
                             &cursor_tree, &cursor_node);
 
-  if (tree_view->priv->cursor_offset >= BACKGROUND_HEIGHT (cursor_node))
+  if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
     {
       _gtk_rbtree_next_full (cursor_tree, cursor_node,
                             &cursor_tree, &cursor_node);
@@ -9711,16 +9714,46 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
 
   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);
+
+  start_cursor_tree = cursor_tree;
+  start_cursor_node = cursor_node;
+
+  if (! search_first_focusable_path (tree_view, &cursor_path,
+                                    (count != -1),
+                                    &cursor_tree, &cursor_node))
+    {
+      /* It looks like we reached the end of the view without finding
+       * a focusable row.  We will step backwards to find the last
+       * focusable row.
+       */
+      cursor_tree = start_cursor_tree;
+      cursor_node = start_cursor_node;
+      cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
+
+      search_first_focusable_path (tree_view, &cursor_path,
+                                  (count == -1),
+                                  &cursor_tree, &cursor_node);
+    }
+
+  if (!cursor_path)
+    goto cleanup;
+
+  /* update y */
+  y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
+
   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
 
   y -= window_y;
   gtk_tree_view_scroll_to_point (tree_view, -1, y);
+  gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
   _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_widget_grab_focus (GTK_WIDGET (tree_view));
+
+cleanup:
   gtk_tree_path_free (old_cursor_path);
   gtk_tree_path_free (cursor_path);
 }
@@ -9814,6 +9847,7 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
                                        cursor_node,
                                        NULL);
       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
+      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
     }
   else
     {
@@ -9847,6 +9881,11 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
     {
       while (cursor_node && cursor_node->left != cursor_tree->nil)
        cursor_node = cursor_node->left;
+
+      /* Now go forward to find the first focusable row. */
+      path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
+      search_first_focusable_path (tree_view, &path,
+                                  TRUE, &cursor_tree, &cursor_node);
     }
   else
     {
@@ -9861,19 +9900,27 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
          cursor_node = cursor_tree->root;
        }
       while (1);
+
+      /* Now go backwards to find last focusable row. */
+      path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
+      search_first_focusable_path (tree_view, &path,
+                                  FALSE, &cursor_tree, &cursor_node);
     }
 
-  path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
+  if (!path)
+    goto cleanup;
 
   if (gtk_tree_path_compare (old_path, path))
     {
       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
     }
   else
     {
       gtk_widget_error_bell (GTK_WIDGET (tree_view));
     }
 
+cleanup:
   gtk_tree_path_free (old_path);
   gtk_tree_path_free (path);
 }
@@ -9910,6 +9957,8 @@ static gboolean
 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
                                      gboolean     start_editing)
 {
+  GtkRBTree *new_tree = NULL;
+  GtkRBNode *new_node = NULL;
   GtkRBTree *cursor_tree = NULL;
   GtkRBNode *cursor_node = NULL;
   GtkTreePath *cursor_path = NULL;
@@ -9955,6 +10004,15 @@ gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
                                             mode,
                                            FALSE);
 
+  /* We bail out if the original (tree, node) don't exist anymore after
+   * handling the selection-changed callback.  We do return TRUE because
+   * the key press has been handled at this point.
+   */
+  _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
+
+  if (cursor_tree != new_tree || cursor_node != new_node)
+    return FALSE;
+
   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
 
   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
@@ -9972,6 +10030,8 @@ gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
 static gboolean
 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
 {
+  GtkRBTree *new_tree = NULL;
+  GtkRBNode *new_node = NULL;
   GtkRBTree *cursor_tree = NULL;
   GtkRBNode *cursor_node = NULL;
   GtkTreePath *cursor_path = NULL;
@@ -10001,6 +10061,15 @@ gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
                                             GTK_TREE_SELECT_MODE_TOGGLE,
                                            FALSE);
 
+  /* We bail out if the original (tree, node) don't exist anymore after
+   * handling the selection-changed callback.  We do return TRUE because
+   * the key press has been handled at this point.
+   */
+  _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
+
+  if (cursor_tree != new_tree || cursor_node != new_node)
+    return FALSE;
+
   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
 
   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
@@ -10060,27 +10129,21 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
   GdkModifierType state;
 
   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
-    return FALSE;
+    goto out;
 
   cursor_path = NULL;
   if (tree_view->priv->cursor)
     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
 
   if (cursor_path == NULL)
-    return FALSE;
+    goto out;
 
   _gtk_tree_view_find_node (tree_view, cursor_path,
                            &cursor_tree, &cursor_node);
   if (cursor_tree == NULL)
     {
       gtk_tree_path_free (cursor_path);
-      return FALSE;
-    }
-
-  if (gtk_get_current_event_state (&state))
-    {
-      if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
-        tree_view->priv->ctrl_pressed = TRUE;
+      goto out;
     }
 
   if (cursor_tree->parent_node)
@@ -10091,19 +10154,30 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
 
       gtk_tree_path_up (cursor_path);
 
+      if (gtk_get_current_event_state (&state))
+       {
+         if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+           tree_view->priv->ctrl_pressed = TRUE;
+       }
+
       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
-    }
+      gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
 
-  gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
+      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+      gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+      gtk_tree_path_free (cursor_path);
 
-  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-  gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
-  gtk_tree_path_free (cursor_path);
+      tree_view->priv->ctrl_pressed = FALSE;
 
-  tree_view->priv->ctrl_pressed = FALSE;
+      return TRUE;
+    }
 
-  return TRUE;
+ out:
+
+  tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
+  return FALSE;
 }
+
 static gboolean
 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
 {
@@ -10143,11 +10217,13 @@ static void
 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
 {
   GtkWidget *frame, *vbox, *toplevel;
+  GdkScreen *screen;
 
   if (tree_view->priv->search_custom_entry_set)
     return;
 
   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
+  screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
 
    if (tree_view->priv->search_window != NULL)
      {
@@ -10157,26 +10233,30 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
         gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
                                         GTK_WINDOW (tree_view->priv->search_window));
+       gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
        return;
      }
    
   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
 
   if (GTK_WINDOW (toplevel)->group)
     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
                                 GTK_WINDOW (tree_view->priv->search_window));
 
+  gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
+                           GDK_WINDOW_TYPE_HINT_UTILITY);
   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
-  g_signal_connect (tree_view->priv->search_window, "delete_event",
+  g_signal_connect (tree_view->priv->search_window, "delete-event",
                    G_CALLBACK (gtk_tree_view_search_delete_event),
                    tree_view);
-  g_signal_connect (tree_view->priv->search_window, "key_press_event",
+  g_signal_connect (tree_view->priv->search_window, "key-press-event",
                    G_CALLBACK (gtk_tree_view_search_key_press_event),
                    tree_view);
-  g_signal_connect (tree_view->priv->search_window, "button_press_event",
+  g_signal_connect (tree_view->priv->search_window, "button-press-event",
                    G_CALLBACK (gtk_tree_view_search_button_press_event),
                    tree_view);
-  g_signal_connect (tree_view->priv->search_window, "scroll_event",
+  g_signal_connect (tree_view->priv->search_window, "scroll-event",
                    G_CALLBACK (gtk_tree_view_search_scroll_event),
                    tree_view);
 
@@ -10193,14 +10273,14 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
   /* add entry */
   tree_view->priv->search_entry = gtk_entry_new ();
   gtk_widget_show (tree_view->priv->search_entry);
-  g_signal_connect (tree_view->priv->search_entry, "populate_popup",
+  g_signal_connect (tree_view->priv->search_entry, "populate-popup",
                    G_CALLBACK (gtk_tree_view_search_disable_popdown),
                    tree_view);
   g_signal_connect (tree_view->priv->search_entry,
                    "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),
@@ -10451,8 +10531,13 @@ gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
         {
           /* 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->in_top_row_to_dy)
+            gtk_tree_view_dy_to_top_row (tree_view);
        }
+
+      gdk_window_process_updates (tree_view->priv->header_window, TRUE);
+      gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
     }
 }
 
@@ -10522,9 +10607,7 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
                         GtkTreeModel *model)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-
-  if (model != NULL)
-    g_return_if_fail (GTK_IS_TREE_MODEL (model));
+  g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
 
   if (model == tree_view->priv->model)
     return;
@@ -10542,11 +10625,7 @@ 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;
-       }
+      remove_expand_collapse_timeout (tree_view);
 
       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
                                            gtk_tree_view_row_changed,
@@ -10621,23 +10700,23 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
 
       g_object_ref (tree_view->priv->model);
       g_signal_connect (tree_view->priv->model,
-                       "row_changed",
+                       "row-changed",
                        G_CALLBACK (gtk_tree_view_row_changed),
                        tree_view);
       g_signal_connect (tree_view->priv->model,
-                       "row_inserted",
+                       "row-inserted",
                        G_CALLBACK (gtk_tree_view_row_inserted),
                        tree_view);
       g_signal_connect (tree_view->priv->model,
-                       "row_has_child_toggled",
+                       "row-has-child-toggled",
                        G_CALLBACK (gtk_tree_view_row_has_child_toggled),
                        tree_view);
       g_signal_connect (tree_view->priv->model,
-                       "row_deleted",
+                       "row-deleted",
                        G_CALLBACK (gtk_tree_view_row_deleted),
                        tree_view);
       g_signal_connect (tree_view->priv->model,
-                       "rows_reordered",
+                       "rows-reordered",
                        G_CALLBACK (gtk_tree_view_rows_reordered),
                        tree_view);
 
@@ -11317,7 +11396,7 @@ gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
   if (GTK_WIDGET_REALIZED (tree_view))
     {
       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-      gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
+      gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
     }
 
   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
@@ -11340,8 +11419,7 @@ gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
                                    GtkTreeViewColumn *column)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-  if (column != NULL)
-    g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
+  g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
 
   if (tree_view->priv->expander_column != column)
     {
@@ -11405,12 +11483,12 @@ void
 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
                                        GtkTreeViewColumnDropFunc  func,
                                        gpointer                   user_data,
-                                       GtkDestroyNotify           destroy)
+                                       GDestroyNotify             destroy)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
   if (tree_view->priv->column_drop_func_data_destroy)
-    (* tree_view->priv->column_drop_func_data_destroy) (tree_view->priv->column_drop_func_data);
+    tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
 
   tree_view->priv->column_drop_func = func;
   tree_view->priv->column_drop_func_data = user_data;
@@ -11621,6 +11699,7 @@ gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
                           gtk_tree_view_expand_all_emission_helper,
                           tree_view);
 }
+
 /**
  * gtk_tree_view_expand_all:
  * @tree_view: A #GtkTreeView.
@@ -11659,6 +11738,55 @@ expand_collapse_timeout (gpointer data)
   return do_expand_collapse (data);
 }
 
+static void
+add_expand_collapse_timeout (GtkTreeView *tree_view,
+                             GtkRBTree   *tree,
+                             GtkRBNode   *node,
+                             gboolean     expand)
+{
+  if (tree_view->priv->expand_collapse_timeout != 0)
+    return;
+
+  tree_view->priv->expand_collapse_timeout =
+      gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
+  tree_view->priv->expanded_collapsed_tree = tree;
+  tree_view->priv->expanded_collapsed_node = node;
+
+  if (expand)
+    GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
+  else
+    GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
+}
+
+static void
+remove_expand_collapse_timeout (GtkTreeView *tree_view)
+{
+  if (tree_view->priv->expand_collapse_timeout)
+    {
+      g_source_remove (tree_view->priv->expand_collapse_timeout);
+      tree_view->priv->expand_collapse_timeout = 0;
+    }
+
+  if (tree_view->priv->expanded_collapsed_node != NULL)
+    {
+      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
+      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
+
+      tree_view->priv->expanded_collapsed_node = NULL;
+    }
+}
+
+static void
+cancel_arrow_animation (GtkTreeView *tree_view)
+{
+  if (tree_view->priv->expand_collapse_timeout)
+    {
+      while (do_expand_collapse (tree_view));
+
+      remove_expand_collapse_timeout (tree_view);
+    }
+}
+
 static gboolean
 do_expand_collapse (GtkTreeView *tree_view)
 {
@@ -11881,28 +12009,10 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
                            gtk_tree_path_get_depth (path) + 1,
                            open_all);
 
-  if (tree_view->priv->expand_collapse_timeout)
-    {
-      g_source_remove (tree_view->priv->expand_collapse_timeout);
-      tree_view->priv->expand_collapse_timeout = 0;
-    }
-
-  if (tree_view->priv->expanded_collapsed_node != NULL)
-    {
-      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
-      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
-
-      tree_view->priv->expanded_collapsed_node = NULL;
-    }
+  remove_expand_collapse_timeout (tree_view);
 
   if (animate)
-    {
-      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;
-
-      GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
-    }
+    add_expand_collapse_timeout (tree_view, tree, node, TRUE);
 
   install_presize_handler (tree_view);
 
@@ -12026,7 +12136,7 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
       gtk_tree_path_down (child_path);
       if (node->children)
        _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
-      (* tree_view->priv->destroy_count_func) (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
+      tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
       gtk_tree_path_free (child_path);
     }
 
@@ -12077,13 +12187,7 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
       gtk_tree_path_free (lsc);
     }
 
-  if (tree_view->priv->expanded_collapsed_node != NULL)
-    {
-      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
-      GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
-      
-      tree_view->priv->expanded_collapsed_node = NULL;
-    }
+  remove_expand_collapse_timeout (tree_view);
 
   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
     {
@@ -12092,21 +12196,9 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
     }
   else
     _gtk_rbtree_remove (node->children);
-
-  if (tree_view->priv->expand_collapse_timeout)
-    {
-      g_source_remove (tree_view->priv->expand_collapse_timeout);
-      tree_view->priv->expand_collapse_timeout = 0;
-    }
   
   if (animate)
-    {
-      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;
-
-      GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
-    }
+    add_expand_collapse_timeout (tree_view, tree, node, FALSE);
   
   if (GTK_WIDGET_MAPPED (tree_view))
     {
@@ -12261,11 +12353,6 @@ gtk_tree_view_row_expanded (GtkTreeView *tree_view,
   return (node->children != NULL);
 }
 
-static const GtkTargetEntry row_targets[] = {
-  { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
-};
-
-
 /**
  * gtk_tree_view_get_reorderable:
  * @tree_view: a #GtkTreeView
@@ -12288,12 +12375,15 @@ gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
  * @tree_view: A #GtkTreeView.
  * @reorderable: %TRUE, if the tree can be reordered.
  *
- * This function is a convenience function to allow you to reorder models that
- * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
- * #GtkTreeStore and #GtkListStore support these.  If @reorderable is %TRUE, then
- * the user can reorder the model by dragging and dropping rows.  The
- * developer can listen to these changes by connecting to the model's
- * row_inserted and row_deleted signals.
+ * This function is a convenience function to allow you to reorder
+ * models that support the #GtkDragSourceIface and the
+ * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
+ * these.  If @reorderable is %TRUE, then the user can reorder the
+ * model by dragging and dropping rows. The developer can listen to
+ * these changes by connecting to the model's row_inserted and
+ * row_deleted signals. The reordering is implemented by setting up
+ * the tree view as a drag source and destination. Therefore, drag and
+ * drop can not be used in a reorderable view for any other purpose.
  *
  * This function does not give you any degree of control over the order -- any
  * reordering is allowed.  If more control is needed, you should probably
@@ -12312,6 +12402,10 @@ gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
 
   if (reorderable)
     {
+      const GtkTargetEntry row_targets[] = {
+        { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
+      };
+
       gtk_tree_view_enable_model_drag_source (tree_view,
                                              GDK_BUTTON1_MASK,
                                              row_targets,
@@ -12351,11 +12445,28 @@ gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
     }
 
   gtk_tree_row_reference_free (tree_view->priv->cursor);
+  tree_view->priv->cursor = NULL;
+
+  /* One cannot set the cursor on a separator.   Also, if
+   * _gtk_tree_view_find_node returns TRUE, it ran out of tree
+   * before finding the tree and node belonging to path.  The
+   * path maps to a non-existing path and we will silently bail out.
+   * We unset tree and node to avoid further processing.
+   */
+  if (!row_is_separator (tree_view, NULL, path)
+      && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
+    {
+      tree_view->priv->cursor =
+          gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+                                            tree_view->priv->model,
+                                            path);
+    }
+  else
+    {
+      tree = NULL;
+      node = NULL;
+    }
 
-  tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
-                                                             tree_view->priv->model,
-                                                             path);
-  _gtk_tree_view_find_node (tree_view, path, &tree, &node);
   if (tree != NULL)
     {
       GtkRBTree *new_tree = NULL;
@@ -12443,6 +12554,9 @@ gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
  * in order to give keyboard focus to the widget.  Please note that editing 
  * can only happen when the widget is realized.
+ *
+ * If @path is invalid for @model, the current cursor (if any) will be unset
+ * and the function will return without failing.
  **/
 void
 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
@@ -12474,6 +12588,9 @@ gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
  * widget.  Please note that editing can only happen when the widget is
  * realized.
  *
+ * If @path is invalid for @model, the current cursor (if any) will be unset
+ * and the function will return without failing.
+ *
  * Since: 2.2
  **/
 void
@@ -12485,8 +12602,11 @@ gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
   g_return_if_fail (path != NULL);
-  if (focus_column)
-    g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
+  g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
+
+  if (!tree_view->priv->model)
+    return;
+
   if (focus_cell)
     {
       g_return_if_fail (focus_column);
@@ -12559,7 +12679,8 @@ gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
  * 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.
+ * @tree_view is realized.  Therefore this function will always return %FALSE
+ * if @tree_view is not realized or does not have a model.
  *
  * For converting widget coordinates (eg. the ones you get from
  * GtkWidget::query-tooltip), please see
@@ -12581,13 +12702,15 @@ gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
   gint y_offset;
 
   g_return_val_if_fail (tree_view != NULL, FALSE);
-  g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
 
   if (path)
     *path = NULL;
   if (column)
     *column = NULL;
 
+  if (tree_view->priv->bin_window == NULL)
+    return FALSE;
+
   if (tree_view->priv->tree == NULL)
     return FALSE;
 
@@ -13107,18 +13230,24 @@ gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
 {
   GtkRBTree *tree;
   GtkRBNode *node;
-
+  gboolean retval;
+  
   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
 
   if (!tree_view->priv->tree)
     return FALSE;
 
+  retval = TRUE;
+
   if (start_path)
     {
       _gtk_rbtree_find_offset (tree_view->priv->tree,
                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
                                &tree, &node);
-      *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
+      if (node)
+        *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
+      else
+        retval = FALSE;
     }
 
   if (end_path)
@@ -13131,10 +13260,13 @@ gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
 
       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
-      *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
+      if (node)
+        *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
+      else
+        retval = FALSE;
     }
 
-  return TRUE;
+  return retval;
 }
 
 static void
@@ -13155,8 +13287,9 @@ unset_reorderable (GtkTreeView *tree_view)
  * @n_targets: the number of items in @targets
  * @actions: the bitmask of possible actions for a drag from this
  *    widget
- * 
- * Turns @tree_view into a drag source for automatic DND.
+ *
+ * Turns @tree_view into a drag source for automatic DND. Calling this
+ * method sets #GtkTreeView:reorderable to %FALSE.
  **/
 void
 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
@@ -13176,12 +13309,9 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
                       actions);
 
   di = ensure_info (tree_view);
-  clear_source_info (di);
 
   di->start_button_mask = start_button_mask;
-  di->source_target_list = gtk_target_list_new (targets, n_targets);
   di->source_actions = actions;
-
   di->source_set = TRUE;
 
   unset_reorderable (tree_view);
@@ -13195,7 +13325,8 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
  * @actions: the bitmask of possible actions for a drag from this
  *    widget
  * 
- * Turns @tree_view into a drop destination for automatic DND.
+ * Turns @tree_view into a drop destination for automatic DND. Calling
+ * this method sets #GtkTreeView:reorderable to %FALSE.
  **/
 void
 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
@@ -13214,11 +13345,6 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
                      actions);
 
   di = ensure_info (tree_view);
-  clear_dest_info (di);
-
-  if (targets)
-    di->dest_target_list = gtk_target_list_new (targets, n_targets);
-
   di->dest_set = TRUE;
 
   unset_reorderable (tree_view);
@@ -13227,8 +13353,10 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
 /**
  * gtk_tree_view_unset_rows_drag_source:
  * @tree_view: a #GtkTreeView
- * 
- * Undoes the effect of gtk_tree_view_enable_model_drag_source().
+ *
+ * Undoes the effect of
+ * gtk_tree_view_enable_model_drag_source(). Calling this method sets
+ * #GtkTreeView:reorderable to %FALSE.
  **/
 void
 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
@@ -13244,7 +13372,6 @@ gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
       if (di->source_set)
         {
           gtk_drag_source_unset (GTK_WIDGET (tree_view));
-          clear_source_info (di);
           di->source_set = FALSE;
         }
 
@@ -13258,8 +13385,10 @@ gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
 /**
  * gtk_tree_view_unset_rows_drag_dest:
  * @tree_view: a #GtkTreeView
- * 
- * Undoes the effect of gtk_tree_view_enable_model_drag_dest().
+ *
+ * Undoes the effect of
+ * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
+ * #GtkTreeView:reorderable to %FALSE.
  **/
 void
 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
@@ -13275,7 +13404,6 @@ gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
       if (di->dest_set)
         {
           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
-          clear_dest_info (di);
           di->dest_set = FALSE;
         }
 
@@ -13405,9 +13533,12 @@ gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
  * @pos: Return location for the drop position, or %NULL
  * 
  * Determines the destination row for a given position.  @drag_x and
- * @drag_y are expected to be in widget coordinates.
+ * @drag_y are expected to be in widget coordinates.  This function is only
+ * meaningful if @tree_view is realized.  Therefore this function will always
+ * return %FALSE if @tree_view is not realized or does not have a model.
  * 
- * Return value: whether there is a row at the given position.
+ * Return value: whether there is a row at the given position, %TRUE if this
+ * is indeed the case.
  **/
 gboolean
 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
@@ -13431,12 +13562,13 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
   g_return_val_if_fail (tree_view != NULL, FALSE);
   g_return_val_if_fail (drag_x >= 0, FALSE);
   g_return_val_if_fail (drag_y >= 0, FALSE);
-  g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
-
 
   if (path)
     *path = NULL;
 
+  if (tree_view->priv->bin_window == NULL)
+    return FALSE;
+
   if (tree_view->priv->tree == NULL)
     return FALSE;
 
@@ -13549,12 +13681,7 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
                                 path))
     return NULL;
   
-  if (tree_view->priv->row_separator_func)
-    {
-      is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
-                                                             &iter,
-                                                             tree_view->priv->row_separator_data);
-    }
+  is_separator = row_is_separator (tree_view, &iter, NULL);
 
   cell_offset = x;
 
@@ -13673,12 +13800,12 @@ void
 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
                                      GtkTreeDestroyCountFunc  func,
                                      gpointer                 data,
-                                     GtkDestroyNotify         destroy)
+                                     GDestroyNotify           destroy)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
   if (tree_view->priv->destroy_count_destroy)
-    (* tree_view->priv->destroy_count_destroy) (tree_view->priv->destroy_count_data);
+    tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
 
   tree_view->priv->destroy_count_func = func;
   tree_view->priv->destroy_count_data = data;
@@ -13756,13 +13883,14 @@ gtk_tree_view_get_search_column (GtkTreeView *tree_view)
  * @column: the column of the model to search in, or -1 to disable searching
  *
  * Sets @column as the column where the interactive search code should
- * search in. 
+ * search in for the current model
  * 
- * If the sort column is set, users can use the "start-interactive-search"
+ * If the search column is set, users can use the "start-interactive-search"
  * key binding to bring up search popup. The enable-search property controls
  * whether simply typing text will also start an interactive search.
  *
- * Note that @column refers to a column of the model. 
+ * Note that @column refers to a column of the current model. The search 
+ * column is reset to -1 when the model is changed.
  */
 void
 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
@@ -13810,13 +13938,13 @@ void
 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
                                     GtkTreeViewSearchEqualFunc  search_equal_func,
                                     gpointer                    search_user_data,
-                                    GtkDestroyNotify            search_destroy)
+                                    GDestroyNotify              search_destroy)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
   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);
+    tree_view->priv->search_destroy (tree_view->priv->search_user_data);
 
   tree_view->priv->search_equal_func = search_equal_func;
   tree_view->priv->search_user_data = search_user_data;
@@ -13829,7 +13957,7 @@ gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
  * gtk_tree_view_get_search_entry:
  * @tree_view: A #GtkTreeView
  *
- * Returns the GtkEntry which is currently in use as interactive search
+ * Returns the #GtkEntry which is currently in use as interactive search
  * entry for @tree_view.  In case the built-in entry is being used, %NULL
  * will be returned.
  *
@@ -13866,8 +13994,7 @@ gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
                                GtkEntry    *entry)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-  if (entry != NULL)
-    g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
 
   if (tree_view->priv->search_custom_entry_set)
     {
@@ -13903,7 +14030,7 @@ gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
                              tree_view);
        }
       
-        g_signal_connect (tree_view->priv->search_entry, "key_press_event",
+        g_signal_connect (tree_view->priv->search_entry, "key-press-event",
                          G_CALLBACK (gtk_tree_view_search_key_press_event),
                          tree_view);
 
@@ -13924,7 +14051,7 @@ gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
  * @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.
+ * Sets the function to use when positioning the search dialog.
  *
  * Since: 2.10
  **/
@@ -13937,7 +14064,7 @@ gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
   if (tree_view->priv->search_position_destroy)
-    (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
+    tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
 
   tree_view->priv->search_position_func = func;
   tree_view->priv->search_position_user_data = user_data;
@@ -14199,7 +14326,7 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
       retval = TRUE;
     }
 
-  if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
+  if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
       && (event->keyval == GDK_g || event->keyval == GDK_G))
     {
       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
@@ -14217,7 +14344,7 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
       retval = TRUE;
     }
 
-  if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
+  if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
       && (event->keyval == GDK_g || event->keyval == GDK_G))
     {
       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
@@ -14381,8 +14508,8 @@ gtk_tree_view_search_iter (GtkTreeModel     *model,
             {
               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
                                            TRUE, 0.5, 0.0);
-             gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
               gtk_tree_selection_select_iter (selection, iter);
+              gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
 
              if (path)
                gtk_tree_path_free (path);
@@ -14468,7 +14595,6 @@ gtk_tree_view_search_init (GtkWidget   *entry,
                           GtkTreeView *tree_view)
 {
   gint ret;
-  gint len;
   gint count = 0;
   const gchar *text;
   GtkTreeIter iter;
@@ -14479,7 +14605,7 @@ gtk_tree_view_search_init (GtkWidget   *entry,
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
   text = gtk_entry_get_text (GTK_ENTRY (entry));
-  len = strlen (text);
+
   model = gtk_tree_view_get_model (tree_view);
   selection = gtk_tree_view_get_selection (tree_view);
 
@@ -14495,7 +14621,7 @@ gtk_tree_view_search_init (GtkWidget   *entry,
                       tree_view);
     }
 
-  if (len < 1)
+  if (*text == '\0')
     return;
 
   if (!gtk_tree_model_get_iter_first (model, &iter))
@@ -14628,8 +14754,7 @@ gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
 
   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
-
-  cell_area->y += pre_val - tree_view->priv->vadjustment->value;
+  cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
 
   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
 
@@ -14655,7 +14780,7 @@ gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
                                   (GdkEvent *)event);
 
   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
-  g_signal_connect (cell_editable, "remove_widget",
+  g_signal_connect (cell_editable, "remove-widget",
                    G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
 }
 
@@ -14742,7 +14867,7 @@ gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
  * @expand: %TRUE to enable hover selection mode
  *
  * Enables of disables the hover expansion mode of @tree_view.
- * Hover expansion makes rows expand or collaps if the pointer 
+ * Hover expansion makes rows expand or collapse if the pointer 
  * moves over them.
  * 
  * Since: 2.6
@@ -14876,19 +15001,23 @@ gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
  * Since: 2.6
  **/
 void
-gtk_tree_view_set_row_separator_func (GtkTreeView                *tree_view,
-                                     GtkTreeViewRowSeparatorFunc func,
-                                     gpointer                    data,
-                                     GtkDestroyNotify            destroy)
+gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
+                                     GtkTreeViewRowSeparatorFunc  func,
+                                     gpointer                     data,
+                                     GDestroyNotify               destroy)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
   if (tree_view->priv->row_separator_destroy)
-    (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
+    tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
 
   tree_view->priv->row_separator_func = func;
   tree_view->priv->row_separator_data = data;
   tree_view->priv->row_separator_destroy = destroy;
+
+  /* Have the tree recalculate heights */
+  _gtk_rbtree_mark_invalid (tree_view->priv->tree);
+  gtk_widget_queue_resize (GTK_WIDGET (tree_view));
 }
 
   
@@ -14982,7 +15111,7 @@ gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
          !priv->grid_line_gc)
        {
          gint line_width;
-         guint8 *dash_list;
+         gint8 *dash_list;
 
          gtk_widget_style_get (widget,
                                "grid-line-width", &line_width,
@@ -15068,7 +15197,7 @@ gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
       if (enabled && !priv->tree_line_gc)
        {
          gint line_width;
-         guint8 *dash_list;
+         gint8 *dash_list;
          gtk_widget_style_get (widget,
                                "tree-line-width", &line_width,
                                "tree-line-pattern", (gchar *)&dash_list,
@@ -15126,7 +15255,7 @@ gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
   else
     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
 
-  if (was_enabled != was_enabled)
+  if (enabled != was_enabled)
     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
 }
 
@@ -15198,6 +15327,7 @@ gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
  * @path: a #GtkTreePath
  *
  * Sets the tip area of @tooltip to be the area covered by the row at @path.
+ * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
  * See also gtk_tooltip_set_tip_area().
  *
  * Since: 2.12
@@ -15219,13 +15349,20 @@ gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
  * @tooltip: a #GtkTooltip
  * @path: a #GtkTreePath or %NULL
  * @column: a #GtkTreeViewColumn or %NULL
- * @cell: a #GtkCellRendererText or %NULL
+ * @cell: a #GtkCellRenderer or %NULL
  *
  * Sets the tip area of @tooltip to the area @path, @column and @cell have
  * in common.  For example if @path is %NULL and @column is set, the tip
  * area will be set to the full area covered by @column.  See also
  * gtk_tooltip_set_tip_area().
  *
+ * Note that if @path is not specified and @cell is set and part of a column
+ * containing the expander, the tooltip might not show and hide at the correct
+ * position.  In such cases @path must be set to the current node under the
+ * mouse cursor for this function to operate correctly.
+ *
+ * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
+ *
  * Since: 2.12
  */
 void
@@ -15239,12 +15376,8 @@ gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
 
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
-
-  if (column)
-    g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
-
-  if (cell)
-    g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+  g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
+  g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
 
   /* Determine x values. */
   if (column && cell)
@@ -15252,11 +15385,16 @@ gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
       GdkRectangle tmp;
       gint start, width;
 
-      gtk_tree_view_get_cell_area (tree_view, NULL, column, &tmp);
+      /* We always pass in path here, whether it is NULL or not.
+       * For cells in expander columns path must be specified so that
+       * we can correctly account for the indentation.  This also means
+       * that the tooltip is constrained vertically by the "Determine y
+       * values" code below; this is not a real problem since cells actually
+       * don't stretch vertically in constrast to columns.
+       */
+      gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
 
-      /* FIXME: a need a path here to correctly correct for indent */
-
       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
                                                         tmp.x + start, 0,
                                                         &rect.x, NULL);
@@ -15274,7 +15412,7 @@ gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
     }
   else
     {
-      rect.x = GTK_WIDGET (tree_view)->allocation.x;
+      rect.x = 0;
       rect.width = GTK_WIDGET (tree_view)->allocation.width;
     }
 
@@ -15308,8 +15446,8 @@ gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
  * @path: a pointer to receive a #GtkTreePath or %NULL
  * @iter: a pointer to receive a #GtkTreeIter or %NULL
  *
- * This function is supposed to be used in a GtkWidget::query-tooltip
- * signal handler for #GtkTreeViews.  The @x, @y and @keyboard_tip values
+ * This function is supposed to be used in a #GtkWidget::query-tooltip
+ * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
  * which are received in the signal handler, should be passed to this
  * function without modification.
  *
@@ -15379,7 +15517,8 @@ gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
                                    GtkTooltip *tooltip,
                                    gpointer    data)
 {
-  gchar *str;
+  GValue value = { 0, };
+  GValue transformed = { 0, };
   GtkTreeIter iter;
   GtkTreePath *path;
   GtkTreeModel *model;
@@ -15391,19 +15530,34 @@ gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
                                          &model, &path, &iter))
     return FALSE;
 
-  gtk_tree_model_get (model, &iter, tree_view->priv->tooltip_column, &str, -1);
+  gtk_tree_model_get_value (model, &iter,
+                            tree_view->priv->tooltip_column, &value);
 
-  if (!str)
+  g_value_init (&transformed, G_TYPE_STRING);
+
+  if (!g_value_transform (&value, &transformed))
+    {
+      g_value_unset (&value);
+      gtk_tree_path_free (path);
+
+      return FALSE;
+    }
+
+  g_value_unset (&value);
+
+  if (!g_value_get_string (&transformed))
     {
+      g_value_unset (&transformed);
       gtk_tree_path_free (path);
+
       return FALSE;
     }
 
-  gtk_tooltip_set_markup (tooltip, str);
+  gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
 
   gtk_tree_path_free (path);
-  g_free (str);
+  g_value_unset (&transformed);
 
   return TRUE;
 }
@@ -15415,11 +15569,14 @@ gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
  *
  * If you only plan to have simple (text-only) tooltips on full rows, you
  * can use this function to have #GtkTreeView handle these automatically
- * for you.  @column should be set to the column in @tree_view's model
- * containing the tooltip texts, or %-1 to disable this feature.
+ * for you. @column should be set to the column in @tree_view's model
+ * containing the tooltip texts, or -1 to disable this feature.
  *
- * When enabled, GtkWidget::has-tooltip will be set to %TRUE and
- * @tree_view will connect a query-tooltip signal handler.
+ * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
+ * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
+ *
+ * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
+ * so &amp;, &lt;, etc have to be escaped in the text.
  *
  * Since: 2.12
  */
@@ -15429,21 +15586,28 @@ gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
 {
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
+  if (column == tree_view->priv->tooltip_column)
+    return;
+
   if (column == -1)
     {
       g_signal_handlers_disconnect_by_func (tree_view,
-                                           gtk_tree_view_set_tooltip_query_cb,
+                                           gtk_tree_view_set_tooltip_query_cb,
                                            NULL);
       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
     }
   else
     {
-      g_signal_connect (tree_view, "query-tooltip",
-                       G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
-      gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
+      if (tree_view->priv->tooltip_column == -1)
+        {
+          g_signal_connect (tree_view, "query-tooltip",
+                           G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
+          gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
+        }
     }
 
   tree_view->priv->tooltip_column = column;
+  g_object_notify (G_OBJECT (tree_view), "tooltip-column");
 }
 
 /**
@@ -15453,10 +15617,10 @@ gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
  * Returns the column of @tree_view's model which is being used for
  * displaying tooltips on @tree_view's rows.
  *
- * Return value: a #gint with the tooltip column that is currently being
- * used, or %-1 if this is disabled.
+ * Return value: the index of the tooltip column that is currently being
+ * used, or -1 if this is disabled.
  *
- * Since 2.12
+ * Since: 2.12
  */
 gint
 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)