657d8e
From 05bca153bb92c5daa5b961214ff7f80af88cb7cf Mon Sep 17 00:00:00 2001
657d8e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
657d8e
Date: Thu, 24 Oct 2019 21:19:36 +0200
657d8e
Subject: [PATCH 1/2] display: Move finishing of touch sequence to the backend
657d8e
657d8e
We need to manipulate an X11 grab when a touch sequence ends; move that
657d8e
logic to where it belongs - in the X11 backend.
657d8e
657d8e
https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
657d8e
---
657d8e
 src/backends/meta-backend-private.h     | 16 ++++++++++++
657d8e
 src/backends/meta-backend.c             | 14 +++++++++++
657d8e
 src/backends/x11/meta-backend-x11.c     | 23 +++++++++++++++++
657d8e
 src/core/display.c                      | 33 +++++++++++--------------
657d8e
 src/core/meta-gesture-tracker-private.h |  9 +------
657d8e
 5 files changed, 69 insertions(+), 26 deletions(-)
657d8e
657d8e
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
657d8e
index 7eba1806b..81ec81e5f 100644
657d8e
--- a/src/backends/meta-backend-private.h
657d8e
+++ b/src/backends/meta-backend-private.h
657d8e
@@ -49,6 +49,14 @@
657d8e
 #define DEFAULT_XKB_RULES_FILE "evdev"
657d8e
 #define DEFAULT_XKB_MODEL "pc105+inet"
657d8e
 
657d8e
+typedef enum
657d8e
+{
657d8e
+  META_SEQUENCE_NONE,
657d8e
+  META_SEQUENCE_ACCEPTED,
657d8e
+  META_SEQUENCE_REJECTED,
657d8e
+  META_SEQUENCE_PENDING_END
657d8e
+} MetaSequenceState;
657d8e
+
657d8e
 struct _MetaBackendClass
657d8e
 {
657d8e
   GObjectClass parent_class;
657d8e
@@ -71,6 +79,10 @@ struct _MetaBackendClass
657d8e
                               int          device_id,
657d8e
                               uint32_t     timestamp);
657d8e
 
657d8e
+  void (* finish_touch_sequence) (MetaBackend          *backend,
657d8e
+                                  ClutterEventSequence *sequence,
657d8e
+                                  MetaSequenceState     state);
657d8e
+
657d8e
   void (* warp_pointer) (MetaBackend *backend,
657d8e
                          int          x,
657d8e
                          int          y);
657d8e
@@ -135,6 +147,10 @@ gboolean meta_backend_ungrab_device (MetaBackend *backend,
657d8e
                                      int          device_id,
657d8e
                                      uint32_t     timestamp);
657d8e
 
657d8e
+void meta_backend_finish_touch_sequence (MetaBackend          *backend,
657d8e
+                                         ClutterEventSequence *sequence,
657d8e
+                                         MetaSequenceState     state);
657d8e
+
657d8e
 void meta_backend_warp_pointer (MetaBackend *backend,
657d8e
                                 int          x,
657d8e
                                 int          y);
657d8e
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
657d8e
index c980cf150..bb7d66f2a 100644
657d8e
--- a/src/backends/meta-backend.c
657d8e
+++ b/src/backends/meta-backend.c
657d8e
@@ -1086,6 +1086,20 @@ meta_backend_ungrab_device (MetaBackend *backend,
657d8e
   return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
657d8e
 }
657d8e
 
657d8e
+/**
657d8e
+ * meta_backend_finish_touch_sequence: (skip)
657d8e
+ */
657d8e
+void
657d8e
+meta_backend_finish_touch_sequence (MetaBackend          *backend,
657d8e
+                                    ClutterEventSequence *sequence,
657d8e
+                                    MetaSequenceState     state)
657d8e
+{
657d8e
+  if (META_BACKEND_GET_CLASS (backend)->finish_touch_sequence)
657d8e
+    META_BACKEND_GET_CLASS (backend)->finish_touch_sequence (backend,
657d8e
+                                                             sequence,
657d8e
+                                                             state);
657d8e
+}
657d8e
+
657d8e
 /**
657d8e
  * meta_backend_warp_pointer: (skip)
657d8e
  */
657d8e
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
657d8e
index c10365f9d..cdefa50a9 100644
657d8e
--- a/src/backends/x11/meta-backend-x11.c
657d8e
+++ b/src/backends/x11/meta-backend-x11.c
657d8e
@@ -591,6 +591,28 @@ meta_backend_x11_ungrab_device (MetaBackend *backend,
657d8e
   return (ret == Success);
657d8e
 }
657d8e
 
657d8e
+static void
657d8e
+meta_backend_x11_finish_touch_sequence (MetaBackend          *backend,
657d8e
+                                        ClutterEventSequence *sequence,
657d8e
+                                        MetaSequenceState     state)
657d8e
+{
657d8e
+  MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
657d8e
+  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
657d8e
+  int event_mode;
657d8e
+
657d8e
+  if (state == META_SEQUENCE_ACCEPTED)
657d8e
+    event_mode = XIAcceptTouch;
657d8e
+  else if (state == META_SEQUENCE_REJECTED)
657d8e
+    event_mode = XIRejectTouch;
657d8e
+  else
657d8e
+    g_return_if_reached ();
657d8e
+
657d8e
+  XIAllowTouchEvents (priv->xdisplay,
657d8e
+                      META_VIRTUAL_CORE_POINTER_ID,
657d8e
+                      clutter_x11_event_sequence_get_touch_detail (sequence),
657d8e
+                      DefaultRootWindow (priv->xdisplay), event_mode);
657d8e
+}
657d8e
+
657d8e
 static void
657d8e
 meta_backend_x11_warp_pointer (MetaBackend *backend,
657d8e
                                int          x,
657d8e
@@ -776,6 +798,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
657d8e
   backend_class->post_init = meta_backend_x11_post_init;
657d8e
   backend_class->grab_device = meta_backend_x11_grab_device;
657d8e
   backend_class->ungrab_device = meta_backend_x11_ungrab_device;
657d8e
+  backend_class->finish_touch_sequence = meta_backend_x11_finish_touch_sequence;
657d8e
   backend_class->warp_pointer = meta_backend_x11_warp_pointer;
657d8e
   backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
657d8e
   backend_class->get_keymap = meta_backend_x11_get_keymap;
657d8e
diff --git a/src/core/display.c b/src/core/display.c
657d8e
index 4c8907f40..eb7dc43b6 100644
657d8e
--- a/src/core/display.c
657d8e
+++ b/src/core/display.c
657d8e
@@ -42,6 +42,7 @@
657d8e
 #include <X11/extensions/Xdamage.h>
657d8e
 #include <X11/extensions/Xfixes.h>
657d8e
 
657d8e
+#include "backends/meta-backend-private.h"
657d8e
 #include "backends/meta-cursor-sprite-xcursor.h"
657d8e
 #include "backends/meta-cursor-tracker-private.h"
657d8e
 #include "backends/meta-idle-monitor-dbus.h"
657d8e
@@ -598,27 +599,23 @@ gesture_tracker_state_changed (MetaGestureTracker   *tracker,
657d8e
                                MetaSequenceState     state,
657d8e
                                MetaDisplay          *display)
657d8e
 {
657d8e
-  if (meta_is_wayland_compositor ())
657d8e
+  switch (state)
657d8e
     {
657d8e
-      if (state == META_SEQUENCE_ACCEPTED)
657d8e
-        meta_display_cancel_touch (display);
657d8e
-    }
657d8e
-  else
657d8e
-    {
657d8e
-      MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
657d8e
-      int event_mode;
657d8e
+    case META_SEQUENCE_NONE:
657d8e
+    case META_SEQUENCE_PENDING_END:
657d8e
+      return;
657d8e
+    case META_SEQUENCE_ACCEPTED:
657d8e
+      meta_display_cancel_touch (display);
657d8e
 
657d8e
-      if (state == META_SEQUENCE_ACCEPTED)
657d8e
-        event_mode = XIAcceptTouch;
657d8e
-      else if (state == META_SEQUENCE_REJECTED)
657d8e
-        event_mode = XIRejectTouch;
657d8e
-      else
657d8e
-        return;
657d8e
+      /* Intentional fall-through */
657d8e
+    case META_SEQUENCE_REJECTED:
657d8e
+      {
657d8e
+        MetaBackend *backend;
657d8e
 
657d8e
-      XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
657d8e
-                          META_VIRTUAL_CORE_POINTER_ID,
657d8e
-                          clutter_x11_event_sequence_get_touch_detail (sequence),
657d8e
-                          DefaultRootWindow (display->x11_display->xdisplay), event_mode);
657d8e
+        backend = meta_get_backend ();
657d8e
+        meta_backend_finish_touch_sequence (backend, sequence, state);
657d8e
+        break;
657d8e
+      }
657d8e
     }
657d8e
 }
657d8e
 
657d8e
diff --git a/src/core/meta-gesture-tracker-private.h b/src/core/meta-gesture-tracker-private.h
657d8e
index a9db35ebc..e7bfc5472 100644
657d8e
--- a/src/core/meta-gesture-tracker-private.h
657d8e
+++ b/src/core/meta-gesture-tracker-private.h
657d8e
@@ -26,6 +26,7 @@
657d8e
 
657d8e
 #include <glib-object.h>
657d8e
 
657d8e
+#include "backends/meta-backend-private.h"
657d8e
 #include "clutter/clutter.h"
657d8e
 #include "meta/window.h"
657d8e
 
657d8e
@@ -39,14 +40,6 @@
657d8e
 typedef struct _MetaGestureTracker MetaGestureTracker;
657d8e
 typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
657d8e
 
657d8e
-typedef enum
657d8e
-{
657d8e
-  META_SEQUENCE_NONE,
657d8e
-  META_SEQUENCE_ACCEPTED,
657d8e
-  META_SEQUENCE_REJECTED,
657d8e
-  META_SEQUENCE_PENDING_END
657d8e
-} MetaSequenceState;
657d8e
-
657d8e
 struct _MetaGestureTracker
657d8e
 {
657d8e
   GObject parent_instance;
657d8e
-- 
657d8e
2.23.0
657d8e
657d8e
657d8e
From 8cf4f500defb421d5c96f2c1f9fcf7bb5545d70d Mon Sep 17 00:00:00 2001
657d8e
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
657d8e
Date: Fri, 25 Oct 2019 10:06:55 +0200
657d8e
Subject: [PATCH 2/2] x11: Limit touch replay pointer events to when replaying
657d8e
657d8e
When a touch sequence was rejected, the emulated pointer events would be
657d8e
replayed with old timestamps. This caused issues with grabs as they
657d8e
would be ignored due to being too old. This was mitigated by making sure
657d8e
device event timestamps never travelled back in time by tampering with
657d8e
any event that had a timestamp seemingly in the past.
657d8e
657d8e
This failed when the most recent timestamp that had been received were
657d8e
much older than the timestamp of the new event. This could for example
657d8e
happen when a session was left not interacted with for 40+ days or so;
657d8e
when interacted with again, as any new timestamp would according to
657d8e
XSERVER_TIME_IS_BEFORE() still be in the past compared to the "most
657d8e
recent" one. The effect is that we'd always use the `latest_evtime` for
657d8e
all new device events without ever updating it.
657d8e
657d8e
The end result of this was that passive grabs would become active when
657d8e
interacted with, but would then newer be released, as the timestamps to
657d8e
XIAllowEvents() would out of date, resulting in the desktop effectively
657d8e
freezing, as the Shell would have an active pointer grab.
657d8e
657d8e
To avoid the situation where we get stuck with an old `latest_evtime`
657d8e
timestamp, limit the tampering with device event timestamp to 1) only
657d8e
pointer events, and 2) only during the replay sequence. The second part
657d8e
is implemented by sending an asynchronous message via the X server after
657d8e
rejecting a touch sequence, only potentially tampering with the device
657d8e
event timestamps until the reply. This should avoid the stuck timestamp
657d8e
as in those situations, we'll always have a relatively up to date
657d8e
`latest_evtime` meaning XSERVER_TIME_IS_BEFORE() will not get confused.
657d8e
657d8e
https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
657d8e
---
657d8e
 src/backends/x11/meta-backend-x11.c | 71 +++++++++++++++++++++++------
657d8e
 1 file changed, 58 insertions(+), 13 deletions(-)
657d8e
657d8e
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
657d8e
index cdefa50a9..821b30f5b 100644
657d8e
--- a/src/backends/x11/meta-backend-x11.c
657d8e
+++ b/src/backends/x11/meta-backend-x11.c
657d8e
@@ -66,6 +66,10 @@ struct _MetaBackendX11Private
657d8e
   XSyncAlarm user_active_alarm;
657d8e
   XSyncCounter counter;
657d8e
 
657d8e
+  int current_touch_replay_sync_serial;
657d8e
+  int pending_touch_replay_sync_serial;
657d8e
+  Atom touch_replay_sync_atom;
657d8e
+
657d8e
   int xinput_opcode;
657d8e
   int xinput_event_base;
657d8e
   int xinput_error_base;
657d8e
@@ -174,6 +178,26 @@ meta_backend_x11_translate_device_event (MetaBackendX11 *x11,
657d8e
   backend_x11_class->translate_device_event (x11, device_event);
657d8e
 }
657d8e
 
657d8e
+static void
657d8e
+maybe_translate_touch_replay_pointer_event (MetaBackendX11 *x11,
657d8e
+                                            XIDeviceEvent  *device_event)
657d8e
+{
657d8e
+  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
657d8e
+
657d8e
+  if (!device_event->send_event &&
657d8e
+      device_event->time != META_CURRENT_TIME &&
657d8e
+      priv->current_touch_replay_sync_serial !=
657d8e
+      priv->pending_touch_replay_sync_serial &&
657d8e
+      XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
657d8e
+    {
657d8e
+      /* Emulated pointer events received after XIRejectTouch is received
657d8e
+       * on a passive touch grab will contain older timestamps, update those
657d8e
+       * so we dont get InvalidTime at grabs.
657d8e
+       */
657d8e
+      device_event->time = priv->latest_evtime;
657d8e
+    }
657d8e
+}
657d8e
+
657d8e
 static void
657d8e
 translate_device_event (MetaBackendX11 *x11,
657d8e
                         XIDeviceEvent  *device_event)
657d8e
@@ -183,19 +207,7 @@ translate_device_event (MetaBackendX11 *x11,
657d8e
   meta_backend_x11_translate_device_event (x11, device_event);
657d8e
 
657d8e
   if (!device_event->send_event && device_event->time != META_CURRENT_TIME)
657d8e
-    {
657d8e
-      if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
657d8e
-        {
657d8e
-          /* Emulated pointer events received after XIRejectTouch is received
657d8e
-           * on a passive touch grab will contain older timestamps, update those
657d8e
-           * so we dont get InvalidTime at grabs.
657d8e
-           */
657d8e
-          device_event->time = priv->latest_evtime;
657d8e
-        }
657d8e
-
657d8e
-      /* Update the internal latest evtime, for any possible later use */
657d8e
-      priv->latest_evtime = device_event->time;
657d8e
-    }
657d8e
+    priv->latest_evtime = device_event->time;
657d8e
 }
657d8e
 
657d8e
 static void
657d8e
@@ -260,6 +272,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
657d8e
     case XI_Motion:
657d8e
     case XI_ButtonPress:
657d8e
     case XI_ButtonRelease:
657d8e
+      maybe_translate_touch_replay_pointer_event (x11,
657d8e
+                                                  (XIDeviceEvent *) input_event);
657d8e
+      /* Intentional fall-through */
657d8e
     case XI_KeyPress:
657d8e
     case XI_KeyRelease:
657d8e
     case XI_TouchBegin:
657d8e
@@ -327,6 +342,17 @@ handle_host_xevent (MetaBackend *backend,
657d8e
   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
657d8e
   gboolean bypass_clutter = FALSE;
657d8e
 
657d8e
+  switch (event->type)
657d8e
+    {
657d8e
+    case ClientMessage:
657d8e
+      if (event->xclient.window == meta_backend_x11_get_xwindow (x11) &&
657d8e
+          event->xclient.message_type == priv->touch_replay_sync_atom)
657d8e
+        priv->current_touch_replay_sync_serial = event->xclient.data.l[0];
657d8e
+      break;
657d8e
+    default:
657d8e
+      break;
657d8e
+    }
657d8e
+
657d8e
   XGetEventData (priv->xdisplay, &event->xcookie);
657d8e
 
657d8e
   {
657d8e
@@ -534,6 +560,10 @@ meta_backend_x11_post_init (MetaBackend *backend)
657d8e
   monitor_manager = meta_backend_get_monitor_manager (backend);
657d8e
   g_signal_connect (monitor_manager, "monitors-changed-internal",
657d8e
                     G_CALLBACK (on_monitors_changed), backend);
657d8e
+
657d8e
+  priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay,
657d8e
+                                              "_MUTTER_TOUCH_SEQUENCE_SYNC",
657d8e
+                                              False);
657d8e
 }
657d8e
 
657d8e
 static ClutterBackend *
657d8e
@@ -611,6 +641,21 @@ meta_backend_x11_finish_touch_sequence (MetaBackend          *backend,
657d8e
                       META_VIRTUAL_CORE_POINTER_ID,
657d8e
                       clutter_x11_event_sequence_get_touch_detail (sequence),
657d8e
                       DefaultRootWindow (priv->xdisplay), event_mode);
657d8e
+
657d8e
+  if (state == META_SEQUENCE_REJECTED)
657d8e
+    {
657d8e
+      XClientMessageEvent ev;
657d8e
+
657d8e
+      ev = (XClientMessageEvent) {
657d8e
+        .type = ClientMessage,
657d8e
+        .window = meta_backend_x11_get_xwindow (x11),
657d8e
+        .message_type = priv->touch_replay_sync_atom,
657d8e
+        .format = 32,
657d8e
+        .data.l[0] = ++priv->pending_touch_replay_sync_serial,
657d8e
+      };
657d8e
+      XSendEvent (priv->xdisplay, meta_backend_x11_get_xwindow (x11),
657d8e
+                  False, 0, (XEvent *) &ev;;
657d8e
+    }
657d8e
 }
657d8e
 
657d8e
 static void
657d8e
-- 
657d8e
2.23.0
657d8e