]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextview.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~andy/gtk] / gtk / gtktextview.c
index dc8126099c7d48b8d02fcc6b0ba538516b5cf11c..589e8af8592697bfefe988b63afeeae626211f97 100644 (file)
@@ -108,6 +108,7 @@ struct _GtkTextViewPrivate
 {
   guint blink_time;  /* time in msec the cursor has blinked since last user event */
   guint im_spot_idle;
+  gchar *im_module;
 };
 
 
@@ -137,6 +138,7 @@ enum
   MOVE_VIEWPORT,
   SELECT_ALL,
   TOGGLE_CURSOR_VISIBLE,
+  PREEDIT_CHANGED,
   LAST_SIGNAL
 };
 
@@ -156,7 +158,8 @@ enum
   PROP_CURSOR_VISIBLE,
   PROP_BUFFER,
   PROP_OVERWRITE,
-  PROP_ACCEPTS_TAB
+  PROP_ACCEPTS_TAB,
+  PROP_IM_MODULE
 };
 
 static void gtk_text_view_destroy              (GtkObject        *object);
@@ -335,6 +338,7 @@ static void gtk_text_view_paste_done_handler     (GtkTextBuffer     *buffer,
 static void gtk_text_view_get_cursor_location    (GtkTextView       *text_view,
                                                  GdkRectangle      *pos);
 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
+                                                  GtkTextIter       *cursor,
                                                   gint              *x,
                                                   gint              *y);
 static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
@@ -347,6 +351,7 @@ static GtkAdjustment* get_vadjustment            (GtkTextView       *text_view);
 static void gtk_text_view_do_popup               (GtkTextView       *text_view,
                                                  GdkEventButton    *event);
 
+static void cancel_pending_scroll                (GtkTextView   *text_view);
 static void gtk_text_view_queue_scroll           (GtkTextView   *text_view,
                                                   GtkTextMark   *mark,
                                                   gdouble        within_margin,
@@ -661,6 +666,26 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                                                         TRUE,
                                                         GTK_PARAM_READWRITE));
 
+   /**
+    * GtkTextView:im-module:
+    *
+    * Which IM (input method) module should be used for this entry. 
+    * See #GtkIMContext.
+    *
+    * Setting this to a non-%NULL value overrides the
+    * system-wide IM module setting. See the GtkSettings 
+    * #GtkSettings:gtk-im-module property.
+    *
+    * Since: 2.16
+    */
+   g_object_class_install_property (gobject_class,
+                                    PROP_IM_MODULE,
+                                    g_param_spec_string ("im-module",
+                                                         P_("IM module"),
+                                                         P_("Which IM module should be used"),
+                                                         NULL,
+                                                         GTK_PARAM_READWRITE));
+
   /*
    * Style properties
    */
@@ -689,7 +714,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
    * the viewport to be moved instead.
    *
    * Applications should not connect to it, but may emit it with 
-   * g_signal_emit_by_name() if they need to control scrolling 
+   * g_signal_emit_by_name() if they need to control the cursor
    * programmatically.
    *
    * The default bindings for this signal come in two variants,
@@ -1023,6 +1048,30 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                                 _gtk_marshal_VOID__VOID,
                                 G_TYPE_NONE, 0);
 
+  /**
+   * GtkTextView::preedit-changed:
+   * @text_view: the object which received the signal
+   * @preedit: the current preedit string
+   *
+   * If an input method is used, the typed text will not immediately
+   * be committed to the buffer. So if you are interested in the text,
+   * connect to this signal.
+   *
+   * This signal is only emitted if the text at the given position
+   * is actually editable.
+   *
+   * Since: 2.20
+   */
+  signals[PREEDIT_CHANGED] =
+    g_signal_new_class_handler (I_("preedit-changed"),
+                                G_OBJECT_CLASS_TYPE (object_class),
+                                G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                                NULL,
+                                NULL, NULL,
+                                _gtk_marshal_VOID__STRING,
+                                G_TYPE_NONE, 1,
+                                G_TYPE_STRING);
+
   /*
    * Key bindings
    */
@@ -1340,7 +1389,7 @@ gtk_text_view_new_with_buffer (GtkTextBuffer *buffer)
 /**
  * gtk_text_view_set_buffer:
  * @text_view: a #GtkTextView
- * @buffer: a #GtkTextBuffer
+ * @buffer: (allow-none): a #GtkTextBuffer
  *
  * Sets @buffer as the buffer being displayed by @text_view. The previous
  * buffer displayed by the text view is unreferenced, and a reference is
@@ -1390,29 +1439,34 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
       g_signal_handlers_disconnect_by_func (text_view->buffer,
                                             gtk_text_view_paste_done_handler,
                                             text_view);
-      g_object_unref (text_view->buffer);
-      text_view->dnd_mark = NULL;
-      text_view->first_para_mark = NULL;
 
       if (GTK_WIDGET_REALIZED (text_view))
        {
          GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
                                                              GDK_SELECTION_PRIMARY);
          gtk_text_buffer_remove_selection_clipboard (text_view->buffer, clipboard);
-       }
+        }
+
+      if (text_view->layout)
+        gtk_text_layout_set_buffer (text_view->layout, NULL);
+
+      g_object_unref (text_view->buffer);
+      text_view->dnd_mark = NULL;
+      text_view->first_para_mark = NULL;
+      cancel_pending_scroll (text_view);
     }
 
   text_view->buffer = buffer;
 
+  if (text_view->layout)
+    gtk_text_layout_set_buffer (text_view->layout, buffer);
+
   if (buffer != NULL)
     {
       GtkTextIter start;
 
       g_object_ref (buffer);
 
-      if (text_view->layout)
-        gtk_text_layout_set_buffer (text_view->layout, buffer);
-
       gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0);
 
       text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer,
@@ -1447,7 +1501,7 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
 
   g_object_notify (G_OBJECT (text_view), "buffer");
   
-  if (GTK_WIDGET_VISIBLE (text_view))
+  if (gtk_widget_get_visible (GTK_WIDGET (text_view)))
     gtk_widget_queue_draw (GTK_WIDGET (text_view));
 
   DV(g_print ("Invalidating due to set_buffer\n"));
@@ -1476,7 +1530,7 @@ get_buffer (GtkTextView *text_view)
  * The reference count on the buffer is not incremented; the caller
  * of this function won't own a new reference.
  *
- * Return value: a #GtkTextBuffer
+ * Return value: (transfer none): a #GtkTextBuffer
  **/
 GtkTextBuffer*
 gtk_text_view_get_buffer (GtkTextView *text_view)
@@ -1837,9 +1891,13 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
     }
   
   if (retval)
-    DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
+    {
+      DV(g_print (">Actually scrolled ("G_STRLOC")\n"));
+    }
   else
-    DV(g_print (">Didn't end up scrolling ("G_STRLOC")\n"));
+    {
+      DV(g_print (">Didn't end up scrolling ("G_STRLOC")\n"));
+    }
   
   return retval;
 }
@@ -2132,6 +2190,11 @@ gtk_text_view_scroll_to_mark (GtkTextView *text_view,
   g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
   g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
 
+  /* We need to verify that the buffer contains the mark, otherwise this
+   * can lead to data structure corruption later on.
+   */
+  g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
+
   gtk_text_view_queue_scroll (text_view, mark,
                               within_margin,
                               use_align,
@@ -2161,6 +2224,11 @@ gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
 
+  /* We need to verify that the buffer contains the mark, otherwise this
+   * can lead to data structure corruption later on.
+   */
+  g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
+
   gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
 }
 
@@ -2303,13 +2371,13 @@ gtk_text_view_set_editable (GtkTextView *text_view,
       if (!setting)
        {
          gtk_text_view_reset_im_context(text_view);
-         if (GTK_WIDGET_HAS_FOCUS (text_view))
+         if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
            gtk_im_context_focus_out (text_view->im_context);
        }
 
       text_view->editable = setting;
 
-      if (setting && GTK_WIDGET_HAS_FOCUS (text_view))
+      if (setting && gtk_widget_has_focus (GTK_WIDGET (text_view)))
        gtk_im_context_focus_in (text_view->im_context);
 
       if (text_view->layout)
@@ -2738,7 +2806,7 @@ gtk_text_view_set_cursor_visible (GtkTextView *text_view,
     {
       text_view->cursor_visible = setting;
 
-      if (GTK_WIDGET_HAS_FOCUS (text_view))
+      if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
         {
           if (text_view->layout)
             {
@@ -2845,8 +2913,10 @@ static void
 gtk_text_view_finalize (GObject *object)
 {
   GtkTextView *text_view;
+  GtkTextViewPrivate *priv;
 
   text_view = GTK_TEXT_VIEW (object);
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
 
   g_assert (text_view->buffer == NULL);
 
@@ -2879,6 +2949,8 @@ gtk_text_view_finalize (GObject *object)
 
   g_object_unref (text_view->im_context);
 
+  g_free (priv->im_module);
+
   G_OBJECT_CLASS (gtk_text_view_parent_class)->finalize (object);
 }
 
@@ -2889,8 +2961,10 @@ gtk_text_view_set_property (GObject         *object,
                            GParamSpec      *pspec)
 {
   GtkTextView *text_view;
+  GtkTextViewPrivate *priv;
 
   text_view = GTK_TEXT_VIEW (object);
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
 
   switch (prop_id)
     {
@@ -2950,6 +3024,13 @@ gtk_text_view_set_property (GObject         *object,
       gtk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
       break;
       
+    case PROP_IM_MODULE:
+      g_free (priv->im_module);
+      priv->im_module = g_value_dup_string (value);
+      if (GTK_IS_IM_MULTICONTEXT (text_view->im_context))
+        gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (text_view->im_context), priv->im_module);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2963,8 +3044,10 @@ gtk_text_view_get_property (GObject         *object,
                            GParamSpec      *pspec)
 {
   GtkTextView *text_view;
+  GtkTextViewPrivate *priv;
 
   text_view = GTK_TEXT_VIEW (object);
+  priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
 
   switch (prop_id)
     {
@@ -3024,6 +3107,10 @@ gtk_text_view_get_property (GObject         *object,
       g_value_set_boolean (value, text_view->accepts_tab);
       break;
       
+    case PROP_IM_MODULE:
+      g_value_set_string (value, priv->im_module);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3796,6 +3883,9 @@ gtk_text_view_realize (GtkWidget *widget)
       
       tmp_list = tmp_list->next;
     }
+
+  /* Ensure updating the spot location. */
+  gtk_text_view_update_im_spot_location (text_view);
 }
 
 static void
@@ -3922,7 +4012,7 @@ gtk_text_view_state_changed (GtkWidget      *widget,
     {
       gtk_text_view_set_background (text_view);
 
-      if (GTK_WIDGET_IS_SENSITIVE (widget))
+      if (gtk_widget_is_sensitive (widget))
         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
       else
         cursor = NULL;
@@ -3935,7 +4025,7 @@ gtk_text_view_state_changed (GtkWidget      *widget,
       text_view->mouse_cursor_obscured = FALSE;
     }
 
-  if (!GTK_WIDGET_IS_SENSITIVE (widget))
+  if (!gtk_widget_is_sensitive (widget))
     {
       /* Clear any selection */
       gtk_text_view_unselect (text_view);
@@ -3947,28 +4037,15 @@ gtk_text_view_state_changed (GtkWidget      *widget,
 static void
 set_invisible_cursor (GdkWindow *window)
 {
-  GdkBitmap *empty_bitmap;
+  GdkDisplay *display;
   GdkCursor *cursor;
-  GdkColor useless;
-  char invisible_cursor_bits[] = { 0x0 };      
-       
-  useless.red = useless.green = useless.blue = 0;
-  useless.pixel = 0;
-  
-  empty_bitmap = gdk_bitmap_create_from_data (window,
-                                             invisible_cursor_bits,
-                                             1, 1);
-  
-  cursor = gdk_cursor_new_from_pixmap (empty_bitmap,
-                                      empty_bitmap,
-                                      &useless,
-                                      &useless, 0, 0);
-  
+
+  display = gdk_drawable_get_display (window);
+  cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
   gdk_window_set_cursor (window, cursor);
   
   gdk_cursor_unref (cursor);
-  
-  g_object_unref (empty_bitmap);
 }
 
 static void
@@ -4283,7 +4360,8 @@ 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))
+              gtk_text_iter_in_range (&iter, &start, &end) &&
+              !(event->state & GDK_SHIFT_MASK))
             {
               text_view->drag_start_x = event->x;
               text_view->drag_start_y = event->y;
@@ -4500,7 +4578,6 @@ gtk_text_view_paint (GtkWidget      *widget,
   GtkTextView *text_view;
   GList *child_exposes;
   GList *tmp_list;
-  GdkRegion *updates;
   
   text_view = GTK_TEXT_VIEW (widget);
 
@@ -4515,19 +4592,6 @@ gtk_text_view_paint (GtkWidget      *widget,
       gtk_text_view_flush_first_validate (text_view);
     }
 
-  /* More regions could have become invalid in the above loop */
-  updates = gdk_window_get_update_area (text_view->text_window->bin_window);
-  if (updates)
-    {
-      GdkRectangle rect;
-      
-      gdk_region_get_clipbox (updates, &rect);
-
-      gdk_rectangle_union (area, &rect, area);
-      
-      gdk_region_destroy (updates);
-    }
-  
   if (!text_view->onscreen_validated)
     {
       g_warning (G_STRLOC ": somehow some text lines were modified or scrolling occurred since the last validation of lines on the screen - may be a text widget bug.");
@@ -4615,9 +4679,9 @@ gtk_text_view_draw_focus (GtkWidget *widget)
                        "interior-focus", &interior_focus,
                        NULL);
   
-  if (GTK_WIDGET_DRAWABLE (widget))
+  if (gtk_widget_is_drawable (widget))
     {
-      if (GTK_WIDGET_HAS_FOCUS (widget) && !interior_focus)
+      if (gtk_widget_has_focus (widget) && !interior_focus)
         {          
           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), 
                            NULL, widget, "textview",
@@ -4824,7 +4888,7 @@ blink_cb (gpointer data)
   text_view = GTK_TEXT_VIEW (data);
   priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
 
-  if (!GTK_WIDGET_HAS_FOCUS (text_view))
+  if (!gtk_widget_has_focus (GTK_WIDGET (text_view)))
     {
       g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
                  "connect a handler to this signal, it must return\n"
@@ -4894,7 +4958,7 @@ gtk_text_view_check_cursor_blink (GtkTextView *text_view)
 {
   if (text_view->layout != NULL &&
       text_view->cursor_visible &&
-      GTK_WIDGET_HAS_FOCUS (text_view))
+      gtk_widget_has_focus (GTK_WIDGET (text_view)))
     {
       if (cursor_blinks (text_view))
        {
@@ -4925,7 +4989,7 @@ gtk_text_view_pend_cursor_blink (GtkTextView *text_view)
 {
   if (text_view->layout != NULL &&
       text_view->cursor_visible &&
-      GTK_WIDGET_HAS_FOCUS (text_view) &&
+      gtk_widget_has_focus (GTK_WIDGET (text_view)) &&
       cursor_blinks (text_view))
     {
       gtk_text_view_stop_cursor_blink (text_view);
@@ -4997,6 +5061,7 @@ gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
 {
   GtkTextIter insert;
   GtkTextIter newplace;
+  gboolean cancel_selection = FALSE;
   gint cursor_x_pos = 0;
   GtkDirectionType leave_direction = -1;
 
@@ -5073,20 +5138,46 @@ gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
 
   gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
                                     gtk_text_buffer_get_insert (get_buffer (text_view)));
+
+  if (! extend_selection)
+    {
+      GtkTextIter sel_bound;
+
+      gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &sel_bound,
+                                        gtk_text_buffer_get_selection_bound (get_buffer (text_view)));
+
+      /* if we move forward, assume the cursor is at the end of the selection;
+       * if we move backward, assume the cursor is at the start
+       */
+      if (count > 0)
+        gtk_text_iter_order (&sel_bound, &insert);
+      else
+        gtk_text_iter_order (&insert, &sel_bound);
+
+      /* if we actually have a selection, just move *to* the beginning/end
+       * of the selection and not *from* there on LOGICAL_POSITIONS
+       * and VISUAL_POSITIONS movement
+       */
+      if (! gtk_text_iter_equal (&sel_bound, &insert))
+        cancel_selection = TRUE;
+    }
+
   newplace = insert;
 
   if (step == GTK_MOVEMENT_DISPLAY_LINES)
-    gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL);
+    gtk_text_view_get_virtual_cursor_pos (text_view, &insert, &cursor_x_pos, NULL);
 
   switch (step)
     {
     case GTK_MOVEMENT_LOGICAL_POSITIONS:
-      gtk_text_iter_forward_visible_cursor_positions (&newplace, count);
+      if (! cancel_selection)
+        gtk_text_iter_forward_visible_cursor_positions (&newplace, count);
       break;
 
     case GTK_MOVEMENT_VISUAL_POSITIONS:
-      gtk_text_layout_move_iter_visually (text_view->layout,
-                                          &newplace, count);
+      if (! cancel_selection)
+        gtk_text_layout_move_iter_visually (text_view->layout,
+                                            &newplace, count);
       break;
 
     case GTK_MOVEMENT_WORDS:
@@ -5195,7 +5286,7 @@ gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
           g_signal_emit_by_name (text_view, "move-focus", leave_direction);
         }
     }
-  else
+  else if (! cancel_selection)
     {
       gtk_widget_error_bell (GTK_WIDGET (text_view));
     }
@@ -5348,7 +5439,7 @@ gtk_text_view_scroll_pages (GtkTextView *text_view,
     }
   else
     {
-      gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
+      gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
 
       oldval = adj->value;
       newval = adj->value;
@@ -5429,7 +5520,7 @@ gtk_text_view_scroll_hpages (GtkTextView *text_view,
     }
   else
     {
-      gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
+      gtk_text_view_get_virtual_cursor_pos (text_view, NULL, &cursor_x_pos, &cursor_y_pos);
 
       oldval = adj->value;
       newval = adj->value;
@@ -6334,7 +6425,7 @@ gtk_text_view_ensure_layout (GtkTextView *text_view)
       if (get_buffer (text_view))
         gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
 
-      if ((GTK_WIDGET_HAS_FOCUS (text_view) && text_view->cursor_visible))
+      if ((gtk_widget_has_focus (widget) && text_view->cursor_visible))
         gtk_text_view_pend_cursor_blink (text_view);
       else
         gtk_text_layout_set_cursor_visible (text_view->layout, FALSE);
@@ -6435,9 +6526,9 @@ gtk_text_view_destroy_layout (GtkTextView *text_view)
                                            invalidated_handler,
                                            text_view);
       g_signal_handlers_disconnect_by_func (text_view->layout,
-                                           changed_handler, 
+                                           changed_handler,
                                            text_view);
-      
+
       /* Remove layout from all anchored children */
       tmp_list = text_view->children;
       while (tmp_list != NULL)
@@ -6452,7 +6543,7 @@ gtk_text_view_destroy_layout (GtkTextView *text_view)
 
           tmp_list = g_slist_next (tmp_list);
         }
-      
+
       gtk_text_view_stop_cursor_blink (text_view);
       gtk_text_view_end_selection_drag (text_view);
 
@@ -7017,7 +7108,7 @@ typedef struct
 
 /* The window to which widget->window is relative */
 #define ALLOCATION_WINDOW(widget)              \
-   (GTK_WIDGET_NO_WINDOW (widget) ?            \
+   (!gtk_widget_get_has_window (widget) ?              \
     (widget)->window :                          \
      gdk_window_get_parent ((widget)->window))
 
@@ -7033,7 +7124,7 @@ adjust_allocation_recurse (GtkWidget *widget,
    */
   if (!GTK_WIDGET_REALIZED (widget))
     {
-      if (GTK_WIDGET_VISIBLE (widget))
+      if (gtk_widget_get_visible (widget))
        {
          GdkRectangle tmp_rectangle = widget->allocation;
          tmp_rectangle.x += scroll_data->dx;
@@ -7178,6 +7269,11 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
    */
   gtk_text_view_update_layout_width (text_view);
   
+  /* We also update the IM spot location here, since the IM context
+   * might do something that leads to validation.
+   */
+  gtk_text_view_update_im_spot_location (text_view);
+
   /* note that validation of onscreen could invoke this function
    * recursively, by scrolling to maintain first_para, or in response
    * to updating the layout width, however there is no problem with
@@ -7212,6 +7308,9 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
       text_view->first_validate_idle = 0;
     }
 
+  /* Finally we update the IM cursor location again, to ensure any
+   * changes made by the validation are pushed through.
+   */
   gtk_text_view_update_im_spot_location (text_view);
   
   DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
@@ -7252,7 +7351,7 @@ gtk_text_view_commit_text (GtkTextView   *text_view,
       if (!had_selection && text_view->overwrite_mode)
        {
          GtkTextIter insert;
-         
+
          gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
                                            &insert,
                                            gtk_text_buffer_get_insert (get_buffer (text_view)));
@@ -7284,26 +7383,32 @@ gtk_text_view_preedit_changed_handler (GtkIMContext *context,
   gint cursor_pos;
   GtkTextIter iter;
 
-  gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, 
+  gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter,
                                    gtk_text_buffer_get_insert (text_view->buffer));
 
-  /* Keypress events are passed to input method even if cursor position is not editable;
-   * so beep here if it's multi-key input sequence, input method will be reset in 
-   * key-press-event handler. */
-  if (!gtk_text_iter_can_insert (&iter, text_view->editable))
+  /* Keypress events are passed to input method even if cursor position is
+   * not editable; so beep here if it's multi-key input sequence, input
+   * method will be reset in key-press-event handler.
+   */
+  gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
+
+  if (str && str[0] && !gtk_text_iter_can_insert (&iter, text_view->editable))
     {
       gtk_widget_error_bell (GTK_WIDGET (text_view));
-      return;
+      goto out;
     }
 
-  gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
-  gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
-  pango_attr_list_unref (attrs);
-  g_free (str);
+  g_signal_emit (text_view, signals[PREEDIT_CHANGED], 0, str);
 
-  if (GTK_WIDGET_HAS_FOCUS (text_view))
+  if (text_view->layout)
+    gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
+  if (gtk_widget_has_focus (GTK_WIDGET (text_view)))
     gtk_text_view_scroll_mark_onscreen (text_view,
                                        gtk_text_buffer_get_insert (get_buffer (text_view)));
+
+out:
+  pango_attr_list_unref (attrs);
+  g_free (str);
 }
 
 static gboolean
@@ -7315,7 +7420,7 @@ gtk_text_view_retrieve_surrounding_handler (GtkIMContext  *context,
   gint pos;
   gchar *text;
 
-  gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
+  gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,
                                    gtk_text_buffer_get_insert (text_view->buffer));
   end = start;
 
@@ -7339,7 +7444,7 @@ gtk_text_view_delete_surrounding_handler (GtkIMContext  *context,
   GtkTextIter start;
   GtkTextIter end;
 
-  gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,  
+  gtk_text_buffer_get_iter_at_mark (text_view->buffer, &start,
                                    gtk_text_buffer_get_insert (text_view->buffer));
   end = start;
 
@@ -7434,14 +7539,22 @@ gtk_text_view_get_cursor_location  (GtkTextView   *text_view,
 
 static void
 gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
+                                      GtkTextIter *cursor,
                                       gint        *x,
                                       gint        *y)
 {
+  GtkTextIter insert;
   GdkRectangle pos;
 
+  if (cursor)
+    insert = *cursor;
+  else
+    gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
+                                      gtk_text_buffer_get_insert (get_buffer (text_view)));
+
   if ((x && text_view->virtual_cursor_x == -1) ||
       (y && text_view->virtual_cursor_y == -1))
-    gtk_text_view_get_cursor_location (text_view, &pos);
+    gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &pos, NULL);
 
   if (x)
     {
@@ -7917,7 +8030,7 @@ text_window_realize (GtkTextWindow *win,
 
   if (win->type == GTK_TEXT_WINDOW_TEXT)
     {
-      if (GTK_WIDGET_IS_SENSITIVE (widget))
+      if (gtk_widget_is_sensitive (widget))
         {
           /* I-beam cursor */
           cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (widget->window),
@@ -8149,7 +8262,7 @@ text_window_get_height (GtkTextWindow *win)
  * height is 0, and are nonexistent before the widget has been
  * realized.
  *
- * Return value: a #GdkWindow, or %NULL
+ * Return value: (transfer none): a #GdkWindow, or %NULL
  **/
 GdkWindow*
 gtk_text_view_get_window (GtkTextView *text_view,
@@ -8912,7 +9025,8 @@ gtk_text_view_move_child (GtkTextView *text_view,
   vc->x = xpos;
   vc->y = ypos;
 
-  if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (text_view))
+  if (gtk_widget_get_visible (child) &&
+      gtk_widget_get_visible (GTK_WIDGET (text_view)))
     gtk_widget_queue_resize (child);
 }