Index: gtktreeview.c
===================================================================
--- gtktreeview.c	(revision 17993)
+++ gtktreeview.c	(working copy)
@@ -2111,7 +2111,7 @@ gtk_tree_view_size_allocate_columns (Gtk
   gint number_of_expand_columns = 0;
   gboolean column_changed = FALSE;
   gboolean rtl;
-  
+
   tree_view = GTK_TREE_VIEW (widget);
 
   for (last_column = g_list_last (tree_view->priv->columns);
@@ -2371,6 +2371,25 @@ grab_focus_and_unset_draw_keyfocus (GtkT
 }
 
 static gboolean
+path_is_row_separator (GtkTreeView *tree_view,
+		       GtkTreePath *path)
+{
+  gboolean is_separator = FALSE;
+
+  if (tree_view->priv->row_separator_func)
+    {
+      GtkTreeIter iter;
+
+      gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+      is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
+							      &iter,
+							      tree_view->priv->row_separator_data);
+    }
+
+  return is_separator;
+}
+
+static gboolean
 gtk_tree_view_button_press (GtkWidget      *widget,
 			    GdkEventButton *event)
 {
@@ -2382,6 +2401,7 @@ gtk_tree_view_button_press (GtkWidget   
   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);
@@ -2461,12 +2481,20 @@ gtk_tree_view_button_press (GtkWidget   
 
       /* Get the path and the node */
       path = _gtk_tree_view_find_path (tree_view, tree, node);
+      path_is_selectable = !path_is_row_separator (tree_view, 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));
       background_area.x = 0;
 
-
       /* Let the column have a chance at selecting it. */
       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
@@ -2636,9 +2664,9 @@ gtk_tree_view_button_press (GtkWidget   
 	  !tree_view->priv->in_grab &&
 	  tree_view->priv->pressed_button < 0)
         {
-          tree_view->priv->pressed_button = event->button;
-          tree_view->priv->press_start_x = event->x;
-          tree_view->priv->press_start_y = event->y;
+	  tree_view->priv->pressed_button = (path_is_selectable) ? event->button : -1;
+	  tree_view->priv->press_start_x = event->x;
+	  tree_view->priv->press_start_y = event->y;
 
 	  if (tree_view->priv->rubber_banding_enable
 	      && !node_selected
@@ -3633,6 +3661,22 @@ gtk_tree_view_update_rubber_band_selecti
 
   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)
@@ -3667,6 +3711,7 @@ gtk_tree_view_update_rubber_band_selecti
 
       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
 
+node_not_selectable:
       if (start_node == end_node)
 	break;
 
@@ -4210,7 +4255,7 @@ gtk_tree_view_bin_expose (GtkWidget     
       gboolean is_separator = FALSE;
       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,
@@ -7679,6 +7724,53 @@ gtk_tree_view_header_focus (GtkTreeView 
   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 && path_is_row_separator (tree_view, *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)
@@ -7886,6 +7978,8 @@ gtk_tree_view_real_move_cursor (GtkTreeV
     return FALSE;
   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
     return FALSE;
+  if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
+    return FALSE;
 
   gtk_tree_view_stop_editing (tree_view, FALSE);
   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
@@ -9421,20 +9515,20 @@ gtk_tree_view_focus_to_cursor (GtkTreeVi
 
 {
   GtkTreePath *cursor_path;
+  GtkRBTree *tree;
+  GtkRBNode *node;
 
   if ((tree_view->priv->tree == NULL) ||
       (! 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 */
       GtkTreeSelection *selection;
       GtkTreeModel     *model;
       GList            *selected_rows;
@@ -9448,28 +9542,46 @@ gtk_tree_view_focus_to_cursor (GtkTreeVi
 	  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)
+  tree = tree_view->priv->tree;
+  node = tree->root;
+
+  if (cursor_path &&
+      _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+					     node, 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;
+		}
 	    }
 	}
     }
@@ -9524,6 +9636,19 @@ gtk_tree_view_move_cursor_up_down (GtkTr
 			       &new_cursor_tree, &new_cursor_node);
     }
 
+  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.
@@ -9594,6 +9719,8 @@ gtk_tree_view_move_cursor_page_up_down (
   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;
@@ -9641,7 +9768,33 @@ gtk_tree_view_move_cursor_page_up_down (
 
   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 sensitive row.  We will step backwards to find the last
+       * sensitive 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;
@@ -9651,8 +9804,11 @@ gtk_tree_view_move_cursor_page_up_down (
   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
     gtk_widget_error_bell (GTK_WIDGET (tree_view));
 
+ cleanup:
+  if (cursor_path)
+    gtk_tree_path_free (cursor_path);
+
   gtk_tree_path_free (old_cursor_path);
-  gtk_tree_path_free (cursor_path);
 }
 
 static void
@@ -9777,6 +9933,11 @@ gtk_tree_view_move_cursor_start_end (Gtk
     {
       while (cursor_node && cursor_node->left != cursor_tree->nil)
 	cursor_node = cursor_node->left;
+
+      /* now go forward to find the first selectable 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
     {
@@ -9791,9 +9952,15 @@ gtk_tree_view_move_cursor_start_end (Gtk
 	  cursor_node = cursor_tree->root;
 	}
       while (1);
+
+      /* now go backwards to find last selectable 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))
     {
@@ -9804,8 +9971,11 @@ gtk_tree_view_move_cursor_start_end (Gtk
       gtk_widget_error_bell (GTK_WIDGET (tree_view));
     }
 
+ cleanup:
+  if (path)
+    gtk_tree_path_free (path);
+
   gtk_tree_path_free (old_path);
-  gtk_tree_path_free (path);
 }
 
 static gboolean
@@ -13729,7 +13899,7 @@ gtk_tree_view_search_dialog_hide (GtkWid
       g_source_remove (tree_view->priv->typeselect_flush_timeout);
       tree_view->priv->typeselect_flush_timeout = 0;
     }
-	
+
   if (GTK_WIDGET_VISIBLE (search_dialog))
     {
       /* send focus-in event */
