forked from AuroraMiddleware/gtk
dragsource: Use double coordinates for checking drag threshold
If multiple nested widgets have drag sources on them, both using bubble phase, we need to reliably pick the inner one. Both of them will try to start dragging, and we need to make sure there are no situations where the outer widget starts drag earlier and cancels the inner one. Currently, this can easily happen via integer rounding: start and current coordinates passed into gtk_drag_check_threshold() are initially doubles (other than in GtkNotebook and GtkIconView), and are casted to ints. Then those rounded values are used to calculate deltas to compare to the drag threshold, losing quite a lot of precision along the way, and often resulting in the outer widget getting larger deltas. To avoid it, just don't round it. Introduce a variant of the function that operates on doubles: gtk_drag_check_threshold_double() and use it instead of the original everywhere.
This commit is contained in:
parent
bbca4c38df
commit
f63e6394ac
@ -39,7 +39,7 @@
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkgestureclick.h"
|
||||
|
||||
@ -1128,7 +1128,7 @@ header_drag_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (!self->in_column_resize && !self->in_column_reorder)
|
||||
{
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, 0))
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, 0))
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
GtkWidget *header;
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgesturesingleprivate.h"
|
||||
@ -292,7 +292,7 @@ gtk_drag_source_update (GtkGesture *gesture,
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
if (gtk_drag_check_threshold (widget, source->start_x, source->start_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (widget, source->start_x, source->start_y, x, y))
|
||||
{
|
||||
gtk_drag_source_drag_begin (source);
|
||||
}
|
||||
@ -796,3 +796,20 @@ gtk_drag_check_threshold (GtkWidget *widget,
|
||||
return (ABS (current_x - start_x) > drag_threshold ||
|
||||
ABS (current_y - start_y) > drag_threshold);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_drag_check_threshold_double (GtkWidget *widget,
|
||||
double start_x,
|
||||
double start_y,
|
||||
double current_x,
|
||||
double current_y)
|
||||
{
|
||||
int drag_threshold;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
|
||||
drag_threshold = gtk_settings_get_dnd_drag_threshold (gtk_widget_get_settings (widget));
|
||||
|
||||
return (ABS (current_x - start_x) > drag_threshold ||
|
||||
ABS (current_y - start_y) > drag_threshold);
|
||||
}
|
||||
|
33
gtk/gtkdragsourceprivate.h
Normal file
33
gtk/gtkdragsourceprivate.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2020 Alexander Mikhaylenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DRAG_SOURCE_PRIVATE_H__
|
||||
#define __GTK_DRAG_SOURCE_PRIVATE_H__
|
||||
|
||||
#include "gtkdragsource.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean gtk_drag_check_threshold_double (GtkWidget *widget,
|
||||
double start_x,
|
||||
double start_y,
|
||||
double current_x,
|
||||
double current_y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_DRAG_SOURCE_PRIVATE_H__ */
|
@ -65,7 +65,7 @@
|
||||
#include "gtkwindow.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
|
||||
@ -1598,7 +1598,7 @@ icon_drag_update_cb (GtkGestureDrag *gesture,
|
||||
icon_info = priv->icons[pos];
|
||||
|
||||
if (icon_info->content != NULL &&
|
||||
gtk_drag_check_threshold (icon_info->widget, 0, 0, offset_x, offset_y))
|
||||
gtk_drag_check_threshold_double (icon_info->widget, 0, 0, offset_x, offset_y))
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
GdkSurface *surface;
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "gtkgesturelongpressprivate.h"
|
||||
#include "gtkgestureprivate.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmarshalers.h"
|
||||
@ -159,7 +159,7 @@ gtk_gesture_long_press_update (GtkGesture *gesture,
|
||||
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
|
||||
gtk_gesture_get_point (gesture, sequence, &x, &y);
|
||||
|
||||
if (gtk_drag_check_threshold (widget, priv->initial_x, priv->initial_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (widget, priv->initial_x, priv->initial_y, x, y))
|
||||
{
|
||||
if (priv->timeout_id)
|
||||
{
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "gtkcellrenderer.h"
|
||||
#include "gtkcellrendererpixbuf.h"
|
||||
#include "gtkcellrenderertext.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkentry.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@ -5884,10 +5884,10 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
if (icon_view->priv->pressed_button < 0)
|
||||
goto out;
|
||||
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y,
|
||||
x, y))
|
||||
if (!gtk_drag_check_threshold_double (GTK_WIDGET (icon_view),
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y,
|
||||
x, y))
|
||||
goto out;
|
||||
|
||||
model = gtk_icon_view_get_model (icon_view);
|
||||
|
@ -133,8 +133,8 @@ struct _GtkIconViewPrivate
|
||||
/* Drag-and-drop. */
|
||||
GdkModifierType start_button_mask;
|
||||
int pressed_button;
|
||||
int press_start_x;
|
||||
int press_start_y;
|
||||
double press_start_x;
|
||||
double press_start_y;
|
||||
|
||||
GdkContentFormats *source_formats;
|
||||
GtkDropTargetAsync *dest;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include "gtk/gtkdragsourceprivate.h"
|
||||
#include "gtk/gtkimcontextwayland.h"
|
||||
#include "gtk/gtkintl.h"
|
||||
#include "gtk/gtkimmoduleprivate.h"
|
||||
@ -524,10 +525,10 @@ released_cb (GtkGestureClick *gesture,
|
||||
if (global->focused &&
|
||||
n_press == 1 &&
|
||||
(hints & GTK_INPUT_HINT_INHIBIT_OSK) == 0 &&
|
||||
!gtk_drag_check_threshold (context->widget,
|
||||
context->press_x,
|
||||
context->press_y,
|
||||
x, y))
|
||||
!gtk_drag_check_threshold_double (context->widget,
|
||||
context->press_x,
|
||||
context->press_y,
|
||||
x, y))
|
||||
{
|
||||
zwp_text_input_v3_enable (global->text_input);
|
||||
g_signal_emit_by_name (global->current, "retrieve-surrounding", &result);
|
||||
|
@ -49,7 +49,7 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
|
||||
@ -4273,7 +4273,7 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (info->in_drag)
|
||||
{
|
||||
if (gtk_drag_check_threshold (widget, info->drag_start_x, info->drag_start_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (widget, info->drag_start_x, info->drag_start_y, x, y))
|
||||
{
|
||||
GdkDrag *drag;
|
||||
GdkSurface *surface;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdropcontrollermotion.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgizmoprivate.h"
|
||||
@ -1709,7 +1709,7 @@ gtk_list_base_drag_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (!priv->rubberband)
|
||||
{
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
|
||||
if (!gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
|
||||
return;
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
@ -50,7 +50,7 @@
|
||||
#include "gtkstack.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
@ -248,14 +248,14 @@ struct _GtkNotebook
|
||||
GList *first_tab; /* The first tab visible (for scrolling notebooks) */
|
||||
GList *focus_tab;
|
||||
|
||||
int drag_begin_x;
|
||||
int drag_begin_y;
|
||||
double drag_begin_x;
|
||||
double drag_begin_y;
|
||||
int drag_offset_x;
|
||||
int drag_offset_y;
|
||||
int drag_surface_x;
|
||||
int drag_surface_y;
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
double mouse_x;
|
||||
double mouse_y;
|
||||
int pressed_button;
|
||||
|
||||
GQuark group;
|
||||
@ -2934,8 +2934,11 @@ gtk_notebook_motion (GtkEventController *controller,
|
||||
|
||||
if (page->reorderable &&
|
||||
(notebook->operation == DRAG_OPERATION_REORDER ||
|
||||
gtk_drag_check_threshold (widget, notebook->drag_begin_x, notebook->drag_begin_y,
|
||||
notebook->mouse_x, notebook->mouse_y)))
|
||||
gtk_drag_check_threshold_double (widget,
|
||||
notebook->drag_begin_x,
|
||||
notebook->drag_begin_y,
|
||||
notebook->mouse_x,
|
||||
notebook->mouse_y)))
|
||||
{
|
||||
GtkNotebookPointerPosition pointer_position = get_pointer_position (notebook);
|
||||
|
||||
|
@ -60,7 +60,7 @@
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
|
||||
/*< private >
|
||||
@ -3451,7 +3451,7 @@ on_row_dragged (GtkGestureDrag *gesture,
|
||||
return;
|
||||
}
|
||||
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (row), 0, 0, x, y))
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (row), 0, 0, x, y))
|
||||
{
|
||||
double start_x, start_y;
|
||||
double drag_x, drag_y;
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkadjustmentprivate.h"
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkeventcontrollerscroll.h"
|
||||
#include "gtkeventcontrollerprivate.h"
|
||||
@ -953,8 +953,8 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
|
||||
GtkAdjustment *vadjustment;
|
||||
double dx, dy;
|
||||
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (scrolled_window),
|
||||
0, 0, offset_x, offset_y))
|
||||
if (!gtk_drag_check_threshold_double (GTK_WIDGET (scrolled_window),
|
||||
0, 0, offset_x, offset_y))
|
||||
return;
|
||||
|
||||
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "gtkbutton.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdroptarget.h"
|
||||
#include "gtkeditable.h"
|
||||
#include "gtkemojichooser.h"
|
||||
@ -2941,9 +2941,7 @@ gtk_text_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
if (priv->in_drag)
|
||||
{
|
||||
if (gtk_text_get_display_mode (self) == DISPLAY_NORMAL &&
|
||||
gtk_drag_check_threshold (widget,
|
||||
priv->drag_start_x, priv->drag_start_y,
|
||||
x, y))
|
||||
gtk_drag_check_threshold_double (widget, 0, 0, offset_x, offset_y))
|
||||
{
|
||||
int *ranges;
|
||||
int n_ranges;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "gtkadjustmentprivate.h"
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdropcontrollermotion.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@ -7232,7 +7233,7 @@ gtk_text_view_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
/* If no data is attached, the initial press happened within the current
|
||||
* text selection, check for drag and drop to be initiated.
|
||||
*/
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (text_view), 0, 0, offset_x, offset_y))
|
||||
{
|
||||
if (!is_touchscreen)
|
||||
{
|
||||
@ -7366,7 +7367,7 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
|
||||
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN;
|
||||
|
||||
if ((is_touchscreen || clicked_in_selection) &&
|
||||
!gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
|
||||
!gtk_drag_check_threshold_double (GTK_WIDGET (text_view), 0, 0, offset_x, offset_y))
|
||||
{
|
||||
GtkTextIter iter;
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "gtkcellrenderer.h"
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkdroptargetasync.h"
|
||||
#include "gtkentryprivate.h"
|
||||
@ -7052,7 +7052,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
|
||||
gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (priv->drag_gesture),
|
||||
&offset_x, &offset_y);
|
||||
|
||||
if (!gtk_drag_check_threshold (widget, 0, 0, offset_x, offset_y))
|
||||
if (!gtk_drag_check_threshold_double (widget, 0, 0, offset_x, offset_y))
|
||||
goto out;
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "gtkcellareabox.h"
|
||||
#include "gtkcellareacontext.h"
|
||||
#include "gtkcelllayout.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkframe.h"
|
||||
#include "gtkimage.h"
|
||||
#include "gtkintl.h"
|
||||
@ -1072,7 +1072,7 @@ column_button_drag_update (GtkGestureDrag *gesture,
|
||||
{
|
||||
GtkTreeViewColumnPrivate *priv = column->priv;
|
||||
|
||||
if (gtk_drag_check_threshold (priv->button, 0, 0, offset_x, offset_y))
|
||||
if (gtk_drag_check_threshold_double (priv->button, 0, 0, offset_x, offset_y))
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
_gtk_tree_view_column_start_drag (GTK_TREE_VIEW (priv->tree_view), column,
|
||||
|
Loading…
Reference in New Issue
Block a user