]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextview.c
Fix includes
[~andy/gtk] / gtk / gtktextview.c
index 205c3a1092280e828f70e5ad049ddc260e392858..ed3d98bb361c6645acd892d300e1a98ab19e704f 100644 (file)
@@ -13,9 +13,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
@@ -26,6 +24,7 @@
  */
 
 #include "config.h"
+
 #include <string.h>
 
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
 #include "gtkmenuitem.h"
 #include "gtkseparatormenuitem.h"
 #include "gtksettings.h"
+#include "gtkselectionprivate.h"
 #include "gtkstock.h"
-#include "gtksizerequest.h"
 #include "gtktextbufferrichtext.h"
 #include "gtktextdisplay.h"
 #include "gtktextview.h"
 #include "gtkimmulticontext.h"
-#include "gdk/gdkkeysyms.h"
 #include "gtkprivate.h"
 #include "gtktextutil.h"
+#include "gtkwidgetprivate.h"
 #include "gtkwindow.h"
+#include "gtkscrollable.h"
+#include "gtktypebuiltins.h"
+#include "gtktexthandleprivate.h"
+#include "gtkstylecontextprivate.h"
+#include "gtkcssstylepropertyprivate.h"
+#include "gtkselectionwindow.h"
+
+#include "a11y/gtktextviewaccessibleprivate.h"
+
+/**
+ * SECTION:gtktextview
+ * @Short_description: Widget that displays a GtkTextBuffer
+ * @Title: GtkTextView
+ * @See_also: #GtkTextBuffer, #GtkTextIter
+ *
+ * You may wish to begin by reading the <link linkend="TextWidget">text widget
+ * conceptual overview</link> which gives an overview of all the objects and data
+ * types related to the text widget and how they work together.
+ */
 
 
 /* How scrolling, validation, exposes, etc. work.
@@ -117,8 +135,10 @@ struct _GtkTextViewPrivate
   GdkDevice *grab_device;
   GdkDevice *dnd_device;
 
-  guint selection_drag_handler;
-  guint scroll_timeout;
+  gulong selection_drag_handler;
+  GtkTextHandle *text_handle;
+  GtkWidget *selection_bubble;
+  guint selection_bubble_timeout_id;
 
   GtkTextWindow *text_window;
   GtkTextWindow *left_window;
@@ -141,7 +161,7 @@ struct _GtkTextViewPrivate
    * FIXME: This could be done in a simpler way by 
    * consulting the above width/height of the buffer + some
    * padding values, however all of this request code needs
-   * to be changed to use GtkSizeRequestIface and deserves
+   * to be changed to use GtkWidget     Iface and deserves
    * more attention.
    */
   GtkRequisition cached_size_request;
@@ -161,12 +181,16 @@ struct _GtkTextViewPrivate
   GtkTextMark *first_para_mark; /* Mark at the beginning of the first onscreen paragraph */
   gint first_para_pixels;       /* Offset of top of screen in the first onscreen paragraph */
 
-  GtkTextMark *dnd_mark;
   guint blink_timeout;
+  guint scroll_timeout;
 
   guint first_validate_idle;        /* Idle to revalidate onscreen portion, runs before resize */
   guint incremental_validate_idle;  /* Idle to revalidate offscreen portions, runs after redraw */
 
+  gint pending_place_cursor_button;
+
+  GtkTextMark *dnd_mark;
+
   GtkIMContext *im_context;
   GtkWidget *popup_menu;
 
@@ -177,8 +201,6 @@ struct _GtkTextViewPrivate
 
   GtkTextPendingScroll *pending_scroll;
 
-  gint pending_place_cursor_button;
-
   /* Default style settings */
   gint pixels_above_lines;
   gint pixels_below_lines;
@@ -194,7 +216,7 @@ struct _GtkTextViewPrivate
   guint overwrite_mode : 1;
   guint cursor_visible : 1;
 
-  /* if we have reset the IM since the last character entered */  
+  /* if we have reset the IM since the last character entered */
   guint need_im_reset : 1;
 
   guint accepts_tab : 1;
@@ -209,6 +231,13 @@ struct _GtkTextViewPrivate
   guint mouse_cursor_obscured : 1;
 
   guint scroll_after_paste : 1;
+
+  /* GtkScrollablePolicy needs to be checked when
+   * driving the scrollable adjustment values */
+  guint hscroll_policy : 1;
+  guint vscroll_policy : 1;
+  guint cursor_handle_dragged : 1;
+  guint selection_handle_dragged : 1;
 };
 
 struct _GtkTextPendingScroll
@@ -222,7 +251,6 @@ struct _GtkTextPendingScroll
 
 enum
 {
-  SET_SCROLL_ADJUSTMENTS,
   POPULATE_POPUP,
   MOVE_CURSOR,
   PAGE_HORIZONTALLY,
@@ -258,10 +286,15 @@ enum
   PROP_BUFFER,
   PROP_OVERWRITE,
   PROP_ACCEPTS_TAB,
-  PROP_IM_MODULE
+  PROP_IM_MODULE,
+  PROP_HADJUSTMENT,
+  PROP_VADJUSTMENT,
+  PROP_HSCROLL_POLICY,
+  PROP_VSCROLL_POLICY,
+  PROP_INPUT_PURPOSE,
+  PROP_INPUT_HINTS
 };
 
-static void gtk_text_view_destroy              (GtkObject        *object);
 static void gtk_text_view_finalize             (GObject          *object);
 static void gtk_text_view_set_property         (GObject         *object,
                                                guint            prop_id,
@@ -271,20 +304,26 @@ static void gtk_text_view_get_property         (GObject         *object,
                                                guint            prop_id,
                                                GValue          *value,
                                                GParamSpec      *pspec);
+static void gtk_text_view_destroy              (GtkWidget        *widget);
 static void gtk_text_view_size_request         (GtkWidget        *widget,
                                                 GtkRequisition   *requisition);
+static void gtk_text_view_get_preferred_width  (GtkWidget        *widget,
+                                               gint             *minimum,
+                                               gint             *natural);
+static void gtk_text_view_get_preferred_height (GtkWidget        *widget,
+                                               gint             *minimum,
+                                               gint             *natural);
 static void gtk_text_view_size_allocate        (GtkWidget        *widget,
                                                 GtkAllocation    *allocation);
 static void gtk_text_view_realize              (GtkWidget        *widget);
 static void gtk_text_view_unrealize            (GtkWidget        *widget);
-static void gtk_text_view_style_set            (GtkWidget        *widget,
-                                                GtkStyle         *previous_style);
+static void gtk_text_view_style_updated        (GtkWidget        *widget);
 static void gtk_text_view_direction_changed    (GtkWidget        *widget,
                                                 GtkTextDirection  previous_direction);
 static void gtk_text_view_grab_notify          (GtkWidget        *widget,
                                                gboolean         was_grabbed);
-static void gtk_text_view_state_changed        (GtkWidget        *widget,
-                                               GtkStateType      previous_state);
+static void gtk_text_view_state_flags_changed  (GtkWidget        *widget,
+                                               GtkStateFlags     previous_state);
 
 static gint gtk_text_view_event                (GtkWidget        *widget,
                                                 GdkEvent         *event);
@@ -308,11 +347,9 @@ static void gtk_text_view_draw_focus           (GtkWidget        *widget,
                                                 cairo_t          *cr);
 static gboolean gtk_text_view_focus            (GtkWidget        *widget,
                                                 GtkDirectionType  direction);
-static void gtk_text_view_move_focus           (GtkWidget        *widget,
-                                                GtkDirectionType  direction_type);
 static void gtk_text_view_select_all           (GtkWidget        *widget,
                                                 gboolean          select);
-
+static gboolean get_middle_click_paste         (GtkTextView      *text_view);
 
 /* Source side drag signals */
 static void gtk_text_view_drag_begin       (GtkWidget        *widget,
@@ -349,16 +386,13 @@ static void     gtk_text_view_drag_data_received (GtkWidget        *widget,
                                                   guint             info,
                                                   guint             time);
 
-static void gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
-                                                  GtkAdjustment *hadj,
-                                                  GtkAdjustment *vadj);
 static gboolean gtk_text_view_popup_menu         (GtkWidget     *widget);
 
 static void gtk_text_view_move_cursor       (GtkTextView           *text_view,
                                              GtkMovementStep        step,
                                              gint                   count,
                                              gboolean               extend_selection);
-static gboolean gtk_text_view_move_viewport (GtkTextView           *text_view,
+static void gtk_text_view_move_viewport     (GtkTextView           *text_view,
                                              GtkScrollStep          step,
                                              gint                   count);
 static void gtk_text_view_set_anchor       (GtkTextView           *text_view);
@@ -379,8 +413,7 @@ static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
 static void gtk_text_view_toggle_cursor_visible (GtkTextView      *text_view);
-static void gtk_text_view_compat_move_focus(GtkTextView           *text_view,
-                                            GtkDirectionType       direction_type);
+
 static void gtk_text_view_unselect         (GtkTextView           *text_view);
 
 static void     gtk_text_view_validate_onscreen     (GtkTextView        *text_view);
@@ -388,8 +421,7 @@ static void     gtk_text_view_get_first_para_iter   (GtkTextView        *text_vi
                                                      GtkTextIter        *iter);
 static void     gtk_text_view_update_layout_width       (GtkTextView        *text_view);
 static void     gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
-                                                         GtkTextAttributes *values,
-                                                         GtkStyle           *style);
+                                                         GtkTextAttributes  *values);
 static void     gtk_text_view_ensure_layout          (GtkTextView        *text_view);
 static void     gtk_text_view_destroy_layout         (GtkTextView        *text_view);
 static void     gtk_text_view_check_keymap_direction (GtkTextView        *text_view);
@@ -405,7 +437,7 @@ static void     gtk_text_view_pend_cursor_blink      (GtkTextView        *text_v
 static void     gtk_text_view_stop_cursor_blink      (GtkTextView        *text_view);
 static void     gtk_text_view_reset_blink_time       (GtkTextView        *text_view);
 
-static void     gtk_text_view_value_changed                (GtkAdjustment *adj,
+static void     gtk_text_view_value_changed                (GtkAdjustment *adjustment,
                                                            GtkTextView   *view);
 static void     gtk_text_view_commit_handler               (GtkIMContext  *context,
                                                            const gchar   *str,
@@ -431,8 +463,8 @@ static void gtk_text_view_target_list_notify     (GtkTextBuffer     *buffer,
 static void gtk_text_view_paste_done_handler     (GtkTextBuffer     *buffer,
                                                   GtkClipboard      *clipboard,
                                                   gpointer           data);
-static void gtk_text_view_get_cursor_location    (GtkTextView       *text_view,
-                                                 GdkRectangle      *pos);
+static void gtk_text_view_buffer_changed_handler (GtkTextBuffer     *buffer,
+                                                  gpointer           data);
 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
                                                   GtkTextIter       *cursor,
                                                   gint              *x,
@@ -441,9 +473,6 @@ static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
                                                   gint               x,
                                                   gint               y);
 
-static GtkAdjustment* get_hadjustment            (GtkTextView       *text_view);
-static GtkAdjustment* get_vadjustment            (GtkTextView       *text_view);
-
 static void gtk_text_view_do_popup               (GtkTextView       *text_view,
                                                  GdkEventButton    *event);
 
@@ -460,6 +489,13 @@ static void     gtk_text_view_update_adjustments   (GtkTextView *text_view);
 static void     gtk_text_view_invalidate           (GtkTextView *text_view);
 static void     gtk_text_view_flush_first_validate (GtkTextView *text_view);
 
+static void     gtk_text_view_set_hadjustment        (GtkTextView   *text_view,
+                                                      GtkAdjustment *adjustment);
+static void     gtk_text_view_set_vadjustment        (GtkTextView   *text_view,
+                                                      GtkAdjustment *adjustment);
+static void     gtk_text_view_set_hadjustment_values (GtkTextView   *text_view);
+static void     gtk_text_view_set_vadjustment_values (GtkTextView   *text_view);
+
 static void gtk_text_view_update_im_spot_location (GtkTextView *text_view);
 
 /* Container methods */
@@ -472,6 +508,22 @@ static void gtk_text_view_forall (GtkContainer *container,
                                   GtkCallback   callback,
                                   gpointer      callback_data);
 
+/* GtkTextHandle handlers */
+static void gtk_text_view_handle_dragged       (GtkTextHandle         *handle,
+                                                GtkTextHandlePosition  pos,
+                                                gint                   x,
+                                                gint                   y,
+                                                GtkTextView           *text_view);
+static void gtk_text_view_handle_drag_finished (GtkTextHandle         *handle,
+                                                GtkTextHandlePosition  pos,
+                                                GtkTextView           *text_view);
+static void gtk_text_view_update_handles       (GtkTextView           *text_view,
+                                                GtkTextHandleMode      mode);
+
+static void gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view);
+static void gtk_text_view_selection_bubble_popup_set   (GtkTextView *text_view);
+
+
 /* FIXME probably need the focus methods. */
 
 typedef struct _GtkTextViewChild GtkTextViewChild;
@@ -534,8 +586,10 @@ static gint           text_window_get_height      (GtkTextWindow     *win);
 
 
 static guint signals[LAST_SIGNAL] = { 0 };
+static gboolean test_touchscreen = FALSE;
 
-G_DEFINE_TYPE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
 
 static void
 add_move_binding (GtkBindingSet  *binding_set,
@@ -564,7 +618,6 @@ static void
 gtk_text_view_class_init (GtkTextViewClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
   GtkBindingSet *binding_set;
@@ -573,17 +626,17 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
    */
   gobject_class->set_property = gtk_text_view_set_property;
   gobject_class->get_property = gtk_text_view_get_property;
-
-  object_class->destroy = gtk_text_view_destroy;
   gobject_class->finalize = gtk_text_view_finalize;
 
+  widget_class->destroy = gtk_text_view_destroy;
   widget_class->realize = gtk_text_view_realize;
   widget_class->unrealize = gtk_text_view_unrealize;
-  widget_class->style_set = gtk_text_view_style_set;
+  widget_class->style_updated = gtk_text_view_style_updated;
   widget_class->direction_changed = gtk_text_view_direction_changed;
   widget_class->grab_notify = gtk_text_view_grab_notify;
-  widget_class->state_changed = gtk_text_view_state_changed;
-  widget_class->size_request = gtk_text_view_size_request;
+  widget_class->state_flags_changed = gtk_text_view_state_flags_changed;
+  widget_class->get_preferred_width = gtk_text_view_get_preferred_width;
+  widget_class->get_preferred_height = gtk_text_view_get_preferred_height;
   widget_class->size_allocate = gtk_text_view_size_allocate;
   widget_class->event = gtk_text_view_event;
   widget_class->key_press_event = gtk_text_view_key_press_event;
@@ -595,14 +648,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   widget_class->motion_notify_event = gtk_text_view_motion_event;
   widget_class->draw = gtk_text_view_draw;
   widget_class->focus = gtk_text_view_focus;
-
-  /* need to override the base class function via override_class_handler,
-   * because the signal slot is not available in GtkWidgetCLass
-   */
-  g_signal_override_class_handler ("move-focus",
-                                   GTK_TYPE_TEXT_VIEW,
-                                   G_CALLBACK (gtk_text_view_move_focus));
-
   widget_class->drag_begin = gtk_text_view_drag_begin;
   widget_class->drag_end = gtk_text_view_drag_end;
   widget_class->drag_data_get = gtk_text_view_drag_data_get;
@@ -628,8 +673,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   klass->copy_clipboard = gtk_text_view_copy_clipboard;
   klass->paste_clipboard = gtk_text_view_paste_clipboard;
   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
-  klass->move_focus = gtk_text_view_compat_move_focus;
-  klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
 
   /*
    * Properties
@@ -764,7 +807,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
    /**
     * GtkTextView:im-module:
     *
-    * Which IM (input method) module should be used for this entry
+    * Which IM (input method) module should be used for this text_view
     * See #GtkIMContext.
     *
     * Setting this to a non-%NULL value overrides the
@@ -781,6 +824,48 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                                                          NULL,
                                                          GTK_PARAM_READWRITE));
 
+  /**
+   * GtkTextView:input-purpose:
+   *
+   * The purpose of this text field.
+   *
+   * This property can be used by on-screen keyboards and other input
+   * methods to adjust their behaviour.
+   *
+   * Since: 3.6
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_INPUT_PURPOSE,
+                                   g_param_spec_enum ("input-purpose",
+                                                      P_("Purpose"),
+                                                      P_("Purpose of the text field"),
+                                                      GTK_TYPE_INPUT_PURPOSE,
+                                                      GTK_INPUT_PURPOSE_FREE_FORM,
+                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GtkTextView:input-hints:
+   *
+   * Additional hints (beyond #GtkTextView:input-purpose) that
+   * allow input methods to fine-tune their behaviour.
+   *
+   * Since: 3.6
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_INPUT_HINTS,
+                                   g_param_spec_flags ("input-hints",
+                                                       P_("hints"),
+                                                       P_("Hints for the text field behaviour"),
+                                                       GTK_TYPE_INPUT_HINTS,
+                                                       GTK_INPUT_HINT_NONE,
+                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+   /* GtkScrollable interface */
+   g_object_class_override_property (gobject_class, PROP_HADJUSTMENT,    "hadjustment");
+   g_object_class_override_property (gobject_class, PROP_VADJUSTMENT,    "vadjustment");
+   g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
+   g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
+
   /*
    * Style properties
    */
@@ -1034,30 +1119,9 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                  _gtk_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
 
-  /**
-   * GtkTextView::set-scroll-adjustments
-   * @horizontal: the horizontal #GtkAdjustment
-   * @vertical: the vertical #GtkAdjustment
-   *
-   * Set the scroll adjustments for the text view. Usually scrolled containers
-   * like #GtkScrolledWindow will emit this signal to connect two instances
-   * of #GtkScrollbar to the scroll directions of the #GtkTextView.
-   */
-  signals[SET_SCROLL_ADJUSTMENTS] =
-    g_signal_new (I_("set-scroll-adjustments"),
-                 G_OBJECT_CLASS_TYPE (gobject_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (GtkTextViewClass, set_scroll_adjustments),
-                 NULL, NULL,
-                 _gtk_marshal_VOID__OBJECT_OBJECT,
-                 G_TYPE_NONE, 2,
-                 GTK_TYPE_ADJUSTMENT,
-                 GTK_TYPE_ADJUSTMENT);
-  widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
-
   /**
    * GtkTextView::populate-popup:
-   * @entry: The text view on which the signal is emitted
+   * @text_view: The text view on which the signal is emitted
    * @menu: the menu that is being populated
    *
    * The ::populate-popup signal gets emitted before showing the 
@@ -1091,7 +1155,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
    */
   signals[SELECT_ALL] =
     g_signal_new_class_handler (I_("select-all"),
-                                G_OBJECT_CLASS_TYPE (object_class),
+                                G_OBJECT_CLASS_TYPE (gobject_class),
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                                 G_CALLBACK (gtk_text_view_select_all),
                                 NULL, NULL,
@@ -1110,7 +1174,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
    */ 
   signals[TOGGLE_CURSOR_VISIBLE] =
     g_signal_new_class_handler (I_("toggle-cursor-visible"),
-                                G_OBJECT_CLASS_TYPE (object_class),
+                                G_OBJECT_CLASS_TYPE (gobject_class),
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                                 G_CALLBACK (gtk_text_view_toggle_cursor_visible),
                                 NULL, NULL,
@@ -1133,7 +1197,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
    */
   signals[PREEDIT_CHANGED] =
     g_signal_new_class_handler (I_("preedit-changed"),
-                                G_OBJECT_CLASS_TYPE (object_class),
+                                G_OBJECT_CLASS_TYPE (gobject_class),
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                                 NULL,
                                 NULL, NULL,
@@ -1352,6 +1416,9 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                                GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
 
   g_type_class_add_private (gobject_class, sizeof (GtkTextViewPrivate));
+
+  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TEXT_VIEW_ACCESSIBLE);
+  test_touchscreen = g_getenv ("GTK_TEST_TOUCHSCREEN") != NULL;
 }
 
 static void
@@ -1418,6 +1485,12 @@ gtk_text_view_init (GtkTextView *text_view)
 
   /* We handle all our own redrawing */
   gtk_widget_set_redraw_on_allocate (widget, FALSE);
+
+  priv->text_handle = _gtk_text_handle_new (widget);
+  g_signal_connect (priv->text_handle, "handle-dragged",
+                    G_CALLBACK (gtk_text_view_handle_dragged), text_view);
+  g_signal_connect (priv->text_handle, "drag-finished",
+                    G_CALLBACK (gtk_text_view_handle_drag_finished), text_view);
 }
 
 /**
@@ -1477,6 +1550,7 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
                           GtkTextBuffer *buffer)
 {
   GtkTextViewPrivate *priv;
+  GtkTextBuffer *old_buffer;
 
   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
@@ -1486,6 +1560,7 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
   if (priv->buffer == buffer)
     return;
 
+  old_buffer = priv->buffer;
   if (priv->buffer != NULL)
     {
       /* Destroy all anchored children */
@@ -1518,6 +1593,9 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
       g_signal_handlers_disconnect_by_func (priv->buffer,
                                             gtk_text_view_paste_done_handler,
                                             text_view);
+      g_signal_handlers_disconnect_by_func (priv->buffer,
+                                            gtk_text_view_buffer_changed_handler,
+                                            text_view);
 
       if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
        {
@@ -1529,7 +1607,6 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
       if (priv->layout)
         gtk_text_layout_set_buffer (priv->layout, NULL);
 
-      g_object_unref (priv->buffer);
       priv->dnd_mark = NULL;
       priv->first_para_mark = NULL;
       cancel_pending_scroll (text_view);
@@ -1568,6 +1645,9 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
       g_signal_connect (priv->buffer, "paste-done",
                        G_CALLBACK (gtk_text_view_paste_done_handler),
                         text_view);
+      g_signal_connect (priv->buffer, "changed",
+                       G_CALLBACK (gtk_text_view_buffer_changed_handler),
+                        text_view);
 
       gtk_text_view_target_list_notify (priv->buffer, NULL, text_view);
 
@@ -1577,8 +1657,14 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
                                                              GDK_SELECTION_PRIMARY);
          gtk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
        }
+
+      gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_NONE);
     }
 
+  _gtk_text_view_accessible_set_buffer (text_view, old_buffer);
+  if (old_buffer)
+    g_object_unref (old_buffer);
+
   g_object_notify (G_OBJECT (text_view), "buffer");
   
   if (gtk_widget_get_visible (GTK_WIDGET (text_view)))
@@ -1620,6 +1706,61 @@ gtk_text_view_get_buffer (GtkTextView *text_view)
   return get_buffer (text_view);
 }
 
+/**
+ * gtk_text_view_get_cursor_locations:
+ * @text_view: a #GtkTextView
+ * @iter: (allow-none): a #GtkTextIter
+ * @strong: (out) (allow-none): location to store the strong
+ *     cursor position (may be %NULL)
+ * @weak: (out) (allow-none): location to store the weak
+ *     cursor position (may be %NULL)
+ *
+ * Given an @iter within a text layout, determine the positions of the
+ * strong and weak cursors if the insertion point is at that
+ * iterator. The position of each cursor is stored as a zero-width
+ * rectangle. The strong cursor location is the location where
+ * characters of the directionality equal to the base direction of the
+ * paragraph are inserted.  The weak cursor location is the location
+ * where characters of the directionality opposite to the base
+ * direction of the paragraph are inserted.
+ *
+ * If @iter is %NULL, the actual cursor position is used.
+ *
+ * Note that if @iter happens to be the actual cursor position, and
+ * there is currently an IM preedit sequence being entered, the
+ * returned locations will be adjusted to account for the preedit
+ * cursor's offset within the preedit sequence.
+ *
+ * The rectangle position is in buffer coordinates; use
+ * gtk_text_view_buffer_to_window_coords() to convert these
+ * coordinates to coordinates for one of the windows in the text view.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_text_view_get_cursor_locations (GtkTextView       *text_view,
+                                    const GtkTextIter *iter,
+                                    GdkRectangle      *strong,
+                                    GdkRectangle      *weak)
+{
+  GtkTextIter insert;
+
+  g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+  g_return_if_fail (iter == NULL ||
+                    gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
+
+  gtk_text_view_ensure_layout (text_view);
+
+  if (iter)
+    insert = *iter;
+  else
+    gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
+                                      gtk_text_buffer_get_insert (get_buffer (text_view)));
+
+  gtk_text_layout_get_cursor_locations (text_view->priv->layout, &insert,
+                                        strong, weak);
+}
+
 /**
  * gtk_text_view_get_iter_at_location:
  * @text_view: a #GtkTextView
@@ -1769,30 +1910,6 @@ gtk_text_view_get_line_at_y (GtkTextView *text_view,
                                  line_top);
 }
 
-static gboolean
-set_adjustment_clamped (GtkAdjustment *adj, gdouble val)
-{
-  DV (g_print ("  Setting adj to raw value %g\n", val));
-  
-  /* We don't really want to clamp to upper; we want to clamp to
-     upper - page_size which is the highest value the scrollbar
-     will let us reach. */
-  if (val > (adj->upper - adj->page_size))
-    val = adj->upper - adj->page_size;
-
-  if (val < adj->lower)
-    val = adj->lower;
-
-  if (val != adj->value)
-    {
-      DV (g_print ("  Setting adj to clamped value %g\n", val));
-      gtk_adjustment_set_value (adj, val);
-      return TRUE;
-    }
-  else
-    return FALSE;
-}
-
 /**
  * gtk_text_view_scroll_to_iter:
  * @text_view: a #GtkTextView
@@ -1927,8 +2044,8 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
   
   if (scroll_inc != 0)
     {
-      retval = set_adjustment_clamped (get_vadjustment (text_view),
-                                       current_y_scroll + scroll_inc);
+      gtk_adjustment_set_value (text_view->priv->vadjustment,
+                                current_y_scroll + scroll_inc);
 
       DV (g_print (" vert increment %d\n", scroll_inc));
     }
@@ -1964,12 +2081,15 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
   
   if (scroll_inc != 0)
     {
-      retval = set_adjustment_clamped (get_hadjustment (text_view),
-                                       current_x_scroll + scroll_inc);
+      gtk_adjustment_set_value (text_view->priv->hadjustment,
+                                current_x_scroll + scroll_inc);
 
       DV (g_print (" horiz increment %d\n", scroll_inc));
     }
   
+  retval = (current_y_scroll != gtk_adjustment_get_value (text_view->priv->vadjustment))
+           || (current_x_scroll != gtk_adjustment_get_value (text_view->priv->hadjustment));
+
   if (retval)
     {
       DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
@@ -2092,33 +2212,6 @@ gtk_text_view_flush_scroll (GtkTextView *text_view)
   return retval;
 }
 
-static void
-gtk_text_view_set_adjustment_upper (GtkAdjustment *adj, gdouble upper)
-{  
-  if (upper != adj->upper)
-    {
-      gdouble min = MAX (0.0, upper - adj->page_size);
-      gboolean value_changed = FALSE;
-
-      adj->upper = upper;
-
-      if (adj->value > min)
-        {
-          adj->value = min;
-          value_changed = TRUE;
-        }
-
-      gtk_adjustment_changed (adj);
-      DV(g_print(">Changed adj upper to %g ("G_STRLOC")\n", upper));
-      
-      if (value_changed)
-        {
-          DV(g_print(">Changed adj value because upper decreased ("G_STRLOC")\n"));
-         gtk_adjustment_value_changed (adj);
-        }
-    }
-}
-
 static void
 gtk_text_view_update_adjustments (GtkTextView *text_view)
 {
@@ -2143,28 +2236,8 @@ gtk_text_view_update_adjustments (GtkTextView *text_view)
       priv->width = width;
       priv->height = height;
 
-      gtk_text_view_set_adjustment_upper (get_hadjustment (text_view),
-                                          MAX (SCREEN_WIDTH (text_view), width));
-      gtk_text_view_set_adjustment_upper (get_vadjustment (text_view),
-                                          MAX (SCREEN_HEIGHT (text_view), height));
-      
-      /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */
-
-      /* Set up the step sizes; we'll say that a page is
-         our allocation minus one step, and a step is
-         1/10 of our allocation. */
-      priv->hadjustment->step_increment =
-        SCREEN_WIDTH (text_view) / 10.0;
-      priv->hadjustment->page_increment =
-        SCREEN_WIDTH (text_view) * 0.9;
-      
-      priv->vadjustment->step_increment =
-        SCREEN_HEIGHT (text_view) / 10.0;
-      priv->vadjustment->page_increment =
-        SCREEN_HEIGHT (text_view) * 0.9;
-
-      gtk_adjustment_changed (get_hadjustment (text_view));
-      gtk_adjustment_changed (get_vadjustment (text_view));
+      gtk_text_view_set_hadjustment_values (text_view);
+      gtk_text_view_set_vadjustment_values (text_view);
     }
 }
 
@@ -2187,13 +2260,13 @@ gtk_text_view_update_im_spot_location (GtkTextView *text_view)
   if (text_view->priv->layout == NULL)
     return;
   
-  gtk_text_view_get_cursor_location (text_view, &area);
+  gtk_text_view_get_cursor_locations (text_view, NULL, &area, NULL);
 
   area.x -= text_view->priv->xoffset;
   area.y -= text_view->priv->yoffset;
     
   /* Width returned by Pango indicates direction of cursor,
-   * by it's sign more than the size of cursor.
+   * by its sign more than the size of cursor.
    */
   area.width = 0;
 
@@ -2361,7 +2434,7 @@ gtk_text_view_move_mark_onscreen (GtkTextView *text_view,
 /**
  * gtk_text_view_get_visible_rect:
  * @text_view: a #GtkTextView
- * @visible_rect: rectangle to fill
+ * @visible_rect: (out): rectangle to fill
  *
  * Fills @visible_rect with the currently-visible
  * region of the buffer, in buffer coordinates. Convert to window coordinates
@@ -2413,7 +2486,7 @@ gtk_text_view_set_wrap_mode (GtkTextView *text_view,
     {
       priv->wrap_mode = wrap_mode;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->wrap_mode = wrap_mode;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2473,7 +2546,7 @@ gtk_text_view_set_editable (GtkTextView *text_view,
       if (setting && gtk_widget_has_focus (GTK_WIDGET (text_view)))
        gtk_im_context_focus_in (priv->im_context);
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
          gtk_text_layout_set_overwrite_mode (priv->layout,
                                              priv->overwrite_mode && priv->editable);
@@ -2524,7 +2597,7 @@ gtk_text_view_set_pixels_above_lines (GtkTextView *text_view,
     {
       priv->pixels_above_lines = pixels_above_lines;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->pixels_above_lines = pixels_above_lines;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2573,7 +2646,7 @@ gtk_text_view_set_pixels_below_lines (GtkTextView *text_view,
     {
       priv->pixels_below_lines = pixels_below_lines;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->pixels_below_lines = pixels_below_lines;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2622,7 +2695,7 @@ gtk_text_view_set_pixels_inside_wrap (GtkTextView *text_view,
     {
       priv->pixels_inside_wrap = pixels_inside_wrap;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->pixels_inside_wrap = pixels_inside_wrap;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2671,7 +2744,7 @@ gtk_text_view_set_justification (GtkTextView     *text_view,
     {
       priv->justify = justification;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->justification = justification;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2720,7 +2793,7 @@ gtk_text_view_set_left_margin (GtkTextView *text_view,
     {
       priv->left_margin = left_margin;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->left_margin = left_margin;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2767,7 +2840,7 @@ gtk_text_view_set_right_margin (GtkTextView *text_view,
     {
       priv->right_margin = right_margin;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->right_margin = right_margin;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2816,7 +2889,7 @@ gtk_text_view_set_indent (GtkTextView *text_view,
     {
       priv->indent = indent;
 
-      if (priv->layout)
+      if (priv->layout && priv->layout->default_style)
         {
           priv->layout->default_style->indent = indent;
           gtk_text_layout_default_style_changed (priv->layout);
@@ -2867,7 +2940,7 @@ gtk_text_view_set_tabs (GtkTextView   *text_view,
 
   priv->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
 
-  if (priv->layout)
+  if (priv->layout && priv->layout->default_style)
     {
       /* some unkosher futzing in internal struct details... */
       if (priv->layout->default_style->tabs)
@@ -3010,12 +3083,12 @@ gtk_text_view_remove_validate_idles (GtkTextView *text_view)
 }
 
 static void
-gtk_text_view_destroy (GtkObject *object)
+gtk_text_view_destroy (GtkWidget *widget)
 {
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
 
-  text_view = GTK_TEXT_VIEW (object);
+  text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
 
   gtk_text_view_remove_validate_idles (text_view);
@@ -3034,7 +3107,7 @@ gtk_text_view_destroy (GtkObject *object)
       priv->im_spot_idle = 0;
     }
 
-  GTK_OBJECT_CLASS (gtk_text_view_parent_class)->destroy (object);
+  GTK_WIDGET_CLASS (gtk_text_view_parent_class)->destroy (widget);
 }
 
 static void
@@ -3046,10 +3119,11 @@ gtk_text_view_finalize (GObject *object)
   text_view = GTK_TEXT_VIEW (object);
   priv = text_view->priv;
 
-  g_assert (priv->buffer == NULL);
-
   gtk_text_view_destroy_layout (text_view);
   gtk_text_view_set_buffer (text_view, NULL);
+
+  /* at this point, no "notify::buffer" handler should recreate the buffer. */
+  g_assert (priv->buffer == NULL);
   
   cancel_pending_scroll (text_view);
 
@@ -3075,6 +3149,10 @@ gtk_text_view_finalize (GObject *object)
   if (priv->bottom_window)
     text_window_free (priv->bottom_window);
 
+  if (priv->selection_bubble)
+    gtk_widget_destroy (priv->selection_bubble);
+
+  g_object_unref (priv->text_handle);
   g_object_unref (priv->im_context);
 
   g_free (priv->im_module);
@@ -3159,6 +3237,32 @@ gtk_text_view_set_property (GObject         *object,
         gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (priv->im_context), priv->im_module);
       break;
 
+    case PROP_HADJUSTMENT:
+      gtk_text_view_set_hadjustment (text_view, g_value_get_object (value));
+      break;
+
+    case PROP_VADJUSTMENT:
+      gtk_text_view_set_vadjustment (text_view, g_value_get_object (value));
+      break;
+
+    case PROP_HSCROLL_POLICY:
+      priv->hscroll_policy = g_value_get_enum (value);
+      gtk_widget_queue_resize (GTK_WIDGET (text_view));
+      break;
+
+    case PROP_VSCROLL_POLICY:
+      priv->vscroll_policy = g_value_get_enum (value);
+      gtk_widget_queue_resize (GTK_WIDGET (text_view));
+      break;
+
+    case PROP_INPUT_PURPOSE:
+      gtk_text_view_set_input_purpose (text_view, g_value_get_enum (value));
+      break;
+
+    case PROP_INPUT_HINTS:
+      gtk_text_view_set_input_hints (text_view, g_value_get_flags (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3239,6 +3343,30 @@ gtk_text_view_get_property (GObject         *object,
       g_value_set_string (value, priv->im_module);
       break;
 
+    case PROP_HADJUSTMENT:
+      g_value_set_object (value, priv->hadjustment);
+      break;
+
+    case PROP_VADJUSTMENT:
+      g_value_set_object (value, priv->vadjustment);
+      break;
+
+    case PROP_HSCROLL_POLICY:
+      g_value_set_enum (value, priv->hscroll_policy);
+      break;
+
+    case PROP_VSCROLL_POLICY:
+      g_value_set_enum (value, priv->vscroll_policy);
+      break;
+
+    case PROP_INPUT_PURPOSE:
+      g_value_set_enum (value, gtk_text_view_get_input_purpose (text_view));
+      break;
+
+    case PROP_INPUT_HINTS:
+      g_value_set_flags (value, gtk_text_view_get_input_hints (text_view));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3310,11 +3438,9 @@ gtk_text_view_size_request (GtkWidget      *widget,
           GtkRequisition child_req;
           GtkRequisition old_req;
 
-          gtk_size_request_get_size (GTK_SIZE_REQUEST (child->widget),
-                                     &old_req, NULL);
+          gtk_widget_get_preferred_size (child->widget, &old_req, NULL);
 
-          gtk_size_request_get_size (GTK_SIZE_REQUEST (child->widget),
-                                     &child_req, NULL);
+          gtk_widget_get_preferred_size (child->widget, &child_req, NULL);
 
           /* Invalidate layout lines if required */
           if (priv->layout &&
@@ -3327,8 +3453,8 @@ gtk_text_view_size_request (GtkWidget      *widget,
         {
           GtkRequisition child_req;
 
-          gtk_size_request_get_size (GTK_SIZE_REQUEST (child->widget),
-                                     &child_req, NULL);
+          gtk_widget_get_preferred_size (child->widget,
+                                         &child_req, NULL);
         }
 
       tmp_list = g_slist_next (tmp_list);
@@ -3339,6 +3465,31 @@ gtk_text_view_size_request (GtkWidget      *widget,
   priv->cached_size_request = *requisition;
 }
 
+static void
+gtk_text_view_get_preferred_width (GtkWidget *widget,
+                                  gint      *minimum,
+                                  gint      *natural)
+{
+  GtkRequisition requisition;
+
+  gtk_text_view_size_request (widget, &requisition);
+
+  *minimum = *natural = requisition.width;
+}
+
+static void
+gtk_text_view_get_preferred_height (GtkWidget *widget,
+                                   gint      *minimum,
+                                   gint      *natural)
+{
+  GtkRequisition requisition;
+
+  gtk_text_view_size_request (widget, &requisition);
+
+  *minimum = *natural = requisition.height;
+}
+
+
 static void
 gtk_text_view_compute_child_allocation (GtkTextView      *text_view,
                                         GtkTextViewChild *vc,
@@ -3360,8 +3511,7 @@ gtk_text_view_compute_child_allocation (GtkTextView      *text_view,
   allocation->x = vc->from_left_of_buffer - text_view->priv->xoffset;
   allocation->y = buffer_y - text_view->priv->yoffset;
 
-  gtk_size_request_get_size (GTK_SIZE_REQUEST (vc->widget),
-                             &req, NULL);
+  gtk_widget_get_preferred_size (vc->widget, &req, NULL);
   allocation->width = req.width;
   allocation->height = req.height;
 }
@@ -3443,7 +3593,7 @@ gtk_text_view_allocate_children (GtkTextView *text_view)
            * get in the way. Invalidating the layout around the anchor
            * achieves this.
           */ 
-         if (GTK_WIDGET_ALLOC_NEEDED (child->widget))
+         if (_gtk_widget_get_alloc_needed (child->widget))
            {
              GtkTextIter end = child_loc;
              gtk_text_iter_forward_char (&end);
@@ -3462,8 +3612,7 @@ gtk_text_view_allocate_children (GtkTextView *text_view)
           allocation.x = child->x;
           allocation.y = child->y;
 
-          gtk_size_request_get_size (GTK_SIZE_REQUEST (child->widget),
-                                     &child_req, NULL);
+          gtk_widget_get_preferred_size (child->widget, &child_req, NULL);
 
           allocation.width = child_req.width;
           allocation.height = child_req.height;
@@ -3482,8 +3631,6 @@ gtk_text_view_size_allocate (GtkWidget *widget,
   GtkAllocation widget_allocation;
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
-  GtkTextIter first_para;
-  gint y;
   gint width, height;
   GdkRectangle text_rect;
   GdkRectangle left_rect;
@@ -3614,44 +3761,9 @@ gtk_text_view_size_allocate (GtkWidget *widget,
   /* Note that this will do some layout validation */
   gtk_text_view_allocate_children (text_view);
 
-  /* Ensure h/v adj exist */
-  get_hadjustment (text_view);
-  get_vadjustment (text_view);
-
-  priv->hadjustment->page_size = SCREEN_WIDTH (text_view);
-  priv->hadjustment->page_increment = SCREEN_WIDTH (text_view) * 0.9;
-  priv->hadjustment->step_increment = SCREEN_WIDTH (text_view) * 0.1;
-  priv->hadjustment->lower = 0;
-  priv->hadjustment->upper = MAX (SCREEN_WIDTH (text_view),
-                                  priv->width);
-
-  if (priv->hadjustment->value > priv->hadjustment->upper - priv->hadjustment->page_size)
-    gtk_adjustment_set_value (priv->hadjustment, MAX (0, priv->hadjustment->upper - priv->hadjustment->page_size));
-
-  gtk_adjustment_changed (priv->hadjustment);
-
-  priv->vadjustment->page_size = SCREEN_HEIGHT (text_view);
-  priv->vadjustment->page_increment = SCREEN_HEIGHT (text_view) * 0.9;
-  priv->vadjustment->step_increment = SCREEN_HEIGHT (text_view) * 0.1;
-  priv->vadjustment->lower = 0;
-  priv->vadjustment->upper = MAX (SCREEN_HEIGHT (text_view),
-                                  priv->height);
-
-  /* Now adjust the value of the adjustment to keep the cursor at the
-   * same place in the buffer
-   */
-  gtk_text_view_get_first_para_iter (text_view, &first_para);
-  gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
-
-  y += priv->first_para_pixels;
-
-  if (y > priv->vadjustment->upper - priv->vadjustment->page_size)
-    y = MAX (0, priv->vadjustment->upper - priv->vadjustment->page_size);
-
-  if (y != priv->yoffset)
-    gtk_adjustment_set_value (priv->vadjustment, y);
-
-  gtk_adjustment_changed (priv->vadjustment);
+  /* Update adjustments */
+  gtk_text_view_set_hadjustment_values (text_view);
+  gtk_text_view_set_vadjustment_values (text_view);
 
   /* The GTK resize loop processes all the pending exposes right
    * after doing the resize stuff, so the idle sizer won't have a
@@ -3904,7 +4016,6 @@ changed_handler (GtkTextLayout     *layout,
   
   if (old_height != new_height)
     {
-      gboolean yoffset_changed = FALSE;
       GSList *tmp_list;
       int new_first_para_top;
       int old_first_para_top;
@@ -3930,14 +4041,7 @@ changed_handler (GtkTextLayout     *layout,
         {
           priv->yoffset += new_first_para_top - old_first_para_top;
           
-          get_vadjustment (text_view)->value = priv->yoffset;
-          yoffset_changed = TRUE;
-        }
-
-      if (yoffset_changed)
-        {
-          DV(g_print ("Changing scroll position (%s)\n", G_STRLOC));
-          gtk_adjustment_value_changed (get_vadjustment (text_view));
+          gtk_adjustment_set_value (text_view->priv->vadjustment, priv->yoffset);
         }
 
       /* FIXME be smarter about which anchored widgets we update */
@@ -3962,7 +4066,7 @@ changed_handler (GtkTextLayout     *layout,
      * to avoid the optimization which just returns widget->requisition
      * if a resize hasn't been queued.
      */
-    GTK_WIDGET_GET_CLASS (widget)->size_request (widget, &new_req);
+    gtk_text_view_size_request (widget, &new_req);
 
     if (old_req.width != new_req.width ||
         old_req.height != new_req.height)
@@ -3978,11 +4082,12 @@ gtk_text_view_realize (GtkWidget *widget)
   GtkAllocation allocation;
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
+  GtkStyleContext *context;
   GdkWindow *window;
   GdkWindowAttr attributes;
   gint attributes_mask;
   GSList *tmp_list;
-  
+
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
 
@@ -4004,13 +4109,14 @@ gtk_text_view_realize (GtkWidget *widget)
   window = gdk_window_new (gtk_widget_get_parent_window (widget),
                            &attributes, attributes_mask);
   gtk_widget_set_window (widget, window);
-  gdk_window_set_user_data (window, widget);
+  gtk_widget_register_window (widget, window);
 
-  /* must come before text_window_realize calls */
-  gtk_widget_style_attach (widget);
+  context = gtk_widget_get_style_context (widget);
 
-  gdk_window_set_background (window,
-                             &gtk_widget_get_style (widget)->bg[gtk_widget_get_state (widget)]);
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
+  gtk_style_context_set_background (context, window);
+  gtk_style_context_restore (context);
 
   text_window_realize (priv->text_window, widget);
 
@@ -4027,6 +4133,7 @@ gtk_text_view_realize (GtkWidget *widget)
     text_window_realize (priv->bottom_window, widget);
 
   gtk_text_view_ensure_layout (text_view);
+  gtk_text_view_invalidate (text_view);
 
   if (priv->buffer)
     {
@@ -4047,6 +4154,8 @@ gtk_text_view_realize (GtkWidget *widget)
 
   /* Ensure updating the spot location. */
   gtk_text_view_update_im_spot_location (text_view);
+
+  _gtk_text_handle_set_relative_to (priv->text_handle, priv->text_window->window);
 }
 
 static void
@@ -4087,7 +4196,7 @@ gtk_text_view_unrealize (GtkWidget *widget)
   if (priv->bottom_window)
     text_window_unrealize (priv->bottom_window);
 
-  gtk_text_view_destroy_layout (text_view);
+  _gtk_text_handle_set_relative_to (priv->text_handle, NULL);
 
   GTK_WIDGET_CLASS (gtk_text_view_parent_class)->unrealize (widget);
 }
@@ -4095,60 +4204,70 @@ gtk_text_view_unrealize (GtkWidget *widget)
 static void
 gtk_text_view_set_background (GtkTextView *text_view)
 {
-  GtkStyle *style;
-  GtkStateType state;
+  GtkStyleContext *context;
+  GtkStateFlags state;
   GtkWidget *widget;
   GtkTextViewPrivate *priv;
+  GdkRGBA color;
 
   widget = GTK_WIDGET (text_view);
   priv = text_view->priv;
 
-  style = gtk_widget_get_style (widget);
-  state = gtk_widget_get_state (widget);
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+
+  /* Set bin window background */
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
 
-  gdk_window_set_background (gtk_widget_get_window (widget),
-                             &style->bg[state]);
+  gtk_style_context_set_background (context, priv->text_window->bin_window);
+  gtk_style_context_set_background (context, gtk_widget_get_window (widget));
 
-  gdk_window_set_background (priv->text_window->bin_window,
-                             &style->base[state]);
+  gtk_style_context_restore (context);
+
+  /* Set lateral panes background */
+  gtk_style_context_get_background_color (context, state, &color);
 
   if (priv->left_window)
-    gdk_window_set_background (priv->left_window->bin_window,
-                               &style->bg[state]);
+    gdk_window_set_background_rgba (priv->left_window->bin_window, &color);
+
   if (priv->right_window)
-    gdk_window_set_background (priv->right_window->bin_window,
-                               &style->bg[state]);
+    gdk_window_set_background_rgba (priv->right_window->bin_window, &color);
 
   if (priv->top_window)
-    gdk_window_set_background (priv->top_window->bin_window,
-                               &style->bg[state]);
+    gdk_window_set_background_rgba (priv->top_window->bin_window, &color);
 
   if (priv->bottom_window)
-    gdk_window_set_background (priv->bottom_window->bin_window,
-                               &style->bg[state]);
+    gdk_window_set_background_rgba (priv->bottom_window->bin_window, &color);
 }
 
 static void
-gtk_text_view_style_set (GtkWidget *widget,
-                         GtkStyle  *previous_style)
+gtk_text_view_style_updated (GtkWidget *widget)
 {
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
   PangoContext *ltr_context, *rtl_context;
+  GtkStyleContext *style_context;
+  const GtkBitmask *changes;
 
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
 
+  GTK_WIDGET_CLASS (gtk_text_view_parent_class)->style_updated (widget);
+
   if (gtk_widget_get_realized (widget))
     {
       gtk_text_view_set_background (text_view);
     }
 
-  if (priv->layout && previous_style)
+
+  style_context = gtk_widget_get_style_context (widget);
+  changes = _gtk_style_context_get_changes (style_context);
+  if ((changes == NULL || _gtk_css_style_property_changes_affect_font (changes)) &&
+      priv->layout && priv->layout->default_style)
     {
       gtk_text_view_set_attributes_from_style (text_view,
-                                               priv->layout->default_style,
-                                               gtk_widget_get_style (widget));
+                                               priv->layout->default_style);
 
       ltr_context = gtk_widget_create_pango_context (widget);
       pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
@@ -4168,7 +4287,7 @@ gtk_text_view_direction_changed (GtkWidget        *widget,
 {
   GtkTextViewPrivate *priv = GTK_TEXT_VIEW (widget)->priv;
 
-  if (priv->layout)
+  if (priv->layout && priv->layout->default_style)
     {
       priv->layout->default_style->direction = gtk_widget_get_direction (widget);
 
@@ -4177,8 +4296,8 @@ gtk_text_view_direction_changed (GtkWidget        *widget,
 }
 
 static void
-gtk_text_view_state_changed (GtkWidget      *widget,
-                            GtkStateType    previous_state)
+gtk_text_view_state_flags_changed (GtkWidget     *widget,
+                                   GtkStateFlags  previous_state)
 {
   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
   GdkCursor *cursor;
@@ -4195,7 +4314,7 @@ gtk_text_view_state_changed (GtkWidget      *widget,
       gdk_window_set_cursor (text_view->priv->text_window->bin_window, cursor);
 
       if (cursor)
-      gdk_cursor_unref (cursor);
+      g_object_unref (cursor);
 
       text_view->priv->mouse_cursor_obscured = FALSE;
     }
@@ -4220,7 +4339,7 @@ set_invisible_cursor (GdkWindow *window)
  
   gdk_window_set_cursor (window, cursor);
   
-  gdk_cursor_unref (cursor);
+  g_object_unref (cursor);
 }
 
 static void
@@ -4244,7 +4363,7 @@ gtk_text_view_unobscure_mouse_cursor (GtkTextView *text_view)
       cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)),
                                           GDK_XTERM);
       gdk_window_set_cursor (text_view->priv->text_window->bin_window, cursor);
-      gdk_cursor_unref (cursor);
+      g_object_unref (cursor);
       text_view->priv->mouse_cursor_obscured = FALSE;
     }
 }
@@ -4260,8 +4379,15 @@ gtk_text_view_grab_notify (GtkWidget *widget,
   if (priv->grab_device &&
       gtk_widget_device_is_shadowed (widget, priv->grab_device))
     {
+      if (priv->drag_start_x >= 0)
+        {
+          priv->drag_start_x = -1;
+          priv->drag_start_y = -1;
+        }
+
       gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget));
       gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
+      priv->grab_device = NULL;
     }
 }
 
@@ -4345,64 +4471,241 @@ emit_event_on_tags (GtkWidget   *widget,
   return retval;
 }
 
-static gint
-gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
+static void
+gtk_text_view_set_handle_position (GtkTextView           *text_view,
+                                   GtkTextIter           *iter,
+                                   GtkTextHandlePosition  pos)
 {
-  GtkTextView *text_view;
   GtkTextViewPrivate *priv;
-  gint x = 0, y = 0;
+  GdkRectangle rect;
+  gint x, y;
 
-  text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
+  gtk_text_view_get_cursor_locations (text_view, iter, &rect, NULL);
 
-  if (priv->layout == NULL ||
-      get_buffer (text_view) == NULL)
-    return FALSE;
-
-  if (event->any.window != priv->text_window->bin_window)
-    return FALSE;
+  x = rect.x - priv->xoffset;
+  y = rect.y - priv->yoffset;
 
-  if (get_event_coordinates (event, &x, &y))
+  if (!_gtk_text_handle_get_is_dragged (priv->text_handle, pos) &&
+      (x < 0 || x > SCREEN_WIDTH (text_view) ||
+       y < 0 || y > SCREEN_HEIGHT (text_view)))
     {
-      GtkTextIter iter;
-
-      x += priv->xoffset;
-      y += priv->yoffset;
-
-      /* FIXME this is slow and we do it twice per event.
-       * My favorite solution is to have GtkTextLayout cache
-       * the last couple lookups.
+      /* Hide the handle if it's not being manipulated
+       * and fell outside of the visible text area.
        */
-      gtk_text_layout_get_iter_at_pixel (priv->layout,
-                                         &iter,
-                                         x, y);
-
-      return emit_event_on_tags (widget, event, &iter);
+      _gtk_text_handle_set_visible (priv->text_handle, pos, FALSE);
     }
-  else if (event->type == GDK_KEY_PRESS ||
-           event->type == GDK_KEY_RELEASE)
+  else
     {
-      GtkTextIter iter;
+      _gtk_text_handle_set_visible (priv->text_handle, pos, TRUE);
 
-      gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
-                                        gtk_text_buffer_get_insert (get_buffer (text_view)));
-
-      return emit_event_on_tags (widget, event, &iter);
+      rect.x = CLAMP (x, 0, SCREEN_WIDTH (text_view));
+      rect.y = CLAMP (y, 0, SCREEN_HEIGHT (text_view));
+      _gtk_text_handle_set_position (priv->text_handle, pos, &rect);
     }
-  else
-    return FALSE;
 }
 
-static gint
-gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
+static void
+gtk_text_view_handle_dragged (GtkTextHandle         *handle,
+                              GtkTextHandlePosition  pos,
+                              gint                   x,
+                              gint                   y,
+                              GtkTextView           *text_view)
 {
-  GtkTextView *text_view;
   GtkTextViewPrivate *priv;
-  GtkTextMark *insert;
-  GtkTextIter iter;
-  gboolean can_insert;
-  gboolean retval = FALSE;
-  gboolean obscure = FALSE;
+  GtkTextIter old_cursor, old_bound;
+  GtkTextIter cursor, bound, iter;
+  GtkTextIter *min, *max;
+  GtkTextHandleMode mode;
+  GtkTextBuffer *buffer;
+  GtkTextHandlePosition cursor_pos;
+
+  priv = text_view->priv;
+  buffer = get_buffer (text_view);
+  mode = _gtk_text_handle_get_mode (handle);
+
+  gtk_text_view_selection_bubble_popup_unset (text_view);
+  gtk_text_layout_get_iter_at_pixel (priv->layout, &iter,
+                                     x + priv->xoffset,
+                                     y + priv->yoffset);
+  gtk_text_buffer_get_iter_at_mark (buffer, &old_cursor,
+                                    gtk_text_buffer_get_insert (buffer));
+  gtk_text_buffer_get_iter_at_mark (buffer, &old_bound,
+                                    gtk_text_buffer_get_selection_bound (buffer));
+  cursor = old_cursor;
+  bound = old_bound;
+
+  if (mode == GTK_TEXT_HANDLE_MODE_CURSOR ||
+      gtk_text_iter_compare (&cursor, &bound) >= 0)
+    {
+      cursor_pos = GTK_TEXT_HANDLE_POSITION_CURSOR;
+      max = &cursor;
+      min = &bound;
+    }
+  else
+    {
+      cursor_pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
+      max = &bound;
+      min = &cursor;
+    }
+
+  if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
+    {
+      if (mode == GTK_TEXT_HANDLE_MODE_SELECTION &&
+         gtk_text_iter_compare (&iter, min) <= 0)
+        {
+          iter = *min;
+          gtk_text_iter_forward_char (&iter);
+        }
+
+      *max = iter;
+      gtk_text_view_set_handle_position (text_view, &iter, pos);
+    }
+  else
+    {
+      if (mode == GTK_TEXT_HANDLE_MODE_SELECTION &&
+         gtk_text_iter_compare (&iter, max) >= 0)
+        {
+          iter = *max;
+          gtk_text_iter_backward_char (&iter);
+        }
+
+      *min = iter;
+      gtk_text_view_set_handle_position (text_view, &iter, pos);
+    }
+
+  if (gtk_text_iter_compare (&old_cursor, &cursor) != 0 ||
+      gtk_text_iter_compare (&old_bound, &bound) != 0)
+    {
+      if (mode == GTK_TEXT_HANDLE_MODE_CURSOR)
+        gtk_text_buffer_place_cursor (buffer, &cursor);
+      else
+        gtk_text_buffer_select_range (buffer, &cursor, &bound);
+
+      if (_gtk_text_handle_get_is_dragged (priv->text_handle, cursor_pos))
+        gtk_text_view_scroll_mark_onscreen (text_view,
+                                            gtk_text_buffer_get_insert (buffer));
+      else
+        gtk_text_view_scroll_mark_onscreen (text_view,
+                                            gtk_text_buffer_get_selection_bound (buffer));
+    }
+}
+
+static void
+gtk_text_view_handle_drag_finished (GtkTextHandle         *handle,
+                                    GtkTextHandlePosition  pos,
+                                    GtkTextView           *text_view)
+{
+  gtk_text_view_selection_bubble_popup_set (text_view);
+}
+
+static void
+gtk_text_view_update_handles (GtkTextView       *text_view,
+                              GtkTextHandleMode  mode)
+{
+  GtkTextViewPrivate *priv = text_view->priv;
+  GtkTextIter cursor, bound, min, max;
+  GtkTextBuffer *buffer;
+
+  buffer = get_buffer (text_view);
+
+  gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
+                                    gtk_text_buffer_get_insert (buffer));
+  gtk_text_buffer_get_iter_at_mark (buffer, &bound,
+                                    gtk_text_buffer_get_selection_bound (buffer));
+
+  if (mode == GTK_TEXT_HANDLE_MODE_SELECTION &&
+      gtk_text_iter_compare (&cursor, &bound) == 0)
+    {
+      mode = GTK_TEXT_HANDLE_MODE_CURSOR;
+    }
+
+  if (mode == GTK_TEXT_HANDLE_MODE_CURSOR &&
+      (!gtk_widget_is_sensitive (GTK_WIDGET (text_view)) || !priv->cursor_visible))
+    {
+      mode = GTK_TEXT_HANDLE_MODE_NONE;
+    }
+
+  _gtk_text_handle_set_mode (priv->text_handle, mode);
+
+  if (gtk_text_iter_compare (&cursor, &bound) >= 0)
+    {
+      min = bound;
+      max = cursor;
+    }
+  else
+    {
+      min = cursor;
+      max = bound;
+    }
+
+  if (mode != GTK_TEXT_HANDLE_MODE_NONE)
+    gtk_text_view_set_handle_position (text_view, &max,
+                                       GTK_TEXT_HANDLE_POSITION_SELECTION_END);
+
+  if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
+    gtk_text_view_set_handle_position (text_view, &min,
+                                       GTK_TEXT_HANDLE_POSITION_SELECTION_START);
+}
+
+static gint
+gtk_text_view_event (GtkWidget *widget, GdkEvent *event)
+{
+  GtkTextView *text_view;
+  GtkTextViewPrivate *priv;
+  gint x = 0, y = 0;
+
+  text_view = GTK_TEXT_VIEW (widget);
+  priv = text_view->priv;
+
+  if (priv->layout == NULL ||
+      get_buffer (text_view) == NULL)
+    return FALSE;
+
+  if (event->any.window != priv->text_window->bin_window)
+    return FALSE;
+
+  if (get_event_coordinates (event, &x, &y))
+    {
+      GtkTextIter iter;
+
+      x += priv->xoffset;
+      y += priv->yoffset;
+
+      /* FIXME this is slow and we do it twice per event.
+       * My favorite solution is to have GtkTextLayout cache
+       * the last couple lookups.
+       */
+      gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                         &iter,
+                                         x, y);
+
+      return emit_event_on_tags (widget, event, &iter);
+    }
+  else if (event->type == GDK_KEY_PRESS ||
+           event->type == GDK_KEY_RELEASE)
+    {
+      GtkTextIter iter;
+
+      gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
+                                        gtk_text_buffer_get_insert (get_buffer (text_view)));
+
+      return emit_event_on_tags (widget, event, &iter);
+    }
+  else
+    return FALSE;
+}
+
+static gint
+gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
+{
+  GtkTextView *text_view;
+  GtkTextViewPrivate *priv;
+  GtkTextMark *insert;
+  GtkTextIter iter;
+  gboolean can_insert;
+  gboolean retval = FALSE;
+  gboolean obscure = FALSE;
 
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
@@ -4476,6 +4779,12 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
   gtk_text_view_reset_blink_time (text_view);
   gtk_text_view_pend_cursor_blink (text_view);
 
+  if (!event->send_event)
+    _gtk_text_handle_set_mode (priv->text_handle,
+                               GTK_TEXT_HANDLE_MODE_NONE);
+
+  gtk_text_view_selection_bubble_popup_unset (text_view);
+
   return retval;
 }
 
@@ -4510,6 +4819,8 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
+  GdkDevice *device;
+  gboolean is_touchscreen;
 
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
@@ -4524,20 +4835,30 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
     }
 
   gtk_text_view_reset_blink_time (text_view);
+  gtk_text_view_selection_bubble_popup_unset (text_view);
 
 #if 0
   /* debug hack */
-  if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
+  if (event->button == GDK_BUTTON_SECONDARY && (event->state & GDK_CONTROL_MASK) != 0)
     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
-  else if (event->button == 3)
+  else if (event->button == GDK_BUTTON_SECONDARY)
     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
 #endif
 
+  device = gdk_event_get_source_device ((GdkEvent *) event);
+  is_touchscreen = test_touchscreen ||
+                   gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN;
+
   if (event->type == GDK_BUTTON_PRESS)
     {
       gtk_text_view_reset_im_context (text_view);
 
-      if (event->button == 1)
+      if (gdk_event_triggers_context_menu ((GdkEvent *) event))
+        {
+         gtk_text_view_do_popup (text_view, event);
+         return TRUE;
+        }
+      else if (event->button == GDK_BUTTON_PRIMARY)
         {
           /* If we're in the selection, start a drag copy/move of the
            * selection; otherwise, start creating a new selection.
@@ -4553,20 +4874,33 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
                                                     &start, &end) &&
               gtk_text_iter_in_range (&iter, &start, &end) &&
-              !(event->state & GDK_SHIFT_MASK))
+              !(event->state &
+                gtk_widget_get_modifier_mask (widget,
+                                              GDK_MODIFIER_INTENT_EXTEND_SELECTION)))
             {
+              priv->grab_device = event->device;
               priv->drag_start_x = event->x;
               priv->drag_start_y = event->y;
               priv->pending_place_cursor_button = event->button;
             }
           else
             {
+              GtkTextHandleMode mode;
+
               gtk_text_view_start_selection_drag (text_view, &iter, event);
+
+              if (gtk_widget_is_sensitive (widget) && is_touchscreen)
+                mode = GTK_TEXT_HANDLE_MODE_CURSOR;
+              else
+                mode = GTK_TEXT_HANDLE_MODE_NONE;
+
+              gtk_text_view_update_handles (text_view, mode);
             }
 
           return TRUE;
         }
-      else if (event->button == 2)
+      else if (event->button == GDK_BUTTON_MIDDLE &&
+               get_middle_click_paste (text_view))
         {
           GtkTextIter iter;
 
@@ -4585,17 +4919,13 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
                                           priv->editable);
           return TRUE;
         }
-      else if (event->button == 3)
-        {
-         gtk_text_view_do_popup (text_view, event);
-         return TRUE;
-        }
     }
   else if ((event->type == GDK_2BUTTON_PRESS ||
            event->type == GDK_3BUTTON_PRESS) &&
-          event->button == 1) 
+          event->button == GDK_BUTTON_PRIMARY)
     {
       GtkTextIter iter;
+      GtkTextHandleMode mode;
 
       gtk_text_view_end_selection_drag (text_view);
 
@@ -4603,11 +4933,18 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
                                         &iter,
                                         event->x + priv->xoffset,
                                         event->y + priv->yoffset);
-      
+
       gtk_text_view_start_selection_drag (text_view, &iter, event);
+
+      if (gtk_widget_is_sensitive (widget) && is_touchscreen)
+        mode = GTK_TEXT_HANDLE_MODE_SELECTION;
+      else
+        mode = GTK_TEXT_HANDLE_MODE_NONE;
+
+      gtk_text_view_update_handles (text_view, mode);
       return TRUE;
     }
-  
+
   return FALSE;
 }
 
@@ -4616,14 +4953,16 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
 {
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
+  GdkDevice *device;
 
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
+  device = gdk_event_get_source_device ((GdkEvent *) event);
 
   if (event->window != priv->text_window->bin_window)
     return FALSE;
 
-  if (event->button == 1)
+  if (event->button == GDK_BUTTON_PRIMARY)
     {
       if (priv->drag_start_x >= 0)
         {
@@ -4632,9 +4971,15 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
         }
 
       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget)))
-        return TRUE;
+       {
+          if (test_touchscreen ||
+              gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN)
+           gtk_text_view_selection_bubble_popup_set (text_view);
+         return TRUE;
+       }
       else if (priv->pending_place_cursor_button == event->button)
         {
+          GtkTextHandleMode mode;
          GtkTextIter iter;
 
           /* Unselect everything; we clicked inside selection, but
@@ -4648,9 +4993,17 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
 
          gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
          gtk_text_view_check_cursor_blink (text_view);
-         
+
+          if (gtk_widget_is_sensitive (widget) &&
+              (test_touchscreen ||
+               gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))
+           mode = GTK_TEXT_HANDLE_MODE_CURSOR;
+          else
+            mode = GTK_TEXT_HANDLE_MODE_NONE;
+
+          gtk_text_view_update_handles (text_view, mode);
           priv->pending_place_cursor_button = 0;
-          
+
           return FALSE;
         }
     }
@@ -4724,6 +5077,9 @@ gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
   g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
                                        keymap_direction_changed,
                                        text_view);
+  gtk_text_view_selection_bubble_popup_unset (text_view);
+  _gtk_text_handle_set_mode (priv->text_handle,
+                             GTK_TEXT_HANDLE_MODE_NONE);
 
   if (priv->editable)
     {
@@ -4786,8 +5142,6 @@ gtk_text_view_paint (GtkWidget      *widget,
 {
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
-  GList *child_exposes;
-  GList *tmp_list;
   
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
@@ -4815,33 +5169,15 @@ gtk_text_view_paint (GtkWidget      *widget,
           area->width, area->height);
 #endif
 
-  child_exposes = NULL;
-
   cairo_save (cr);
   cairo_translate (cr, -priv->xoffset, -priv->yoffset);
 
   gtk_text_layout_draw (priv->layout,
                         widget,
                         cr,
-                        &child_exposes);
+                        NULL);
 
   cairo_restore (cr);
-
-  tmp_list = child_exposes;
-  while (tmp_list != NULL)
-    {
-      GtkWidget *child = tmp_list->data;
-  
-      gtk_container_propagate_draw (GTK_CONTAINER (text_view),
-                                    child,
-                                    cr);
-
-      g_object_unref (child);
-      
-      tmp_list = tmp_list->next;
-    }
-
-  g_list_free (child_exposes);
 }
 
 static gboolean
@@ -4850,20 +5186,30 @@ gtk_text_view_draw (GtkWidget *widget,
 {
   GSList *tmp_list;
   GdkWindow *window;
-  
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (widget);
+
   if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
-    gtk_text_view_draw_focus (widget, cr);
+    {
+      gtk_style_context_save (context);
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
+      gtk_render_background (context, cr,
+                            0, 0,
+                            gtk_widget_get_allocated_width (widget),
+                            gtk_widget_get_allocated_height (widget));
+      gtk_style_context_restore (context);
+
+      gtk_text_view_draw_focus (widget, cr);
+    }
 
   window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget),
                                      GTK_TEXT_WINDOW_TEXT);
   if (gtk_cairo_should_draw_window (cr, window))
     {
-      int x, y;
-
       DV(g_print (">Exposed ("G_STRLOC")\n"));
       cairo_save (cr);
-      gdk_window_get_position (window, &x, &y);
-      cairo_translate (cr, x, y);
+      gtk_cairo_transform_to_window (cr, widget, window);
       gtk_text_view_paint (widget, cr);
       cairo_restore (cr);
     }
@@ -4876,13 +5222,12 @@ gtk_text_view_draw (GtkWidget *widget,
     {
       GtkTextViewChild *vc = tmp_list->data;
 
-      /* propagate_expose checks that event->window matches
+      /* propagate_draw checks that event->window matches
        * child->window
        */
-      if (!vc->anchor)
-        gtk_container_propagate_draw (GTK_CONTAINER (widget),
-                                      vc->widget,
-                                      cr);
+      gtk_container_propagate_draw (GTK_CONTAINER (widget),
+                                    vc->widget,
+                                    cr);
       
       tmp_list = tmp_list->next;
     }
@@ -4901,14 +5246,15 @@ gtk_text_view_draw_focus (GtkWidget *widget,
                        "interior-focus", &interior_focus,
                        NULL);
   
-  if (gtk_widget_has_focus (widget) && !interior_focus)
-    {          
-      gtk_cairo_paint_focus (gtk_widget_get_style (widget), cr,
-                       gtk_widget_get_state (widget),
-                       widget, "textview",
-                       0, 0,
-                       gtk_widget_get_allocated_width (widget),
-                       gtk_widget_get_allocated_height (widget));
+  if (gtk_widget_has_visible_focus (widget) && !interior_focus)
+    {
+      GtkStyleContext *context;
+
+      context = gtk_widget_get_style_context (widget);
+
+      gtk_render_focus (context, cr, 0, 0,
+                        gtk_widget_get_allocated_width (widget),
+                        gtk_widget_get_allocated_height (widget));
     }
 }
 
@@ -4918,40 +5264,36 @@ gtk_text_view_focus (GtkWidget        *widget,
 {
   GtkContainer *container;
   gboolean result;
-  
-  container = GTK_CONTAINER (widget);  
+
+  container = GTK_CONTAINER (widget);
 
   if (!gtk_widget_is_focus (widget) &&
       gtk_container_get_focus_child (container) == NULL)
     {
-      gtk_widget_grab_focus (widget);
-      return TRUE;
+      if (gtk_widget_get_can_focus (widget))
+        {
+          gtk_widget_grab_focus (widget);
+          return TRUE;
+        }
+
+      return FALSE;
     }
   else
     {
+      gboolean can_focus;
       /*
        * Unset CAN_FOCUS flag so that gtk_container_focus() allows
        * children to get the focus
        */
+      can_focus = gtk_widget_get_can_focus (widget);
       gtk_widget_set_can_focus (widget, FALSE);
       result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
-      gtk_widget_set_can_focus (widget, TRUE);
+      gtk_widget_set_can_focus (widget, can_focus);
 
       return result;
     }
 }
 
-static void
-gtk_text_view_move_focus (GtkWidget        *widget,
-                          GtkDirectionType  direction_type)
-{
-  GtkTextView *text_view = GTK_TEXT_VIEW (widget);
-
-  if (GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus)
-    GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus (text_view,
-                                                     direction_type);
-}
-
 /*
  * Container
  */
@@ -5068,6 +5410,18 @@ cursor_blinks (GtkTextView *text_view)
   return FALSE;
 }
 
+static gboolean
+get_middle_click_paste (GtkTextView *text_view)
+{
+  GtkSettings *settings;
+  gboolean paste;
+
+  settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
+  g_object_get (settings, "gtk-enable-primary-paste", &paste, NULL);
+
+  return paste;
+}
+
 static gint
 get_cursor_time (GtkTextView *text_view)
 {
@@ -5291,6 +5645,7 @@ gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
   if (!priv->cursor_visible) 
     {
       GtkScrollStep scroll_step;
+      gdouble old_xpos, old_ypos;
 
       switch (step) 
        {
@@ -5325,14 +5680,15 @@ gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
           break;
        }
 
-      if (!gtk_text_view_move_viewport (text_view, scroll_step, count))
+      old_xpos = priv->xoffset;
+      old_ypos = priv->yoffset;
+      gtk_text_view_move_viewport (text_view, scroll_step, count);
+      if ((old_xpos == priv->xoffset && old_ypos == priv->yoffset) &&
+          leave_direction != -1 &&
+          !gtk_widget_keynav_failed (GTK_WIDGET (text_view),
+                                     leave_direction))
         {
-          if (leave_direction != -1 &&
-              !gtk_widget_keynav_failed (GTK_WIDGET (text_view),
-                                         leave_direction))
-            {
-              g_signal_emit_by_name (text_view, "move-focus", leave_direction);
-            }
+          g_signal_emit_by_name (text_view, "move-focus", leave_direction);
         }
 
       return;
@@ -5527,7 +5883,7 @@ gtk_text_view_move_cursor (GtkTextView     *text_view,
   gtk_text_view_move_cursor_internal (text_view, step, count, extend_selection);
 }
 
-static gboolean
+static void
 gtk_text_view_move_viewport (GtkTextView     *text_view,
                              GtkScrollStep    step,
                              gint             count)
@@ -5540,15 +5896,15 @@ gtk_text_view_move_viewport (GtkTextView     *text_view,
     case GTK_SCROLL_STEPS:
     case GTK_SCROLL_PAGES:
     case GTK_SCROLL_ENDS:
-      adjustment = get_vadjustment (text_view);
+      adjustment = text_view->priv->vadjustment;
       break;
     case GTK_SCROLL_HORIZONTAL_STEPS:
     case GTK_SCROLL_HORIZONTAL_PAGES:
     case GTK_SCROLL_HORIZONTAL_ENDS:
-      adjustment = get_hadjustment (text_view);
+      adjustment = text_view->priv->hadjustment;
       break;
     default:
-      adjustment = get_vadjustment (text_view);
+      adjustment = text_view->priv->vadjustment;
       break;
     }
 
@@ -5556,22 +5912,22 @@ gtk_text_view_move_viewport (GtkTextView     *text_view,
     {
     case GTK_SCROLL_STEPS:
     case GTK_SCROLL_HORIZONTAL_STEPS:
-      increment = adjustment->step_increment;
+      increment = gtk_adjustment_get_step_increment (adjustment);
       break;
     case GTK_SCROLL_PAGES:
     case GTK_SCROLL_HORIZONTAL_PAGES:
-      increment = adjustment->page_increment;
+      increment = gtk_adjustment_get_page_increment (adjustment);
       break;
     case GTK_SCROLL_ENDS:
     case GTK_SCROLL_HORIZONTAL_ENDS:
-      increment = adjustment->upper - adjustment->lower;
+      increment = gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment);
       break;
     default:
       increment = 0.0;
       break;
     }
 
-  return set_adjustment_clamped (adjustment, adjustment->value + count * increment);
+  gtk_adjustment_set_value (adjustment, gtk_adjustment_get_value (adjustment) + count * increment);
 }
 
 static void
@@ -5591,7 +5947,7 @@ gtk_text_view_scroll_pages (GtkTextView *text_view,
                             gboolean     extend_selection)
 {
   GtkTextViewPrivate *priv;
-  GtkAdjustment *adj;
+  GtkAdjustment *adjustment;
   gint cursor_x_pos, cursor_y_pos;
   GtkTextMark *insert_mark;
   GtkTextIter old_insert;
@@ -5605,7 +5961,7 @@ gtk_text_view_scroll_pages (GtkTextView *text_view,
 
   g_return_val_if_fail (priv->vadjustment != NULL, FALSE);
   
-  adj = priv->vadjustment;
+  adjustment = priv->vadjustment;
 
   insert_mark = gtk_text_buffer_get_insert (get_buffer (text_view));
 
@@ -5626,13 +5982,13 @@ gtk_text_view_scroll_pages (GtkTextView *text_view,
   if (count < 0)
     {
       gtk_text_view_get_first_para_iter (text_view, &anchor);
-      y0 = adj->page_size;
-      y1 = adj->page_size + count * adj->page_increment;
+      y0 = gtk_adjustment_get_page_size (adjustment);
+      y1 = gtk_adjustment_get_page_size (adjustment) + count * gtk_adjustment_get_page_increment (adjustment);
     }
   else
     {
       gtk_text_view_get_first_para_iter (text_view, &anchor);
-      y0 = count * adj->page_increment + adj->page_size;
+      y0 = count * gtk_adjustment_get_page_increment (adjustment) + gtk_adjustment_get_page_size (adjustment);
       y1 = 0;
     }
 
@@ -5641,13 +5997,13 @@ gtk_text_view_scroll_pages (GtkTextView *text_view,
 
   new_insert = old_insert;
 
-  if (count < 0 && adj->value <= (adj->lower + 1e-12))
+  if (count < 0 && gtk_adjustment_get_value (adjustment) <= (gtk_adjustment_get_lower (adjustment) + 1e-12))
     {
       /* already at top, just be sure we are at offset 0 */
       gtk_text_buffer_get_start_iter (get_buffer (text_view), &new_insert);
       move_cursor (text_view, &new_insert, extend_selection);
     }
-  else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
+  else if (count > 0 && gtk_adjustment_get_value (adjustment) >= (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_page_size (adjustment) - 1e-12))
     {
       /* already at bottom, just be sure we are at the end */
       gtk_text_buffer_get_end_iter (get_buffer (text_view), &new_insert);
@@ -5657,13 +6013,13 @@ gtk_text_view_scroll_pages (GtkTextView *text_view,
     {
       gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
 
-      oldval = adj->value;
-      newval = adj->value;
+      oldval = gtk_adjustment_get_value (adjustment);
+      newval = gtk_adjustment_get_value (adjustment);
 
-      newval += count * adj->page_increment;
+      newval += count * gtk_adjustment_get_page_increment (adjustment);
 
-      set_adjustment_clamped (adj, newval);
-      cursor_y_pos += adj->value - oldval;
+      gtk_adjustment_set_value (adjustment, newval);
+      cursor_y_pos += gtk_adjustment_get_value (adjustment) - oldval;
 
       gtk_text_layout_get_iter_at_pixel (priv->layout, &new_insert, cursor_x_pos, cursor_y_pos);
       clamp_iter_onscreen (text_view, &new_insert);
@@ -5687,7 +6043,7 @@ gtk_text_view_scroll_hpages (GtkTextView *text_view,
                              gboolean     extend_selection)
 {
   GtkTextViewPrivate *priv;
-  GtkAdjustment *adj;
+  GtkAdjustment *adjustment;
   gint cursor_x_pos, cursor_y_pos;
   GtkTextMark *insert_mark;
   GtkTextIter old_insert;
@@ -5700,7 +6056,7 @@ gtk_text_view_scroll_hpages (GtkTextView *text_view,
 
   g_return_val_if_fail (priv->hadjustment != NULL, FALSE);
 
-  adj = priv->hadjustment;
+  adjustment = priv->hadjustment;
 
   insert_mark = gtk_text_buffer_get_insert (get_buffer (text_view));
 
@@ -5724,13 +6080,13 @@ gtk_text_view_scroll_hpages (GtkTextView *text_view,
 
   new_insert = old_insert;
 
-  if (count < 0 && adj->value <= (adj->lower + 1e-12))
+  if (count < 0 && gtk_adjustment_get_value (adjustment) <= (gtk_adjustment_get_lower (adjustment) + 1e-12))
     {
       /* already at far left, just be sure we are at offset 0 */
       gtk_text_iter_set_line_offset (&new_insert, 0);
       move_cursor (text_view, &new_insert, extend_selection);
     }
-  else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
+  else if (count > 0 && gtk_adjustment_get_value (adjustment) >= (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_page_size (adjustment) - 1e-12))
     {
       /* already at far right, just be sure we are at the end */
       if (!gtk_text_iter_ends_line (&new_insert))
@@ -5741,13 +6097,13 @@ gtk_text_view_scroll_hpages (GtkTextView *text_view,
     {
       gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
 
-      oldval = adj->value;
-      newval = adj->value;
+      oldval = gtk_adjustment_get_value (adjustment);
+      newval = gtk_adjustment_get_value (adjustment);
 
-      newval += count * adj->page_increment;
+      newval += count * gtk_adjustment_get_page_increment (adjustment);
 
-      set_adjustment_clamped (adj, newval);
-      cursor_x_pos += adj->value - oldval;
+      gtk_adjustment_set_value (adjustment, newval);
+      cursor_x_pos += gtk_adjustment_get_value (adjustment) - oldval;
 
       gtk_text_layout_get_iter_at_pixel (priv->layout, &new_insert, cursor_x_pos, cursor_y_pos);
       clamp_iter_onscreen (text_view, &new_insert);
@@ -6003,6 +6359,7 @@ gtk_text_view_cut_clipboard (GtkTextView *text_view)
   DV(g_print (G_STRLOC": scrolling onscreen\n"));
   gtk_text_view_scroll_mark_onscreen (text_view,
                                       gtk_text_buffer_get_insert (get_buffer (text_view)));
+  gtk_text_view_selection_bubble_popup_unset (text_view);
 }
 
 static void
@@ -6048,6 +6405,17 @@ gtk_text_view_paste_done_handler (GtkTextBuffer *buffer,
   priv->scroll_after_paste = TRUE;
 }
 
+static void
+gtk_text_view_buffer_changed_handler (GtkTextBuffer *buffer,
+                                      gpointer       data)
+{
+  GtkTextView *text_view = data;
+  GtkTextViewPrivate *priv = text_view->priv;
+
+  gtk_text_view_update_handles (text_view,
+                                _gtk_text_handle_get_mode (priv->text_handle));
+}
+
 static void
 gtk_text_view_toggle_overwrite (GtkTextView *text_view)
 {
@@ -6158,36 +6526,6 @@ gtk_text_view_get_accepts_tab (GtkTextView *text_view)
   return text_view->priv->accepts_tab;
 }
 
-static void
-gtk_text_view_compat_move_focus (GtkTextView     *text_view,
-                                 GtkDirectionType direction_type)
-{
-  GSignalInvocationHint *hint = g_signal_get_invocation_hint (text_view);
-
-  /*  as of GTK+ 2.12, the "move-focus" signal has been moved to GtkWidget,
-   *  the evil code below makes sure that both emitting the signal and
-   *  calling the virtual function directly continue to work as expetcted
-   */
-
-  if (hint->signal_id == g_signal_lookup ("move-focus", GTK_TYPE_WIDGET))
-    {
-      /*  if this is a signal emission, chain up  */
-
-      gboolean retval;
-
-      g_signal_chain_from_overridden_handler (text_view,
-                                              direction_type, &retval);
-    }
-  else
-    {
-      /*  otherwise emit the signal, since somebody called the virtual
-       *  function directly
-       */
-
-      g_signal_emit_by_name (text_view, "move-focus", direction_type);
-    }
-}
-
 /*
  * Selections
  */
@@ -6233,24 +6571,25 @@ get_iter_at_pointer (GtkTextView *text_view,
 }
 
 static void
-move_mark_to_pointer_and_scroll (GtkTextView *text_view,
-                                 const gchar *mark_name,
-                                 GdkDevice   *device)
+move_mark_to_pointer_and_scroll (GtkTextView    *text_view,
+                                 const gchar    *mark_name,
+                                 GdkDevice      *device,
+                                 GdkInputSource  source)
 {
   GtkTextIter newplace;
+  GtkTextBuffer *buffer;
   GtkTextMark *mark;
 
+  buffer = get_buffer (text_view);
   get_iter_at_pointer (text_view, device, &newplace, NULL, NULL);
-  
-  mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
-  
+
+  mark = gtk_text_buffer_get_mark (buffer, mark_name);
+
   /* This may invalidate the layout */
   DV(g_print (G_STRLOC": move mark\n"));
-  
-  gtk_text_buffer_move_mark (get_buffer (text_view),
-                            mark,
-                            &newplace);
-  
+
+  gtk_text_buffer_move_mark (buffer, mark, &newplace);
+
   DV(g_print (G_STRLOC": scrolling onscreen\n"));
   gtk_text_view_scroll_mark_onscreen (text_view, mark);
 
@@ -6275,12 +6614,12 @@ selection_scan_timeout (gpointer data)
 #define LOWER_OFFSET_ANCHOR 0.2
 
 static gboolean
-check_scroll (gdouble offset, GtkAdjustment *adj)
+check_scroll (gdouble offset, GtkAdjustment *adjustment)
 {
   if ((offset > UPPER_OFFSET_ANCHOR &&
-       adj->value + adj->page_size < adj->upper) ||
+       gtk_adjustment_get_value (adjustment) + gtk_adjustment_get_page_size (adjustment) < gtk_adjustment_get_upper (adjustment)) ||
       (offset < LOWER_OFFSET_ANCHOR &&
-       adj->value > adj->lower))
+       gtk_adjustment_get_value (adjustment) > gtk_adjustment_get_lower (adjustment)))
     return TRUE;
 
   return FALSE;
@@ -6292,21 +6631,20 @@ drag_scan_timeout (gpointer data)
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
   GtkTextIter newplace;
-  gint x, y, width, height;
+  gint x, y;
   gdouble pointer_xoffset, pointer_yoffset;
 
   text_view = GTK_TEXT_VIEW (data);
   priv = text_view->priv;
 
   get_iter_at_pointer (text_view, priv->dnd_device, &newplace, &x, &y);
-  gdk_drawable_get_size (priv->text_window->bin_window, &width, &height);
 
   gtk_text_buffer_move_mark (get_buffer (text_view),
                              priv->dnd_mark,
                              &newplace);
 
-  pointer_xoffset = (gdouble) x / width;
-  pointer_yoffset = (gdouble) y / height;
+  pointer_xoffset = (gdouble) x / gdk_window_get_width (priv->text_window->bin_window);
+  pointer_yoffset = (gdouble) y / gdk_window_get_height (priv->text_window->bin_window);
 
   if (check_scroll (pointer_xoffset, priv->hadjustment) ||
       check_scroll (pointer_yoffset, priv->vadjustment))
@@ -6436,16 +6774,22 @@ selection_motion_event_handler (GtkTextView    *text_view,
                                SelectionData  *data)
 {
   GtkTextViewPrivate *priv;
+  GdkInputSource input_source;
+  GdkDevice *device;
 
   priv = text_view->priv;
   gdk_event_request_motions (event);
 
+  device = gdk_event_get_source_device ((GdkEvent *) event);
+  input_source = gdk_device_get_source (device);
+
   if (priv->grab_device != event->device)
     return FALSE;
 
   if (data->granularity == SELECT_CHARACTERS) 
     {
-      move_mark_to_pointer_and_scroll (text_view, "insert", event->device);
+      move_mark_to_pointer_and_scroll (text_view, "insert",
+                                       event->device, input_source);
     }
   else 
     {
@@ -6469,7 +6813,7 @@ selection_motion_event_handler (GtkTextView    *text_view,
       else
         gtk_text_buffer_select_range (buffer, &end, &orig_start);
 
-      gtk_text_view_scroll_mark_onscreen (text_view, 
+      gtk_text_view_scroll_mark_onscreen (text_view,
                                          gtk_text_buffer_get_insert (buffer));
     }
 
@@ -6484,6 +6828,9 @@ selection_motion_event_handler (GtkTextView    *text_view,
   text_view->priv->scroll_timeout =
     gdk_threads_add_timeout (50, selection_scan_timeout, text_view);
 
+  if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN)
+    gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_SELECTION);
+
   return TRUE;
 }
 
@@ -6525,7 +6872,9 @@ gtk_text_view_start_selection_drag (GtkTextView       *text_view,
   orig_start = ins;
   orig_end = bound;
 
-  if (button->state & GDK_SHIFT_MASK)
+  if (button->state &
+      gtk_widget_get_modifier_mask (GTK_WIDGET (text_view),
+                                    GDK_MODIFIER_INTENT_EXTEND_SELECTION))
     {
       /* Extend selection */
       GtkTextIter old_ins, old_bound;
@@ -6609,16 +6958,35 @@ gtk_text_view_end_selection_drag (GtkTextView *text_view)
 
 static void
 gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
-                                         GtkTextAttributes  *values,
-                                         GtkStyle           *style)
+                                         GtkTextAttributes  *values)
 {
-  values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
-  values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
+  GtkStyleContext *context;
+  GdkRGBA bg_color, fg_color;
+  GtkStateFlags state;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (text_view));
+  state = gtk_widget_get_state_flags (GTK_WIDGET (text_view));
+
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
+
+  gtk_style_context_get_background_color (context, state, &bg_color);
+  gtk_style_context_get_color (context, state, &fg_color);
+
+  values->appearance.bg_color.red = CLAMP (bg_color.red * 65535. + 0.5, 0, 65535);
+  values->appearance.bg_color.green = CLAMP (bg_color.green * 65535. + 0.5, 0, 65535);
+  values->appearance.bg_color.blue = CLAMP (bg_color.blue * 65535. + 0.5, 0, 65535);
+
+  values->appearance.fg_color.red = CLAMP (fg_color.red * 65535. + 0.5, 0, 65535);
+  values->appearance.fg_color.green = CLAMP (fg_color.green * 65535. + 0.5, 0, 65535);
+  values->appearance.fg_color.blue = CLAMP (fg_color.blue * 65535. + 0.5, 0, 65535);
 
   if (values->font)
     pango_font_description_free (values->font);
 
-  values->font = pango_font_description_copy (style->font_desc);
+  gtk_style_context_get (context, state, "font", &values->font, NULL);
+
+  gtk_style_context_restore (context);
 }
 
 static void
@@ -6712,10 +7080,7 @@ gtk_text_view_ensure_layout (GtkTextView *text_view)
 
       style = gtk_text_attributes_new ();
 
-      gtk_widget_ensure_style (widget);
-      gtk_text_view_set_attributes_from_style (text_view,
-                                               style,
-                                               gtk_widget_get_style (widget));
+      gtk_text_view_set_attributes_from_style (text_view, style);
 
       style->pixels_above_lines = priv->pixels_above_lines;
       style->pixels_below_lines = priv->pixels_below_lines;
@@ -6749,8 +7114,6 @@ gtk_text_view_ensure_layout (GtkTextView *text_view)
 
           tmp_list = g_slist_next (tmp_list);
         }
-
-      gtk_text_view_invalidate (text_view);
     }
 }
 
@@ -6863,7 +7226,7 @@ gtk_text_view_reset_im_context (GtkTextView *text_view)
  * gtk_foo_bar_key_press_event (GtkWidget   *widget,
  *                              GdkEventKey *event)
  * {
- *   if ((key->keyval == GDK_Return || key->keyval == GDK_KP_Enter))
+ *   if ((key->keyval == GDK_KEY_Return || key->keyval == GDK_KEY_KP_Enter))
  *     {
  *       if (gtk_text_view_im_context_filter_keypress (GTK_TEXT_VIEW (view), event))
  *         return TRUE;
@@ -6981,7 +7344,7 @@ gtk_text_view_drag_data_get (GtkWidget        *widget,
         {
           /* Extract the selected text */
           str = gtk_text_buffer_serialize (buffer, buffer,
-                                           selection_data->target,
+                                           gtk_selection_data_get_target (selection_data),
                                            &start, &end,
                                            &len);
         }
@@ -6989,7 +7352,7 @@ gtk_text_view_drag_data_get (GtkWidget        *widget,
       if (str)
         {
           gtk_selection_data_set (selection_data,
-                                  selection_data->target,
+                                  gtk_selection_data_get_target (selection_data),
                                   8, /* bytes */
                                   (guchar *) str, len);
           g_free (str);
@@ -7102,7 +7465,7 @@ gtk_text_view_drag_motion (GtkWidget        *widget,
         {
           GtkWidget *source_widget;
           
-          suggested_action = context->suggested_action;
+          suggested_action = gdk_drag_context_get_suggested_action (context);
           
           source_widget = gtk_drag_get_source_widget (context);
           
@@ -7111,7 +7474,7 @@ gtk_text_view_drag_motion (GtkWidget        *widget,
               /* Default to MOVE, unless the user has
                * pressed ctrl or alt to affect available actions
                */
-              if ((context->actions & GDK_ACTION_MOVE) != 0)
+              if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
                 suggested_action = GDK_ACTION_MOVE;
             }
         }
@@ -7245,10 +7608,10 @@ gtk_text_view_drag_data_received (GtkWidget        *widget,
       GtkTextIter start, end;
       gboolean copy_tags = TRUE;
 
-      if (selection_data->length != sizeof (src_buffer))
+      if (gtk_selection_data_get_length (selection_data) != sizeof (src_buffer))
         return;
 
-      memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
+      memcpy (&src_buffer, gtk_selection_data_get_data (selection_data), sizeof (src_buffer));
 
       if (src_buffer == NULL)
         return;
@@ -7268,7 +7631,7 @@ gtk_text_view_drag_data_received (GtkWidget        *widget,
 
           atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
 
-          for (list = context->targets; list; list = g_list_next (list))
+          for (list = gdk_drag_context_list_targets (context); list; list = g_list_next (list))
             {
               gint i;
 
@@ -7312,17 +7675,17 @@ gtk_text_view_drag_data_received (GtkWidget        *widget,
             }
         }
     }
-  else if (selection_data->length > 0 &&
+  else if (gtk_selection_data_get_length (selection_data) > 0 &&
            info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
     {
       gboolean retval;
       GError *error = NULL;
 
       retval = gtk_text_buffer_deserialize (buffer, buffer,
-                                            selection_data->target,
+                                            gtk_selection_data_get_target (selection_data),
                                             &drop_point,
-                                            (guint8 *) selection_data->data,
-                                            selection_data->length,
+                                            (guint8 *) gtk_selection_data_get_data (selection_data),
+                                            gtk_selection_data_get_length (selection_data),
                                             &error);
 
       if (!retval)
@@ -7336,7 +7699,7 @@ gtk_text_view_drag_data_received (GtkWidget        *widget,
 
  done:
   gtk_drag_finish (context, success,
-                  success && context->action == GDK_ACTION_MOVE,
+                  success && gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE,
                   time);
 
   if (success)
@@ -7359,13 +7722,43 @@ gtk_text_view_drag_data_received (GtkWidget        *widget,
  * Returns: (transfer none): pointer to the horizontal #GtkAdjustment
  *
  * Since: 2.22
+ *
+ * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
  **/
 GtkAdjustment*
 gtk_text_view_get_hadjustment (GtkTextView *text_view)
 {
   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
 
-  return get_hadjustment (text_view);
+  return text_view->priv->hadjustment;
+}
+
+static void
+gtk_text_view_set_hadjustment (GtkTextView   *text_view,
+                               GtkAdjustment *adjustment)
+{
+  GtkTextViewPrivate *priv = text_view->priv;
+
+  if (adjustment && priv->hadjustment == adjustment)
+    return;
+
+  if (priv->hadjustment != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (priv->hadjustment,
+                                            gtk_text_view_value_changed,
+                                            text_view);
+      g_object_unref (priv->hadjustment);
+    }
+
+  if (adjustment == NULL)
+    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
+  g_signal_connect (adjustment, "value-changed",
+                    G_CALLBACK (gtk_text_view_value_changed), text_view);
+  priv->hadjustment = g_object_ref_sink (adjustment);
+  gtk_text_view_set_hadjustment_values (text_view);
+
+  g_object_notify (G_OBJECT (text_view), "hadjustment");
 }
 
 /**
@@ -7377,95 +7770,111 @@ gtk_text_view_get_hadjustment (GtkTextView *text_view)
  * Returns: (transfer none): pointer to the vertical #GtkAdjustment
  *
  * Since: 2.22
+ *
+ * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
  **/
 GtkAdjustment*
 gtk_text_view_get_vadjustment (GtkTextView *text_view)
 {
   g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
 
-  return get_vadjustment (text_view);
+  return text_view->priv->vadjustment;
 }
 
-static GtkAdjustment*
-get_hadjustment (GtkTextView *text_view)
+static void
+gtk_text_view_set_vadjustment (GtkTextView   *text_view,
+                               GtkAdjustment *adjustment)
 {
-  if (text_view->priv->hadjustment == NULL)
-    gtk_text_view_set_scroll_adjustments (text_view,
-                                          NULL, /* forces creation */
-                                          text_view->priv->vadjustment);
+  GtkTextViewPrivate *priv = text_view->priv;
 
-  return text_view->priv->hadjustment;
+  if (adjustment && priv->vadjustment == adjustment)
+    return;
+
+  if (priv->vadjustment != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (priv->vadjustment,
+                                            gtk_text_view_value_changed,
+                                            text_view);
+      g_object_unref (priv->vadjustment);
+    }
+
+  if (adjustment == NULL)
+    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
+  g_signal_connect (adjustment, "value-changed",
+                    G_CALLBACK (gtk_text_view_value_changed), text_view);
+  priv->vadjustment = g_object_ref_sink (adjustment);
+  gtk_text_view_set_vadjustment_values (text_view);
+
+  g_object_notify (G_OBJECT (text_view), "vadjustment");
 }
 
-static GtkAdjustment*
-get_vadjustment (GtkTextView *text_view)
+static void
+gtk_text_view_set_hadjustment_values (GtkTextView *text_view)
 {
-  if (text_view->priv->vadjustment == NULL)
-    gtk_text_view_set_scroll_adjustments (text_view,
-                                          text_view->priv->hadjustment,
-                                          NULL); /* forces creation */
-  return text_view->priv->vadjustment;
-}
+  GtkTextViewPrivate *priv;
+  gint screen_width;
+  gdouble old_value;
+  gdouble new_value;
+  gdouble new_upper;
+
+  priv = text_view->priv;
+
+  screen_width = SCREEN_WIDTH (text_view);
+  old_value = gtk_adjustment_get_value (priv->hadjustment);
+  new_upper = MAX (screen_width, priv->width);
 
+  g_object_set (priv->hadjustment,
+                "lower", 0.0,
+                "upper", new_upper,
+                "page-size", (gdouble)screen_width,
+                "step-increment", screen_width * 0.1,
+                "page-increment", screen_width * 0.9,
+                NULL);
+
+  new_value = CLAMP (old_value, 0, new_upper - screen_width);
+  if (new_value != old_value)
+    gtk_adjustment_set_value (priv->hadjustment, new_value);
+}
 
 static void
-gtk_text_view_set_scroll_adjustments (GtkTextView   *text_view,
-                                      GtkAdjustment *hadj,
-                                      GtkAdjustment *vadj)
+gtk_text_view_set_vadjustment_values (GtkTextView *text_view)
 {
-  GtkTextViewPrivate *priv = text_view->priv;
-  gboolean need_adjust = FALSE;
+  GtkTextViewPrivate *priv;
+  GtkTextIter first_para;
+  gint screen_height;
+  gint y;
+  gdouble old_value;
+  gdouble new_value;
+  gdouble new_upper;
 
-  if (hadj)
-    g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
-  else
-    hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-  if (vadj)
-    g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
-  else
-    vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+  priv = text_view->priv;
 
-  if (priv->hadjustment && (priv->hadjustment != hadj))
-    {
-      g_signal_handlers_disconnect_by_func (priv->hadjustment,
-                                           gtk_text_view_value_changed,
-                                           text_view);
-      g_object_unref (priv->hadjustment);
-    }
+  screen_height = SCREEN_HEIGHT (text_view);
+  old_value = gtk_adjustment_get_value (priv->vadjustment);
+  new_upper = MAX (screen_height, priv->height);
 
-  if (priv->vadjustment && (priv->vadjustment != vadj))
-    {
-      g_signal_handlers_disconnect_by_func (priv->vadjustment,
-                                           gtk_text_view_value_changed,
-                                           text_view);
-      g_object_unref (priv->vadjustment);
-    }
+  g_object_set (priv->vadjustment,
+                "lower", 0.0,
+                "upper", new_upper,
+                "page-size", (gdouble)screen_height,
+                "step-increment", screen_height * 0.1,
+                "page-increment", screen_height * 0.9,
+                NULL);
 
-  if (priv->hadjustment != hadj)
-    {
-      priv->hadjustment = hadj;
-      g_object_ref_sink (priv->hadjustment);
-      
-      g_signal_connect (priv->hadjustment, "value-changed",
-                        G_CALLBACK (gtk_text_view_value_changed),
-                       text_view);
-      need_adjust = TRUE;
-    }
+  /* Now adjust the value of the adjustment to keep the cursor at the
+   * same place in the buffer */
+  gtk_text_view_ensure_layout (text_view);
+  gtk_text_view_get_first_para_iter (text_view, &first_para);
+  gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
 
-  if (priv->vadjustment != vadj)
-    {
-      priv->vadjustment = vadj;
-      g_object_ref_sink (priv->vadjustment);
-      
-      g_signal_connect (priv->vadjustment, "value-changed",
-                        G_CALLBACK (gtk_text_view_value_changed),
-                       text_view);
-      need_adjust = TRUE;
-    }
+  y += priv->first_para_pixels;
+
+  new_value = CLAMP (y, 0, new_upper - screen_height);
+  if (new_value != old_value)
+    gtk_adjustment_set_value (priv->vadjustment, new_value);
+ }
 
-  if (need_adjust)
-    gtk_text_view_value_changed (NULL, text_view);
-}
 
 /* FIXME this adjust_allocation is a big cut-and-paste from
  * GtkCList, needs to be some "official" way to do this
@@ -7495,6 +7904,8 @@ adjust_allocation_recurse (GtkWidget *widget,
    * into widget->allocation if the widget is not realized.
    * FIXME someone figure out why this was.
    */
+  gtk_widget_get_allocation (widget, &allocation);
+
   if (!gtk_widget_get_realized (widget))
     {
       if (gtk_widget_get_visible (widget))
@@ -7541,9 +7952,9 @@ adjust_allocation (GtkWidget *widget,
   
   adjust_allocation_recurse (widget, &scroll_data);
 }
-            
+
 static void
-gtk_text_view_value_changed (GtkAdjustment *adj,
+gtk_text_view_value_changed (GtkAdjustment *adjustment,
                              GtkTextView   *text_view)
 {
   GtkTextViewPrivate *priv;
@@ -7554,20 +7965,20 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
 
   priv = text_view->priv;
 
-  /* Note that we oddly call this function with adj == NULL
+  /* Note that we oddly call this function with adjustment == NULL
    * sometimes
    */
   
   priv->onscreen_validated = FALSE;
 
   DV(g_print(">Scroll offset changed %s/%g, onscreen_validated = FALSE ("G_STRLOC")\n",
-             adj == priv->hadjustment ? "hadj" : adj == priv->vadjustment ? "vadj" : "none",
-             adj ? adj->value : 0.0));
+             adjustment == priv->hadjustment ? "hadjustment" : adjustment == priv->vadjustment ? "vadjustment" : "none",
+             adjustment ? gtk_adjustment_get_value (adjustment) : 0.0));
   
-  if (adj == priv->hadjustment)
+  if (adjustment == priv->hadjustment)
     {
-      dx = priv->xoffset - (gint)adj->value;
-      priv->xoffset = adj->value;
+      dx = priv->xoffset - (gint)gtk_adjustment_get_value (adjustment);
+      priv->xoffset = gtk_adjustment_get_value (adjustment);
 
       /* If the change is due to a size change we need 
        * to invalidate the entire text window because there might be
@@ -7581,18 +7992,18 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
          priv->width_changed = FALSE;
        }
     }
-  else if (adj == priv->vadjustment)
+  else if (adjustment == priv->vadjustment)
     {
-      dy = priv->yoffset - (gint)adj->value;
-      priv->yoffset = adj->value;
+      dy = priv->yoffset - (gint)gtk_adjustment_get_value (adjustment);
+      priv->yoffset = gtk_adjustment_get_value (adjustment);
 
       if (priv->layout)
         {
-          gtk_text_layout_get_line_at_y (priv->layout, &iter, adj->value, &line_top);
+          gtk_text_layout_get_line_at_y (priv->layout, &iter, gtk_adjustment_get_value (adjustment), &line_top);
 
           gtk_text_buffer_move_mark (get_buffer (text_view), priv->first_para_mark, &iter);
 
-          priv->first_para_pixels = adj->value - line_top;
+          priv->first_para_pixels = gtk_adjustment_get_value (adjustment) - line_top;
         }
     }
   
@@ -7660,26 +8071,6 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
    */
   gtk_text_view_validate_onscreen (text_view);
   
-  /* process exposes */
-  if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
-    {
-      DV (g_print ("Processing updates (%s)\n", G_STRLOC));
-      
-      if (priv->left_window)
-        gdk_window_process_updates (priv->left_window->bin_window, TRUE);
-
-      if (priv->right_window)
-        gdk_window_process_updates (priv->right_window->bin_window, TRUE);
-
-      if (priv->top_window)
-        gdk_window_process_updates (priv->top_window->bin_window, TRUE);
-      
-      if (priv->bottom_window)
-        gdk_window_process_updates (priv->bottom_window->bin_window, TRUE);
-  
-      gdk_window_process_updates (priv->text_window->bin_window, TRUE);
-    }
-
   /* If this got installed, get rid of it, it's just a waste of time. */
   if (priv->first_validate_idle != 0)
     {
@@ -7691,7 +8082,10 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
    * changes made by the validation are pushed through.
    */
   gtk_text_view_update_im_spot_location (text_view);
-  
+
+  gtk_text_view_update_handles (text_view,
+                                _gtk_text_handle_get_mode (priv->text_handle));
+
   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
 }
 
@@ -7867,7 +8261,11 @@ gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
     }
 
   if (need_reset)
-    gtk_text_view_reset_im_context (text_view);
+    {
+      gtk_text_view_reset_im_context (text_view);
+      gtk_text_view_update_handles (text_view,
+                                    _gtk_text_handle_get_mode (text_view->priv->text_handle));
+    }
 }
 
 static void
@@ -7913,18 +8311,6 @@ gtk_text_view_target_list_notify (GtkTextBuffer    *buffer,
   gtk_target_list_unref (view_list);
 }
 
-static void
-gtk_text_view_get_cursor_location  (GtkTextView   *text_view,
-                                   GdkRectangle  *pos)
-{
-  GtkTextIter insert;
-  
-  gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
-                                    gtk_text_buffer_get_insert (get_buffer (text_view)));
-
-  gtk_text_layout_get_cursor_locations (text_view->priv->layout, &insert, pos, NULL);
-}
-
 static void
 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
                                       GtkTextIter *cursor,
@@ -7975,7 +8361,7 @@ gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
     return;
 
   if (x == -1 || y == -1)
-    gtk_text_view_get_cursor_location (text_view, &pos);
+    gtk_text_view_get_cursor_locations (text_view, NULL, &pos, NULL);
 
   text_view->priv->virtual_cursor_x = (x == -1) ? pos.x : x;
   text_view->priv->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
@@ -8092,8 +8478,8 @@ popup_position_func (GtkMenu   *menu,
 
   gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
 
-  gtk_size_request_get_size (GTK_SIZE_REQUEST (text_view->priv->popup_menu),
-                             &req, NULL);
+  gtk_widget_get_preferred_size (text_view->priv->popup_menu,
+                                 &req, NULL);
 
   gtk_widget_get_allocation (widget, &allocation);
 
@@ -8124,7 +8510,7 @@ popup_position_func (GtkMenu   *menu,
 
   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
   gtk_menu_set_monitor (menu, monitor_num);
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
 
   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
@@ -8137,6 +8523,7 @@ typedef struct
   GtkTextView *text_view;
   gint button;
   guint time;
+  GdkDevice *device;
 } PopupInfo;
 
 static gboolean
@@ -8237,6 +8624,8 @@ popup_targets_received (GtkClipboard     *clipboard,
       gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
 
       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
+      gtk_widget_set_sensitive (menuitem,
+                                gtk_text_buffer_get_char_count (priv->buffer) > 0);
       g_signal_connect (menuitem, "activate",
                        G_CALLBACK (select_all_cb), text_view);
       gtk_widget_show (menuitem);
@@ -8288,9 +8677,9 @@ popup_targets_received (GtkClipboard     *clipboard,
                     0,
                     priv->popup_menu);
       
-      if (info->button)
-       gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
-                       NULL, NULL,
+      if (info->device)
+       gtk_menu_popup_for_device (GTK_MENU (priv->popup_menu), 
+      info->device, NULL, NULL, NULL, NULL, NULL,
                        info->button, info->time);
       else
        {
@@ -8321,11 +8710,13 @@ gtk_text_view_do_popup (GtkTextView    *text_view,
     {
       info->button = event->button;
       info->time = event->time;
+      info->device = event->device;
     }
   else
     {
       info->button = 0;
       info->time = gtk_get_current_event_time ();
+      info->device = NULL;
     }
 
   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
@@ -8342,6 +8733,114 @@ gtk_text_view_popup_menu (GtkWidget *widget)
   return TRUE;
 }
 
+static void
+gtk_text_view_get_selection_rect (GtkTextView           *text_view,
+                                 cairo_rectangle_int_t *rect)
+{
+  cairo_rectangle_int_t rect_cursor, rect_bound;
+  GtkTextIter cursor, bound;
+  GtkTextBuffer *buffer;
+  gint x1, y1, x2, y2;
+
+  buffer = get_buffer (text_view);
+  gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
+                                    gtk_text_buffer_get_insert (buffer));
+  gtk_text_buffer_get_iter_at_mark (buffer, &bound,
+                                    gtk_text_buffer_get_selection_bound (buffer));
+
+  gtk_text_view_get_cursor_locations (text_view, &cursor, &rect_cursor, NULL);
+  gtk_text_view_get_cursor_locations (text_view, &bound, &rect_bound, NULL);
+
+  x1 = MIN (rect_cursor.x, rect_bound.x);
+  x2 = MAX (rect_cursor.x, rect_bound.x);
+  y1 = MIN (rect_cursor.y, rect_bound.y);
+  y2 = MAX (rect_cursor.y + rect_cursor.height, rect_bound.y + rect_bound.height);
+
+  rect->x = x1;
+  rect->y = y1;
+  rect->width = x2 - x1;
+  rect->height = y2 - y1;
+}
+
+static gboolean
+gtk_text_view_selection_bubble_popup_cb (gpointer user_data)
+{
+  GtkTextView *text_view = user_data;
+  GtkTextViewPrivate *priv = text_view->priv;
+  cairo_rectangle_int_t rect;
+  gboolean has_selection;
+  GdkWindow *window;
+
+  has_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
+                                                        NULL, NULL);
+  if (!priv->editable && !has_selection)
+    {
+      priv->selection_bubble_timeout_id = 0;
+      return FALSE;
+    }
+
+  if (priv->selection_bubble)
+    gtk_widget_destroy (priv->selection_bubble);
+
+  window = gtk_widget_get_window (GTK_WIDGET (text_view));
+  priv->selection_bubble = gtk_selection_window_new ();
+  gtk_selection_window_set_editable (GTK_SELECTION_WINDOW (priv->selection_bubble),
+                                     priv->editable);
+  gtk_selection_window_set_has_selection (GTK_SELECTION_WINDOW (priv->selection_bubble),
+                                          has_selection);
+
+  g_signal_connect_swapped (priv->selection_bubble, "cut",
+                           G_CALLBACK (gtk_text_view_cut_clipboard),
+                           text_view);
+  g_signal_connect_swapped (priv->selection_bubble, "copy",
+                           G_CALLBACK (gtk_text_view_copy_clipboard),
+                           text_view);
+  g_signal_connect_swapped (priv->selection_bubble, "paste",
+                           G_CALLBACK (gtk_text_view_paste_clipboard),
+                           text_view);
+
+  gtk_text_view_get_selection_rect (text_view, &rect);
+  rect.x -= priv->xoffset;
+  rect.y -= priv->yoffset;
+  gtk_bubble_window_popup (GTK_BUBBLE_WINDOW (priv->selection_bubble),
+                           window, &rect, GTK_POS_TOP);
+
+  priv->selection_bubble_timeout_id = 0;
+  return FALSE;
+}
+
+static void
+gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view)
+{
+  GtkTextViewPrivate *priv;
+
+  priv = text_view->priv;
+
+  if (priv->selection_bubble)
+    gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
+
+  if (priv->selection_bubble_timeout_id)
+    {
+      g_source_remove (priv->selection_bubble_timeout_id);
+      priv->selection_bubble_timeout_id = 0;
+    }
+}
+
+static void
+gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view)
+{
+  GtkTextViewPrivate *priv;
+
+  priv = text_view->priv;
+
+  if (priv->selection_bubble_timeout_id)
+    g_source_remove (priv->selection_bubble_timeout_id);
+
+  priv->selection_bubble_timeout_id =
+    gdk_threads_add_timeout_seconds (1, gtk_text_view_selection_bubble_popup_cb,
+                                     text_view);
+}
+
 /* Child GdkWindows */
 
 
@@ -8382,10 +8881,13 @@ static void
 text_window_realize (GtkTextWindow *win,
                      GtkWidget     *widget)
 {
+  GtkStyleContext *context;
+  GtkStateFlags state;
   GdkWindow *window;
   GdkWindowAttr attributes;
   gint attributes_mask;
   GdkCursor *cursor;
+  GdkRGBA color;
 
   attributes.window_type = GDK_WINDOW_CHILD;
   attributes.x = win->allocation.x;
@@ -8404,7 +8906,7 @@ text_window_realize (GtkTextWindow *win,
                                 &attributes, attributes_mask);
 
   gdk_window_show (win->window);
-  gdk_window_set_user_data (win->window, win->widget);
+  gtk_widget_register_window (win->widget, win->window);
   gdk_window_lower (win->window);
 
   attributes.x = 0;
@@ -8413,6 +8915,7 @@ text_window_realize (GtkTextWindow *win,
   attributes.height = win->allocation.height;
   attributes.event_mask = (GDK_EXPOSURE_MASK            |
                            GDK_SCROLL_MASK              |
+                           GDK_SMOOTH_SCROLL_MASK       |
                            GDK_KEY_PRESS_MASK           |
                            GDK_BUTTON_PRESS_MASK        |
                            GDK_BUTTON_RELEASE_MASK      |
@@ -8425,7 +8928,10 @@ text_window_realize (GtkTextWindow *win,
                                     attributes_mask);
 
   gdk_window_show (win->bin_window);
-  gdk_window_set_user_data (win->bin_window, win->widget);
+  gtk_widget_register_window (win->widget, win->bin_window);
+
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
 
   if (win->type == GTK_TEXT_WINDOW_TEXT)
     {
@@ -8435,20 +8941,24 @@ text_window_realize (GtkTextWindow *win,
           cursor = gdk_cursor_new_for_display (gdk_window_get_display (window),
                                               GDK_XTERM);
           gdk_window_set_cursor (win->bin_window, cursor);
-          gdk_cursor_unref (cursor);
+          g_object_unref (cursor);
         } 
 
       gtk_im_context_set_client_window (GTK_TEXT_VIEW (widget)->priv->im_context,
                                         win->window);
 
+      gtk_style_context_save (context);
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
+
+      gtk_style_context_get_background_color (context, state, &color);
+      gdk_window_set_background_rgba (win->bin_window, &color);
 
-      gdk_window_set_background (win->bin_window,
-                                 &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
+      gtk_style_context_restore (context);
     }
   else
     {
-      gdk_window_set_background (win->bin_window,
-                                 &gtk_widget_get_style (widget)->bg[gtk_widget_get_state (widget)]);
+      gtk_style_context_get_background_color (context, state, &color);
+      gdk_window_set_background_rgba (win->bin_window, &color);
     }
 
   g_object_set_qdata (G_OBJECT (win->window),
@@ -8469,8 +8979,8 @@ text_window_unrealize (GtkTextWindow *win)
                                         NULL);
     }
 
-  gdk_window_set_user_data (win->window, NULL);
-  gdk_window_set_user_data (win->bin_window, NULL);
+  gtk_widget_unregister_window (win->widget, win->window);
+  gtk_widget_unregister_window (win->widget, win->bin_window);
   gdk_window_destroy (win->bin_window);
   gdk_window_destroy (win->window);
   win->window = NULL;
@@ -8587,7 +9097,7 @@ text_window_invalidate_cursors (GtkTextWindow *win)
   gtk_text_layout_get_cursor_locations (priv->layout, &iter,
                                         &strong, &weak);
 
-  /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
+  /* cursor width calculation as in gtkstylecontext.c:draw_insertion_cursor(),
    * ignoring the text direction be exposing both sides of the cursor
    */
 
@@ -9370,7 +9880,9 @@ gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
  * @ypos: Y position of child in window coordinates
  *
  * Adds a child at fixed coordinates in one of the text widget's
- * windows. The window must have nonzero size (see
+ * windows.
+ *
+ * The window must have nonzero size (see
  * gtk_text_view_set_border_window_size()). Note that the child
  * coordinates are given relative to the #GdkWindow in question, and
  * that these coordinates have no sane relationship to scrolling. When
@@ -9380,12 +9892,8 @@ gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,
  * text window), you'll need to compute the child's correct position
  * in buffer coordinates any time scrolling occurs or buffer changes
  * occur, and then call gtk_text_view_move_child() to update the
- * child's position. Unfortunately there's no good way to detect that
- * scrolling has occurred, using the current API; a possible hack
- * would be to update all child positions when the scroll adjustments
- * change or the text buffer changes. See bug 64518 on
- * bugzilla.gnome.org for status of fixing this issue.
- **/
+ * child's position.
+ */
 void
 gtk_text_view_add_child_in_window (GtkTextView       *text_view,
                                    GtkWidget         *child,
@@ -9617,3 +10125,106 @@ gtk_text_view_move_visually (GtkTextView *text_view,
 
   return gtk_text_layout_move_iter_visually (text_view->priv->layout, iter, count);
 }
+
+/**
+ * gtk_text_view_set_input_purpose:
+ * @text_view: a #GtkTextView
+ * @purpose: the purpose
+ *
+ * Sets the #GtkTextView:input-purpose property which
+ * can be used by on-screen keyboards and other input
+ * methods to adjust their behaviour.
+ *
+ * Since: 3.6
+ */
+
+void
+gtk_text_view_set_input_purpose (GtkTextView     *text_view,
+                                 GtkInputPurpose  purpose)
+
+{
+  g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+
+  if (gtk_text_view_get_input_purpose (text_view) != purpose)
+    {
+      g_object_set (G_OBJECT (text_view->priv->im_context),
+                    "input-purpose", purpose,
+                    NULL);
+
+      g_object_notify (G_OBJECT (text_view), "input-purpose");
+    }
+}
+
+/**
+ * gtk_text_view_get_input_purpose:
+ * @text_view: a #GtkTextView
+ *
+ * Gets the value of the #GtkTextView:input-purpose property.
+ *
+ * Since: 3.6
+ */
+
+GtkInputPurpose
+gtk_text_view_get_input_purpose (GtkTextView *text_view)
+{
+  GtkInputPurpose purpose;
+
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_INPUT_PURPOSE_FREE_FORM);
+
+  g_object_get (G_OBJECT (text_view->priv->im_context),
+                "input-purpose", &purpose,
+                NULL);
+
+  return purpose;
+}
+
+/**
+ * gtk_text_view_set_input_hints:
+ * @text_view: a #GtkTextView
+ * @hints: the hints
+ *
+ * Sets the #GtkTextView:input-hints property, which
+ * allows input methods to fine-tune their behaviour.
+ *
+ * Since: 3.6
+ */
+
+void
+gtk_text_view_set_input_hints (GtkTextView   *text_view,
+                               GtkInputHints  hints)
+
+{
+  g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+
+  if (gtk_text_view_get_input_hints (text_view) != hints)
+    {
+      g_object_set (G_OBJECT (text_view->priv->im_context),
+                    "input-hints", hints,
+                    NULL);
+
+      g_object_notify (G_OBJECT (text_view), "input-hints");
+    }
+}
+
+/**
+ * gtk_text_view_get_input_hints:
+ * @text_view: a #GtkTextView
+ *
+ * Gets the value of the #GtkTextView:input-hints property.
+ *
+ * Since: 3.6
+ */
+
+GtkInputHints
+gtk_text_view_get_input_hints (GtkTextView *text_view)
+{
+  GtkInputHints hints;
+
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), GTK_INPUT_HINT_NONE);
+
+  g_object_get (G_OBJECT (text_view->priv->im_context),
+                "input-hints", &hints,
+                NULL);
+
+  return hints;
+}