]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktreeview.c
Estonian translation update by Ivar Smolin.
[~andy/gtk] / gtk / gtktreeview.c
index 26ff3484820c7cba1787f0dfc07dc5fbdbae56b0..65c1a17f3f29e0b07390622da6747d7b34e9c882 100644 (file)
@@ -29,6 +29,7 @@
 #include "gtkcellrenderer.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
+#include "gtkbuildable.h"
 #include "gtkbutton.h"
 #include "gtkalignment.h"
 #include "gtklabel.h"
@@ -41,6 +42,7 @@
 #include "gtkentry.h"
 #include "gtkframe.h"
 #include "gtktreemodelsort.h"
+#include "gtktooltip.h"
 #include "gtkprivate.h"
 #include "gtkalias.h"
 
 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
 
+/* Translate from bin_window coordinates to rbtree (tree coordinates) and
+ * vice versa.
+ */
 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
 
-/* This is in Window coordinates */
+/* This is in bin_window coordinates */
 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
 
@@ -138,7 +143,8 @@ enum {
   PROP_LEVEL_INDENTATION,
   PROP_RUBBER_BANDING,
   PROP_ENABLE_GRID_LINES,
-  PROP_ENABLE_TREE_LINES
+  PROP_ENABLE_TREE_LINES,
+  PROP_TOOLTIP_COLUMN
 };
 
 /* object signals */
@@ -352,7 +358,8 @@ static void     gtk_tree_view_clamp_node_visible             (GtkTreeView
                                                              GtkRBTree         *tree,
                                                              GtkRBNode         *node);
 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView       *tree_view,
-                                                             GtkTreeViewColumn *column);
+                                                             GtkTreeViewColumn *column,
+                                                             gboolean           focus_to_cell);
 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView       *tree_view,
                                                              GdkEventMotion    *event);
 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView       *tree_view);
@@ -456,11 +463,13 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree
                                                         GtkTreeViewColumn *column,
                                                         gint               drop_position);
 
-static void gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
-                                                     gint         wx,
-                                                     gint         wy,
-                                                     gint        *tx,
-                                                     gint        *ty);
+/* GtkBuildable */
+static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
+                                              GtkBuilder  *builder,
+                                              GObject     *child,
+                                              const gchar *type);
+static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
+
 
 static gboolean scroll_row_timeout                   (gpointer     data);
 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
@@ -473,7 +482,9 @@ static guint tree_view_signals [LAST_SIGNAL] = { 0 };
 /* GType Methods
  */
 
-G_DEFINE_TYPE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+                                               gtk_tree_view_buildable_init))
 
 static void
 gtk_tree_view_class_init (GtkTreeViewClass *class)
@@ -689,6 +700,13 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                            FALSE,
                                                            GTK_PARAM_READWRITE));
 
+    /**
+     * GtkTreeView:show-expanders:
+     *
+     * %TRUE if the view has expanders.
+     *
+     * Since: 2.12
+     */
     g_object_class_install_property (o_class,
                                     PROP_SHOW_EXPANDERS,
                                     g_param_spec_boolean ("show-expanders",
@@ -697,6 +715,13 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                           TRUE,
                                                           GTK_PARAM_READWRITE));
 
+    /**
+     * GtkTreeView:level-indentation:
+     *
+     * Extra indentation for each level.
+     *
+     * Since: 2.12
+     */
     g_object_class_install_property (o_class,
                                     PROP_LEVEL_INDENTATION,
                                     g_param_spec_int ("level-indentation",
@@ -732,6 +757,16 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                            FALSE,
                                                            GTK_PARAM_READWRITE));
 
+    g_object_class_install_property (o_class,
+                                    PROP_TOOLTIP_COLUMN,
+                                    g_param_spec_int ("tooltip-column",
+                                                      P_("Tooltip Column"),
+                                                      P_("The column in the model containing the tooltip texts for the rows"),
+                                                      -1,
+                                                      G_MAXINT,
+                                                      -1,
+                                                      GTK_PARAM_READWRITE));
+
   /* Style properties */
 #define _TREE_VIEW_EXPANDER_SIZE 12
 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
@@ -874,7 +909,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
    * The given row is about to be expanded (show its children nodes). Use this
    * signal if you need to control the expandability of individual rows.
    *
-   * Returns: %TRUE to allow expansion, %FALSE to reject
+   * Returns: %FALSE to allow expansion, %TRUE to reject
    */
   tree_view_signals[TEST_EXPAND_ROW] =
     g_signal_new (I_("test-expand-row"),
@@ -896,7 +931,7 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
    * The given row is about to be collapsed (hide its children nodes). Use this
    * signal if you need to control the collapsibility of individual rows.
    *
-   * Returns: %TRUE to allow expansion, %FALSE to reject
+   * Returns: %FALSE to allow collapsing, %TRUE to reject
    */
   tree_view_signals[TEST_COLLAPSE_ROW] =
     g_signal_new (I_("test-collapse-row"),
@@ -1269,6 +1304,12 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
 }
 
+static void
+gtk_tree_view_buildable_init (GtkBuildableIface *iface)
+{
+  iface->add_child = gtk_tree_view_buildable_add_child;
+}
+
 static void
 gtk_tree_view_init (GtkTreeView *tree_view)
 {
@@ -1284,6 +1325,7 @@ gtk_tree_view_init (GtkTreeView *tree_view)
 
   /* We need some padding */
   tree_view->priv->dy = 0;
+  tree_view->priv->cursor_offset = 0;
   tree_view->priv->n_columns = 0;
   tree_view->priv->header_height = 1;
   tree_view->priv->x_drag = 0;
@@ -1318,6 +1360,8 @@ gtk_tree_view_init (GtkTreeView *tree_view)
 
   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
   tree_view->priv->tree_lines_enabled = FALSE;
+
+  tree_view->priv->tooltip_column = -1;
 }
 
 \f
@@ -1391,6 +1435,9 @@ gtk_tree_view_set_property (GObject         *object,
     case PROP_ENABLE_TREE_LINES:
       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
       break;
+    case PROP_TOOLTIP_COLUMN:
+      gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
+      break;
     default:
       break;
     }
@@ -1462,6 +1509,9 @@ gtk_tree_view_get_property (GObject    *object,
     case PROP_ENABLE_TREE_LINES:
       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);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1476,6 +1526,15 @@ gtk_tree_view_finalize (GObject *object)
 
 \f
 
+static void
+gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
+                                  GtkBuilder  *builder,
+                                  GObject     *child,
+                                  const gchar *type)
+{
+  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
+}
+
 /* GtkObject Methods
  */
 
@@ -1807,6 +1866,12 @@ gtk_tree_view_unrealize (GtkWidget *widget)
       priv->scroll_timeout = 0;
     }
 
+  if (priv->auto_expand_timeout != 0)
+    {
+      g_source_remove (priv->auto_expand_timeout);
+      priv->auto_expand_timeout = 0;
+    }
+
   if (priv->open_dest_timeout != 0)
     {
       g_source_remove (priv->open_dest_timeout);
@@ -2951,7 +3016,7 @@ static gboolean
 coords_are_over_arrow (GtkTreeView *tree_view,
                        GtkRBTree   *tree,
                        GtkRBNode   *node,
-                       /* these are in window coords */
+                       /* these are in bin window coords */
                        gint         x,
                        gint         y)
 {
@@ -3017,7 +3082,7 @@ static void
 do_prelight (GtkTreeView *tree_view,
              GtkRBTree   *tree,
              GtkRBNode   *node,
-            /* these are in tree_window coords */
+            /* these are in bin_window coords */
              gint         x,
              gint         y)
 {
@@ -3113,7 +3178,7 @@ static void
 prelight_or_select (GtkTreeView *tree_view,
                    GtkRBTree   *tree,
                    GtkRBNode   *node,
-                   /* these are in tree_window coords */
+                   /* these are in bin_window coords */
                    gint         x,
                    gint         y)
 {
@@ -5073,6 +5138,14 @@ gtk_tree_view_key_press (GtkWidget   *widget,
 {
   GtkTreeView *tree_view = (GtkTreeView *) widget;
 
+  if (tree_view->priv->rubber_band_status)
+    {
+      if (event->keyval == GDK_Escape)
+       gtk_tree_view_stop_rubber_band (tree_view);
+
+      return TRUE;
+    }
+
   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
     {
       if (event->keyval == GDK_Escape)
@@ -5086,7 +5159,6 @@ gtk_tree_view_key_press (GtkWidget   *widget,
   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
     {
       GList *focus_column;
-      gint focus_column_width = 0;
       gboolean rtl;
 
       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
@@ -5099,9 +5171,6 @@ gtk_tree_view_key_press (GtkWidget   *widget,
 
           if (GTK_WIDGET_HAS_FOCUS (column->button))
             break;
-
-          if (column->visible)
-            focus_column_width += GTK_TREE_VIEW_COLUMN (column)->width;
         }
 
       if (focus_column &&
@@ -5220,61 +5289,6 @@ gtk_tree_view_key_press (GtkWidget   *widget,
 
           return TRUE;
         }
-
-      if (focus_column &&
-          (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
-           || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
-        {
-          if ((event->keyval == (rtl ? GDK_Right : GDK_Left)
-               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left)))
-            {
-              GList *tmp;
-
-              for (tmp = focus_column->prev; tmp; tmp = tmp->prev)
-                if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
-                  break;
-
-              if (!tmp)
-                {
-                  gtk_widget_error_bell (widget);
-                  return TRUE;
-                }
-
-              tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
-              gtk_widget_grab_focus (tree_view->priv->focus_column->button);
-              focus_column_width -= tree_view->priv->focus_column->width;
-              gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                        CLAMP (focus_column_width,
-                                               tree_view->priv->hadjustment->lower,
-                                               tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
-            }
-          else if ((event->keyval == (rtl ? GDK_Left : GDK_Right)
-                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right)))
-            {
-              GList *tmp;
-
-              for (tmp = focus_column->next; tmp; tmp = tmp->next)
-                if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
-                  break;
-
-              if (!tmp)
-                {
-                  gtk_widget_error_bell (widget);
-                  return TRUE;
-                }
-
-              tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
-
-              gtk_widget_grab_focus (tree_view->priv->focus_column->button);
-              focus_column_width += tree_view->priv->focus_column->width;
-              gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                        CLAMP (focus_column_width,
-                                               tree_view->priv->hadjustment->lower,
-                                               tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
-            }
-
-          return TRUE;
-        }
     }
 
   /* Chain up to the parent class.  It handles the keybindings. */
@@ -5352,6 +5366,11 @@ static gboolean
 gtk_tree_view_key_release (GtkWidget   *widget,
                           GdkEventKey *event)
 {
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+  if (tree_view->priv->rubber_band_status)
+    return TRUE;
+
   return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
 }
 
@@ -6721,6 +6740,7 @@ scroll_row_timeout (gpointer data)
 static gboolean
 set_destination_row (GtkTreeView    *tree_view,
                      GdkDragContext *context,
+                     /* coordinates relative to the widget */
                      gint            x,
                      gint            y,
                      GdkDragAction  *suggested_action,
@@ -7130,6 +7150,7 @@ gtk_tree_view_drag_leave (GtkWidget      *widget,
 static gboolean
 gtk_tree_view_drag_motion (GtkWidget        *widget,
                            GdkDragContext   *context,
+                          /* coordinates relative to the widget */
                            gint              x,
                            gint              y,
                            guint             time)
@@ -7195,6 +7216,7 @@ gtk_tree_view_drag_motion (GtkWidget        *widget,
 static gboolean
 gtk_tree_view_drag_drop (GtkWidget        *widget,
                          GdkDragContext   *context,
+                        /* coordinates relative to the widget */
                          gint              x,
                          gint              y,
                          guint             time)
@@ -7259,6 +7281,7 @@ gtk_tree_view_drag_drop (GtkWidget        *widget,
 static void
 gtk_tree_view_drag_data_received (GtkWidget        *widget,
                                   GdkDragContext   *context,
+                                 /* coordinates relative to the widget */
                                   gint              x,
                                   gint              y,
                                   GtkSelectionData *selection_data,
@@ -7577,7 +7600,8 @@ gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
  */
 static gboolean
 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
-                           GtkDirectionType  dir)
+                           GtkDirectionType  dir,
+                           gboolean          clamp_column_visible)
 {
   GtkWidget *focus_child;
 
@@ -7618,12 +7642,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
     }
 
 
-   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-   if (rtl) {
-     GList *temp = first_column;
-     first_column = last_column;
-     last_column = temp;
-   }
+  rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
 
   switch (dir)
     {
@@ -7668,16 +7687,10 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
        if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
          break;
 
-      if (tmp_list == first_column && dir == GTK_DIR_LEFT)
-       {
-         focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
-         gtk_widget_grab_focus (focus_child);
-         break;
-       }
-      else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
-       {
-         focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
-         gtk_widget_grab_focus (focus_child);
+      if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
+         || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
+        {
+         gtk_widget_error_bell (GTK_WIDGET (tree_view));
          break;
        }
 
@@ -7685,7 +7698,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
        {
          GtkTreeViewColumn *column;
 
-         if (dir == GTK_DIR_RIGHT)
+         if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
            tmp_list = tmp_list->next;
          else
            tmp_list = tmp_list->prev;
@@ -7722,20 +7735,11 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
            break;
          }
 
-      /* If the following isn't true, then the view is smaller then the scrollpane.
-       */
-      if ((focus_child->allocation.x + focus_child->allocation.width) <=
-         (tree_view->priv->hadjustment->upper))
-       {
-         /* Scroll to the button, if needed */
-         if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
-             (focus_child->allocation.x + focus_child->allocation.width))
-           gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                     focus_child->allocation.x + focus_child->allocation.width -
-                                     tree_view->priv->hadjustment->page_size);
-         else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
-           gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                                     focus_child->allocation.x);
+      if (clamp_column_visible)
+        {
+         gtk_tree_view_clamp_column_visible (tree_view,
+                                             tree_view->priv->focus_column,
+                                             FALSE);
        }
     }
 
@@ -7769,7 +7773,7 @@ gtk_tree_view_focus (GtkWidget        *widget,
        {
        case GTK_DIR_LEFT:
        case GTK_DIR_RIGHT:
-         gtk_tree_view_header_focus (tree_view, direction);
+         gtk_tree_view_header_focus (tree_view, direction, TRUE);
          return TRUE;
        case GTK_DIR_TAB_BACKWARD:
        case GTK_DIR_UP:
@@ -7787,14 +7791,14 @@ gtk_tree_view_focus (GtkWidget        *widget,
   /* Case 2. We don't have focus at all. */
   if (!GTK_WIDGET_HAS_FOCUS (container))
     {
-      if (!gtk_tree_view_header_focus (tree_view, direction))
+      if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
        gtk_widget_grab_focus (widget);
       return TRUE;
     }
 
   /* Case 3. We have focus already. */
   if (direction == GTK_DIR_TAB_BACKWARD)
-    return (gtk_tree_view_header_focus (tree_view, direction));
+    return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
   else if (direction == GTK_DIR_TAB_FORWARD)
     return FALSE;
 
@@ -7827,6 +7831,7 @@ gtk_tree_view_style_set (GtkWidget *widget,
     {
       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
+      gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
 
       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
@@ -7991,6 +7996,7 @@ gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
 static void
 gtk_tree_view_put (GtkTreeView *tree_view,
                   GtkWidget   *child_widget,
+                  /* in tree coordinates */
                   gint         x,
                   gint         y,
                   gint         width,
@@ -8020,6 +8026,7 @@ gtk_tree_view_put (GtkTreeView *tree_view,
 void
 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
                                  GtkWidget   *widget,
+                                 /* in tree coordinates */
                                  gint         x,
                                  gint         y,
                                  gint         width,
@@ -8066,7 +8073,6 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   GtkRBTree *tree;
   GtkRBNode *node;
   gboolean free_path = FALSE;
-  gint vertical_separator;
   GList *list;
   GtkTreePath *cursor_path;
 
@@ -8084,8 +8090,6 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
   if (cursor_path != NULL)
     gtk_tree_path_free (cursor_path);
 
-  gtk_widget_style_get (GTK_WIDGET (data), "vertical-separator", &vertical_separator, NULL);
-
   if (path == NULL)
     {
       path = gtk_tree_model_get_path (model, iter);
@@ -8834,18 +8838,76 @@ gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
 
 static void
 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
-                                   GtkTreeViewColumn *column)
+                                   GtkTreeViewColumn *column,
+                                   gboolean           focus_to_cell)
 {
+  gint x, width;
+
   if (column == NULL)
     return;
-  if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
-      (column->button->allocation.x + column->button->allocation.width))
-    gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                             column->button->allocation.x + column->button->allocation.width -
-                             tree_view->priv->hadjustment->page_size);
-  else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
-    gtk_adjustment_set_value (tree_view->priv->hadjustment,
-                             column->button->allocation.x);
+
+  x = column->button->allocation.x;
+  width = column->button->allocation.width;
+
+  if (width > tree_view->priv->hadjustment->page_size)
+    {
+      /* The column is larger than the horizontal page size.  If the
+       * column has cells which can be focussed individually, then we make
+       * sure the cell which gets focus is fully visible (if even the
+       * focus cell is bigger than the page size, we make sure the
+       * left-hand side of the cell is visible).
+       *
+       * If the column does not have those so-called special cells, we
+       * make sure the left-hand side of the column is visible.
+       */
+
+      if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
+        {
+         GtkTreePath *cursor_path;
+         GdkRectangle background_area, cell_area, focus_area;
+
+         cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+
+         gtk_tree_view_get_cell_area (tree_view,
+                                      cursor_path, column, &cell_area);
+         gtk_tree_view_get_background_area (tree_view,
+                                            cursor_path, column,
+                                            &background_area);
+
+         gtk_tree_path_free (cursor_path);
+
+         _gtk_tree_view_column_get_focus_area (column,
+                                               &background_area,
+                                               &cell_area,
+                                               &focus_area);
+
+         x = focus_area.x;
+         width = focus_area.width;
+
+         if (width < tree_view->priv->hadjustment->page_size)
+           {
+             if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
+               gtk_adjustment_set_value (tree_view->priv->hadjustment,
+                                         x + width - tree_view->priv->hadjustment->page_size);
+             else if (tree_view->priv->hadjustment->value > x)
+               gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
+           }
+       }
+
+      gtk_adjustment_set_value (tree_view->priv->hadjustment,
+                               CLAMP (x,
+                                      tree_view->priv->hadjustment->lower,
+                                      tree_view->priv->hadjustment->upper
+                                      - tree_view->priv->hadjustment->page_size));
+    }
+  else
+    {
+      if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
+         gtk_adjustment_set_value (tree_view->priv->hadjustment,
+                                   x + width - tree_view->priv->hadjustment->page_size);
+      else if (tree_view->priv->hadjustment->value > x)
+       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
+  }
 }
 
 /* This function could be more efficient.  I'll optimize it if profiling seems
@@ -9353,6 +9415,7 @@ static void
 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
                           GtkRBTree   *tree,
                          GtkRBNode   *node,
+                         /* in bin_window coordinates */
                          gint         x,
                          gint         y)
 {
@@ -9628,13 +9691,25 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
 
   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
+  y += tree_view->priv->cursor_offset;
   y += count * (int)tree_view->priv->vadjustment->page_increment;
   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
 
   if (y >= tree_view->priv->height)
     y = tree_view->priv->height - 1;
 
-  y -= _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
+  tree_view->priv->cursor_offset =
+    _gtk_rbtree_find_offset (tree_view->priv->tree, y,
+                            &cursor_tree, &cursor_node);
+
+  if (tree_view->priv->cursor_offset >= BACKGROUND_HEIGHT (cursor_node))
+    {
+      _gtk_rbtree_next_full (cursor_tree, cursor_node,
+                            &cursor_tree, &cursor_node);
+      tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
+    }
+
+  y -= tree_view->priv->cursor_offset;
   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
   g_return_if_fail (cursor_path != NULL);
   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
@@ -9745,7 +9820,8 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
       gtk_widget_error_bell (GTK_WIDGET (tree_view));
     }
 
-  gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
+  gtk_tree_view_clamp_column_visible (tree_view,
+                                     tree_view->priv->focus_column, TRUE);
 }
 
 static void
@@ -11349,7 +11425,7 @@ gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
  *
  * Scrolls the tree view such that the top-left corner of the visible
  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
- * in tree window coordinates.  The @tree_view must be realized before
+ * in tree coordinates.  The @tree_view must be realized before
  * this function is called.  If it isn't, you probably want to be
  * using gtk_tree_view_scroll_to_cell().
  *
@@ -11456,9 +11532,10 @@ gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
       gint dest_x, dest_y;
 
       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
-      gtk_tree_view_tree_window_to_tree_coords (tree_view, cell_rect.x, cell_rect.y, &(cell_rect.x), &(cell_rect.y));
       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
 
+      cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
+
       dest_x = vis_rect.x;
       dest_y = vis_rect.y;
 
@@ -12464,23 +12541,29 @@ gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
 /**
  * gtk_tree_view_get_path_at_pos:
  * @tree_view: A #GtkTreeView.
- * @x: The x position to be identified.
- * @y: The y position to be identified.
+ * @x: The x position to be identified (relative to bin_window).
+ * @y: The y position to be identified (relative to bin_window).
  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
  *
- * Finds the path at the point (@x, @y), relative to widget coordinates.  That
- * is, @x and @y are relative to an events coordinates. @x and @y must come
- * from an event on the @tree_view only where <literal>event->window ==
- * gtk_tree_view_get_bin (<!-- -->)</literal>. It is primarily for things 
- * like popup menus. If @path is non-%NULL, then it will be filled with the 
- * #GtkTreePath at that point.  This path should be freed with gtk_tree_path_free().  
- * If @column is non-%NULL, then it will be filled with the column at that point.
- * @cell_x and @cell_y return the coordinates relative to the cell background
- * (i.e. the @background_area passed to gtk_cell_renderer_render()).  This
- * function is only meaningful if @tree_view is realized.
+ * Finds the path at the point (@x, @y), relative to bin_window coordinates
+ * (please see gtk_tree_view_get_bin_window()).
+ * That is, @x and @y are relative to an events coordinates. @x and @y must
+ * come from an event on the @tree_view only where <literal>event->window ==
+ * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
+ * things like popup menus. If @path is non-%NULL, then it will be filled
+ * with the #GtkTreePath at that point.  This path should be freed with
+ * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
+ * with the column at that point.  @cell_x and @cell_y return the coordinates
+ * relative to the cell background (i.e. the @background_area passed to
+ * gtk_cell_renderer_render()).  This function is only meaningful if
+ * @tree_view is realized.
+ *
+ * For converting widget coordinates (eg. the ones you get from
+ * GtkWidget::query-tooltip), please see
+ * gtk_tree_view_convert_widget_to_bin_window_coords().
  *
  * Return value: %TRUE if a row exists at that coordinate.
  **/
@@ -12593,7 +12676,7 @@ gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
  * @rect: rectangle to fill with cell rect
  *
- * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * Fills the bounding rectangle in bin_window coordinates for the cell at the
  * row specified by @path and the column specified by @column.  If @path is
  * %NULL, or points to a path not currently displayed, the @y and @height fields
  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
@@ -12678,16 +12761,15 @@ gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
  * @rect: rectangle to fill with cell background rect
  *
- * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * Fills the bounding rectangle in bin_window coordinates for the cell at the
  * row specified by @path and the column specified by @column.  If @path is
  * %NULL, or points to a node not found in the tree, the @y and @height fields of
  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
  * fields will be filled with 0.  The returned rectangle is equivalent to the
  * @background_area passed to gtk_cell_renderer_render().  These background
- * areas tile to cover the entire tree window (except for the area used for
- * header buttons). Contrast with the @cell_area, returned by
- * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
- * surrounding borders and the tree expander area.
+ * areas tile to cover the entire bin window.  Contrast with the @cell_area,
+ * returned by gtk_tree_view_get_cell_area(), which returns only the cell
+ * itself, excluding surrounding borders and the tree expander area.
  *
  **/
 void
@@ -12736,10 +12818,10 @@ gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
  * @visible_rect: rectangle to fill
  *
  * Fills @visible_rect with the currently-visible region of the
- * buffer, in tree coordinates. Convert to widget coordinates with
- * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
- * 0,0 for row 0 of the tree, and cover the entire scrollable area of
- * the tree.
+ * buffer, in tree coordinates. Convert to bin_window coordinates with
+ * gtk_tree_view_convert_tree_to_bin_window_coords().
+ * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
+ * scrollable area of the tree.
  **/
 void
 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
@@ -12763,13 +12845,18 @@ gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
 /**
  * gtk_tree_view_widget_to_tree_coords:
  * @tree_view: a #GtkTreeView
- * @wx: widget X coordinate
- * @wy: widget Y coordinate
+ * @wx: X coordinate relative to bin_window
+ * @wy: Y coordinate relative to bin_window
  * @tx: return location for tree X coordinate
  * @ty: return location for tree Y coordinate
  *
- * Converts widget coordinates to coordinates for the
- * tree window (the full scrollable area of the tree).
+ * Converts bin_window coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Deprecated: 2.12: Due to historial reasons the name of this function is
+ * incorrect.  For converting coordinates relative to the widget to
+ * bin_window coordinates, please see
+ * gtk_tree_view_convert_widget_to_bin_window_coords().
  *
  **/
 void
@@ -12787,31 +12874,21 @@ gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
     *ty = wy + tree_view->priv->dy;
 }
 
-static void
-gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
-                                         gint         wx,
-                                         gint         wy,
-                                         gint        *tx,
-                                         gint        *ty)
-{
-  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-
-  if (tx)
-    *tx = wx;
-  if (ty)
-    *ty = wy + tree_view->priv->dy;
-}
-
 /**
  * gtk_tree_view_tree_to_widget_coords:
  * @tree_view: a #GtkTreeView
  * @tx: tree X coordinate
  * @ty: tree Y coordinate
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
+ * @wx: return location for X coordinate relative to bin_window
+ * @wy: return location for Y coordinate relative to bin_window
  *
  * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to widget coordinates.
+ * to bin_window coordinates.
+ *
+ * Deprecated: 2.12: Due to historial reasons the name of this function is
+ * incorrect.  For converting bin_window coordinates to coordinates relative
+ * to bin_window, please see
+ * gtk_tree_view_convert_bin_window_to_widget_coords().
  *
  **/
 void
@@ -12829,6 +12906,185 @@ gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
     *wy = ty - tree_view->priv->dy;
 }
 
+
+/**
+ * gtk_tree_view_convert_widget_to_tree_coords:
+ * @tree_view: a #GtkTreeView
+ * @wx: X coordinate relative to the widget
+ * @wy: Y coordinate relative to the widget
+ * @tx: return location for tree X coordinate
+ * @ty: return location for tree Y coordinate
+ *
+ * Converts widget coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
+                                             gint         wx,
+                                             gint         wy,
+                                             gint        *tx,
+                                             gint        *ty)
+{
+  gint x, y;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
+                                                    wx, wy,
+                                                    &x, &y);
+  gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
+                                                  x, y,
+                                                  tx, ty);
+}
+
+/**
+ * gtk_tree_view_convert_tree_to_widget_coords:
+ * @tree_view: a #GtkTreeView
+ * @tx: X coordinate relative to the tree
+ * @ty: Y coordinate relative to the tree
+ * @wx: return location for widget X coordinate
+ * @wy: return location for widget Y coordinate
+ *
+ * Converts tree coordinates (coordinates in full scrollable area of the tree)
+ * to widget coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
+                                             gint         tx,
+                                             gint         ty,
+                                             gint        *wx,
+                                             gint        *wy)
+{
+  gint x, y;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
+                                                  tx, ty,
+                                                  &x, &y);
+  gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+                                                    x, y,
+                                                    wx, wy);
+}
+
+/**
+ * gtk_tree_view_convert_widget_to_bin_window_coords:
+ * @tree_view: a #GtkTreeView
+ * @wx: X coordinate relative to the widget
+ * @wy: Y coordinate relative to the widget
+ * @bx: return location for bin_window X coordinate
+ * @by: return location for bin_window Y coordinate
+ *
+ * Converts widget coordinates to coordinates for the bin_window
+ * (see gtk_tree_view_get_bin_window()).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
+                                                   gint         wx,
+                                                   gint         wy,
+                                                   gint        *bx,
+                                                   gint        *by)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (bx)
+    *bx = wx + tree_view->priv->hadjustment->value;
+  if (by)
+    *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
+}
+
+/**
+ * gtk_tree_view_convert_bin_window_to_widget_coords:
+ * @tree_view: a #GtkTreeView
+ * @bx: bin_window X coordinate
+ * @by: bin_window Y coordinate
+ * @wx: return location for widget X coordinate
+ * @wy: return location for widget Y coordinate
+ *
+ * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
+ * to widget relative coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
+                                                   gint         bx,
+                                                   gint         by,
+                                                   gint        *wx,
+                                                   gint        *wy)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (wx)
+    *wx = bx - tree_view->priv->hadjustment->value;
+  if (wy)
+    *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
+}
+
+/**
+ * gtk_tree_view_convert_tree_to_bin_window_coords:
+ * @tree_view: a #GtkTreeView
+ * @tx: tree X coordinate
+ * @ty: tree Y coordinate
+ * @bx: return location for X coordinate relative to bin_window
+ * @by: return location for Y coordinate relative to bin_window
+ *
+ * Converts tree coordinates (coordinates in full scrollable area of the tree)
+ * to bin_window coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
+                                                 gint         tx,
+                                                 gint         ty,
+                                                 gint        *bx,
+                                                 gint        *by)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (bx)
+    *bx = tx;
+  if (by)
+    *by = ty - tree_view->priv->dy;
+}
+
+/**
+ * gtk_tree_view_convert_bin_window_to_tree_coords:
+ * @tree_view: a #GtkTreeView
+ * @bx: X coordinate relative to bin_window
+ * @by: Y coordinate relative to bin_window
+ * @tx: return location for tree X coordinate
+ * @ty: return location for tree Y coordinate
+ *
+ * Converts bin_window coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
+                                                 gint         bx,
+                                                 gint         by,
+                                                 gint        *tx,
+                                                 gint        *ty)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (tx)
+    *tx = bx;
+  if (ty)
+    *ty = by + tree_view->priv->dy;
+}
+
+
+
 /**
  * gtk_tree_view_get_visible_range:
  * @tree_view: A #GtkTreeView
@@ -13148,7 +13404,8 @@ gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
  * @path: Return location for the path of the highlighted row, or %NULL.
  * @pos: Return location for the drop position, or %NULL
  * 
- * Determines the destination row for a given position.
+ * Determines the destination row for a given position.  @drag_x and
+ * @drag_y are expected to be in widget coordinates.
  * 
  * Return value: whether there is a row at the given position.
  **/
@@ -13160,6 +13417,7 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
                                    GtkTreeViewDropPosition *pos)
 {
   gint cell_y;
+  gint bin_x, bin_y;
   gdouble offset_into_row;
   gdouble third;
   GdkRectangle cell;
@@ -13186,10 +13444,12 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
    * in the bottom third, drop after that row; if in the middle,
    * and the row has children, drop into the row.
    */
+  gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
+                                                    &bin_x, &bin_y);
 
   if (!gtk_tree_view_get_path_at_pos (tree_view,
-                                      drag_x,
-                                     drag_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
+                                     bin_x,
+                                     bin_y,
                                       &tmp_path,
                                       &column,
                                       NULL,
@@ -13724,10 +13984,14 @@ gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
       tree_view->priv->typeselect_flush_timeout = 0;
     }
        
-  /* send focus-in event */
-  send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
-  gtk_widget_hide (search_dialog);
-  gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+  if (GTK_WIDGET_VISIBLE (search_dialog))
+    {
+      /* send focus-in event */
+      send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
+      gtk_widget_hide (search_dialog);
+      gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+      send_focus_change (GTK_WIDGET (tree_view), TRUE);
+    }
 }
 
 static void
@@ -14556,6 +14820,30 @@ gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
   return tree_view->priv->rubber_banding_enable;
 }
 
+/**
+ * gtk_tree_view_is_rubber_banding_active:
+ * @tree_view: a #GtkTreeView
+ * 
+ * Returns whether a rubber banding operation is currently being done
+ * in @tree_view.
+ *
+ * Return value: %TRUE if a rubber banding operation is currently being
+ * done in @tree_view.
+ *
+ * Since: 2.12
+ **/
+gboolean
+gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+  if (tree_view->priv->rubber_banding_enable
+      && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+    return TRUE;
+
+  return FALSE;
+}
+
 /**
  * gtk_tree_view_get_row_separator_func:
  * @tree_view: a #GtkTreeView
@@ -14613,7 +14901,12 @@ gtk_tree_view_grab_notify (GtkWidget *widget,
   tree_view->priv->in_grab = !was_grabbed;
 
   if (!was_grabbed)
-    tree_view->priv->pressed_button = -1;
+    {
+      tree_view->priv->pressed_button = -1;
+
+      if (tree_view->priv->rubber_band_status)
+       gtk_tree_view_stop_rubber_band (tree_view);
+    }
 }
 
 static void
@@ -14898,5 +15191,287 @@ gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
   return tree_view->priv->level_indentation;
 }
 
+/**
+ * gtk_tree_view_set_tooltip_row:
+ * @tree_view: a #GtkTreeView
+ * @tooltip: a #GtkTooltip
+ * @path: a #GtkTreePath
+ *
+ * Sets the tip area of @tooltip to be the area covered by the row at @path.
+ * See also gtk_tooltip_set_tip_area().
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
+                              GtkTooltip  *tooltip,
+                              GtkTreePath *path)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+  g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+
+  gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
+}
+
+/**
+ * gtk_tree_view_set_tooltip_cell:
+ * @tree_view: a #GtkTreeView
+ * @tooltip: a #GtkTooltip
+ * @path: a #GtkTreePath or %NULL
+ * @column: a #GtkTreeViewColumn 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().
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
+                               GtkTooltip        *tooltip,
+                               GtkTreePath       *path,
+                               GtkTreeViewColumn *column,
+                               GtkCellRenderer   *cell)
+{
+  GdkRectangle rect;
+
+  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));
+
+  /* Determine x values. */
+  if (column && cell)
+    {
+      GdkRectangle tmp;
+      gint start, width;
+
+      gtk_tree_view_get_cell_area (tree_view, NULL, 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);
+      rect.width = width;
+    }
+  else if (column)
+    {
+      GdkRectangle tmp;
+
+      gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
+      gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+                                                        tmp.x, 0,
+                                                        &rect.x, NULL);
+      rect.width = tmp.width;
+    }
+  else
+    {
+      rect.x = 0;
+      rect.width = GTK_WIDGET (tree_view)->allocation.width;
+    }
+
+  /* Determine y values. */
+  if (path)
+    {
+      GdkRectangle tmp;
+
+      gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
+      gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+                                                        0, tmp.y,
+                                                        NULL, &rect.y);
+      rect.height = tmp.height;
+    }
+  else
+    {
+      rect.y = 0;
+      rect.height = tree_view->priv->vadjustment->page_size;
+    }
+
+  gtk_tooltip_set_tip_area (tooltip, &rect);
+}
+
+/**
+ * gtk_tree_view_get_tooltip_context:
+ * @tree_view: a #GtkTreeView
+ * @x: the x coordinate (relative to widget coordinates)
+ * @y: the y coordinate (relative to widget coordinates)
+ * @keyboard_tip: whether this is a keyboard tooltip or not
+ * @model: a pointer to receive a #GtkTreeModel or %NULL
+ * @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 #GtkTreeView.  The @x, @y and @keyboard_tip values
+ * which are received in the signal handler, should be passed to this
+ * function without modification.
+ *
+ * The return value indicates whether there is a tree view row at the given
+ * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
+ * tooltips the row returned will be the cursor row.  When %TRUE, then any of
+ * @model, @path and @iter which have been provided will be set to point to
+ * that row and the corresponding model.  @x and @y will always be converted
+ * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
+ *
+ * Return value: whether or not the given tooltip context points to a row.
+ *
+ * Since: 2.12
+ */
+gboolean
+gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
+                                  gint          *x,
+                                  gint          *y,
+                                  gboolean       keyboard_tip,
+                                  GtkTreeModel **model,
+                                  GtkTreePath  **path,
+                                  GtkTreeIter   *iter)
+{
+  GtkTreePath *tmppath = NULL;
+
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+  g_return_val_if_fail (x != NULL, FALSE);
+  g_return_val_if_fail (y != NULL, FALSE);
+
+  if (keyboard_tip)
+    {
+      gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
+
+      if (!tmppath)
+       return FALSE;
+    }
+  else
+    {
+      gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
+                                                        x, y);
+
+      if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
+                                         &tmppath, NULL, NULL, NULL))
+       return FALSE;
+    }
+
+  if (model)
+    *model = gtk_tree_view_get_model (tree_view);
+
+  if (iter)
+    gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
+                            iter, tmppath);
+
+  if (path)
+    *path = tmppath;
+  else
+    gtk_tree_path_free (tmppath);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
+                                   gint        x,
+                                   gint        y,
+                                   gboolean    keyboard_tip,
+                                   GtkTooltip *tooltip,
+                                   gpointer    data)
+{
+  gchar *str;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  GtkTreeModel *model;
+  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+  if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
+                                         &x, &y,
+                                         keyboard_tip,
+                                         &model, &path, &iter))
+    return FALSE;
+
+  gtk_tree_model_get (model, &iter, tree_view->priv->tooltip_column, &str, -1);
+
+  if (!str)
+    {
+      gtk_tree_path_free (path);
+      return FALSE;
+    }
+
+  gtk_tooltip_set_markup (tooltip, str);
+  gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
+
+  gtk_tree_path_free (path);
+  g_free (str);
+
+  return TRUE;
+}
+
+/**
+ * gtk_tree_view_set_tooltip_column:
+ * @tree_view: a #GtkTreeView
+ * @column: an integer, which is a valid column number for @tree_view's model
+ *
+ * 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.
+ *
+ * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
+ * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
+                                 gint         column)
+{
+  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,
+                                           NULL);
+      gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
+    }
+  else
+    {
+      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");
+}
+
+/**
+ * gtk_tree_view_get_tooltip_column:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns the column of @tree_view's model which is being used for
+ * displaying tooltips on @tree_view's rows.
+ *
+ * Return value: the index of the tooltip column that is currently being
+ * used, or -1 if this is disabled.
+ *
+ * Since: 2.12
+ */
+gint
+gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
+{
+  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+  return tree_view->priv->tooltip_column;
+}
+
 #define __GTK_TREE_VIEW_C__
 #include "gtkaliasdef.c"