8156c2
From 388ed4984586f96250934a025b1c78915c4cd856 Mon Sep 17 00:00:00 2001
8156c2
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
8156c2
Date: Thu, 24 Oct 2019 21:19:36 +0200
8156c2
Subject: [PATCH 1/2] display: Move finishing of touch sequence to the backend
8156c2
8156c2
We need to manipulate an X11 grab when a touch sequence ends; move that
8156c2
logic to where it belongs - in the X11 backend.
8156c2
8156c2
https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
8156c2
---
8156c2
 src/backends/meta-backend-private.h     | 16 ++++++++++++
8156c2
 src/backends/meta-backend.c             | 14 +++++++++++
8156c2
 src/backends/x11/meta-backend-x11.c     | 23 +++++++++++++++++
8156c2
 src/core/display.c                      | 33 +++++++++++--------------
8156c2
 src/core/meta-gesture-tracker-private.h |  7 +-----
8156c2
 src/core/meta-gesture-tracker.c         |  1 +
8156c2
 6 files changed, 70 insertions(+), 24 deletions(-)
8156c2
8156c2
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
8156c2
index a25275499..7f4a4ea0f 100644
8156c2
--- a/src/backends/meta-backend-private.h
8156c2
+++ b/src/backends/meta-backend-private.h
8156c2
@@ -51,6 +51,14 @@
8156c2
 #define META_TYPE_BACKEND (meta_backend_get_type ())
8156c2
 G_DECLARE_DERIVABLE_TYPE (MetaBackend, meta_backend, META, BACKEND, GObject)
8156c2
 
8156c2
+typedef enum _MetaSequenceState
8156c2
+{
8156c2
+  META_SEQUENCE_NONE,
8156c2
+  META_SEQUENCE_ACCEPTED,
8156c2
+  META_SEQUENCE_REJECTED,
8156c2
+  META_SEQUENCE_PENDING_END
8156c2
+} MetaSequenceState;
8156c2
+
8156c2
 struct _MetaBackendClass
8156c2
 {
8156c2
   GObjectClass parent_class;
8156c2
@@ -73,6 +81,10 @@ struct _MetaBackendClass
8156c2
                               int          device_id,
8156c2
                               uint32_t     timestamp);
8156c2
 
8156c2
+  void (* finish_touch_sequence) (MetaBackend          *backend,
8156c2
+                                  ClutterEventSequence *sequence,
8156c2
+                                  MetaSequenceState     state);
8156c2
+
8156c2
   void (* warp_pointer) (MetaBackend *backend,
8156c2
                          int          x,
8156c2
                          int          y);
8156c2
@@ -134,6 +146,10 @@ gboolean meta_backend_ungrab_device (MetaBackend *backend,
8156c2
                                      int          device_id,
8156c2
                                      uint32_t     timestamp);
8156c2
 
8156c2
+void meta_backend_finish_touch_sequence (MetaBackend          *backend,
8156c2
+                                         ClutterEventSequence *sequence,
8156c2
+                                         MetaSequenceState     state);
8156c2
+
8156c2
 void meta_backend_warp_pointer (MetaBackend *backend,
8156c2
                                 int          x,
8156c2
                                 int          y);
8156c2
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
8156c2
index ce7e385b9..fb4f69fe6 100644
8156c2
--- a/src/backends/meta-backend.c
8156c2
+++ b/src/backends/meta-backend.c
8156c2
@@ -846,6 +846,20 @@ meta_backend_ungrab_device (MetaBackend *backend,
8156c2
   return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
8156c2
 }
8156c2
 
8156c2
+/**
8156c2
+ * meta_backend_finish_touch_sequence: (skip)
8156c2
+ */
8156c2
+void
8156c2
+meta_backend_finish_touch_sequence (MetaBackend          *backend,
8156c2
+                                    ClutterEventSequence *sequence,
8156c2
+                                    MetaSequenceState     state)
8156c2
+{
8156c2
+  if (META_BACKEND_GET_CLASS (backend)->finish_touch_sequence)
8156c2
+    META_BACKEND_GET_CLASS (backend)->finish_touch_sequence (backend,
8156c2
+                                                             sequence,
8156c2
+                                                             state);
8156c2
+}
8156c2
+
8156c2
 /**
8156c2
  * meta_backend_warp_pointer: (skip)
8156c2
  */
8156c2
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
8156c2
index 2b131d2d0..2835d47d6 100644
8156c2
--- a/src/backends/x11/meta-backend-x11.c
8156c2
+++ b/src/backends/x11/meta-backend-x11.c
8156c2
@@ -583,6 +583,28 @@ meta_backend_x11_ungrab_device (MetaBackend *backend,
8156c2
   return (ret == Success);
8156c2
 }
8156c2
 
8156c2
+static void
8156c2
+meta_backend_x11_finish_touch_sequence (MetaBackend          *backend,
8156c2
+                                        ClutterEventSequence *sequence,
8156c2
+                                        MetaSequenceState     state)
8156c2
+{
8156c2
+  MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
8156c2
+  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
8156c2
+  int event_mode;
8156c2
+
8156c2
+  if (state == META_SEQUENCE_ACCEPTED)
8156c2
+    event_mode = XIAcceptTouch;
8156c2
+  else if (state == META_SEQUENCE_REJECTED)
8156c2
+    event_mode = XIRejectTouch;
8156c2
+  else
8156c2
+    g_return_if_reached ();
8156c2
+
8156c2
+  XIAllowTouchEvents (priv->xdisplay,
8156c2
+                      META_VIRTUAL_CORE_POINTER_ID,
8156c2
+                      clutter_x11_event_sequence_get_touch_detail (sequence),
8156c2
+                      DefaultRootWindow (priv->xdisplay), event_mode);
8156c2
+}
8156c2
+
8156c2
 static void
8156c2
 meta_backend_x11_warp_pointer (MetaBackend *backend,
8156c2
                                int          x,
8156c2
@@ -768,6 +790,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
8156c2
   backend_class->post_init = meta_backend_x11_post_init;
8156c2
   backend_class->grab_device = meta_backend_x11_grab_device;
8156c2
   backend_class->ungrab_device = meta_backend_x11_ungrab_device;
8156c2
+  backend_class->finish_touch_sequence = meta_backend_x11_finish_touch_sequence;
8156c2
   backend_class->warp_pointer = meta_backend_x11_warp_pointer;
8156c2
   backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
8156c2
   backend_class->get_keymap = meta_backend_x11_get_keymap;
8156c2
diff --git a/src/core/display.c b/src/core/display.c
8156c2
index e7dd4534b..d4775cec3 100644
8156c2
--- a/src/core/display.c
8156c2
+++ b/src/core/display.c
8156c2
@@ -55,6 +55,7 @@
8156c2
 #include "backends/x11/meta-backend-x11.h"
8156c2
 #include "backends/meta-stage-private.h"
8156c2
 #include "backends/meta-input-settings-private.h"
8156c2
+#include "backends/meta-backend-private.h"
8156c2
 #include <clutter/x11/clutter-x11.h>
8156c2
 
8156c2
 #ifdef HAVE_RANDR
8156c2
@@ -533,27 +534,23 @@ gesture_tracker_state_changed (MetaGestureTracker   *tracker,
8156c2
                                MetaSequenceState     state,
8156c2
                                MetaDisplay          *display)
8156c2
 {
8156c2
-  if (meta_is_wayland_compositor ())
8156c2
+  switch (state)
8156c2
     {
8156c2
-      if (state == META_SEQUENCE_ACCEPTED)
8156c2
-        meta_display_cancel_touch (display);
8156c2
-    }
8156c2
-  else
8156c2
-    {
8156c2
-      MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
8156c2
-      int event_mode;
8156c2
+    case META_SEQUENCE_NONE:
8156c2
+    case META_SEQUENCE_PENDING_END:
8156c2
+      return;
8156c2
+    case META_SEQUENCE_ACCEPTED:
8156c2
+      meta_display_cancel_touch (display);
8156c2
 
8156c2
-      if (state == META_SEQUENCE_ACCEPTED)
8156c2
-        event_mode = XIAcceptTouch;
8156c2
-      else if (state == META_SEQUENCE_REJECTED)
8156c2
-        event_mode = XIRejectTouch;
8156c2
-      else
8156c2
-        return;
8156c2
+      /* Intentional fall-through */
8156c2
+    case META_SEQUENCE_REJECTED:
8156c2
+      {
8156c2
+        MetaBackend *backend;
8156c2
 
8156c2
-      XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
8156c2
-                          META_VIRTUAL_CORE_POINTER_ID,
8156c2
-                          clutter_x11_event_sequence_get_touch_detail (sequence),
8156c2
-                          DefaultRootWindow (display->xdisplay), event_mode);
8156c2
+        backend = meta_get_backend ();
8156c2
+        meta_backend_finish_touch_sequence (backend, sequence, state);
8156c2
+        break;
8156c2
+      }
8156c2
     }
8156c2
 }
8156c2
 
8156c2
diff --git a/src/core/meta-gesture-tracker-private.h b/src/core/meta-gesture-tracker-private.h
8156c2
index 0e39af27f..b4fb02a1e 100644
8156c2
--- a/src/core/meta-gesture-tracker-private.h
8156c2
+++ b/src/core/meta-gesture-tracker-private.h
8156c2
@@ -38,12 +38,7 @@
8156c2
 typedef struct _MetaGestureTracker MetaGestureTracker;
8156c2
 typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
8156c2
 
8156c2
-typedef enum {
8156c2
-  META_SEQUENCE_NONE,
8156c2
-  META_SEQUENCE_ACCEPTED,
8156c2
-  META_SEQUENCE_REJECTED,
8156c2
-  META_SEQUENCE_PENDING_END
8156c2
-} MetaSequenceState;
8156c2
+typedef enum _MetaSequenceState MetaSequenceState;
8156c2
 
8156c2
 struct _MetaGestureTracker
8156c2
 {
8156c2
diff --git a/src/core/meta-gesture-tracker.c b/src/core/meta-gesture-tracker.c
8156c2
index e3b702f56..1313aad6d 100644
8156c2
--- a/src/core/meta-gesture-tracker.c
8156c2
+++ b/src/core/meta-gesture-tracker.c
8156c2
@@ -31,6 +31,7 @@
8156c2
 #include "config.h"
8156c2
 #include "meta-gesture-tracker-private.h"
8156c2
 #include "meta-surface-actor.h"
8156c2
+#include "meta-backend-private.h"
8156c2
 
8156c2
 #define DISTANCE_THRESHOLD 30
8156c2
 
8156c2
-- 
8156c2
2.23.0
8156c2
8156c2
8156c2
From 75cf52ac533675ecf5d3542e9fba2937a56bfefd Mon Sep 17 00:00:00 2001
8156c2
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
8156c2
Date: Fri, 25 Oct 2019 10:06:55 +0200
8156c2
Subject: [PATCH 2/2] x11: Limit touch replay pointer events to when replaying
8156c2
8156c2
When a touch sequence was rejected, the emulated pointer events would be
8156c2
replayed with old timestamps. This caused issues with grabs as they
8156c2
would be ignored due to being too old. This was mitigated by making sure
8156c2
device event timestamps never travelled back in time by tampering with
8156c2
any event that had a timestamp seemingly in the past.
8156c2
8156c2
This failed when the most recent timestamp that had been received were
8156c2
much older than the timestamp of the new event. This could for example
8156c2
happen when a session was left not interacted with for 40+ days or so;
8156c2
when interacted with again, as any new timestamp would according to
8156c2
XSERVER_TIME_IS_BEFORE() still be in the past compared to the "most
8156c2
recent" one. The effect is that we'd always use the `latest_evtime` for
8156c2
all new device events without ever updating it.
8156c2
8156c2
The end result of this was that passive grabs would become active when
8156c2
interacted with, but would then newer be released, as the timestamps to
8156c2
XIAllowEvents() would out of date, resulting in the desktop effectively
8156c2
freezing, as the Shell would have an active pointer grab.
8156c2
8156c2
To avoid the situation where we get stuck with an old `latest_evtime`
8156c2
timestamp, limit the tampering with device event timestamp to 1) only
8156c2
pointer events, and 2) only during the replay sequence. The second part
8156c2
is implemented by sending an asynchronous message via the X server after
8156c2
rejecting a touch sequence, only potentially tampering with the device
8156c2
event timestamps until the reply. This should avoid the stuck timestamp
8156c2
as in those situations, we'll always have a relatively up to date
8156c2
`latest_evtime` meaning XSERVER_TIME_IS_BEFORE() will not get confused.
8156c2
8156c2
https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
8156c2
---
8156c2
 src/backends/x11/meta-backend-x11.c | 71 +++++++++++++++++++++++------
8156c2
 1 file changed, 58 insertions(+), 13 deletions(-)
8156c2
8156c2
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
8156c2
index 2835d47d6..3f8645e93 100644
8156c2
--- a/src/backends/x11/meta-backend-x11.c
8156c2
+++ b/src/backends/x11/meta-backend-x11.c
8156c2
@@ -60,6 +60,10 @@ struct _MetaBackendX11Private
8156c2
   XSyncAlarm user_active_alarm;
8156c2
   XSyncCounter counter;
8156c2
 
8156c2
+  int current_touch_replay_sync_serial;
8156c2
+  int pending_touch_replay_sync_serial;
8156c2
+  Atom touch_replay_sync_atom;
8156c2
+
8156c2
   int xinput_opcode;
8156c2
   int xinput_event_base;
8156c2
   int xinput_error_base;
8156c2
@@ -168,6 +172,26 @@ meta_backend_x11_translate_device_event (MetaBackendX11 *x11,
8156c2
   backend_x11_class->translate_device_event (x11, device_event);
8156c2
 }
8156c2
 
8156c2
+static void
8156c2
+maybe_translate_touch_replay_pointer_event (MetaBackendX11 *x11,
8156c2
+                                            XIDeviceEvent  *device_event)
8156c2
+{
8156c2
+  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
8156c2
+
8156c2
+  if (!device_event->send_event &&
8156c2
+      device_event->time != CurrentTime &&
8156c2
+      priv->current_touch_replay_sync_serial !=
8156c2
+      priv->pending_touch_replay_sync_serial &&
8156c2
+      XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
8156c2
+    {
8156c2
+      /* Emulated pointer events received after XIRejectTouch is received
8156c2
+       * on a passive touch grab will contain older timestamps, update those
8156c2
+       * so we dont get InvalidTime at grabs.
8156c2
+       */
8156c2
+      device_event->time = priv->latest_evtime;
8156c2
+    }
8156c2
+}
8156c2
+
8156c2
 static void
8156c2
 translate_device_event (MetaBackendX11 *x11,
8156c2
                         XIDeviceEvent  *device_event)
8156c2
@@ -177,19 +201,7 @@ translate_device_event (MetaBackendX11 *x11,
8156c2
   meta_backend_x11_translate_device_event (x11, device_event);
8156c2
 
8156c2
   if (!device_event->send_event && device_event->time != CurrentTime)
8156c2
-    {
8156c2
-      if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
8156c2
-        {
8156c2
-          /* Emulated pointer events received after XIRejectTouch is received
8156c2
-           * on a passive touch grab will contain older timestamps, update those
8156c2
-           * so we dont get InvalidTime at grabs.
8156c2
-           */
8156c2
-          device_event->time = priv->latest_evtime;
8156c2
-        }
8156c2
-
8156c2
-      /* Update the internal latest evtime, for any possible later use */
8156c2
-      priv->latest_evtime = device_event->time;
8156c2
-    }
8156c2
+    priv->latest_evtime = device_event->time;
8156c2
 }
8156c2
 
8156c2
 static void
8156c2
@@ -254,6 +266,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
8156c2
     case XI_Motion:
8156c2
     case XI_ButtonPress:
8156c2
     case XI_ButtonRelease:
8156c2
+      maybe_translate_touch_replay_pointer_event (x11,
8156c2
+                                                  (XIDeviceEvent *) input_event);
8156c2
+      /* Intentional fall-through */
8156c2
     case XI_KeyPress:
8156c2
     case XI_KeyRelease:
8156c2
     case XI_TouchBegin:
8156c2
@@ -321,6 +336,17 @@ handle_host_xevent (MetaBackend *backend,
8156c2
   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
8156c2
   gboolean bypass_clutter = FALSE;
8156c2
 
8156c2
+  switch (event->type)
8156c2
+    {
8156c2
+    case ClientMessage:
8156c2
+      if (event->xclient.window == meta_backend_x11_get_xwindow (x11) &&
8156c2
+          event->xclient.message_type == priv->touch_replay_sync_atom)
8156c2
+        priv->current_touch_replay_sync_serial = event->xclient.data.l[0];
8156c2
+      break;
8156c2
+    default:
8156c2
+      break;
8156c2
+    }
8156c2
+
8156c2
   XGetEventData (priv->xdisplay, &event->xcookie);
8156c2
 
8156c2
   {
8156c2
@@ -528,6 +554,10 @@ meta_backend_x11_post_init (MetaBackend *backend)
8156c2
   monitor_manager = meta_backend_get_monitor_manager (backend);
8156c2
   g_signal_connect (monitor_manager, "monitors-changed-internal",
8156c2
                     G_CALLBACK (on_monitors_changed), backend);
8156c2
+
8156c2
+  priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay,
8156c2
+                                              "_MUTTER_TOUCH_SEQUENCE_SYNC",
8156c2
+                                              False);
8156c2
 }
8156c2
 
8156c2
 static ClutterBackend *
8156c2
@@ -603,6 +633,21 @@ meta_backend_x11_finish_touch_sequence (MetaBackend          *backend,
8156c2
                       META_VIRTUAL_CORE_POINTER_ID,
8156c2
                       clutter_x11_event_sequence_get_touch_detail (sequence),
8156c2
                       DefaultRootWindow (priv->xdisplay), event_mode);
8156c2
+
8156c2
+  if (state == META_SEQUENCE_REJECTED)
8156c2
+    {
8156c2
+      XClientMessageEvent ev;
8156c2
+
8156c2
+      ev = (XClientMessageEvent) {
8156c2
+          .type = ClientMessage,
8156c2
+            .window = meta_backend_x11_get_xwindow (x11),
8156c2
+            .message_type = priv->touch_replay_sync_atom,
8156c2
+            .format = 32,
8156c2
+            .data.l[0] = ++priv->pending_touch_replay_sync_serial,
8156c2
+      };
8156c2
+      XSendEvent (priv->xdisplay, meta_backend_x11_get_xwindow (x11),
8156c2
+                  False, 0, (XEvent *) &ev;;
8156c2
+    }
8156c2
 }
8156c2
 
8156c2
 static void
8156c2
-- 
8156c2
2.23.0
8156c2