#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"
#include "gtkalias.h"
#define SPACE_FOR_CURSOR 1
+typedef struct _GtkTextViewPrivate GtkTextViewPrivate;
+
+#define GTK_TEXT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_VIEW, GtkTextViewPrivate))
+
+struct _GtkTextViewPrivate
+{
+ guint blink_time; /* time in msec the cursor has blinked since last user event */
+};
+
+
struct _GtkTextPendingScroll
{
GtkTextMark *mark;
LAST_PROP
};
-static void gtk_text_view_init (GtkTextView *text_view);
-static void gtk_text_view_class_init (GtkTextViewClass *klass);
static void gtk_text_view_destroy (GtkObject *object);
static void gtk_text_view_finalize (GObject *object);
static void gtk_text_view_set_property (GObject *object,
GtkScrollStep step,
gint count);
static void gtk_text_view_set_anchor (GtkTextView *text_view);
-static void gtk_text_view_scroll_pages (GtkTextView *text_view,
+static gboolean gtk_text_view_scroll_pages (GtkTextView *text_view,
gint count,
gboolean extend_selection);
-static void gtk_text_view_scroll_hpages (GtkTextView *text_view,
+static gboolean gtk_text_view_scroll_hpages(GtkTextView *text_view,
gint count,
gboolean extend_selection);
static void gtk_text_view_insert_at_cursor (GtkTextView *text_view,
static void gtk_text_view_check_cursor_blink (GtkTextView *text_view);
static void gtk_text_view_pend_cursor_blink (GtkTextView *text_view);
static void gtk_text_view_stop_cursor_blink (GtkTextView *text_view);
+static void gtk_text_view_reset_blink_time (GtkTextView *text_view);
static void gtk_text_view_value_changed (GtkAdjustment *adj,
GtkTextView *view);
static gint text_window_get_height (GtkTextWindow *win);
-static GtkContainerClass *parent_class = NULL;
static guint signals[LAST_SIGNAL] = { 0 };
-GType
-gtk_text_view_get_type (void)
-{
- static GType our_type = 0;
-
- if (our_type == 0)
- {
- static const GTypeInfo our_info =
- {
- sizeof (GtkTextViewClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_text_view_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkTextView),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_text_view_init,
- };
-
- our_type = g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkTextView"),
- &our_info, 0);
- }
-
- return our_type;
-}
+G_DEFINE_TYPE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER)
static void
add_move_binding (GtkBindingSet *binding_set,
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GtkBindingSet *binding_set;
- parent_class = g_type_class_peek_parent (klass);
-
/* Default handlers and virtual methods
*/
gobject_class->set_property = gtk_text_view_set_property;
GTK_MOVEMENT_WORDS, -1);
add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
- GTK_MOVEMENT_WORDS, 1);
+ GTK_MOVEMENT_WORDS, -1);
add_move_binding (binding_set, GDK_Up, 0,
GTK_MOVEMENT_DISPLAY_LINES, -1);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
"move_focus", 1,
GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
+
+ g_type_class_add_private (gobject_class, sizeof (GtkTextViewPrivate));
}
static void
gtk_text_view_set_buffer (text_view, NULL);
gtk_text_view_destroy_layout (text_view);
- (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+ (* GTK_OBJECT_CLASS (gtk_text_view_parent_class)->destroy) (object);
}
static void
g_object_unref (text_view->im_context);
- (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+ (* G_OBJECT_CLASS (gtk_text_view_parent_class)->finalize) (object);
}
static void
{
GtkTextViewChild *child = tmp_list->data;
+ g_assert (child != NULL);
+
if (child->anchor)
{
/* We need to force-validate the regions containing
GtkAllocation allocation;
GtkRequisition child_req;
- g_assert (child != NULL);
-
allocation.x = child->x;
allocation.y = child->y;
{
GtkTextView *text_view = data;
- GDK_THREADS_ENTER ();
-
/* Note that some of this code is duplicated at the end of size_allocate,
* keep in sync with that.
*/
gtk_text_view_flush_first_validate (text_view);
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
GtkTextView *text_view = data;
gboolean result = TRUE;
- GDK_THREADS_ENTER ();
-
DV(g_print(G_STRLOC"\n"));
gtk_text_layout_validate (text_view->layout, 2000);
result = FALSE;
}
- GDK_THREADS_LEAVE ();
-
return result;
}
if (!text_view->first_validate_idle)
{
- text_view->first_validate_idle = g_idle_add_full (GTK_PRIORITY_RESIZE - 2, first_validate_callback, text_view, NULL);
+ text_view->first_validate_idle = gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, first_validate_callback, text_view, NULL);
DV (g_print (G_STRLOC": adding first validate idle %d\n",
text_view->first_validate_idle));
}
if (!text_view->incremental_validate_idle)
{
- text_view->incremental_validate_idle = g_idle_add_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE, incremental_validate_callback, text_view, NULL);
+ text_view->incremental_validate_idle = gdk_threads_add_idle_full (GTK_TEXT_VIEW_PRIORITY_VALIDATE, incremental_validate_callback, text_view, NULL);
DV (g_print (G_STRLOC": adding incremental validate idle %d\n",
text_view->incremental_validate_idle));
}
gtk_text_view_destroy_layout (text_view);
- (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+ (* GTK_WIDGET_CLASS (gtk_text_view_parent_class)->unrealize) (widget);
}
static void
GtkStyle *previous_style)
{
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+ PangoContext *ltr_context, *rtl_context;
if (GTK_WIDGET_REALIZED (widget))
{
gtk_text_view_set_attributes_from_style (text_view,
text_view->layout->default_style,
widget->style);
- gtk_text_layout_default_style_changed (text_view->layout);
+
+
+ ltr_context = gtk_widget_create_pango_context (widget);
+ pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
+ rtl_context = gtk_widget_create_pango_context (widget);
+ pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
+
+ gtk_text_layout_set_contexts (text_view->layout, ltr_context, rtl_context);
+
+ g_object_unref (ltr_context);
+ g_object_unref (rtl_context);
}
}
if (text_view->layout)
{
text_view->layout->default_style->direction = gtk_widget_get_direction (widget);
+
gtk_text_layout_default_style_changed (text_view->layout);
}
}
gboolean was_grabbed)
{
if (!was_grabbed)
- gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
+ {
+ gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), NULL);
+ gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
+ }
}
retval = TRUE;
}
/* Binding set */
- else if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
- GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
+ else if (GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_press_event &&
+ GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_press_event (widget, event))
retval = TRUE;
/* use overall editability not can_insert, more predictable for users */
else if (text_view->editable &&
if (obscure)
gtk_text_view_obscure_mouse_cursor (text_view);
+ gtk_text_view_reset_blink_time (text_view);
gtk_text_view_pend_cursor_blink (text_view);
+ if (!retval && event->length)
+ gtk_widget_error_bell (widget);
+
return retval;
}
return TRUE;
}
else
- return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
+ return GTK_WIDGET_CLASS (gtk_text_view_parent_class)->key_release_event (widget, event);
}
static gint
return FALSE;
}
+ gtk_text_view_reset_blink_time (text_view);
+
#if 0
/* debug hack */
if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
gtk_widget_queue_draw (widget);
DV(g_print (G_STRLOC": focus_in_event\n"));
-
+
+ gtk_text_view_reset_blink_time (text_view);
+
if (text_view->cursor_visible && text_view->layout)
{
gtk_text_layout_set_cursor_visible (text_view->layout, TRUE);
* children to get the focus
*/
GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
- result = GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
+ result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
return result;
g_slist_free (copy);
}
-#define CURSOR_ON_MULTIPLIER 0.66
-#define CURSOR_OFF_MULTIPLIER 0.34
-#define CURSOR_PEND_MULTIPLIER 1.0
+#define CURSOR_ON_MULTIPLIER 2
+#define CURSOR_OFF_MULTIPLIER 1
+#define CURSOR_PEND_MULTIPLIER 3
+#define CURSOR_DIVIDER 3
static gboolean
cursor_blinks (GtkTextView *text_view)
return time;
}
+static gint
+get_cursor_blink_timeout (GtkTextView *text_view)
+{
+ GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
+ gint time;
+
+ g_object_get (settings, "gtk-cursor-blink-timeout", &time, NULL);
+
+ return time;
+}
+
+
/*
* Blink!
*/
blink_cb (gpointer data)
{
GtkTextView *text_view;
+ GtkTextViewPrivate *priv;
gboolean visible;
-
- GDK_THREADS_ENTER ();
+ gint blink_timeout;
text_view = GTK_TEXT_VIEW (data);
-
+ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
if (!GTK_WIDGET_HAS_FOCUS (text_view))
{
g_warning ("GtkTextView - did not receive focus-out-event. If you\n"
"connect a handler to this signal, it must return\n"
- "FALSE so the entry gets the event as well");
+ "FALSE so the text view gets the event as well");
}
g_assert (text_view->layout);
visible = gtk_text_layout_get_cursor_visible (text_view->layout);
- if (visible)
- text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER,
- blink_cb,
- text_view);
- else
- text_view->blink_timeout = g_timeout_add (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER,
+ blink_timeout = get_cursor_blink_timeout (text_view);
+ if (priv->blink_time > 1000 * blink_timeout &&
+ blink_timeout < G_MAXINT/1000)
+ {
+ /* we've blinked enough without the user doing anything, stop blinking */
+ visible = 0;
+ text_view->blink_timeout = 0;
+ }
+ else if (visible)
+ text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
blink_cb,
text_view);
+ else
+ {
+ text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
+ blink_cb,
+ text_view);
+ priv->blink_time += get_cursor_time (text_view);
+ }
/* Block changed_handler while changing the layout's cursor visibility
* because it would expose the whole paragraph. Instead, we expose
text_window_invalidate_cursors (text_view->text_window);
- GDK_THREADS_LEAVE ();
-
/* Remove ourselves */
return FALSE;
}
{
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,
+ text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
blink_cb,
text_view);
}
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,
+ text_view->blink_timeout = gdk_threads_add_timeout (get_cursor_time (text_view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
blink_cb,
text_view);
}
}
+static void
+gtk_text_view_reset_blink_time (GtkTextView *text_view)
+{
+ GtkTextViewPrivate *priv;
+
+ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
+ priv->blink_time = 0;
+}
+
/*
* Key binding handlers
{
GtkTextIter insert;
GtkTextIter newplace;
-
gint cursor_x_pos = 0;
+ GtkDirectionType leave_direction = -1;
if (!text_view->cursor_visible)
{
if (step == GTK_MOVEMENT_PAGES)
{
- gtk_text_view_scroll_pages (text_view, count, extend_selection);
+ if (!gtk_text_view_scroll_pages (text_view, count, extend_selection))
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+
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);
+ if (!gtk_text_view_scroll_hpages (text_view, count, extend_selection))
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+
gtk_text_view_check_cursor_blink (text_view);
gtk_text_view_pend_cursor_blink (text_view);
return;
case GTK_MOVEMENT_DISPLAY_LINES:
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_set_line_offset (&newplace, 0);
- }
+ {
+ leave_direction = GTK_DIR_UP;
+
+ 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_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_line_end (&newplace);
- }
+ {
+ leave_direction = GTK_DIR_DOWN;
+
+ 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_line_end (&newplace);
+ }
break;
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
if (step == GTK_MOVEMENT_DISPLAY_LINES)
gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1);
}
+ else if (leave_direction != -1)
+ {
+ if (!gtk_widget_keynav_failed (GTK_WIDGET (text_view),
+ leave_direction))
+ {
+ gtk_text_view_move_focus (text_view, leave_direction);
+ }
+ }
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
gtk_text_view_check_cursor_blink (text_view);
gtk_text_view_pend_cursor_blink (text_view);
gtk_text_buffer_create_mark (get_buffer (text_view), "anchor", &insert, TRUE);
}
-static void
+static gboolean
gtk_text_view_scroll_pages (GtkTextView *text_view,
gint count,
gboolean extend_selection)
gdouble oldval;
GtkAdjustment *adj;
gint cursor_x_pos, cursor_y_pos;
+ GtkTextIter old_insert;
GtkTextIter new_insert;
GtkTextIter anchor;
gint y0, y1;
- g_return_if_fail (text_view->vadjustment != NULL);
+ g_return_val_if_fail (text_view->vadjustment != NULL, FALSE);
adj = text_view->vadjustment;
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
+
+ /* Validate the region that will be brought into view by the cursor motion
*/
+ gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
+ &old_insert,
+ gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
+
if (count < 0)
{
gtk_text_view_get_first_para_iter (text_view, &anchor);
gtk_text_layout_validate_yrange (text_view->layout, &anchor, y0, y1);
/* FIXME do we need to update the adjustment ranges here? */
+ new_insert = old_insert;
+
if (count < 0 && adj->value <= (adj->lower + 1e-12))
{
/* already at top, just be sure we are at offset 0 */
{
gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
- newval = adj->value;
oldval = adj->value;
-
+ newval = adj->value;
+
newval += count * adj->page_increment;
set_adjustment_clamped (adj, newval);
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_mark (get_buffer (text_view),
"insert"));
+
+ return !gtk_text_iter_equal (&old_insert, &new_insert);
}
-static void
+static gboolean
gtk_text_view_scroll_hpages (GtkTextView *text_view,
gint count,
gboolean extend_selection)
gdouble oldval;
GtkAdjustment *adj;
gint cursor_x_pos, cursor_y_pos;
+ GtkTextIter old_insert;
GtkTextIter new_insert;
gint y, height;
- g_return_if_fail (text_view->hadjustment != NULL);
+ g_return_val_if_fail (text_view->hadjustment != NULL, FALSE);
adj = text_view->hadjustment;
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),
- &new_insert,
+ &old_insert,
gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
gtk_text_layout_get_line_yrange (text_view->layout, &new_insert, &y, &height);
gtk_text_layout_validate_yrange (text_view->layout, &new_insert, y, y + height);
/* FIXME do we need to update the adjustment ranges here? */
-
+
+ new_insert = old_insert;
+
if (count < 0 && adj->value <= (adj->lower + 1e-12))
{
/* already at far left, just be sure we are at offset 0 */
{
gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, &cursor_y_pos);
- newval = adj->value;
oldval = adj->value;
-
+ newval = adj->value;
+
newval += count * adj->page_increment;
set_adjustment_clamped (adj, newval);
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_mark (get_buffer (text_view),
"insert"));
+
+ return !gtk_text_iter_equal (&old_insert, &new_insert);
}
static gboolean
gtk_text_view_insert_at_cursor (GtkTextView *text_view,
const gchar *str)
{
- gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
- text_view->editable);
+ if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
+ text_view->editable))
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
}
static void
" ", 1,
text_view->editable);
}
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
gtk_text_buffer_end_user_action (get_buffer (text_view));
gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
}
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
}
static void
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
&insert,
- gtk_text_buffer_get_mark (get_buffer (text_view),
- "insert"));
+ gtk_text_buffer_get_insert (get_buffer (text_view)));
if (gtk_text_buffer_backspace (get_buffer (text_view), &insert,
TRUE, text_view->editable))
gtk_text_view_set_virtual_cursor_pos (text_view, -1, -1);
DV(g_print (G_STRLOC": scrolling onscreen\n"));
gtk_text_view_scroll_mark_onscreen (text_view,
- gtk_text_buffer_get_mark (get_buffer (text_view), "insert"));
+ gtk_text_buffer_get_insert (get_buffer (text_view)));
+ }
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
}
}
text_view->editable);
DV(g_print (G_STRLOC": scrolling onscreen\n"));
gtk_text_view_scroll_mark_onscreen (text_view,
- gtk_text_buffer_get_mark (get_buffer (text_view),
- "insert"));
+ gtk_text_buffer_get_insert (get_buffer (text_view)));
}
static void
gtk_text_buffer_copy_clipboard (get_buffer (text_view),
clipboard);
- DV(g_print (G_STRLOC": scrolling onscreen\n"));
- gtk_text_view_scroll_mark_onscreen (text_view,
- gtk_text_buffer_get_mark (get_buffer (text_view),
- "insert"));
+
+ /* on copy do not scroll, we are already onscreen */
}
static void
text_view->editable);
DV(g_print (G_STRLOC": scrolling onscreen\n"));
gtk_text_view_scroll_mark_onscreen (text_view,
- gtk_text_buffer_get_mark (get_buffer (text_view),
- "insert"));
+ gtk_text_buffer_get_insert (get_buffer (text_view)));
}
static void
}
static void
-move_mark_to_pointer_and_scroll (GtkTextView *text_view,
- const gchar *mark_name)
+get_iter_at_pointer (GtkTextView *text_view,
+ GtkTextIter *iter)
{
gint x, y;
GdkModifierType state;
- GtkTextIter newplace;
- /* DV(g_print (G_STRLOC": begin\n")); */
-
gdk_window_get_pointer (text_view->text_window->bin_window,
&x, &y, &state);
-
- /* DV(g_print (G_STRLOC": get iter at pixel\n"); */
+
gtk_text_layout_get_iter_at_pixel (text_view->layout,
- &newplace,
+ iter,
x + text_view->xoffset,
y + text_view->yoffset);
+}
- {
- GtkTextMark *mark =
- gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
-
- /* This may invalidate the layout */
- DV(g_print (G_STRLOC": move mark\n"));
- gtk_text_buffer_move_mark (get_buffer (text_view),
- mark,
- &newplace);
+static void
+move_mark_to_pointer_and_scroll (GtkTextView *text_view,
+ const gchar *mark_name)
+{
+ GtkTextIter newplace;
+ GtkTextMark *mark;
- DV(g_print (G_STRLOC": scrolling onscreen\n"));
- gtk_text_view_scroll_mark_onscreen (text_view, mark);
- }
+ get_iter_at_pointer (text_view, &newplace);
+
+ mark = gtk_text_buffer_get_mark (get_buffer (text_view), mark_name);
+
+ /* This may invalidate the layout */
+ DV(g_print (G_STRLOC": move mark\n"));
+
+ gtk_text_buffer_move_mark (get_buffer (text_view),
+ mark,
+ &newplace);
+
+ DV(g_print (G_STRLOC": scrolling onscreen\n"));
+ gtk_text_view_scroll_mark_onscreen (text_view, mark);
DV (g_print ("first validate idle leaving %s is %d\n",
G_STRLOC, text_view->first_validate_idle));
}
-static gint
+static gboolean
selection_scan_timeout (gpointer data)
{
GtkTextView *text_view;
- GDK_THREADS_ENTER ();
-
text_view = GTK_TEXT_VIEW (data);
DV(g_print (G_STRLOC": calling move_mark_to_pointer_and_scroll\n"));
gtk_text_buffer_get_mark (get_buffer (text_view),
"insert"));
- GDK_THREADS_LEAVE ();
-
return TRUE; /* remain installed. */
}
drag_scan_timeout (gpointer data)
{
GtkTextView *text_view;
- gint x, y;
- GdkModifierType state;
GtkTextIter newplace;
- GDK_THREADS_ENTER ();
-
text_view = GTK_TEXT_VIEW (data);
- gdk_window_get_pointer (text_view->text_window->bin_window,
- &x, &y, &state);
-
- gtk_text_layout_get_iter_at_pixel (text_view->layout,
- &newplace,
- x + text_view->xoffset,
- y + text_view->yoffset);
-
+ get_iter_at_pointer (text_view, &newplace);
+
gtk_text_buffer_move_mark (get_buffer (text_view),
text_view->dnd_mark,
&newplace);
text_view->dnd_mark,
DND_SCROLL_MARGIN, FALSE, 0.0, 0.0);
- GDK_THREADS_LEAVE ();
-
return TRUE;
}
}
else
{
- gint x, y;
- GdkModifierType state;
- GtkTextIter start, end;
- GtkTextIter ins, bound;
+ GtkTextIter cursor, start, end;
+ GtkTextIter orig_start, orig_end;
GtkTextBuffer *buffer;
- gboolean extend;
buffer = get_buffer (text_view);
- gtk_text_buffer_get_iter_at_mark (buffer, &ins, data->orig_start);
- gtk_text_buffer_get_iter_at_mark (buffer, &bound, data->orig_end);
+ gtk_text_buffer_get_iter_at_mark (buffer, &orig_start, data->orig_start);
+ gtk_text_buffer_get_iter_at_mark (buffer, &orig_end, data->orig_end);
- gdk_window_get_pointer (text_view->text_window->bin_window,
- &x, &y, &state);
-
- gtk_text_layout_get_iter_at_pixel (text_view->layout,
- &start,
- event->x + text_view->xoffset,
- event->y + text_view->yoffset);
+ get_iter_at_pointer (text_view, &cursor);
- extend = !gtk_text_iter_in_range (&start, &ins, &bound);
-
+ start = cursor;
extend_selection (text_view, data->granularity, &start, &end);
- if (extend)
- {
- /* Extend selection */
- gtk_text_iter_order (&ins, &start);
- gtk_text_iter_order (&end, &bound);
- gtk_text_buffer_select_range (buffer, &ins, &bound);
- }
+ /* either the selection extends to the front, or end (or not) */
+ if (gtk_text_iter_compare (&cursor, &orig_start) < 0)
+ gtk_text_buffer_select_range (buffer, &start, &orig_end);
else
- {
- /* Shrink selection */
- gtk_text_iter_order (&ins, &start);
- gtk_text_iter_order (&end, &bound);
- gtk_text_buffer_select_range (buffer, &ins, &end);
- }
+ gtk_text_buffer_select_range (buffer, &end, &orig_start);
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_insert (buffer));
g_source_remove (text_view->scroll_timeout);
text_view->scroll_timeout =
- g_timeout_add (50, selection_scan_timeout, text_view);
+ gdk_threads_add_timeout (50, selection_scan_timeout, text_view);
return TRUE;
}
const GtkTextIter *iter,
GdkEventButton *button)
{
- GtkTextIter start, end;
+ GtkTextIter cursor, ins, bound;
+ GtkTextIter orig_start, orig_end;
GtkTextBuffer *buffer;
SelectionData *data;
- g_assert (text_view->selection_drag_handler == 0);
+ if (text_view->selection_drag_handler != 0)
+ return;
data = g_new0 (SelectionData, 1);
buffer = get_buffer (text_view);
- start = *iter;
+ cursor = *iter;
+ ins = cursor;
- extend_selection (text_view, data->granularity, &start, &end);
+ extend_selection (text_view, data->granularity, &ins, &bound);
+ orig_start = ins;
+ orig_end = bound;
if (button->state & GDK_SHIFT_MASK)
{
/* Extend selection */
+ GtkTextIter old_ins, old_bound;
GtkTextIter old_start, old_end;
- gtk_text_buffer_get_selection_bounds (buffer, &old_start, &old_end);
+ gtk_text_buffer_get_iter_at_mark (buffer, &old_ins, gtk_text_buffer_get_insert (buffer));
+ gtk_text_buffer_get_iter_at_mark (buffer, &old_bound, gtk_text_buffer_get_selection_bound (buffer));
+ old_start = old_ins;
+ old_end = old_bound;
+ gtk_text_iter_order (&old_start, &old_end);
- gtk_text_iter_order (&start, &old_start);
- gtk_text_iter_order (&old_end, &end);
-
- /* Now start is the first of the starts, and end is the
- * last of the ends
- */
+ /* move the front cursor, if the mouse is in front of the selection. Should the
+ * cursor however be inside the selection (this happens on tripple click) then we
+ * move the side which was last moved (current insert mark) */
+ if (gtk_text_iter_compare (&cursor, &old_start) <= 0 ||
+ (gtk_text_iter_compare (&cursor, &old_end) < 0 &&
+ gtk_text_iter_compare (&old_ins, &old_bound) <= 0))
+ {
+ bound = old_end;
+ orig_start = old_end;
+ orig_end = old_end;
+ }
+ else
+ {
+ ins = bound;
+ bound = old_start;
+ orig_end = bound;
+ orig_start = bound;
+ }
}
- gtk_text_buffer_select_range (buffer, &end, &start);
+ gtk_text_buffer_select_range (buffer, &ins, &bound);
+ gtk_text_iter_order (&orig_start, &orig_end);
data->orig_start = gtk_text_buffer_create_mark (buffer, NULL,
- &start, TRUE);
+ &orig_start, TRUE);
data->orig_end = gtk_text_buffer_create_mark (buffer, NULL,
- &end, TRUE);
+ &orig_end, TRUE);
gtk_text_view_check_cursor_blink (text_view);
target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
- g_signal_connect (text_view, "drag-begin",
+ g_signal_connect (text_view, "drag_begin",
G_CALLBACK (drag_begin_cb), NULL);
gtk_drag_begin (GTK_WIDGET (text_view), target_list,
GDK_ACTION_COPY | GDK_ACTION_MOVE,
g_source_remove (text_view->scroll_timeout);
text_view->scroll_timeout =
- g_timeout_add (50, drag_scan_timeout, text_view);
+ gdk_threads_add_timeout (50, drag_scan_timeout, text_view);
/* TRUE return means don't propagate the drag motion to parent
* widgets that may also be drop sites.
if (str)
{
- gtk_text_buffer_insert_interactive (get_buffer (text_view),
- drop_point, (gchar *) str, -1,
- text_view->editable);
+ if (!gtk_text_buffer_insert_interactive (get_buffer (text_view),
+ drop_point, (gchar *) str, -1,
+ text_view->editable))
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
+
g_free (str);
}
}
*/
if (text_view->width_changed)
{
- gdk_window_invalidate_rect (text_view->text_window->bin_window, NULL, FALSE);
+ if (GTK_WIDGET_REALIZED (text_view))
+ gdk_window_invalidate_rect (text_view->text_window->bin_window, NULL, FALSE);
text_view->width_changed = FALSE;
}
if (!strcmp (str, "\n"))
{
- gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
- text_view->editable);
+ if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), "\n", 1,
+ text_view->editable))
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
}
else
{
if (!gtk_text_iter_ends_line (&insert))
gtk_text_view_delete_from_cursor (text_view, GTK_DELETE_CHARS, 1);
}
- gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
- text_view->editable);
+
+ if (!gtk_text_buffer_insert_interactive_at_cursor (get_buffer (text_view), str, -1,
+ text_view->editable))
+ {
+ gtk_widget_error_bell (GTK_WIDGET (text_view));
+ }
}
gtk_text_buffer_end_user_action (get_buffer (text_view));
while (list)
{
GtkTargetPair *pair = list->data;
- guint info;
list = g_list_next (list); /* get next element before removing */
- for (info = GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS;
- info >= GTK_TEXT_BUFFER_TARGET_INFO_TEXT;
- info--)
+ if (pair->info >= GTK_TEXT_BUFFER_TARGET_INFO_TEXT &&
+ pair->info <= GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
{
- if (pair->info == info)
- gtk_target_list_remove (view_list, pair->target);
+ gtk_target_list_remove (view_list, pair->target);
}
}
{
PopupInfo *info = g_new (PopupInfo, 1);
- /* should not need this, see http://bugzilla.gnome.org/show_bug.cgi?id=74620 */
- gtk_text_view_end_selection_drag (text_view, event);
-
/* In order to know what entries we should make sensitive, we
* ask for the current targets of the clipboard, and when
* we get them, then we actually pop up the menu.
gdk_window_show (win->window);
gdk_window_set_user_data (win->window, win->widget);
+ gdk_window_lower (win->window);
attributes.x = 0;
attributes.y = 0;