[gtk/wip/exalm/consumes-motion: 126/127] dragsource: Use double coordinates for checking drag threshold




commit f63e6394ac32c9cbc85a344e1b22cbbd3188d7ee
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Fri Dec 25 22:57:48 2020 +0500

    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.

 gtk/gtkcolumnview.c        |  4 ++--
 gtk/gtkdragsource.c        | 21 +++++++++++++++++++--
 gtk/gtkdragsourceprivate.h | 33 +++++++++++++++++++++++++++++++++
 gtk/gtkentry.c             |  4 ++--
 gtk/gtkgesturelongpress.c  |  4 ++--
 gtk/gtkiconview.c          | 10 +++++-----
 gtk/gtkiconviewprivate.h   |  4 ++--
 gtk/gtkimcontextwayland.c  |  9 +++++----
 gtk/gtklabel.c             |  4 ++--
 gtk/gtklistbase.c          |  4 ++--
 gtk/gtknotebook.c          | 17 ++++++++++-------
 gtk/gtkplacessidebar.c     |  4 ++--
 gtk/gtkscrolledwindow.c    |  6 +++---
 gtk/gtktext.c              |  6 ++----
 gtk/gtktextview.c          |  5 +++--
 gtk/gtktreeview.c          |  4 ++--
 gtk/gtktreeviewcolumn.c    |  4 ++--
 17 files changed, 98 insertions(+), 45 deletions(-)
---
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index f00bede003..2e835d366a 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -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;
diff --git a/gtk/gtkdragsource.c b/gtk/gtkdragsource.c
index 98b96c7594..47f0ba179d 100644
--- a/gtk/gtkdragsource.c
+++ b/gtk/gtkdragsource.c
@@ -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);
+}
diff --git a/gtk/gtkdragsourceprivate.h b/gtk/gtkdragsourceprivate.h
new file mode 100644
index 0000000000..8226e3fee1
--- /dev/null
+++ b/gtk/gtkdragsourceprivate.h
@@ -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__ */
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 6a5d5cc6a1..cbffee7ffd 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -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;
diff --git a/gtk/gtkgesturelongpress.c b/gtk/gtkgesturelongpress.c
index 7a27a307fc..6bd92e380d 100644
--- a/gtk/gtkgesturelongpress.c
+++ b/gtk/gtkgesturelongpress.c
@@ -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)
         {
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 5d24c1f0bf..cce12cc45d 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -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);
diff --git a/gtk/gtkiconviewprivate.h b/gtk/gtkiconviewprivate.h
index ef785bad04..b5fa1358d1 100644
--- a/gtk/gtkiconviewprivate.h
+++ b/gtk/gtkiconviewprivate.h
@@ -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;
diff --git a/gtk/gtkimcontextwayland.c b/gtk/gtkimcontextwayland.c
index ad89d83a07..77264087eb 100644
--- a/gtk/gtkimcontextwayland.c
+++ b/gtk/gtkimcontextwayland.c
@@ -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);
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 9e8fe679a7..e6ca3a631c 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -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;
diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c
index ccb9ad23a5..53bf995c77 100644
--- a/gtk/gtklistbase.c
+++ b/gtk/gtklistbase.c
@@ -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);
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index ac1dbd88fe..ed712517b4 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -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);
 
diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c
index 41df790cc6..7c055296d3 100644
--- a/gtk/gtkplacessidebar.c
+++ b/gtk/gtkplacessidebar.c
@@ -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;
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 53136833c8..e0454e108d 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -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);
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index c39e007d61..6d10722e6b 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -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;
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 6f0bdb18bc..bece4d5839 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -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;
 
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index f6ed73b689..d1396e0d8a 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -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);
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index d546c994f2..74060e916b 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]