#include <config.h>
#include <string.h>
-#include "gtkalias.h"
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
#include "gtkbindings.h"
#include "gtkdnd.h"
#include "gtksizegroup.h" /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=72258 */
#include "gtktextutil.h"
#include "gtkwindow.h"
+#include "gtkalias.h"
/* How scrolling, validation, exposes, etc. work.
*
gint dy);
static void text_window_invalidate_rect (GtkTextWindow *win,
GdkRectangle *rect);
+static void text_window_invalidate_cursors (GtkTextWindow *win);
static gint text_window_get_width (GtkTextWindow *win);
static gint text_window_get_height (GtkTextWindow *win);
-static GtkTargetEntry target_table[] = {
+static const GtkTargetEntry target_table[] = {
{ "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP, 0 },
};
(GInstanceInitFunc) gtk_text_view_init,
};
- our_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTextView",
+ our_type = g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkTextView"),
&our_info, 0);
}
g_object_class_install_property (gobject_class,
PROP_PIXELS_ABOVE_LINES,
- g_param_spec_int ("pixels_above_lines",
+ g_param_spec_int ("pixels-above-lines",
P_("Pixels Above Lines"),
P_("Pixels of blank space above paragraphs"),
0,
G_MAXINT,
0,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PIXELS_BELOW_LINES,
- g_param_spec_int ("pixels_below_lines",
+ g_param_spec_int ("pixels-below-lines",
P_("Pixels Below Lines"),
P_("Pixels of blank space below paragraphs"),
0,
G_MAXINT,
0,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PIXELS_INSIDE_WRAP,
- g_param_spec_int ("pixels_inside_wrap",
+ g_param_spec_int ("pixels-inside-wrap",
P_("Pixels Inside Wrap"),
P_("Pixels of blank space between wrapped lines in a paragraph"),
0,
G_MAXINT,
0,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_EDITABLE,
P_("Editable"),
P_("Whether the text can be modified by the user"),
TRUE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_WRAP_MODE,
- g_param_spec_enum ("wrap_mode",
+ g_param_spec_enum ("wrap-mode",
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));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_JUSTIFICATION,
P_("Left, right, or center justification"),
GTK_TYPE_JUSTIFICATION,
GTK_JUSTIFY_LEFT,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_LEFT_MARGIN,
- g_param_spec_int ("left_margin",
+ g_param_spec_int ("left-margin",
P_("Left Margin"),
P_("Width of the left margin in pixels"),
0,
G_MAXINT,
0,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_RIGHT_MARGIN,
- g_param_spec_int ("right_margin",
+ g_param_spec_int ("right-margin",
P_("Right Margin"),
P_("Width of the right margin in pixels"),
0,
G_MAXINT,
0,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_INDENT,
0,
G_MAXINT,
0,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_TABS,
P_("Tabs"),
P_("Custom tabs for this text"),
PANGO_TYPE_TAB_ARRAY,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_CURSOR_VISIBLE,
- g_param_spec_boolean ("cursor_visible",
+ g_param_spec_boolean ("cursor-visible",
P_("Cursor Visible"),
P_("If the insertion cursor is shown"),
TRUE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_BUFFER,
P_("Buffer"),
P_("The buffer which is displayed"),
GTK_TYPE_TEXT_BUFFER,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_OVERWRITE,
P_("Overwrite mode"),
P_("Whether entered text overwrites existing contents"),
FALSE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ACCEPTS_TAB,
- g_param_spec_boolean ("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));
+ GTK_PARAM_READWRITE));
/*
* Style properties
P_("Error underline color"),
P_("Color with which to draw error-indication underlines"),
GDK_TYPE_COLOR,
- G_PARAM_READABLE));
+ GTK_PARAM_READABLE));
/*
* Signals
*
*/
signals[MOVE_CURSOR] =
- g_signal_new ("move_cursor",
+ g_signal_new (I_("move_cursor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, move_cursor),
G_TYPE_BOOLEAN);
signals[PAGE_HORIZONTALLY] =
- g_signal_new ("page_horizontally",
+ g_signal_new (I_("page_horizontally"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, page_horizontally),
G_TYPE_BOOLEAN);
signals[MOVE_VIEWPORT] =
- _gtk_binding_signal_new ("move_viewport",
+ _gtk_binding_signal_new (I_("move_viewport"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_CALLBACK (gtk_text_view_move_viewport),
G_TYPE_INT);
signals[SET_ANCHOR] =
- g_signal_new ("set_anchor",
+ g_signal_new (I_("set_anchor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, set_anchor),
G_TYPE_NONE, 0);
signals[INSERT_AT_CURSOR] =
- g_signal_new ("insert_at_cursor",
+ g_signal_new (I_("insert_at_cursor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, insert_at_cursor),
G_TYPE_STRING);
signals[DELETE_FROM_CURSOR] =
- g_signal_new ("delete_from_cursor",
+ g_signal_new (I_("delete_from_cursor"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, delete_from_cursor),
G_TYPE_INT);
signals[BACKSPACE] =
- g_signal_new ("backspace",
+ g_signal_new (I_("backspace"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, backspace),
G_TYPE_NONE, 0);
signals[CUT_CLIPBOARD] =
- g_signal_new ("cut_clipboard",
+ g_signal_new (I_("cut_clipboard"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, cut_clipboard),
G_TYPE_NONE, 0);
signals[COPY_CLIPBOARD] =
- g_signal_new ("copy_clipboard",
+ g_signal_new (I_("copy_clipboard"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, copy_clipboard),
G_TYPE_NONE, 0);
signals[PASTE_CLIPBOARD] =
- g_signal_new ("paste_clipboard",
+ g_signal_new (I_("paste_clipboard"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, paste_clipboard),
G_TYPE_NONE, 0);
signals[TOGGLE_OVERWRITE] =
- g_signal_new ("toggle_overwrite",
+ g_signal_new (I_("toggle_overwrite"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, toggle_overwrite),
G_TYPE_NONE, 0);
signals[MOVE_FOCUS] =
- g_signal_new ("move_focus",
+ g_signal_new (I_("move_focus"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTextViewClass, move_focus),
GTK_TYPE_DIRECTION_TYPE);
signals[SET_SCROLL_ADJUSTMENTS] =
- g_signal_new ("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),
widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
signals[POPULATE_POPUP] =
- g_signal_new ("populate_popup",
+ g_signal_new (I_("populate_popup"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTextViewClass, populate_popup),
GTK_TYPE_MENU);
signals[SELECT_ALL] =
- _gtk_binding_signal_new ("select_all",
+ _gtk_binding_signal_new (I_("select_all"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_CALLBACK (gtk_text_view_select_all),
"select_all", 1,
G_TYPE_BOOLEAN, FALSE);
+ gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+ "select_all", 1,
+ G_TYPE_BOOLEAN, FALSE);
+
/* Deleting text */
gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
"delete_from_cursor", 2,
gtk_text_view_ensure_layout (text_view);
gtk_text_layout_get_iter_at_pixel (text_view->layout,
- iter,
- x,
- y);
+ iter, x, y);
+}
+
+/**
+ * gtk_text_view_get_iter_at_position:
+ * @text_view: a #GtkTextView
+ * @iter: a #GtkTextIter
+ * @trailing: location to store an integer indicating where
+ * in the grapheme the user clicked. It will either be
+ * zero, or the number of characters in the grapheme.
+ * 0 represents the trailing edge of the grapheme.
+ * @x: x position, in buffer coordinates
+ * @y: y position, in buffer coordinates
+ *
+ * Retrieves the iterator pointing to the character at buffer
+ * coordinates @x and @y. Buffer coordinates are coordinates for
+ * the entire buffer, not just the currently-displayed portion.
+ * If you have coordinates from an event, you have to convert
+ * those to buffer coordinates with
+ * gtk_text_view_window_to_buffer_coords().
+ *
+ * Note that this is different from gtk_text_view_get_iter_at_location(),
+ * which returns cursor locations, i.e. positions <emphasis>between</emphasis>
+ * characters.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_text_view_get_iter_at_position (GtkTextView *text_view,
+ GtkTextIter *iter,
+ gint *trailing,
+ gint x,
+ gint y)
+{
+ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+ g_return_if_fail (iter != NULL);
+
+ gtk_text_view_ensure_layout (text_view);
+
+ gtk_text_layout_get_iter_at_position (text_view->layout,
+ iter, trailing, x, y);
}
/**
scroll->use_align,
scroll->xalign,
scroll->yalign);
-
+
free_pending_scroll (scroll);
return retval;
if (text_view->width != width || text_view->height != height)
{
+ if (text_view->width != width)
+ text_view->width_changed = TRUE;
+
text_view->width = width;
text_view->height = height;
}
}
- g_object_notify (G_OBJECT (text_view), "wrap_mode");
+ g_object_notify (G_OBJECT (text_view), "wrap-mode");
}
/**
gtk_text_layout_default_style_changed (text_view->layout);
}
- g_object_notify (G_OBJECT (text_view), "pixels_above_lines");
+ g_object_notify (G_OBJECT (text_view), "pixels-above-lines");
}
}
gtk_text_layout_default_style_changed (text_view->layout);
}
- g_object_notify (G_OBJECT (text_view), "pixels_below_lines");
+ g_object_notify (G_OBJECT (text_view), "pixels-below-lines");
}
}
gtk_text_layout_default_style_changed (text_view->layout);
}
- g_object_notify (G_OBJECT (text_view), "pixels_inside_wrap");
+ g_object_notify (G_OBJECT (text_view), "pixels-inside-wrap");
}
}
gtk_text_layout_default_style_changed (text_view->layout);
}
- g_object_notify (G_OBJECT (text_view), "left_margin");
+ g_object_notify (G_OBJECT (text_view), "left-margin");
}
}
gtk_text_layout_default_style_changed (text_view->layout);
}
- g_object_notify (G_OBJECT (text_view), "right_margin");
+ g_object_notify (G_OBJECT (text_view), "right-margin");
}
}
}
}
- g_object_notify (G_OBJECT (text_view), "cursor_visible");
+ g_object_notify (G_OBJECT (text_view), "cursor-visible");
}
}
text_view = GTK_TEXT_VIEW (widget);
gtk_widget_style_get (widget,
- "interior_focus", &interior_focus,
- "focus_line_width", &focus_width,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
NULL);
if (interior_focus)
*/
gtk_widget_style_get (widget,
- "interior_focus", &interior_focus,
- "focus_line_width", &focus_width,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
NULL);
if (interior_focus)
/* this won't actually insert the newline if the cursor isn't
* editable
*/
+ gtk_text_view_reset_im_context (text_view);
gtk_text_view_commit_text (text_view, "\n");
obscure = TRUE;
*/
if (text_view->accepts_tab && text_view->editable)
{
+ gtk_text_view_reset_im_context (text_view);
gtk_text_view_commit_text (text_view, "\t");
obscure = TRUE;
}
event->y + text_view->yoffset);
gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
-
+ gtk_text_view_check_cursor_blink (text_view);
+
text_view->pending_place_cursor_button = 0;
return FALSE;
if (event->window == widget->window)
gtk_text_view_draw_focus (widget);
- /* Propagate exposes to all children not in the buffer. */
+ /* Propagate exposes to all unanchored children.
+ * Anchored children are handled in gtk_text_view_paint().
+ */
tmp_list = GTK_TEXT_VIEW (widget)->children;
while (tmp_list != NULL)
{
/* propagate_expose checks that event->window matches
* child->window
*/
- if (vc->type != GTK_TEXT_WINDOW_TEXT)
+ if (!vc->anchor)
gtk_container_propagate_expose (GTK_CONTAINER (widget),
vc->widget,
event);
/* We clear the focus if we are in interior focus mode. */
gtk_widget_style_get (widget,
- "interior_focus", &interior_focus,
+ "interior-focus", &interior_focus,
NULL);
if (GTK_WIDGET_DRAWABLE (widget))
#endif
if (gtk_debug_flags & GTK_DEBUG_UPDATES)
return FALSE;
-
- g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
- return blink;
+
+ if (text_view->editable)
+ {
+ GtkTextMark *insert;
+ GtkTextIter iter;
+
+ insert = gtk_text_buffer_get_insert (get_buffer (text_view));
+ gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
+
+ if (gtk_text_iter_editable (&iter, text_view->editable))
+ {
+ g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
+ return blink;
+ }
+ }
+
+ return FALSE;
}
static gint
text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER,
blink_cb,
text_view);
-
- gtk_text_layout_set_cursor_visible (text_view->layout,
- !visible);
+
+ /* Block changed_handler while changing the layout's cursor visibility
+ * because it would expose the whole paragraph. Instead, we expose
+ * the cursor's area(s) manually below.
+ */
+ g_signal_handlers_block_by_func (text_view->layout,
+ changed_handler,
+ text_view);
+
+ gtk_text_layout_set_cursor_visible (text_view->layout, !visible);
+
+ g_signal_handlers_unblock_by_func (text_view->layout,
+ changed_handler,
+ text_view);
+
+ text_window_invalidate_cursors (text_view->text_window);
GDK_THREADS_LEAVE ();
{
if (text_view->layout != NULL &&
text_view->cursor_visible &&
- GTK_WIDGET_HAS_FOCUS (text_view))
+ GTK_WIDGET_HAS_FOCUS (text_view) &&
+ cursor_blinks (text_view))
{
- if (cursor_blinks (text_view))
+ if (text_view->blink_timeout == 0)
{
- if (text_view->blink_timeout == 0)
- {
- gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
-
- text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
- blink_cb,
- text_view);
- }
+ gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
+
+ text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
+ blink_cb,
+ text_view);
}
- else
- gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
}
else
{
gtk_text_view_stop_cursor_blink (text_view);
+ gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
}
}
static void
-gtk_text_view_pend_cursor_blink(GtkTextView *text_view)
+gtk_text_view_pend_cursor_blink (GtkTextView *text_view)
{
if (text_view->layout != NULL &&
text_view->cursor_visible &&
GTK_WIDGET_HAS_FOCUS (text_view) &&
cursor_blinks (text_view))
{
- if (text_view->blink_timeout != 0)
- {
- g_source_remove (text_view->blink_timeout);
- text_view->blink_timeout = 0;
- }
-
+ gtk_text_view_stop_cursor_blink (text_view);
gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER,
"insert",
new_location);
else
- gtk_text_buffer_place_cursor (get_buffer (text_view),
- new_location);
+ gtk_text_buffer_place_cursor (get_buffer (text_view),
+ new_location);
+ gtk_text_view_check_cursor_blink (text_view);
}
static void
if (step == GTK_MOVEMENT_PAGES)
{
gtk_text_view_scroll_pages (text_view, count, extend_selection);
+ gtk_text_view_check_cursor_blink (text_view);
gtk_text_view_pend_cursor_blink (text_view);
return;
}
else if (step == GTK_MOVEMENT_HORIZONTAL_PAGES)
{
gtk_text_view_scroll_hpages (text_view, count, extend_selection);
+ gtk_text_view_check_cursor_blink (text_view);
gtk_text_view_pend_cursor_blink (text_view);
return;
}
else if (count > 0)
{
if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
- gtk_text_iter_forward_to_end (&newplace);
+ gtk_text_iter_forward_to_line_end (&newplace);
}
break;
if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
else
- /* we currently do not have a backward_to_start, use offset */
- gtk_text_iter_set_offset (&newplace, 0);
+ gtk_text_iter_set_line_offset (&newplace, 0);
}
if (count > 0)
{
if (gtk_text_view_move_iter_by_lines (text_view, &newplace, count))
gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos);
else
- gtk_text_iter_forward_to_end (&newplace);
+ gtk_text_iter_forward_to_line_end (&newplace);
}
break;
gtk_text_iter_forward_to_line_end (&newplace);
--count;
}
- gtk_text_iter_forward_lines (&newplace, count);
+ gtk_text_iter_forward_visible_lines (&newplace, count);
gtk_text_iter_forward_to_line_end (&newplace);
}
else if (count < 0)
{
if (gtk_text_iter_get_line_offset (&newplace) > 0)
- {
- gtk_text_iter_set_line_offset (&newplace, 0);
- ++count;
- }
- gtk_text_iter_forward_lines (&newplace, count);
+ gtk_text_iter_set_line_offset (&newplace, 0);
+ gtk_text_iter_forward_visible_lines (&newplace, count);
gtk_text_iter_set_line_offset (&newplace, 0);
}
break;
"insert"));
if (step == GTK_MOVEMENT_DISPLAY_LINES)
- {
- gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
- }
+ gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
}
+ gtk_text_view_check_cursor_blink (text_view);
gtk_text_view_pend_cursor_blink (text_view);
}
else if (count > 0 && adj->value >= (adj->upper - adj->page_size - 1e-12))
{
/* already at far right, just be sure we are at the end */
- gtk_text_iter_forward_to_line_end (&new_insert);
+ if (!gtk_text_iter_ends_line (&new_insert))
+ gtk_text_iter_forward_to_line_end (&new_insert);
move_cursor (text_view, &new_insert, extend_selection);
}
else
{
text_view->accepts_tab = accepts_tab;
- g_object_notify (G_OBJECT (text_view), "accepts_tab");
+ g_object_notify (G_OBJECT (text_view), "accepts-tab");
}
}
/*
* Move @start and @end to the boundaries of the selection unit (indicated by
- * @granularity) which contained @start initially. Return wether @start was
- * contained in a selection unit at all (which may not be the case for words).
+ * @granularity) which contained @start initially.
+ * If the selction unit is SELECT_WORDS and @start is not contained in a word
+ * the selection is extended to all the white spaces between the end of the
+ * word preceding @start and the start of the one following.
*/
-static gboolean
+static void
extend_selection (GtkTextView *text_view,
SelectionGranularity granularity,
GtkTextIter *start,
GtkTextIter *end)
{
- gboolean extend = TRUE;
-
*end = *start;
if (granularity == SELECT_WORDS)
}
}
else
- extend = FALSE;
+ {
+ GtkTextIter tmp;
+
+ tmp = *start;
+ if (gtk_text_iter_backward_visible_word_start (&tmp))
+ gtk_text_iter_forward_visible_word_end (&tmp);
+
+ if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (start))
+ *start = tmp;
+ else
+ gtk_text_iter_set_line_offset (start, 0);
+
+ tmp = *end;
+ if (!gtk_text_iter_forward_visible_word_end (&tmp))
+ gtk_text_iter_forward_to_end (&tmp);
+
+ if (gtk_text_iter_ends_word (&tmp))
+ gtk_text_iter_backward_visible_word_start (&tmp);
+
+ if (gtk_text_iter_get_line (&tmp) == gtk_text_iter_get_line (end))
+ *end = tmp;
+ else
+ gtk_text_iter_forward_to_line_end (end);
+ }
}
else if (granularity == SELECT_LINES)
{
gtk_text_view_forward_display_line_end (text_view, end);
}
}
-
- return extend;
}
static gint
event->x + text_view->xoffset,
event->y + text_view->yoffset);
- if (extend_selection (text_view, granularity, &start, &end))
- {
- /* Extend selection */
- gtk_text_buffer_get_iter_at_mark (buffer,
- &ins,
- gtk_text_buffer_get_insert (buffer));
- gtk_text_buffer_get_iter_at_mark (buffer,
+ extend_selection (text_view, granularity, &start, &end);
+
+ /* Extend selection */
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &ins,
+ gtk_text_buffer_get_insert (buffer));
+ gtk_text_buffer_get_iter_at_mark (buffer,
&bound,
gtk_text_buffer_get_selection_bound (buffer));
- if (gtk_text_iter_compare (&ins, &bound) < 0)
- {
- old_start = ins;
- old_end = bound;
- }
- else
- {
- old_start = bound;
- old_end = ins;
- }
-
- if (gtk_text_iter_compare (&start, &old_start) < 0)
- {
- /* newly selected unit before the current selection */
- ins = start;
- bound = old_end;
- }
- else if (gtk_text_iter_compare (&old_end, &end) < 0)
- {
- /* newly selected unit after the current selection */
- ins = end;
- bound = old_start;
- }
- else if (gtk_text_iter_equal (&ins, &old_start))
- {
- /* newly selected unit inside the current selection
- at the start */
- if (!gtk_text_iter_equal (&ins, &start))
- ins = end;
- }
- else
- {
- /* newly selected unit inside the current selection
- at the end */
- if (!gtk_text_iter_equal (&ins, &end))
- ins = start;
- }
+ if (gtk_text_iter_compare (&ins, &bound) < 0)
+ {
+ old_start = ins;
+ old_end = bound;
+ }
+ else
+ {
+ old_start = bound;
+ old_end = ins;
+ }
- gtk_text_buffer_select_range (buffer, &ins, &bound);
+ if (gtk_text_iter_compare (&start, &old_start) < 0)
+ {
+ /* newly selected unit before the current selection */
+ ins = start;
+ bound = old_end;
+ }
+ else if (gtk_text_iter_compare (&old_end, &end) < 0)
+ {
+ /* newly selected unit after the current selection */
+ ins = end;
+ bound = old_start;
+ }
+ else if (gtk_text_iter_equal (&ins, &old_start))
+ {
+ /* newly selected unit inside the current selection at the start */
+ if (!gtk_text_iter_equal (&ins, &start))
+ ins = end;
+ }
+ else
+ {
+ /* newly selected unit inside the current selection at the end */
+ if (!gtk_text_iter_equal (&ins, &end))
+ ins = start;
}
+ gtk_text_buffer_select_range (buffer, &ins, &bound);
+
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_mark (buffer,
"insert"));
}
-
/* If we had to scroll offscreen, insert a timeout to do so
* again. Note that in the timeout, even if the mouse doesn't
* move, due to this scroll xoffset/yoffset will have changed
}
gtk_text_buffer_select_range (buffer, &end, &start);
-
+ gtk_text_view_check_cursor_blink (text_view);
+
text_view->selection_drag_handler = g_signal_connect (text_view,
"motion_notify_event",
G_CALLBACK (selection_motion_event_handler),
"gtk-split-cursor", &split_cursor,
NULL);
- if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR)
- new_keyboard_dir = GTK_TEXT_DIR_LTR;
+ if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
+ new_keyboard_dir = GTK_TEXT_DIR_RTL;
else
- new_keyboard_dir = GTK_TEXT_DIR_RTL;
+ new_keyboard_dir = GTK_TEXT_DIR_LTR;
if (split_cursor)
new_cursor_dir = GTK_TEXT_DIR_NONE;
}
}
+static gchar*
+_gtk_text_view_get_selected_text (GtkTextView *text_view)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ gchar *text = NULL;
+
+ buffer = gtk_text_view_get_buffer (text_view);
+
+ if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+ text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+
+ return text;
+}
+
/*
* DND feature
*/
+static void
+drag_begin_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gpointer data)
+{
+ GtkTextView *text_view;
+ gchar *text;
+ GdkPixmap *pixmap = NULL;
+
+ g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
+
+ text_view = GTK_TEXT_VIEW (widget);
+
+ text = _gtk_text_view_get_selected_text (text_view);
+ pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
+
+ if (pixmap)
+ gtk_drag_set_icon_pixmap (context,
+ gdk_drawable_get_colormap (pixmap),
+ pixmap,
+ NULL,
+ -2, -2);
+ else
+ gtk_drag_set_icon_default (context);
+
+ if (pixmap)
+ g_object_unref (pixmap);
+ g_free (text);
+}
+
static void
gtk_text_view_start_selection_dnd (GtkTextView *text_view,
const GtkTextIter *iter,
GdkEventMotion *event)
{
GdkDragContext *context;
- GtkTargetList *target_list;
+ GtkTargetList *target_list;
text_view->drag_start_x = -1;
text_view->drag_start_y = -1;
G_N_ELEMENTS (target_table));
gtk_target_list_add_text_targets (target_list, 0);
+ g_signal_connect (text_view, "drag-begin",
+ G_CALLBACK (drag_begin_cb), NULL);
context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
GDK_ACTION_COPY | GDK_ACTION_MOVE,
1, (GdkEvent*)event);
gtk_target_list_unref (target_list);
-
- gtk_drag_set_icon_default (context);
}
static void
text_view = GTK_TEXT_VIEW (widget);
- if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
+ if (selection_data->target == gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
gtk_selection_data_set (selection_data,
- gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
+ gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
8, /* bytes */
(void*)&buffer,
sizeof (buffer));
gtk_text_buffer_begin_user_action (buffer);
- if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
+ if (selection_data->target == gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
{
GtkTextBuffer *src_buffer = NULL;
GtkTextIter start, end;
{
dx = text_view->xoffset - (gint)adj->value;
text_view->xoffset = adj->value;
+
+ /* If the change is due to a size change we need
+ * to invalidate the entire text window because there might be
+ * right-aligned or centered text
+ */
+ if (text_view->width_changed)
+ {
+ gdk_window_invalidate_rect (text_view->text_window->bin_window, NULL, FALSE);
+
+ text_view->width_changed = FALSE;
+ }
}
else if (adj == text_view->vadjustment)
{
{
GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
- g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal);
+ g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
g_signal_connect (menuitem, "activate",
G_CALLBACK (activate_cb), text_view);
gtk_widget_show (menuitem);
gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
- menuitem = gtk_menu_item_new_with_mnemonic (_("Select _All"));
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
g_signal_connect (menuitem, "activate",
G_CALLBACK (select_all_cb), text_view);
gtk_widget_show (menuitem);
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
GDK_SELECTION_CLIPBOARD),
- gdk_atom_intern ("TARGETS", FALSE),
+ gdk_atom_intern_static_string ("TARGETS"),
popup_targets_received,
info);
}
&attributes,
attributes_mask);
+ gdk_window_set_back_pixmap (win->window, NULL, FALSE);
+
gdk_window_show (win->window);
gdk_window_set_user_data (win->window, win->widget);
#if 0
{
- GdkColor color = { 0, 65535, 0, 0 };
- GdkGC *gc = gdk_gc_new (win->bin_window);
- gdk_gc_set_rgb_fg_color (gc, &color);
- gdk_draw_rectangle (win->bin_window,
- gc, TRUE, window_rect.x, window_rect.y,
- window_rect.width, window_rect.height);
- g_object_unref (gc);
+ cairo_t *cr = gdk_cairo_create (win->bin_window);
+ gdk_cairo_rectangle (cr, &window_rect);
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */
+ cairo_fill (cr);
+ cairo_destroy (cr);
}
#endif
}
+static void
+text_window_invalidate_cursors (GtkTextWindow *win)
+{
+ GtkTextView *text_view = GTK_TEXT_VIEW (win->widget);
+ GtkTextIter iter;
+ GdkRectangle strong;
+ GdkRectangle weak;
+ gboolean draw_arrow;
+ gfloat cursor_aspect_ratio;
+ gint stem_width;
+ gint arrow_width;
+
+ gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter,
+ gtk_text_buffer_get_insert (text_view->buffer));
+
+ gtk_text_layout_get_cursor_locations (text_view->layout, &iter,
+ &strong, &weak);
+
+ /* cursor width calculation as in gtkstyle.c:draw_insertion_cursor(),
+ * ignoring the text direction be exposing both sides of the cursor
+ */
+
+ draw_arrow = (strong.x != weak.x || strong.y != weak.y);
+
+ gtk_widget_style_get (win->widget,
+ "cursor-aspect-ratio", &cursor_aspect_ratio,
+ NULL);
+
+ stem_width = strong.height * cursor_aspect_ratio + 1;
+ arrow_width = stem_width + 1;
+
+ /* round up to the next even number */
+ if (stem_width & 1)
+ stem_width++;
+
+ strong.x -= stem_width / 2;
+ strong.width += stem_width;
+
+ if (draw_arrow)
+ {
+ strong.x -= arrow_width;
+ strong.width += arrow_width * 2;
+ }
+
+ text_window_invalidate_rect (win, &strong);
+
+ if (draw_arrow) /* == have weak */
+ {
+ stem_width = weak.height * cursor_aspect_ratio + 1;
+ arrow_width = stem_width + 1;
+
+ /* round up to the next even number */
+ if (stem_width & 1)
+ stem_width++;
+
+ weak.x -= stem_width / 2;
+ weak.width += stem_width;
+
+ weak.x -= arrow_width;
+ weak.width += arrow_width * 2;
+
+ text_window_invalidate_rect (win, &weak);
+ }
+}
+
static gint
text_window_get_width (GtkTextWindow *win)
{
g_object_ref (vc->anchor);
g_object_set_data (G_OBJECT (child),
- "gtk-text-view-child",
+ I_("gtk-text-view-child"),
vc);
gtk_text_child_anchor_register_child (anchor, child, layout);
vc->y = y;
g_object_set_data (G_OBJECT (child),
- "gtk-text-view-child",
+ I_("gtk-text-view-child"),
vc);
return vc;
text_view_child_free (GtkTextViewChild *child)
{
g_object_set_data (G_OBJECT (child->widget),
- "gtk-text-view-child", NULL);
+ I_("gtk-text-view-child"), NULL);
if (child->anchor)
{
return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
}
+
+#define __GTK_TEXT_VIEW_C__
+#include "gtkaliasdef.c"