[libhandy] swipe-tracker: Special case dragging from buttons



commit 52eabe10f52a53794a90921baa78792f99c304a9
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Wed Sep 23 13:29:02 2020 +0500

    swipe-tracker: Special case dragging from buttons
    
    Fixes https://source.puri.sm/Librem5/phosh/-/issues/373

 src/hdy-swipe-tracker.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 64 insertions(+), 2 deletions(-)
---
diff --git a/src/hdy-swipe-tracker.c b/src/hdy-swipe-tracker.c
index 0cbf4a44..5b1fc3e9 100644
--- a/src/hdy-swipe-tracker.c
+++ b/src/hdy-swipe-tracker.c
@@ -59,6 +59,7 @@ struct _HdySwipeTracker
 
   gint start_x;
   gint start_y;
+  gboolean use_capture_phase;
 
   guint32 prev_time;
   gdouble velocity;
@@ -113,6 +114,7 @@ reset (HdySwipeTracker *self)
 
   self->start_x = 0;
   self->start_y = 0;
+  self->use_capture_phase = FALSE;
 
   self->prev_time = 0;
   self->velocity = 0;
@@ -541,6 +543,27 @@ is_window_handle (GtkWidget *widget)
   return parent == titlebar;
 }
 
+/* HACK: Since we don't have _gtk_widget_consumes_motion(), we can't do a proper
+ * check for whether we can drag from a widget or not. So we trust the widgets
+ * to propagate or stop their events. However, GtkButton stops press events,
+ * making it impossible to drag from it.
+ */
+static gboolean
+should_force_drag (HdySwipeTracker *self,
+                   GtkWidget       *widget)
+{
+  GtkWidget *parent;
+
+  if (!GTK_IS_BUTTON (widget))
+    return FALSE;
+
+  parent = widget;
+  while (parent && !HDY_IS_SWIPEABLE (parent))
+    parent = gtk_widget_get_parent (parent);
+
+  return parent == GTK_WIDGET (self->swipeable);
+}
+
 static gboolean
 handle_event_cb (HdySwipeTracker *self,
                  GdkEvent        *event)
@@ -553,6 +576,9 @@ handle_event_cb (HdySwipeTracker *self,
   if (!self->enabled && self->state != HDY_SWIPE_TRACKER_STATE_SCROLLING)
     return GDK_EVENT_PROPAGATE;
 
+  if (self->use_capture_phase)
+    return GDK_EVENT_PROPAGATE;
+
   if (event->type == GDK_SCROLL)
     return handle_scroll_event (self, event, FALSE);
 
@@ -592,16 +618,52 @@ captured_event_cb (HdySwipeable *swipeable,
                    GdkEvent     *event)
 {
   HdySwipeTracker *self = hdy_swipeable_get_swipe_tracker (swipeable);
+  GtkWidget *widget;
+  GdkEventSequence *sequence;
+  gboolean retval;
+  GtkEventSequenceState state;
 
   g_assert (HDY_IS_SWIPE_TRACKER (self));
 
   if (!self->enabled && self->state != HDY_SWIPE_TRACKER_STATE_SCROLLING)
     return GDK_EVENT_PROPAGATE;
 
-  if (event->type != GDK_SCROLL)
+  if (event->type == GDK_SCROLL)
+    return handle_scroll_event (self, event, TRUE);
+
+  if (event->type != GDK_BUTTON_PRESS &&
+      event->type != GDK_BUTTON_RELEASE &&
+      event->type != GDK_MOTION_NOTIFY &&
+      event->type != GDK_TOUCH_BEGIN &&
+      event->type != GDK_TOUCH_END &&
+      event->type != GDK_TOUCH_UPDATE &&
+      event->type != GDK_TOUCH_CANCEL)
+    return GDK_EVENT_PROPAGATE;
+
+  widget = gtk_get_event_widget (event);
+
+  if (!self->use_capture_phase && !should_force_drag (self, widget))
+    return GDK_EVENT_PROPAGATE;
+
+  self->use_capture_phase = TRUE;
+
+  sequence = gdk_event_get_event_sequence (event);
+  retval = gtk_event_controller_handle_event (GTK_EVENT_CONTROLLER (self->touch_gesture), event);
+  state = gtk_gesture_get_sequence_state (self->touch_gesture, sequence);
+
+  if (state == GTK_EVENT_SEQUENCE_DENIED) {
+    gtk_event_controller_reset (GTK_EVENT_CONTROLLER (self->touch_gesture));
     return GDK_EVENT_PROPAGATE;
+  }
+
+  if (self->state == HDY_SWIPE_TRACKER_STATE_SCROLLING) {
+    return GDK_EVENT_STOP;
+  } else if (self->state == HDY_SWIPE_TRACKER_STATE_FINISHING) {
+    reset (self);
+    return GDK_EVENT_STOP;
+  }
 
-  return handle_scroll_event (self, event, TRUE);
+  return retval;
 }
 
 static void


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