]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktreeview.c
Remove spew.
[~andy/gtk] / gtk / gtktreeview.c
index f92feee66c372859d7bf9b5b81a3525f66e305c5..19c5fffa268399ab199c596e4acd2d7e6549648a 100644 (file)
@@ -303,6 +303,7 @@ static gboolean gtk_tree_view_is_expander_column             (GtkTreeView
 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,
@@ -385,7 +386,8 @@ static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_vi
 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
                                                         GtkTreeView      *tree_view);
 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
-                                                        GtkWidget        *search_dialog);
+                                                        GtkWidget        *search_dialog,
+                                                        gpointer          user_data);
 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
                                                         GtkMenu          *menu,
                                                         gpointer          data);
@@ -484,7 +486,7 @@ gtk_tree_view_get_type (void)
       };
 
       tree_view_type =
-       g_type_register_static (GTK_TYPE_CONTAINER, g_intern_static_string ("GtkTreeView"),
+       g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkTreeView"),
                                &tree_view_info, 0);
     }
 
@@ -768,7 +770,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
 
   /* Signals */
   widget_class->set_scroll_adjustments_signal =
-    g_signal_new ("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),
@@ -778,8 +780,23 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_ADJUSTMENT,
                  GTK_TYPE_ADJUSTMENT);
 
+  /**
+   * GtkTreeView::row-activated:
+   * @tree_view: the object on which the signal is emitted
+   * @path: the #GtkTreePath for the activated row
+   * @column: the #GtkTreeViewColumn in which the activation occurred
+   *
+   * The "row-activated" signal is emitted when the method
+   * gtk_tree_view_row_activated() is called or the user double clicks 
+   * a treeview row. It is also emitted when a non-editable row is 
+   * selected and one of the keys: Space, Shift+Space, Return or 
+   * Enter is pressed.
+   * 
+   * For selection handling refer to the <link linkend="TreeWidget">tree 
+   * widget conceptual overview</link> as well as #GtkTreeSelection.
+   */
   tree_view_signals[ROW_ACTIVATED] =
-    g_signal_new ("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),
@@ -790,7 +807,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_VIEW_COLUMN);
 
   tree_view_signals[TEST_EXPAND_ROW] =
-    g_signal_new ("test_expand_row",
+    g_signal_new (I_("test_expand_row"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
@@ -801,7 +818,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_PATH);
 
   tree_view_signals[TEST_COLLAPSE_ROW] =
-    g_signal_new ("test_collapse_row",
+    g_signal_new (I_("test_collapse_row"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
@@ -812,7 +829,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_PATH);
 
   tree_view_signals[ROW_EXPANDED] =
-    g_signal_new ("row_expanded",
+    g_signal_new (I_("row_expanded"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
@@ -823,7 +840,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_PATH);
 
   tree_view_signals[ROW_COLLAPSED] =
-    g_signal_new ("row_collapsed",
+    g_signal_new (I_("row_collapsed"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
@@ -834,7 +851,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  GTK_TYPE_TREE_PATH);
 
   tree_view_signals[COLUMNS_CHANGED] =
-    g_signal_new ("columns_changed",
+    g_signal_new (I_("columns_changed"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
@@ -843,7 +860,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_NONE, 0);
 
   tree_view_signals[CURSOR_CHANGED] =
-    g_signal_new ("cursor_changed",
+    g_signal_new (I_("cursor_changed"),
                  G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
@@ -852,7 +869,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_NONE, 0);
 
   tree_view_signals[MOVE_CURSOR] =
-    g_signal_new ("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),
@@ -863,7 +880,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_INT);
 
   tree_view_signals[SELECT_ALL] =
-    g_signal_new ("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),
@@ -872,7 +889,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[UNSELECT_ALL] =
-    g_signal_new ("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),
@@ -881,7 +898,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[SELECT_CURSOR_ROW] =
-    g_signal_new ("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),
@@ -891,7 +908,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN);
 
   tree_view_signals[TOGGLE_CURSOR_ROW] =
-    g_signal_new ("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),
@@ -900,7 +917,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
-    g_signal_new ("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),
@@ -912,7 +929,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN);
 
   tree_view_signals[SELECT_CURSOR_PARENT] =
-    g_signal_new ("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),
@@ -921,7 +938,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN, 0);
 
   tree_view_signals[START_INTERACTIVE_SEARCH] =
-    g_signal_new ("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),
@@ -930,40 +947,40 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                  G_TYPE_BOOLEAN, 0);
 
   /* Key bindings */
-  gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
                                  GTK_MOVEMENT_DISPLAY_LINES, -1);
-  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
                                  GTK_MOVEMENT_DISPLAY_LINES, -1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
                                  GTK_MOVEMENT_DISPLAY_LINES, 1);
-  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
                                  GTK_MOVEMENT_DISPLAY_LINES, 1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
+  gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
                                  GTK_MOVEMENT_DISPLAY_LINES, -1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
+  gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
                                  GTK_MOVEMENT_DISPLAY_LINES, 1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
                                  GTK_MOVEMENT_BUFFER_ENDS, -1);
-  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
                                  GTK_MOVEMENT_BUFFER_ENDS, -1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
                                  GTK_MOVEMENT_BUFFER_ENDS, 1);
-  gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
                                  GTK_MOVEMENT_BUFFER_ENDS, 1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
                                  GTK_MOVEMENT_PAGES, -1);
-  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
                                  GTK_MOVEMENT_PAGES, -1);
 
-  gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
                                  GTK_MOVEMENT_PAGES, 1);
-  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
+  gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
                                  GTK_MOVEMENT_PAGES, 1);
 
 
@@ -1136,12 +1153,15 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
   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));
 }
 
 static void
 gtk_tree_view_init (GtkTreeView *tree_view)
 {
-  tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
+  tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
+
   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
 
   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
@@ -1170,8 +1190,9 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
   tree_view->priv->enable_search = TRUE;
   tree_view->priv->search_column = -1;
-  tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
+  tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
+  tree_view->priv->search_custom_entry_set = FALSE;
   tree_view->priv->typeselect_flush_timeout = 0;
   tree_view->priv->init_hadjust_value = TRUE;    
   tree_view->priv->width = 0;
@@ -1265,6 +1286,9 @@ gtk_tree_view_get_property (GObject    *object,
     case PROP_HEADERS_VISIBLE:
       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
       break;
+    case PROP_HEADERS_CLICKABLE:
+      g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
+      break;
     case PROP_EXPANDER_COLUMN:
       g_value_set_object (value, tree_view->priv->expander_column);
       break;
@@ -1298,10 +1322,6 @@ gtk_tree_view_get_property (GObject    *object,
 static void
 gtk_tree_view_finalize (GObject *object)
 {
-  GtkTreeView *tree_view = (GtkTreeView *) object;
-
-  g_free (tree_view->priv);
-
   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
 }
 
@@ -1310,6 +1330,20 @@ gtk_tree_view_finalize (GObject *object)
 /* GtkObject Methods
  */
 
+static void
+gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
+{
+  _gtk_rbtree_free (tree_view->priv->tree);
+  
+  tree_view->priv->tree = NULL;
+  tree_view->priv->button_pressed_node = NULL;
+  tree_view->priv->button_pressed_tree = NULL;
+  tree_view->priv->prelight_tree = NULL;
+  tree_view->priv->prelight_node = NULL;
+  tree_view->priv->expanded_collapsed_node = NULL;
+  tree_view->priv->expanded_collapsed_tree = NULL;
+}
+
 static void
 gtk_tree_view_destroy (GtkObject *object)
 {
@@ -1334,8 +1368,8 @@ gtk_tree_view_destroy (GtkObject *object)
   if (tree_view->priv->tree != NULL)
     {
       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
-      _gtk_rbtree_free (tree_view->priv->tree);
-      tree_view->priv->tree = NULL;
+
+      gtk_tree_view_free_rbtree (tree_view);
     }
 
   if (tree_view->priv->selection != NULL)
@@ -1408,13 +1442,19 @@ gtk_tree_view_destroy (GtkObject *object)
        }
     }
 
-  if (tree_view->priv->search_destroy)
+  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_user_data = NULL;
     }
 
-  if (tree_view->priv->row_separator_destroy)
+  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_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_data = NULL;
@@ -1514,7 +1554,6 @@ gtk_tree_view_realize (GtkWidget *widget)
 {
   GList *tmp_list;
   GtkTreeView *tree_view;
-  GdkGCValues values;
   GdkWindowAttr attributes;
   gint attributes_mask;
 
@@ -1576,12 +1615,6 @@ gtk_tree_view_realize (GtkWidget *widget)
                                                   &attributes, attributes_mask);
   gdk_window_set_user_data (tree_view->priv->header_window, widget);
 
-
-  values.foreground = (widget->style->white.pixel==0 ?
-                      widget->style->black:widget->style->white);
-  values.function = GDK_XOR;
-  values.subwindow_mode = GDK_INCLUDE_INFERIORS;
-
   /* Add them all up. */
   widget->style = gtk_style_attach (widget->style, widget->window);
   gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
@@ -2105,6 +2138,9 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
+  else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+    gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
+                              tree_view->priv->height - tree_view->priv->vadjustment->page_size);
   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
     gtk_tree_view_top_row_to_dy (tree_view);
   else
@@ -2265,12 +2301,12 @@ gtk_tree_view_button_press (GtkWidget      *widget,
       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
           list; list = (rtl ? list->prev : list->next))
        {
-         column = list->data;
+         GtkTreeViewColumn *candidate = list->data;
 
-         if (!column->visible)
+         if (!candidate->visible)
            continue;
 
-         background_area.width = column->width;
+         background_area.width = candidate->width;
          if ((background_area.x > (gint) event->x) ||
              (background_area.x + background_area.width <= (gint) event->x))
            {
@@ -2279,6 +2315,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
            }
 
          /* we found the focus column */
+         column = candidate;
          cell_area = background_area;
          cell_area.width -= horizontal_separator;
          cell_area.height -= vertical_separator;
@@ -2705,7 +2742,7 @@ gtk_tree_view_configure (GtkWidget *widget,
   GtkTreeView *tree_view;
 
   tree_view = GTK_TREE_VIEW (widget);
-  tree_view->priv->search_dialog_position_func (tree_view, tree_view->priv->search_window);
+  tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
 
   return FALSE;
 }
@@ -3215,7 +3252,7 @@ gtk_tree_view_motion_resize_column (GtkWidget      *widget,
   new_width = gtk_tree_view_new_column_width (tree_view,
                                              tree_view->priv->drag_pos, &x);
   if (x != tree_view->priv->x_drag &&
-      (new_width != column->fixed_width));
+      (new_width != column->fixed_width))
     {
       column->use_resized_width = TRUE;
       column->resized_width = new_width;
@@ -3454,13 +3491,14 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   GtkRBTree *drag_highlight_tree = NULL;
   GtkTreeIter iter;
   gint new_y;
-  gint y_offset, x_offset, cell_offset;
+  gint y_offset, cell_offset;
   gint max_height;
   gint depth;
   GdkRectangle background_area;
   GdkRectangle cell_area;
   guint flags;
   gint highlight_x;
+  gint expander_cell_width;
   gint bin_window_width;
   gint bin_window_height;
   GtkTreePath *cursor_path;
@@ -3588,9 +3626,9 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
 
       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
 
-      x_offset = -event->area.x;
       cell_offset = 0;
       highlight_x = 0; /* should match x coord of first cell */
+      expander_cell_width = 0;
 
       background_area.y = y_offset + event->area.y;
       background_area.height = max_height;
@@ -3747,6 +3785,8 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
                * level of the tree we're dropping at.
                */
               highlight_x = cell_area.x;
+             expander_cell_width = cell_area.width;
+
              if (is_separator)
                gtk_paint_hline (widget->style,
                                 event->window,
@@ -3860,10 +3900,10 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
           if (highlight_y >= 0)
             {
               gdk_draw_line (event->window,
-                             widget->style->black_gc,
-                             highlight_x,
+                             widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                             rtl ? highlight_x + expander_cell_width : highlight_x,
                              highlight_y,
-                             bin_window_width - highlight_x,
+                             rtl ? 0 : bin_window_width,
                              highlight_y);
             }
         }
@@ -4422,7 +4462,8 @@ gtk_tree_view_key_press (GtkWidget   *widget,
                                                            
   /* 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 (tree_view->priv->enable_search
+      && !tree_view->priv->search_custom_entry_set)
     {
       GdkEvent *new_event;
       char *old_text;
@@ -4437,7 +4478,8 @@ gtk_tree_view_key_press (GtkWidget   *widget,
       /* Make a copy of the current text */
       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
       new_event = gdk_event_copy ((GdkEvent *) event);
-      ((GdkEventKey *) new_event)->window = tree_view->priv->search_entry->window;
+      g_object_unref (((GdkEventKey *) new_event)->window);
+      ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
       gtk_widget_realize (tree_view->priv->search_window);
 
       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
@@ -4453,7 +4495,8 @@ gtk_tree_view_key_press (GtkWidget   *widget,
       /* Send the event to the window.  If the preedit_changed signal is emitted
        * during this event, we will set priv->imcontext_changed  */
       tree_view->priv->imcontext_changed = FALSE;
-      retval = gtk_widget_event (tree_view->priv->search_entry, new_event);
+      retval = gtk_widget_event (tree_view->priv->search_window, new_event);
+      gdk_event_free (new_event);
       gtk_widget_hide (tree_view->priv->search_window);
 
       g_signal_handler_disconnect (tree_view->priv->search_entry, 
@@ -5041,6 +5084,11 @@ validate_visible_area (GtkTreeView *tree_view)
       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
       gtk_tree_view_dy_to_top_row (tree_view);
     }
+  else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+    {
+      gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
+      gtk_tree_view_dy_to_top_row (tree_view);
+    }
   else
     gtk_tree_view_top_row_to_dy (tree_view);
 
@@ -5491,7 +5539,7 @@ set_source_row (GdkDragContext *context,
                 GtkTreePath    *source_row)
 {
   g_object_set_data_full (G_OBJECT (context),
-                          g_intern_static_string ("gtk-tree-view-source-row"),
+                          I_("gtk-tree-view-source-row"),
                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
 }
@@ -5539,7 +5587,7 @@ set_dest_row (GdkDragContext *context,
 
   if (!dest_row)
     {
-      g_object_set_data_full (G_OBJECT (context), g_intern_static_string ("gtk-tree-view-dest-row"),
+      g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
                               NULL, NULL);
       return;
     }
@@ -5551,7 +5599,7 @@ set_dest_row (GdkDragContext *context,
   dr->empty_view_drop = empty_view_drop;
   dr->drop_append_mode = drop_append_mode;
 
-  g_object_set_data_full (G_OBJECT (context), g_intern_static_string ("gtk-tree-view-dest-row"),
+  g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
                           dr, (GDestroyNotify) dest_row_free);
 }
 
@@ -5594,7 +5642,7 @@ set_status_pending (GdkDragContext *context,
                     GdkDragAction   suggested_action)
 {
   g_object_set_data (G_OBJECT (context),
-                     g_intern_static_string ("gtk-tree-view-status-pending"),
+                     I_("gtk-tree-view-status-pending"),
                      GINT_TO_POINTER (suggested_action));
 }
 
@@ -5649,7 +5697,7 @@ ensure_info (GtkTreeView *tree_view)
       di = g_new0 (TreeViewDragInfo, 1);
 
       g_object_set_data_full (G_OBJECT (tree_view),
-                              g_intern_static_string ("gtk-tree-view-drag-info"),
+                              I_("gtk-tree-view-drag-info"),
                               di,
                               (GDestroyNotify) destroy_info);
     }
@@ -5660,7 +5708,7 @@ ensure_info (GtkTreeView *tree_view)
 static void
 remove_info (GtkTreeView *tree_view)
 {
-  g_object_set_data (G_OBJECT (tree_view), g_intern_static_string ("gtk-tree-view-drag-info"), NULL);
+  g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
 }
 
 #if 0
@@ -6156,7 +6204,7 @@ gtk_tree_view_drag_data_get (GtkWidget        *widget,
     goto done;
 
   /* If drag_data_get does nothing, try providing row data. */
-  if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+  if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
     {
       gtk_tree_set_row_drag_data (selection_data,
                                  model,
@@ -6206,10 +6254,6 @@ gtk_tree_view_drag_leave (GtkWidget      *widget,
                           GdkDragContext *context,
                           guint             time)
 {
-  TreeViewDragInfo *di;
-
-  di = get_info (GTK_TREE_VIEW (widget));
-
   /* unset any highlight row */
   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
                                    NULL,
@@ -6229,7 +6273,6 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
 {
   gboolean empty;
   GtkTreePath *path = NULL;
-  GtkTreeModel *model;
   GtkTreeViewDropPosition pos;
   GtkTreeView *tree_view;
   GdkDragAction suggested_action = 0;
@@ -6243,7 +6286,6 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
 
   /* we only know this *after* set_desination_row */
-  model = gtk_tree_view_get_model (tree_view);
   empty = tree_view->priv->empty_view_drop;
 
   if (path == NULL && !empty)
@@ -6266,7 +6308,7 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
            g_timeout_add (150, scroll_row_timeout, tree_view);
        }
 
-      if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+      if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
         {
           /* Request data so we can use the source row when
            * determining whether to accept the drop
@@ -6676,7 +6718,6 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
                            GtkDirectionType  dir)
 {
   GtkWidget *focus_child;
-  GtkContainer *container;
 
   GList *last_column, *first_column;
   GList *tmp_list;
@@ -6686,7 +6727,6 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
     return FALSE;
 
   focus_child = GTK_CONTAINER (tree_view)->focus_child;
-  container = GTK_CONTAINER (tree_view);
 
   first_column = tree_view->priv->columns;
   while (first_column)
@@ -6815,9 +6855,10 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
     {
       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
        if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
-         break;
-
-      tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
+         {
+           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
+           break;
+         }
 
       /* If the following isn't true, then the view is smaller then the scrollpane.
        */
@@ -7000,8 +7041,7 @@ gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
   if (tree_view->priv->hadjustment != hadj)
     {
       tree_view->priv->hadjustment = hadj;
-      g_object_ref (tree_view->priv->hadjustment);
-      gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
+      g_object_ref_sink (tree_view->priv->hadjustment);
 
       g_signal_connect (tree_view->priv->hadjustment, "value_changed",
                        G_CALLBACK (gtk_tree_view_adjustment_changed),
@@ -7012,8 +7052,7 @@ gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
   if (tree_view->priv->vadjustment != vadj)
     {
       tree_view->priv->vadjustment = vadj;
-      g_object_ref (tree_view->priv->vadjustment);
-      gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
+      g_object_ref_sink (tree_view->priv->vadjustment);
 
       g_signal_connect (tree_view->priv->vadjustment, "value_changed",
                        G_CALLBACK (gtk_tree_view_adjustment_changed),
@@ -7205,6 +7244,11 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   if (tree == NULL)
     goto done;
 
+  /* Check if the node became insensitive, and if so, unselect it */
+  if (!_gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+                                             node, path))
+    gtk_tree_selection_unselect_path (tree_view->priv->selection, path);
+
   if (tree_view->priv->fixed_height_mode
       && tree_view->priv->fixed_height >= 0)
     {
@@ -7688,23 +7732,14 @@ gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
       else
        x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
     }
-  if (x1)
-    {
-      *x1 = x_offset;
-    }
 
+  *x1 = x_offset;
+  
   if (tmp_column && tmp_column->visible)
-    {
-      /* +1 because x2 isn't included in the range. */
-      if (x2)
-        *x2 = *x1 + tree_view->priv->expander_size + 1;
-    }
+    /* +1 because x2 isn't included in the range. */
+    *x2 = *x1 + tree_view->priv->expander_size + 1;
   else
-    {
-      /* return an empty range, the expander column is hidden */
-      if (x2)
-        *x2 = *x1;
-    }
+    *x2 = *x1;
 }
 
 static void
@@ -8046,6 +8081,7 @@ static void
 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
                                guint           keyval,
                                guint           modmask,
+                               gboolean        add_shifted_binding,
                                GtkMovementStep step,
                                gint            count)
 {
@@ -8055,10 +8091,11 @@ gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
                                 G_TYPE_ENUM, step,
                                 G_TYPE_INT, count);
 
-  gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
-                                "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,
+                                 G_TYPE_ENUM, step,
+                                 G_TYPE_INT, count);
 
   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
    return;
@@ -8434,6 +8471,7 @@ gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
   GtkStateType state;
   GtkWidget *widget;
   gint x_offset = 0;
+  gint x2;
   gint vertical_separator;
   gint expander_size;
   GtkExpanderStyle expander_style;
@@ -8448,7 +8486,7 @@ gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
 
   widget = GTK_WIDGET (tree_view);
 
-  gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL);
+  gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
 
   area.x = x_offset;
   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
@@ -9025,6 +9063,7 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
 
   return TRUE;
 }
+
 static gboolean
 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
 {
@@ -9035,7 +9074,7 @@ gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
 
   GDK_THREADS_LEAVE ();
 
-  return TRUE;
+  return FALSE;
 }
 
 /* Cut and paste from gtkwindow.c */
@@ -9069,6 +9108,9 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
 {
   GtkWidget *frame, *vbox, *toplevel;
 
+  if (tree_view->priv->search_custom_entry_set)
+    return;
+
   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
 
    if (tree_view->priv->search_window != NULL)
@@ -9149,6 +9191,9 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
   if (!tree_view->priv->enable_search && !keybinding)
     return FALSE;
 
+  if (tree_view->priv->search_custom_entry_set)
+    return FALSE;
+
   if (tree_view->priv->search_window != NULL &&
       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
     return TRUE;
@@ -9183,7 +9228,7 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
 
   /* done, show it */
-  tree_view->priv->search_dialog_position_func (tree_view, tree_view->priv->search_window);
+  tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
   gtk_widget_show (tree_view->priv->search_window);
   if (tree_view->priv->search_entry_changed_id == 0)
     {
@@ -9218,6 +9263,7 @@ gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
 {
   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
 }
+
 /* this function returns the new width of the column being resized given
  * the column and x position of the cursor; the x cursor position is passed
  * in as a pointer and automagicly corrected if it's beyond min/max limits
@@ -9478,15 +9524,7 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
                                           tree_view->priv->model);
 
       if (tree_view->priv->tree)
-       {
-         _gtk_rbtree_free (tree_view->priv->tree);
-         tree_view->priv->tree = NULL;
-       }
-
-      tree_view->priv->prelight_node = NULL;
-      tree_view->priv->prelight_tree = NULL;
-      tree_view->priv->button_pressed_node = NULL;
-      tree_view->priv->button_pressed_tree = NULL;
+       gtk_tree_view_free_rbtree (tree_view);
 
       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
       tree_view->priv->drag_dest_row = NULL;
@@ -9515,7 +9553,6 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
 
   tree_view->priv->model = model;
 
-
   if (tree_view->priv->model)
     {
       gint i;
@@ -9579,6 +9616,9 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
 
   g_object_notify (G_OBJECT (tree_view), "model");
 
+  if (tree_view->priv->selection)
+  _gtk_tree_selection_emit_changed (tree_view->priv->selection);
+
   if (GTK_WIDGET_REALIZED (tree_view))
     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
 }
@@ -9809,6 +9849,30 @@ gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
 }
 
 
+/**
+ * gtk_tree_view_get_headers_clickable:
+ * @tree_view: A #GtkTreeView.
+ *
+ * Returns whether all header columns are clickable.
+ *
+ * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
+ *
+ * Since: 2.10
+ **/
+gboolean 
+gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
+{
+  GList *list;
+  
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+  for (list = tree_view->priv->columns; list; list = list->next)
+    if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
+      return FALSE;
+
+  return TRUE;
+}
+
 /**
  * gtk_tree_view_set_rules_hint
  * @tree_view: a #GtkTreeView
@@ -9977,8 +10041,7 @@ gtk_tree_view_insert_column (GtkTreeView       *tree_view,
     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
 
-  g_object_ref (column);
-  gtk_object_sink (GTK_OBJECT (column));
+  g_object_ref_sink (column);
 
   if (tree_view->priv->n_columns == 0 &&
       GTK_WIDGET_REALIZED (tree_view) &&
@@ -10393,6 +10456,7 @@ gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
    * it is much slower than just going to the point.
    */
   if (! GTK_WIDGET_VISIBLE (tree_view) ||
+      ! GTK_WIDGET_REALIZED (tree_view) ||
       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
     {
@@ -10708,6 +10772,11 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
   GtkTreeIter temp;
   gboolean expand;
 
+  if (animate)
+    g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
+                  "gtk-enable-animations", &animate,
+                  NULL);
+
   remove_auto_expand_timeout (tree_view);
 
   if (node->children && !open_all)
@@ -10851,9 +10920,13 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
   gboolean collapse;
   gint x, y;
   GList *list;
-  GdkDisplay *display;
   GdkWindow *child, *parent;
 
+  if (animate)
+    g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
+                  "gtk-enable-animations", &animate,
+                  NULL);
+
   remove_auto_expand_timeout (tree_view);
 
   if (node->children == NULL)
@@ -10959,6 +11032,14 @@ 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;
+    }
+
   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
     {
       _gtk_rbtree_remove (node->children);
@@ -10973,14 +11054,6 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
       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;
-    }
-
   if (animate)
     {
       tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
@@ -11002,7 +11075,6 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
       /* now that we've collapsed all rows, we want to try to set the prelight
        * again. To do this, we fake a motion event and send it to ourselves. */
 
-      display = gdk_drawable_get_display (tree_view->priv->bin_window);
       child = tree_view->priv->bin_window;
       parent = gdk_window_get_parent (child);
 
@@ -11787,6 +11859,8 @@ gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
  * Sets @start_path and @end_path to be the first and last visible path.
  * Note that there may be invisible paths in between.
  *
+ * The paths should be freed with gtk_tree_path_free() after use.
+ *
  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
  *
  * Since: 2.8
@@ -12188,8 +12262,8 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
  * @tree_view: a #GtkTreeView
  * @path: a #GtkTreePath in @tree_view
  *
- * Creates a #GdkPixmap representation of the row at @path.  This image is used
- * for a drag icon.
+ * Creates a #GdkPixmap representation of the row at @path.  
+ * This image is used for a drag icon.
  *
  * Return value: a newly-allocated pixmap of the drag icon.
  **/
@@ -12212,8 +12286,14 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
   gint bin_window_width;
   gboolean is_separator = FALSE;
 
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+  g_return_val_if_fail (path != NULL, NULL);
+
   widget = GTK_WIDGET (tree_view);
 
+  if (!GTK_WIDGET_REALIZED (tree_view))
+    return NULL;
+
   depth = gtk_tree_path_get_depth (path);
 
   _gtk_tree_view_find_node (tree_view,
@@ -12491,6 +12571,146 @@ gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
 }
 
+/**
+ * gtk_tree_view_get_search_entry:
+ * @tree_view: A #GtkTreeView
+ *
+ * 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.
+ *
+ * Return value: the entry currently in use as search entry.
+ *
+ * Since: 2.10
+ */
+GtkEntry *
+gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+  if (tree_view->priv->search_custom_entry_set)
+    return GTK_ENTRY (tree_view->priv->search_entry);
+
+  return NULL;
+}
+
+/**
+ * gtk_tree_view_set_search_entry:
+ * @tree_view: A #GtkTreeView
+ * @entry: the entry the interactive search code of @tree_view should use or %NULL
+ *
+ * Sets the entry which the interactive search code will use for this
+ * @tree_view.  This is useful when you want to provide a search entry
+ * in our interface at all time at a fixed position.  Passing %NULL for
+ * @entry will make the interactive search code use the built-in popup
+ * entry again.
+ *
+ * Since: 2.10
+ */
+void
+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));
+
+  if (tree_view->priv->search_custom_entry_set)
+    {
+      if (tree_view->priv->search_entry_changed_id)
+        {
+         g_signal_handler_disconnect (tree_view->priv->search_entry,
+                                      tree_view->priv->search_entry_changed_id);
+         tree_view->priv->search_entry_changed_id = 0;
+       }
+      g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
+                                           G_CALLBACK (gtk_tree_view_search_key_press_event),
+                                           tree_view);
+
+      g_object_unref (tree_view->priv->search_entry);
+    }
+  else if (tree_view->priv->search_window)
+    {
+      gtk_widget_destroy (tree_view->priv->search_window);
+
+      tree_view->priv->search_window = NULL;
+    }
+
+  if (entry)
+    {
+      tree_view->priv->search_entry = g_object_ref (entry);
+      tree_view->priv->search_custom_entry_set = TRUE;
+
+      if (tree_view->priv->search_entry_changed_id == 0)
+        {
+          tree_view->priv->search_entry_changed_id =
+           g_signal_connect (tree_view->priv->search_entry, "changed",
+                             G_CALLBACK (gtk_tree_view_search_init),
+                             tree_view);
+       }
+      
+        g_signal_connect (tree_view->priv->search_entry, "key_press_event",
+                         G_CALLBACK (gtk_tree_view_search_key_press_event),
+                         tree_view);
+
+       gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
+    }
+  else
+    {
+      tree_view->priv->search_entry = NULL;
+      tree_view->priv->search_custom_entry_set = FALSE;
+    }
+}
+
+/**
+ * gtk_tree_view_set_search_position_func:
+ * @tree_view: A #GtkTreeView
+ * @func: the function to use to position the search dialog
+ * @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.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
+                                       GtkTreeViewSearchPositionFunc  func,
+                                       gpointer                       user_data,
+                                       GDestroyNotify                 destroy)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+  g_return_if_fail (func !=NULL);
+
+  if (tree_view->priv->search_position_destroy)
+    (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
+
+  tree_view->priv->search_position_func = func;
+  tree_view->priv->search_position_user_data = user_data;
+  tree_view->priv->search_position_destroy = destroy;
+  if (tree_view->priv->search_position_func == NULL)
+    tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
+}
+
+/**
+ * gtk_tree_view_get_search_position_func:
+ * @tree_view: A #GtkTreeView
+ *
+ * Returns the positioning function currently in use.
+ *
+ * Return value: the currently used function for positioning the search dialog.
+ *
+ * Since: 2.10
+ */
+GtkTreeViewSearchPositionFunc
+gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+  return tree_view->priv->search_position_func;
+}
+
+
 static void
 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
                                  GtkTreeView *tree_view)
@@ -12518,7 +12738,8 @@ gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
 
 static void
 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
-                                   GtkWidget   *search_dialog)
+                                   GtkWidget   *search_dialog,
+                                   gpointer     user_data)
 {
   gint x, y;
   gint tree_x, tree_y;
@@ -12540,14 +12761,14 @@ gtk_tree_view_search_position_func (GtkTreeView *tree_view,
                         &tree_height);
   gtk_widget_size_request (search_dialog, &requisition);
 
-  if (tree_x + tree_width - requisition.width > gdk_screen_get_width (screen))
+  if (tree_x + tree_width > gdk_screen_get_width (screen))
     x = gdk_screen_get_width (screen) - requisition.width;
   else if (tree_x + tree_width - requisition.width < 0)
     x = 0;
   else
     x = tree_x + tree_width - requisition.width;
 
-  if (tree_y + tree_height > gdk_screen_get_height (screen))
+  if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
     y = gdk_screen_get_height (screen) - requisition.height;
   else if (tree_y + tree_height < 0) /* isn't really possible ... */
     y = 0;
@@ -12694,8 +12915,11 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
 
   /* close window and cancel the search */
-  if (event->keyval == GDK_Escape ||
-      event->keyval == GDK_Tab)
+  if (!tree_view->priv->search_custom_entry_set
+      && (event->keyval == GDK_Escape ||
+          event->keyval == GDK_Tab ||
+           event->keyval == GDK_KP_Tab ||
+           event->keyval == GDK_ISO_Left_Tab))
     {
       gtk_tree_view_search_dialog_hide (widget, tree_view);
       return TRUE;
@@ -12708,6 +12932,13 @@ 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))
+      && (event->keyval == GDK_g || event->keyval == GDK_G))
+    {
+      gtk_tree_view_search_move (widget, tree_view, TRUE);
+      retval = TRUE;
+    }
+
   /* select next matching iter */
   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
     {
@@ -12715,7 +12946,7 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
       retval = TRUE;
     }
 
-  if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK
+  if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
       && (event->keyval == GDK_g || event->keyval == GDK_G))
     {
       gtk_tree_view_search_move (widget, tree_view, FALSE);
@@ -12723,7 +12954,8 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
     }
 
   /* renew the flush timeout */
-  if (retval && tree_view->priv->typeselect_flush_timeout)
+  if (retval && tree_view->priv->typeselect_flush_timeout
+      && !tree_view->priv->search_custom_entry_set)
     {
       g_source_remove (tree_view->priv->typeselect_flush_timeout);
       tree_view->priv->typeselect_flush_timeout =
@@ -12973,7 +13205,8 @@ gtk_tree_view_search_init (GtkWidget   *entry,
 
   /* search */
   gtk_tree_selection_unselect_all (selection);
-  if (tree_view->priv->typeselect_flush_timeout)
+  if (tree_view->priv->typeselect_flush_timeout
+      && tree_view->priv->search_custom_entry_set)
     {
       g_source_remove (tree_view->priv->typeselect_flush_timeout);
       tree_view->priv->typeselect_flush_timeout =