diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index d80a94eee7..a6cb66ceb5 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -33,6 +33,7 @@ #include "gtkbindings.h" #include "gtkcsscolorvalueprivate.h" #include "gtkdebug.h" +#include "gtkdropcontrollermotion.h" #include "gtkintl.h" #include "gtkmain.h" #include "gtkmarshalers.h" @@ -661,6 +662,118 @@ G_DEFINE_TYPE_WITH_CODE (GtkTextView, gtk_text_view, GTK_TYPE_CONTAINER, G_ADD_PRIVATE (GtkTextView) G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) +static GtkTextBuffer* +get_buffer (GtkTextView *text_view) +{ + if (text_view->priv->buffer == NULL) + { + GtkTextBuffer *b; + b = GTK_TEXT_VIEW_GET_CLASS (text_view)->create_buffer (text_view); + gtk_text_view_set_buffer (text_view, b); + g_object_unref (b); + } + + return text_view->priv->buffer; +} + +#define UPPER_OFFSET_ANCHOR 0.8 +#define LOWER_OFFSET_ANCHOR 0.2 + +static gboolean +check_scroll (gdouble offset, GtkAdjustment *adjustment) +{ + if ((offset > UPPER_OFFSET_ANCHOR && + gtk_adjustment_get_value (adjustment) + gtk_adjustment_get_page_size (adjustment) < gtk_adjustment_get_upper (adjustment)) || + (offset < LOWER_OFFSET_ANCHOR && + gtk_adjustment_get_value (adjustment) > gtk_adjustment_get_lower (adjustment))) + return TRUE; + + return FALSE; +} + +static int +gtk_text_view_drop_motion_scroll_timeout (gpointer data) +{ + GtkTextView *text_view; + GtkTextViewPrivate *priv; + GtkTextIter newplace; + gdouble pointer_xoffset, pointer_yoffset; + + text_view = GTK_TEXT_VIEW (data); + priv = text_view->priv; + + gtk_text_layout_get_iter_at_pixel (priv->layout, + &newplace, + priv->dnd_x + priv->xoffset, + priv->dnd_y + priv->yoffset); + + gtk_text_buffer_move_mark (get_buffer (text_view), priv->dnd_mark, &newplace); + + pointer_xoffset = (gdouble) priv->dnd_x / text_window_get_width (priv->text_window); + pointer_yoffset = (gdouble) priv->dnd_y / text_window_get_height (priv->text_window); + + if (check_scroll (pointer_xoffset, priv->hadjustment) || + check_scroll (pointer_yoffset, priv->vadjustment)) + { + /* do not make offsets surpass lower nor upper anchors, this makes + * scrolling speed relative to the distance of the pointer to the + * anchors when it moves beyond them. + */ + pointer_xoffset = CLAMP (pointer_xoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR); + pointer_yoffset = CLAMP (pointer_yoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR); + + gtk_text_view_scroll_to_mark (text_view, + priv->dnd_mark, + 0., TRUE, pointer_xoffset, pointer_yoffset); + } + + return G_SOURCE_CONTINUE; +} + +static void +gtk_text_view_drop_scroll_motion (GtkDropControllerMotion *motion, + double x, + double y, + GtkTextView *self) +{ + GtkTextViewPrivate *priv = self->priv; + GdkRectangle target_rect; + + target_rect = priv->text_window->allocation; + + if (x < target_rect.x || + y < target_rect.y || + x > (target_rect.x + target_rect.width) || + y > (target_rect.y + target_rect.height)) + { + priv->dnd_x = priv->dnd_y = -1; + g_clear_handle_id (&priv->scroll_timeout, g_source_remove); + return; + } + + /* DnD uses text window coords, so subtract extra widget + * coords that happen e.g. when displaying line numbers. + */ + priv->dnd_x = x - target_rect.x; + priv->dnd_y = y - target_rect.y; + + if (!priv->scroll_timeout) + { + priv->scroll_timeout = g_timeout_add (100, gtk_text_view_drop_motion_scroll_timeout, self); + g_source_set_name_by_id (priv->scroll_timeout, "[gtk] gtk_text_view_drop_motion_scroll_timeout"); + } +} + +static void +gtk_text_view_drop_scroll_leave (GtkDropControllerMotion *motion, + GtkTextView *self) +{ + GtkTextViewPrivate *priv = self->priv; + + priv->dnd_x = priv->dnd_y = -1; + g_clear_handle_id (&priv->scroll_timeout, g_source_remove); +} + static void add_move_binding (GtkBindingSet *binding_set, guint keyval, @@ -1645,6 +1758,12 @@ gtk_text_view_init (GtkTextView *text_view) g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_view_drag_drop), text_view); gtk_widget_add_controller (GTK_WIDGET (text_view), GTK_EVENT_CONTROLLER (dest)); + controller = gtk_drop_controller_motion_new (); + g_signal_connect (controller, "enter", G_CALLBACK (gtk_text_view_drop_scroll_motion), text_view); + g_signal_connect (controller, "motion", G_CALLBACK (gtk_text_view_drop_scroll_motion), text_view); + g_signal_connect (controller, "leave", G_CALLBACK (gtk_text_view_drop_scroll_leave), text_view); + gtk_widget_add_controller (GTK_WIDGET (text_view), controller); + priv->virtual_cursor_x = -1; priv->virtual_cursor_y = -1; @@ -1950,20 +2069,6 @@ gtk_text_view_create_buffer (GtkTextView *text_view) return gtk_text_buffer_new (NULL); } -static GtkTextBuffer* -get_buffer (GtkTextView *text_view) -{ - if (text_view->priv->buffer == NULL) - { - GtkTextBuffer *b; - b = GTK_TEXT_VIEW_GET_CLASS (text_view)->create_buffer (text_view); - gtk_text_view_set_buffer (text_view, b); - g_object_unref (b); - } - - return text_view->priv->buffer; -} - /** * gtk_text_view_get_buffer: * @text_view: a #GtkTextView @@ -6896,60 +7001,6 @@ selection_scan_timeout (gpointer data) return TRUE; /* remain installed. */ } -#define UPPER_OFFSET_ANCHOR 0.8 -#define LOWER_OFFSET_ANCHOR 0.2 - -static gboolean -check_scroll (gdouble offset, GtkAdjustment *adjustment) -{ - if ((offset > UPPER_OFFSET_ANCHOR && - gtk_adjustment_get_value (adjustment) + gtk_adjustment_get_page_size (adjustment) < gtk_adjustment_get_upper (adjustment)) || - (offset < LOWER_OFFSET_ANCHOR && - gtk_adjustment_get_value (adjustment) > gtk_adjustment_get_lower (adjustment))) - return TRUE; - - return FALSE; -} - -static gint -drag_scan_timeout (gpointer data) -{ - GtkTextView *text_view; - GtkTextViewPrivate *priv; - GtkTextIter newplace; - gdouble pointer_xoffset, pointer_yoffset; - - text_view = GTK_TEXT_VIEW (data); - priv = text_view->priv; - - gtk_text_layout_get_iter_at_pixel (priv->layout, - &newplace, - priv->dnd_x + priv->xoffset, - priv->dnd_y + priv->yoffset); - - gtk_text_buffer_move_mark (get_buffer (text_view), priv->dnd_mark, &newplace); - - pointer_xoffset = (gdouble) priv->dnd_x / text_window_get_width (priv->text_window); - pointer_yoffset = (gdouble) priv->dnd_y / text_window_get_height (priv->text_window); - - if (check_scroll (pointer_xoffset, priv->hadjustment) || - check_scroll (pointer_yoffset, priv->vadjustment)) - { - /* do not make offsets surpass lower nor upper anchors, this makes - * scrolling speed relative to the distance of the pointer to the - * anchors when it moves beyond them. - */ - pointer_xoffset = CLAMP (pointer_xoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR); - pointer_yoffset = CLAMP (pointer_yoffset, LOWER_OFFSET_ANCHOR, UPPER_OFFSET_ANCHOR); - - gtk_text_view_scroll_to_mark (text_view, - priv->dnd_mark, - 0., TRUE, pointer_xoffset, pointer_yoffset); - } - - return TRUE; -} - static void extend_selection (GtkTextView *text_view, SelectionGranularity granularity, @@ -7743,13 +7794,6 @@ gtk_text_view_drag_leave (GtkDropTarget *dest, GtkTextViewPrivate *priv = text_view->priv; gtk_text_mark_set_visible (priv->dnd_mark, FALSE); - - priv->dnd_x = priv->dnd_y = -1; - - if (priv->scroll_timeout != 0) - g_source_remove (priv->scroll_timeout); - - priv->scroll_timeout = 0; } static gboolean @@ -7763,18 +7807,9 @@ gtk_text_view_drag_motion (GtkDropTarget *dest, GtkTextIter newplace; GtkTextIter start; GtkTextIter end; - GdkRectangle target_rect; gint bx, by; gboolean can_accept = FALSE; - target_rect = priv->text_window->allocation; - - if (x < target_rect.x || - y < target_rect.y || - x > (target_rect.x + target_rect.width) || - y > (target_rect.y + target_rect.height)) - return FALSE; /* outside the text window, allow parent widgets to handle event */ - gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_WIDGET, x, y, @@ -7807,18 +7842,6 @@ gtk_text_view_drag_motion (GtkDropTarget *dest, gtk_text_mark_set_visible (priv->dnd_mark, FALSE); } - /* DnD uses text window coords, so subtract extra widget - * coords that happen e.g. when displaying line numbers. - */ - priv->dnd_x = x - target_rect.x; - priv->dnd_y = y - target_rect.y; - - if (!priv->scroll_timeout) - { - priv->scroll_timeout = g_timeout_add (100, drag_scan_timeout, text_view); - g_source_set_name_by_id (text_view->priv->scroll_timeout, "[gtk] drag_scan_timeout"); - } - /* TRUE return means don't propagate the drag motion to parent * widgets that may also be drop sites. */ @@ -7900,11 +7923,6 @@ gtk_text_view_drag_drop (GtkDropTarget *dest, GtkTextIter drop_point; GtkTextBuffer *buffer = NULL; - if (priv->scroll_timeout != 0) - g_source_remove (priv->scroll_timeout); - - priv->scroll_timeout = 0; - gtk_text_mark_set_visible (priv->dnd_mark, FALSE); buffer = get_buffer (text_view);