Merge branch 'wip/carlosg/for-master' into 'master'

Text handle fixes

Closes #3176

See merge request GNOME/gtk!2785
This commit is contained in:
Matthias Clasen 2020-11-06 01:23:16 +00:00
commit 0d82faa239
4 changed files with 122 additions and 63 deletions

View File

@ -2798,6 +2798,7 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
}
impl->has_uncommitted_ack_configure = FALSE;
impl->input_region_dirty = TRUE;
unset_transient_for_exported (surface);

View File

@ -546,6 +546,7 @@ gtk_im_context_wayland_set_client_widget (GtkIMContext *context,
if (context_wayland->widget)
{
gtk_im_context_wayland_focus_out (context);
gtk_widget_remove_controller (context_wayland->widget, GTK_EVENT_CONTROLLER (context_wayland->gesture));
context_wayland->gesture = NULL;
}

View File

@ -44,9 +44,10 @@ struct _GtkTextHandle
{
GtkWidget parent_instance;
GtkWidget *parent;
GdkSurface *surface;
GskRenderer *renderer;
GtkEventController *controller;
GtkWidget *controller_widget;
GdkRectangle pointing_to;
GtkBorder border;
@ -61,6 +62,19 @@ struct _GtkTextHandle
static void gtk_text_handle_native_interface_init (GtkNativeInterface *iface);
static void handle_drag_begin (GtkGestureDrag *gesture,
double x,
double y,
GtkTextHandle *handle);
static void handle_drag_update (GtkGestureDrag *gesture,
double offset_x,
double offset_y,
GtkWidget *widget);
static void handle_drag_end (GtkGestureDrag *gesture,
double offset_x,
double offset_y,
GtkTextHandle *handle);
G_DEFINE_TYPE_WITH_CODE (GtkTextHandle, gtk_text_handle, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
gtk_text_handle_native_interface_init))
@ -185,15 +199,6 @@ surface_render (GdkSurface *surface,
return TRUE;
}
static gboolean
surface_event (GdkSurface *surface,
GdkEvent *event,
GtkTextHandle *handle)
{
gtk_main_do_event (event);
return TRUE;
}
static void
surface_mapped_changed (GtkWidget *widget)
{
@ -226,11 +231,11 @@ gtk_text_handle_realize (GtkWidget *widget)
handle->surface = gdk_surface_new_popup (parent_surface, FALSE);
gdk_surface_set_widget (handle->surface, widget);
gdk_surface_set_input_region (handle->surface, cairo_region_create ());
g_signal_connect_swapped (handle->surface, "notify::mapped",
G_CALLBACK (surface_mapped_changed), widget);
g_signal_connect (handle->surface, "render", G_CALLBACK (surface_render), widget);
g_signal_connect (handle->surface, "event", G_CALLBACK (surface_event), widget);
GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->realize (widget);
@ -248,7 +253,6 @@ gtk_text_handle_unrealize (GtkWidget *widget)
g_clear_object (&handle->renderer);
g_signal_handlers_disconnect_by_func (handle->surface, surface_render, widget);
g_signal_handlers_disconnect_by_func (handle->surface, surface_event, widget);
g_signal_handlers_disconnect_by_func (handle->surface, surface_mapped_changed, widget);
gdk_surface_set_widget (handle->surface, NULL);
@ -256,6 +260,28 @@ gtk_text_handle_unrealize (GtkWidget *widget)
g_clear_object (&handle->surface);
}
static void
text_handle_set_up_gesture (GtkTextHandle *handle)
{
GtkNative *native;
/* The drag gesture is hooked on the parent native */
native = gtk_widget_get_native (gtk_widget_get_parent (GTK_WIDGET (handle)));
handle->controller_widget = GTK_WIDGET (native);
handle->controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
gtk_event_controller_set_propagation_phase (handle->controller,
GTK_PHASE_CAPTURE);
g_signal_connect (handle->controller, "drag-begin",
G_CALLBACK (handle_drag_begin), handle);
g_signal_connect (handle->controller, "drag-update",
G_CALLBACK (handle_drag_update), handle);
g_signal_connect (handle->controller, "drag-end",
G_CALLBACK (handle_drag_end), handle);
gtk_widget_add_controller (handle->controller_widget, handle->controller);
}
static void
gtk_text_handle_map (GtkWidget *widget)
{
@ -264,7 +290,10 @@ gtk_text_handle_map (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->map (widget);
if (handle->has_point)
gtk_text_handle_present_surface (handle);
{
gtk_text_handle_present_surface (handle);
text_handle_set_up_gesture (handle);
}
}
static void
@ -274,6 +303,14 @@ gtk_text_handle_unmap (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->unmap (widget);
gdk_surface_hide (handle->surface);
if (handle->controller_widget)
{
gtk_widget_remove_controller (handle->controller_widget,
handle->controller);
handle->controller_widget = NULL;
handle->controller = NULL;
}
}
static void
@ -330,26 +367,67 @@ gtk_text_handle_class_init (GtkTextHandleClass *klass)
gtk_widget_class_set_css_name (widget_class, I_("cursor-handle"));
}
/* Relative to pointing_to x/y */
static void
handle_get_input_extents (GtkTextHandle *handle,
GtkBorder *border)
{
GtkWidget *widget = GTK_WIDGET (handle);
if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
{
border->left = (-gtk_widget_get_width (widget) / 2) - handle->border.left;
border->right = (gtk_widget_get_width (widget) / 2) + handle->border.right;
}
else if ((handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END &&
gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ||
(handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START &&
gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL))
{
border->left = -gtk_widget_get_width (widget) - handle->border.left;
border->right = handle->border.right;
}
else
{
border->left = -handle->border.left;
border->right = gtk_widget_get_width (widget) + handle->border.right;
}
border->top = - handle->border.top;
border->bottom = gtk_widget_get_height (widget) + handle->border.bottom;
}
static void
handle_drag_begin (GtkGestureDrag *gesture,
double x,
double y,
GtkTextHandle *handle)
{
GtkWidget *widget;
GtkBorder input_extents;
double widget_x, widget_y;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
x -= handle->pointing_to.x;
y -= handle->pointing_to.y;
if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
x -= gtk_widget_get_width (widget) / 2;
else if ((handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END &&
gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ||
(handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START &&
gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL))
x -= gtk_widget_get_width (widget);
/* Figure out if the coordinates fall into the handle input area, coordinates
* are relative to the parent widget.
*/
handle_get_input_extents (handle, &input_extents);
gtk_widget_translate_coordinates (handle->controller_widget,
gtk_widget_get_parent (GTK_WIDGET (handle)),
x, y, &widget_x, &widget_y);
y += handle->border.top / 2;
if (widget_x < input_extents.left || widget_x >= input_extents.right ||
widget_y < input_extents.top || widget_y >= input_extents.bottom)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
/* Store untranslated coordinates here, so ::update does not need
* an extra translation
*/
handle->dx = x;
handle->dy = y;
handle->dragged = TRUE;
@ -368,19 +446,8 @@ handle_drag_update (GtkGestureDrag *gesture,
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
x = handle->pointing_to.x + handle->pointing_to.width / 2 +
start_x + offset_x - handle->dx;
y = handle->pointing_to.y + handle->pointing_to.height +
start_y + offset_y - handle->dy;
if (handle->role == GTK_TEXT_HANDLE_ROLE_CURSOR)
x -= gtk_widget_get_width (widget) / 2;
else if ((handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_END &&
gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ||
(handle->role == GTK_TEXT_HANDLE_ROLE_SELECTION_START &&
gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL))
x -= gtk_widget_get_width (widget);
x = start_x + offset_x - handle->dx;
y = start_y + offset_y - handle->dy;
g_signal_emit (widget, signals[HANDLE_DRAGGED], 0, x, y);
}
@ -390,7 +457,15 @@ handle_drag_end (GtkGestureDrag *gesture,
double offset_y,
GtkTextHandle *handle)
{
g_signal_emit (handle, signals[DRAG_FINISHED], 0);
GdkEventSequence *sequence;
GtkEventSequenceState state;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
state = gtk_gesture_get_sequence_state (GTK_GESTURE (gesture), sequence);
if (state == GTK_EVENT_SEQUENCE_CLAIMED)
g_signal_emit (handle, signals[DRAG_FINISHED], 0);
handle->dragged = FALSE;
}
@ -422,20 +497,9 @@ gtk_text_handle_update_for_role (GtkTextHandle *handle)
}
static void
gtk_text_handle_init (GtkTextHandle *widget)
gtk_text_handle_init (GtkTextHandle *handle)
{
GtkEventController *controller;
controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
g_signal_connect (controller, "drag-begin",
G_CALLBACK (handle_drag_begin), widget);
g_signal_connect (controller, "drag-update",
G_CALLBACK (handle_drag_update), widget);
g_signal_connect (controller, "drag-end",
G_CALLBACK (handle_drag_end), widget);
gtk_widget_add_controller (GTK_WIDGET (widget), controller);
gtk_text_handle_update_for_role (GTK_TEXT_HANDLE (widget));
gtk_text_handle_update_for_role (handle);
}
GtkTextHandle *

View File

@ -5217,7 +5217,6 @@ gtk_text_view_update_handles (GtkTextView *text_view)
&cursor);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_CURSOR],
GTK_TEXT_HANDLE_ROLE_CURSOR);
gtk_widget_show (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
}
else if (gtk_text_iter_compare (&cursor, &bound) != 0)
{
@ -5227,14 +5226,12 @@ gtk_text_view_update_handles (GtkTextView *text_view)
&cursor);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_CURSOR],
GTK_TEXT_HANDLE_ROLE_SELECTION_START);
gtk_widget_show (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
gtk_text_view_set_handle_position (text_view,
priv->text_handles[TEXT_HANDLE_SELECTION_BOUND],
&bound);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND],
GTK_TEXT_HANDLE_ROLE_SELECTION_END);
gtk_widget_show (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
else
{
@ -5473,10 +5470,7 @@ gtk_text_view_click_gesture_pressed (GtkGestureClick *gesture,
gtk_text_view_selection_bubble_popup_unset (text_view);
if (is_touchscreen)
{
gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
priv->handle_place_time = g_get_monotonic_time ();
}
priv->handle_place_time = g_get_monotonic_time ();
else
gtk_text_view_start_selection_drag (text_view, &iter,
SELECT_CHARACTERS, extends);
@ -7344,11 +7338,6 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
priv = text_view->priv;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (!drag_gesture_get_text_surface_coords (gesture, text_view,
&start_x, &start_y, &x, &y))
return;
clicked_in_selection =
g_object_get_qdata (G_OBJECT (gesture), quark_text_selection_data) == NULL;
g_object_set_qdata (G_OBJECT (gesture), quark_text_selection_data, NULL);
@ -7363,6 +7352,10 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
if (priv->magnifier_popover)
gtk_widget_hide (priv->magnifier_popover);
if (!drag_gesture_get_text_surface_coords (gesture, text_view,
&start_x, &start_y, &x, &y))
return;
/* Check whether the drag was cancelled rather than finished */
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
return;
@ -7372,7 +7365,7 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
is_touchscreen = gtk_simulate_touchscreen () ||
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN;
if (!is_touchscreen && clicked_in_selection &&
if ((is_touchscreen || clicked_in_selection) &&
!gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
{
GtkTextIter iter;