MOVE_VIEWPORT,
SELECT_ALL,
TOGGLE_CURSOR_VISIBLE,
+ PREEDIT_CHANGED,
LAST_SIGNAL
};
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,
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,
_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
*/
/**
* 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
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,
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"));
* 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)
}
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;
}
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,
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);
}
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)
{
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)
{
case PROP_IM_MODULE:
g_free (priv->im_module);
- priv->im_module = g_strdup (g_value_get_string (value));
+ 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;
{
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;
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);
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;
GtkTextView *text_view;
GList *child_exposes;
GList *tmp_list;
- GdkRegion *updates;
text_view = GTK_TEXT_VIEW (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.");
"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",
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"
{
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))
{
{
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);
{
GtkTextIter insert;
GtkTextIter newplace;
+ gboolean cancel_selection = FALSE;
gint cursor_x_pos = 0;
GtkDirectionType leave_direction = -1;
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:
g_signal_emit_by_name (text_view, "move-focus", leave_direction);
}
}
- else
+ else if (! cancel_selection)
{
gtk_widget_error_bell (GTK_WIDGET (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;
}
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;
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);
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)
tmp_list = g_slist_next (tmp_list);
}
-
+
gtk_text_view_stop_cursor_blink (text_view);
gtk_text_view_end_selection_drag (text_view);
/* 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))
*/
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;
*/
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
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"));
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)));
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
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;
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;
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)
{
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),
* 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,
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);
}