* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include <config.h>
#include <string.h>
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
#include "gtktextview.h"
#include "gtkimmulticontext.h"
#include "gdk/gdkkeysyms.h"
+#include "gtkprivate.h"
#include "gtksizegroup.h" /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=72258 */
#include "gtktextutil.h"
#include "gtkwindow.h"
#define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
#define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
+#define SPACE_FOR_CURSOR 1
+
struct _GtkTextPendingScroll
{
GtkTextMark *mark;
PASTE_CLIPBOARD,
TOGGLE_OVERWRITE,
MOVE_FOCUS,
+ MOVE_VIEWPORT,
+ SELECT_ALL,
LAST_SIGNAL
};
PROP_TABS,
PROP_CURSOR_VISIBLE,
PROP_BUFFER,
+ PROP_OVERWRITE,
+ PROP_ACCEPTS_TAB,
LAST_PROP
};
GtkStyle *previous_style);
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 gint gtk_text_view_expose_event (GtkWidget *widget,
GdkEventExpose *expose);
static void gtk_text_view_draw_focus (GtkWidget *widget);
-static void gtk_text_view_grab_focus (GtkWidget *widget);
static gboolean gtk_text_view_focus (GtkWidget *widget,
GtkDirectionType direction);
+static void gtk_text_view_select_all (GtkWidget *widget,
+ gboolean select);
/* Source side drag signals */
static void gtk_text_view_page_horizontally (GtkTextView *text_view,
gint count,
gboolean extend_selection);
+static void gtk_text_view_move_viewport (GtkTextView *text_view,
+ GtkScrollStep step,
+ gint count);
static void gtk_text_view_set_anchor (GtkTextView *text_view);
static void gtk_text_view_scroll_pages (GtkTextView *text_view,
gint count,
const GtkTextIter *location,
GtkTextMark *mark,
gpointer data);
+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,
gint *x,
gint *y);
GtkWidget *child);
static void gtk_text_view_forall (GtkContainer *container,
gboolean include_internals,
- GtkCallback callback,
+ GtkCallback callback,
gpointer callback_data);
/* FIXME probably need the focus methods. */
widget_class->unrealize = gtk_text_view_unrealize;
widget_class->style_set = gtk_text_view_style_set;
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->size_allocate = gtk_text_view_size_allocate;
widget_class->focus_out_event = gtk_text_view_focus_out_event;
widget_class->motion_notify_event = gtk_text_view_motion_event;
widget_class->expose_event = gtk_text_view_expose_event;
- widget_class->grab_focus = gtk_text_view_grab_focus;
widget_class->focus = gtk_text_view_focus;
widget_class->drag_begin = gtk_text_view_drag_begin;
g_object_class_install_property (gobject_class,
PROP_PIXELS_ABOVE_LINES,
g_param_spec_int ("pixels_above_lines",
- _("Pixels Above Lines"),
- _("Pixels of blank space above paragraphs"),
+ P_("Pixels Above Lines"),
+ P_("Pixels of blank space above paragraphs"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_PIXELS_BELOW_LINES,
g_param_spec_int ("pixels_below_lines",
- _("Pixels Below Lines"),
- _("Pixels of blank space below paragraphs"),
+ P_("Pixels Below Lines"),
+ P_("Pixels of blank space below paragraphs"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_PIXELS_INSIDE_WRAP,
g_param_spec_int ("pixels_inside_wrap",
- _("Pixels Inside Wrap"),
- _("Pixels of blank space between wrapped lines in a paragraph"),
+ P_("Pixels Inside Wrap"),
+ P_("Pixels of blank space between wrapped lines in a paragraph"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_EDITABLE,
g_param_spec_boolean ("editable",
- _("Editable"),
- _("Whether the text can be modified by the user"),
+ P_("Editable"),
+ P_("Whether the text can be modified by the user"),
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_WRAP_MODE,
g_param_spec_enum ("wrap_mode",
- _("Wrap Mode"),
- _("Whether to wrap lines never, at word boundaries, or at character boundaries"),
+ P_("Wrap Mode"),
+ P_("Whether to wrap lines never, at word boundaries, or at character boundaries"),
GTK_TYPE_WRAP_MODE,
GTK_WRAP_NONE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_JUSTIFICATION,
g_param_spec_enum ("justification",
- _("Justification"),
- _("Left, right, or center justification"),
+ P_("Justification"),
+ P_("Left, right, or center justification"),
GTK_TYPE_JUSTIFICATION,
GTK_JUSTIFY_LEFT,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_LEFT_MARGIN,
g_param_spec_int ("left_margin",
- _("Left Margin"),
- _("Width of the left margin in pixels"),
+ P_("Left Margin"),
+ P_("Width of the left margin in pixels"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_RIGHT_MARGIN,
g_param_spec_int ("right_margin",
- _("Right Margin"),
- _("Width of the right margin in pixels"),
+ P_("Right Margin"),
+ P_("Width of the right margin in pixels"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_INDENT,
g_param_spec_int ("indent",
- _("Indent"),
- _("Amount to indent the paragraph, in pixels"),
+ P_("Indent"),
+ P_("Amount to indent the paragraph, in pixels"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_TABS,
g_param_spec_boxed ("tabs",
- _("Tabs"),
- _("Custom tabs for this text"),
+ P_("Tabs"),
+ P_("Custom tabs for this text"),
PANGO_TYPE_TAB_ARRAY,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_CURSOR_VISIBLE,
g_param_spec_boolean ("cursor_visible",
- _("Cursor Visible"),
- _("If the insertion cursor is shown"),
+ P_("Cursor Visible"),
+ P_("If the insertion cursor is shown"),
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_BUFFER,
g_param_spec_object ("buffer",
- _("Buffer"),
- _("The buffer which is displayed"),
+ P_("Buffer"),
+ P_("The buffer which is displayed"),
GTK_TYPE_TEXT_BUFFER,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_OVERWRITE,
+ g_param_spec_boolean ("overwrite",
+ P_("Overwrite mode"),
+ P_("Whether entered text overwrites existing contents"),
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ACCEPTS_TAB,
+ g_param_spec_boolean ("accepts_tab",
+ P_("Accepts tab"),
+ P_("Whether Tab will result in a tab character being entered"),
+ TRUE,
+ G_PARAM_READWRITE));
+
+ /*
+ * Style properties
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boxed ("error-underline-color",
+ P_("Error underline color"),
+ P_("Color with which to draw error-indication underlines"),
+ GDK_TYPE_COLOR,
+ G_PARAM_READABLE));
/*
* Signals
G_TYPE_INT,
G_TYPE_BOOLEAN);
+ signals[MOVE_VIEWPORT] =
+ _gtk_binding_signal_new ("move_viewport",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_CALLBACK (gtk_text_view_move_viewport),
+ NULL, NULL,
+ _gtk_marshal_VOID__ENUM_INT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_SCROLL_STEP,
+ G_TYPE_INT);
+
signals[SET_ANCHOR] =
g_signal_new ("set_anchor",
G_OBJECT_CLASS_TYPE (gobject_class),
G_TYPE_NONE, 1,
GTK_TYPE_MENU);
+ signals[SELECT_ALL] =
+ _gtk_binding_signal_new ("select_all",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_CALLBACK (gtk_text_view_select_all),
+ NULL, NULL,
+ _gtk_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1,
+ G_TYPE_BOOLEAN, TRUE);
+
+
/*
* Key bindings
*/
add_move_binding (binding_set, GDK_KP_Page_Down, GDK_CONTROL_MASK,
GTK_MOVEMENT_HORIZONTAL_PAGES, 1);
- /* Select all
- */
- gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
- "move_cursor", 3,
- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, -1,
- G_TYPE_BOOLEAN, FALSE);
+ /* Select all */
gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
- "move_cursor", 3,
- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, 1,
- G_TYPE_BOOLEAN, TRUE);
+ "select_all", 1,
+ G_TYPE_BOOLEAN, TRUE);
gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
- "move_cursor", 3,
- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, -1,
- G_TYPE_BOOLEAN, FALSE);
- gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
- "move_cursor", 3,
- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, 1,
- G_TYPE_BOOLEAN, TRUE);
-
- /* Unselect all
- */
+ "select_all", 1,
+ G_TYPE_BOOLEAN, TRUE);
+
+ /* Unselect all */
gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
- "move_cursor", 3,
- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, 0,
- G_TYPE_BOOLEAN, FALSE);
+ "select_all", 1,
+ G_TYPE_BOOLEAN, FALSE);
/* Deleting text */
gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
text_view->cursor_visible = TRUE;
+ text_view->accepts_tab = TRUE;
+
text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
widget, 200, 200);
gtk_text_layout_get_size (text_view->layout, &width, &height);
/* Make room for the cursor after the last character in the widest line */
- width++;
+ width += SPACE_FOR_CURSOR;
if (text_view->width != width || text_view->height != height)
{
gtk_text_view_ensure_layout (text_view);
gtk_text_layout_set_screen_width (text_view->layout,
- SCREEN_WIDTH (text_view));
+ MAX (1, SCREEN_WIDTH (text_view) - SPACE_FOR_CURSOR));
}
static void
gtk_text_view_update_im_spot_location (GtkTextView *text_view)
{
GdkRectangle area;
- gint cursor_x_pos, cursor_y_pos;
if (text_view->layout == NULL)
return;
- gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
+ gtk_text_view_get_cursor_location (text_view, &area);
- area.x = cursor_x_pos;
- area.y = cursor_y_pos;
- area.width = area.height = 0;
+ area.x -= text_view->xoffset;
+ area.y -= text_view->yoffset;
+
+ /* Width returned by Pango indicates direction of cursor,
+ * by it's sign more than the size of cursor.
+ */
+ area.width = 0;
gtk_im_context_set_cursor_location (text_view->im_context, &area);
}
gtk_text_view_set_cursor_visible (text_view, g_value_get_boolean (value));
break;
+ case PROP_OVERWRITE:
+ gtk_text_view_set_overwrite (text_view, g_value_get_boolean (value));
+ break;
+
case PROP_BUFFER:
gtk_text_view_set_buffer (text_view, GTK_TEXT_BUFFER (g_value_get_object (value)));
break;
+ case PROP_ACCEPTS_TAB:
+ gtk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
+ break;
+
default:
g_assert_not_reached ();
break;
g_value_set_object (value, get_buffer (text_view));
break;
+ case PROP_OVERWRITE:
+ g_value_set_boolean (value, text_view->overwrite_mode);
+ break;
+
+ case PROP_ACCEPTS_TAB:
+ g_value_set_boolean (value, text_view->accepts_tab);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
&child_loc,
child->anchor);
+ /* Since anchored children are only ever allocated from
+ * gtk_text_layout_get_line_display() we have to make sure
+ * that the display line caching in the layout doesn't
+ * get in the way. Invalidating the layout around the anchor
+ * achieves this.
+ */
+ if (GTK_WIDGET_ALLOC_NEEDED (child->widget))
+ {
+ GtkTextIter end = child_loc;
+ gtk_text_iter_forward_char (&end);
+ gtk_text_layout_invalidate (text_view->layout, &child_loc, &end);
+ }
+
gtk_text_layout_validate_yrange (text_view->layout,
&child_loc,
0, 1);
if (old_req.width != new_req.width ||
old_req.height != new_req.height)
{
- /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=72258 */
- _gtk_size_group_queue_resize (widget);
+ gtk_widget_queue_resize_no_redraw (widget);
}
}
}
text_view->mouse_cursor_obscured = TRUE;
}
+static void
+gtk_text_view_unobscure_mouse_cursor (GtkTextView *text_view)
+{
+ if (text_view->mouse_cursor_obscured)
+ {
+ GdkCursor *cursor;
+
+ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)),
+ GDK_XTERM);
+ gdk_window_set_cursor (text_view->text_window->bin_window, cursor);
+ gdk_cursor_unref (cursor);
+ text_view->mouse_cursor_obscured = FALSE;
+ }
+}
+
+static void
+gtk_text_view_grab_notify (GtkWidget *widget,
+ gboolean was_grabbed)
+{
+ if (!was_grabbed)
+ gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
+}
+
+
/*
* Events
*/
event->keyval == GDK_KP_Tab) &&
!(event->state & GDK_CONTROL_MASK))
{
- /* If the text widget isn't editable overall, move the focus
- * instead
+ /* If the text widget isn't editable overall, or if the application
+ * has turned off "accepts_tab", move the focus instead
*/
- if (text_view->editable)
+ if (text_view->accepts_tab && text_view->editable)
{
gtk_text_view_commit_text (text_view, "\t");
obscure = TRUE;
text_view = GTK_TEXT_VIEW (widget);
- text_view->disable_scroll_on_focus = TRUE;
gtk_widget_grab_focus (widget);
- text_view->disable_scroll_on_focus = FALSE;
if (event->window != text_view->text_window->bin_window)
{
{
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
- if (text_view->mouse_cursor_obscured)
- {
- GdkCursor *cursor;
-
- cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
- GDK_XTERM);
- gdk_window_set_cursor (text_view->text_window->bin_window, cursor);
- gdk_cursor_unref (cursor);
- text_view->mouse_cursor_obscured = FALSE;
- }
+ gtk_text_view_unobscure_mouse_cursor (text_view);
if (event->window == text_view->text_window->bin_window &&
text_view->drag_start_x >= 0)
while (tmp_list != NULL)
{
GtkWidget *child = tmp_list->data;
-
+
gtk_container_propagate_expose (GTK_CONTAINER (text_view),
child,
event);
}
}
-static void
-gtk_text_view_grab_focus (GtkWidget *widget)
-{
- GtkTextView *text_view;
-
- text_view = GTK_TEXT_VIEW (widget);
-
- GTK_WIDGET_CLASS (parent_class)->grab_focus (widget);
-
- if (!text_view->disable_scroll_on_focus)
- gtk_text_view_scroll_mark_onscreen (text_view,
- gtk_text_buffer_get_mark (get_buffer (text_view),
- "insert"));
-}
-
static gboolean
gtk_text_view_focus (GtkWidget *widget,
GtkDirectionType direction)
gint cursor_x_pos = 0;
+ if (!text_view->cursor_visible)
+ {
+ GtkScrollStep scroll_step;
+
+ switch (step)
+ {
+ case GTK_MOVEMENT_LOGICAL_POSITIONS:
+ case GTK_MOVEMENT_VISUAL_POSITIONS:
+ case GTK_MOVEMENT_WORDS:
+ scroll_step = GTK_SCROLL_HORIZONTAL_STEPS;
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
+ scroll_step = GTK_SCROLL_HORIZONTAL_ENDS;
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINES:
+ case GTK_MOVEMENT_PARAGRAPHS:
+ case GTK_MOVEMENT_PARAGRAPH_ENDS:
+ scroll_step = GTK_SCROLL_STEPS;
+ break;
+ case GTK_MOVEMENT_PAGES:
+ scroll_step = GTK_SCROLL_PAGES;
+ break;
+ case GTK_MOVEMENT_HORIZONTAL_PAGES:
+ scroll_step = GTK_SCROLL_HORIZONTAL_PAGES;
+ break;
+ case GTK_MOVEMENT_BUFFER_ENDS:
+ scroll_step = GTK_SCROLL_ENDS;
+ break;
+ default:
+ scroll_step = GTK_SCROLL_PAGES;
+ break;
+ }
+
+ gtk_text_view_move_viewport (text_view, scroll_step, count);
+
+ return;
+ }
+
gtk_text_view_reset_im_context (text_view);
if (step == GTK_MOVEMENT_PAGES)
case GTK_MOVEMENT_WORDS:
if (count < 0)
gtk_text_iter_backward_visible_word_starts (&newplace, -count);
- else if (count > 0)
- gtk_text_iter_forward_visible_word_ends (&newplace, count);
+ else if (count > 0)
+ {
+ if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
+ gtk_text_iter_forward_to_end (&newplace);
+ }
break;
case GTK_MOVEMENT_DISPLAY_LINES:
count, extend_selection);
}
+
+static void
+gtk_text_view_move_viewport (GtkTextView *text_view,
+ GtkScrollStep step,
+ gint count)
+{
+ GtkAdjustment *adjustment;
+ gdouble increment;
+
+ switch (step)
+ {
+ case GTK_SCROLL_STEPS:
+ case GTK_SCROLL_PAGES:
+ case GTK_SCROLL_ENDS:
+ adjustment = get_vadjustment (text_view);
+ break;
+ case GTK_SCROLL_HORIZONTAL_STEPS:
+ case GTK_SCROLL_HORIZONTAL_PAGES:
+ case GTK_SCROLL_HORIZONTAL_ENDS:
+ adjustment = get_hadjustment (text_view);
+ break;
+ default:
+ adjustment = get_vadjustment (text_view);
+ break;
+ }
+
+ switch (step)
+ {
+ case GTK_SCROLL_STEPS:
+ case GTK_SCROLL_HORIZONTAL_STEPS:
+ increment = adjustment->step_increment;
+ break;
+ case GTK_SCROLL_PAGES:
+ case GTK_SCROLL_HORIZONTAL_PAGES:
+ increment = adjustment->page_increment;
+ break;
+ case GTK_SCROLL_ENDS:
+ case GTK_SCROLL_HORIZONTAL_ENDS:
+ increment = adjustment->upper - adjustment->lower;
+ break;
+ default:
+ increment = 0.0;
+ break;
+ }
+
+ set_adjustment_clamped (adjustment, adjustment->value + count * increment);
+}
+
static void
gtk_text_view_set_anchor (GtkTextView *text_view)
{
adj = text_view->vadjustment;
- /* Validate the region that will be brought into view by the cursor motion
+ /* Make sure we start from the current cursor position, even
+ * if it was offscreen.
+ */
+ gtk_text_view_scroll_mark_onscreen (text_view,
+ gtk_text_buffer_get_mark (get_buffer (text_view),
+ "insert"));
+
+/* Validate the region that will be brought into view by the cursor motion
*/
if (count < 0)
{
adj = text_view->hadjustment;
+ /* Make sure we start from the current cursor position, even
+ * if it was offscreen.
+ */
+ gtk_text_view_scroll_mark_onscreen (text_view,
+ gtk_text_buffer_get_mark (get_buffer (text_view),
+ "insert"));
+
/* Validate the line that we're moving within.
*/
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
gtk_text_view_toggle_overwrite (GtkTextView *text_view)
{
text_view->overwrite_mode = !text_view->overwrite_mode;
+ g_object_notify (G_OBJECT (text_view), "overwrite");
+}
+
+/**
+ * gtk_text_view_get_overwrite:
+ * @text_view: a #GtkTextView
+ *
+ * Returns whether the #GtkTextView is in overwrite mode or not.
+ *
+ * Return value: whether @text_view is in overwrite mode or not.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_view_get_overwrite (GtkTextView *text_view)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+
+ return text_view->overwrite_mode;
+}
+
+/**
+ * gtk_text_view_set_overwrite:
+ * @text_view: a #GtkTextView
+ * @overwrite: %TRUE to turn on overwrite mode, %FALSE to turn it off
+ *
+ * Changes the #GtkTextView overwrite mode.
+ *
+ * Since: 2.4
+ **/
+void
+gtk_text_view_set_overwrite (GtkTextView *text_view,
+ gboolean overwrite)
+{
+ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+ overwrite = overwrite != FALSE;
+
+ if (text_view->overwrite_mode != overwrite)
+ {
+ text_view->overwrite_mode = overwrite;
+
+ g_object_notify (G_OBJECT (text_view), "overwrite");
+ }
+}
+
+/**
+ * gtk_text_view_set_accepts_tab:
+ * @text_view: A #GtkTextView
+ * @accepts_tab: %TRUE if pressing the Tab key should insert a tab character, %FALSE, if pressing the Tab key should move the keyboard focus.
+ *
+ * Sets the behavior of the text widget when the Tab key is pressed. If @accepts_tab
+ * is %TRUE a tab character is inserted. If @accepts_tab is %FALSE the keyboard focus
+ * is moved to the next widget in the focus chain.
+ *
+ * Since: 2.4
+ **/
+void
+gtk_text_view_set_accepts_tab (GtkTextView *text_view,
+ gboolean accepts_tab)
+{
+ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+
+ accepts_tab = accepts_tab != FALSE;
+
+ if (text_view->accepts_tab != accepts_tab)
+ {
+ text_view->accepts_tab = accepts_tab;
+
+ g_object_notify (G_OBJECT (text_view), "accepts_tab");
+ }
+}
+
+/**
+ * gtk_text_view_get_accepts_tab:
+ * @text_view: A #GtkTextView
+ *
+ * Returns whether pressing the Tab key inserts a tab characters.
+ * gtk_text_view_set_accepts_tab().
+ *
+ * Return value: %TRUE if pressing the Tab key inserts a tab character, %FALSE if pressing the Tab key moves the keyboard focus.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_view_get_accepts_tab (GtkTextView *text_view)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+
+ return text_view->accepts_tab;
}
static void
gtk_text_iter_backward_visible_word_start (start);
if (!gtk_text_iter_ends_word (end))
- gtk_text_iter_forward_visible_word_end (end);
+ {
+ if (!gtk_text_iter_forward_visible_word_end (end))
+ gtk_text_iter_forward_to_end (end);
+ }
}
else
extend = FALSE;
{
if (text_view->layout)
{
- gboolean split_cursor;
- GtkTextDirection new_dir;
GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
-
+ GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
+ GtkTextDirection new_cursor_dir;
+ GtkTextDirection new_keyboard_dir;
+ gboolean split_cursor;
+
g_object_get (settings,
"gtk-split-cursor", &split_cursor,
NULL);
+
+ if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR)
+ new_keyboard_dir = GTK_TEXT_DIR_LTR;
+ else
+ new_keyboard_dir = GTK_TEXT_DIR_RTL;
+
if (split_cursor)
- {
- new_dir = GTK_TEXT_DIR_NONE;
- }
+ new_cursor_dir = GTK_TEXT_DIR_NONE;
else
- {
- GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
- new_dir = (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
- GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
- }
+ new_cursor_dir = new_keyboard_dir;
- if (text_view->layout->cursor_direction != new_dir)
- gtk_text_layout_set_cursor_direction (text_view->layout, new_dir);
+ gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
+ gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
}
}
GtkTextIter drop_point;
GtkTextView *text_view;
gboolean success = FALSE;
+ GtkTextBuffer *buffer = NULL;
text_view = GTK_TEXT_VIEW (widget);
if (!text_view->dnd_mark)
goto done;
- gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
+ buffer = get_buffer (text_view);
+
+ gtk_text_buffer_get_iter_at_mark (buffer,
&drop_point,
text_view->dnd_mark);
if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
goto done;
+ success = TRUE;
+
+ gtk_text_buffer_begin_user_action (buffer);
+
if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
{
GtkTextBuffer *src_buffer = NULL;
g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
if (gtk_text_buffer_get_tag_table (src_buffer) !=
- gtk_text_buffer_get_tag_table (get_buffer (text_view)))
+ gtk_text_buffer_get_tag_table (buffer))
copy_tags = FALSE;
if (gtk_text_buffer_get_selection_bounds (src_buffer,
&end))
{
if (copy_tags)
- gtk_text_buffer_insert_range_interactive (get_buffer (text_view),
+ gtk_text_buffer_insert_range_interactive (buffer,
&drop_point,
&start,
&end,
gchar *str;
str = gtk_text_iter_get_visible_text (&start, &end);
- gtk_text_buffer_insert_interactive (get_buffer (text_view),
+ gtk_text_buffer_insert_interactive (buffer,
&drop_point, str, -1,
text_view->editable);
g_free (str);
}
else
insert_text_data (text_view, &drop_point, selection_data);
-
- gtk_text_buffer_place_cursor (get_buffer (text_view), &drop_point);
-
- success = TRUE;
-
+
done:
gtk_drag_finish (context, success,
success && context->action == GDK_ACTION_MOVE,
time);
+
+ if (success)
+ {
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &drop_point,
+ text_view->dnd_mark);
+ gtk_text_buffer_place_cursor (buffer, &drop_point);
+
+ gtk_text_buffer_end_user_action (buffer);
+ }
}
static GtkAdjustment*
}
static void
-gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
- gint *x,
- gint *y)
+gtk_text_view_get_cursor_location (GtkTextView *text_view,
+ GdkRectangle *pos)
{
- GdkRectangle strong_pos;
GtkTextIter insert;
-
+
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
gtk_text_buffer_get_mark (get_buffer (text_view),
"insert"));
+ gtk_text_layout_get_cursor_locations (text_view->layout, &insert, pos, NULL);
+}
+
+static void
+gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
+ gint *x,
+ gint *y)
+{
+ GdkRectangle pos;
+
if ((x && text_view->virtual_cursor_x == -1) ||
(y && text_view->virtual_cursor_y == -1))
- gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
+ gtk_text_view_get_cursor_location (text_view, &pos);
if (x)
{
if (text_view->virtual_cursor_x != -1)
*x = text_view->virtual_cursor_x;
else
- *x = strong_pos.x;
+ *x = pos.x;
}
if (y)
if (text_view->virtual_cursor_x != -1)
*y = text_view->virtual_cursor_y;
else
- *y = strong_pos.y + strong_pos.height / 2;
+ *y = pos.y + pos.height / 2;
}
}
gint x,
gint y)
{
- GdkRectangle strong_pos;
- GtkTextIter insert;
-
- gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &insert,
- gtk_text_buffer_get_mark (get_buffer (text_view),
- "insert"));
+ GdkRectangle pos;
if (x == -1 || y == -1)
- gtk_text_layout_get_cursor_locations (text_view->layout, &insert, &strong_pos, NULL);
+ gtk_text_view_get_cursor_location (text_view, &pos);
- text_view->virtual_cursor_x = (x == -1) ? strong_pos.x : x;
- text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
+ text_view->virtual_cursor_x = (x == -1) ? pos.x : x;
+ text_view->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
}
/* Quick hack of a popup menu
}
static void
-select_all_cb (GtkWidget *menuitem,
- GtkTextView *text_view)
+gtk_text_view_select_all (GtkWidget *widget,
+ gboolean select)
{
+ GtkTextView *text_view = GTK_TEXT_VIEW (widget);
GtkTextBuffer *buffer;
- GtkTextIter start_iter, end_iter;
+ GtkTextIter start_iter, end_iter, insert;
buffer = text_view->buffer;
- gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
- gtk_text_buffer_move_mark_by_name (buffer, "insert", &start_iter);
- gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &end_iter);
- gtk_text_buffer_copy_clipboard (buffer, gtk_clipboard_get (GDK_NONE));
+ if (select)
+ {
+ gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
+ gtk_text_buffer_move_mark_by_name (buffer, "insert", &start_iter);
+ gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &end_iter);
+ }
+ else
+ {
+ gtk_text_buffer_get_iter_at_mark (buffer, &insert,
+ gtk_text_buffer_get_insert (buffer));
+ gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &insert);
+ }
+}
+
+static void
+select_all_cb (GtkWidget *menuitem,
+ GtkTextView *text_view)
+{
+ gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
}
static void
menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
gtk_widget_show (menuitem);
+ gtk_widget_set_sensitive (menuitem, can_insert);
+
submenu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);