etrunko / rpms / spice-gtk

Forked from rpms/spice-gtk 4 years ago
Clone

Blame 0002-clipboard-do-not-release-between-remote-grabs.patch

56f7953
From 271656ae32e756eacfcc522d1aaab9d7102b0ce7 Mon Sep 17 00:00:00 2001
56f7953
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
56f7953
Date: Thu, 21 Mar 2019 13:21:34 +0100
56f7953
Subject: [PATCH 2/6] clipboard: do not release between remote grabs
56f7953
MIME-Version: 1.0
56f7953
Content-Type: text/plain; charset=UTF-8
56f7953
Content-Transfer-Encoding: 8bit
56f7953
56f7953
Delay the release events for 0.5 sec. If no further grab comes in,
56f7953
then release the grab. Otherwise, let's skip the release. This avoids
56f7953
some races with clipboard managers.
56f7953
56f7953
Related to:
56f7953
https://gitlab.freedesktop.org/spice/spice-gtk/issues/82
56f7953
56f7953
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
56f7953
---
56f7953
 src/spice-gtk-session.c | 80 ++++++++++++++++++++++++++++++++++++-----
56f7953
 1 file changed, 72 insertions(+), 8 deletions(-)
56f7953
56f7953
diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
56f7953
index cb00fa5..79385a4 100644
56f7953
--- a/src/spice-gtk-session.c
56f7953
+++ b/src/spice-gtk-session.c
56f7953
@@ -59,6 +59,7 @@ struct _SpiceGtkSessionPrivate {
56f7953
     gboolean                clip_hasdata[CLIPBOARD_LAST];
56f7953
     gboolean                clip_grabbed[CLIPBOARD_LAST];
56f7953
     gboolean                clipboard_by_guest[CLIPBOARD_LAST];
56f7953
+    guint                   clipboard_release_delay[CLIPBOARD_LAST];
56f7953
     /* auto-usbredir related */
56f7953
     gboolean                auto_usbredir_enable;
56f7953
     int                     auto_usbredir_reqs;
56f7953
@@ -95,6 +96,7 @@ struct _SpiceGtkSessionPrivate {
56f7953
 
56f7953
 /* ------------------------------------------------------------------ */
56f7953
 /* Prototypes for private functions */
56f7953
+static void clipboard_release(SpiceGtkSession *self, guint selection);
56f7953
 static void clipboard_owner_change(GtkClipboard *clipboard,
56f7953
                                    GdkEventOwnerChange *event,
56f7953
                                    gpointer user_data);
56f7953
@@ -255,6 +257,23 @@ static void spice_gtk_session_dispose(GObject *gobject)
56f7953
         G_OBJECT_CLASS(spice_gtk_session_parent_class)->dispose(gobject);
56f7953
 }
56f7953
 
56f7953
+static void clipboard_release_delay_remove(SpiceGtkSession *self, guint selection,
56f7953
+                                           gboolean release_if_delayed)
56f7953
+{
56f7953
+    SpiceGtkSessionPrivate *s = self->priv;
56f7953
+
56f7953
+    if (!s->clipboard_release_delay[selection])
56f7953
+        return;
56f7953
+
56f7953
+    if (release_if_delayed) {
56f7953
+        SPICE_DEBUG("delayed clipboard release, sel:%u", selection);
56f7953
+        clipboard_release(self, selection);
56f7953
+    }
56f7953
+
56f7953
+    g_source_remove(s->clipboard_release_delay[selection]);
56f7953
+    s->clipboard_release_delay[selection] = 0;
56f7953
+}
56f7953
+
56f7953
 static void spice_gtk_session_finalize(GObject *gobject)
56f7953
 {
56f7953
     SpiceGtkSession *self = SPICE_GTK_SESSION(gobject);
56f7953
@@ -264,6 +283,7 @@ static void spice_gtk_session_finalize(GObject *gobject)
56f7953
     /* release stuff */
56f7953
     for (i = 0; i < CLIPBOARD_LAST; ++i) {
56f7953
         g_clear_pointer(&s->clip_targets[i], g_free);
56f7953
+        clipboard_release_delay_remove(self, i, true);
56f7953
     }
56f7953
 
56f7953
     /* Chain up to the parent class */
56f7953
@@ -823,6 +843,8 @@ static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,
56f7953
     int m, n;
56f7953
     int num_targets = 0;
56f7953
 
56f7953
+    clipboard_release_delay_remove(self, selection, false);
56f7953
+
56f7953
     cb = get_clipboard_from_selection(s, selection);
56f7953
     g_return_val_if_fail(cb != NULL, FALSE);
56f7953
 
56f7953
@@ -1052,17 +1074,12 @@ static gboolean clipboard_request(SpiceMainChannel *main, guint selection,
56f7953
     return TRUE;
56f7953
 }
56f7953
 
56f7953
-static void clipboard_release(SpiceMainChannel *main, guint selection,
56f7953
-                              gpointer user_data)
56f7953
+static void clipboard_release(SpiceGtkSession *self, guint selection)
56f7953
 {
56f7953
-    g_return_if_fail(SPICE_IS_GTK_SESSION(user_data));
56f7953
-
56f7953
-    SpiceGtkSession *self = user_data;
56f7953
     SpiceGtkSessionPrivate *s = self->priv;
56f7953
     GtkClipboard* clipboard = get_clipboard_from_selection(s, selection);
56f7953
 
56f7953
-    if (!clipboard)
56f7953
-        return;
56f7953
+    g_return_if_fail(clipboard != NULL);
56f7953
 
56f7953
     s->nclip_targets[selection] = 0;
56f7953
 
56f7953
@@ -1072,6 +1089,53 @@ static void clipboard_release(SpiceMainChannel *main, guint selection,
56f7953
     s->clipboard_by_guest[selection] = FALSE;
56f7953
 }
56f7953
 
56f7953
+typedef struct SpiceGtkClipboardRelease {
56f7953
+    SpiceGtkSession *self;
56f7953
+    guint selection;
56f7953
+} SpiceGtkClipboardRelease;
56f7953
+
56f7953
+static gboolean clipboard_release_timeout(gpointer user_data)
56f7953
+{
56f7953
+    SpiceGtkClipboardRelease *rel = user_data;
56f7953
+
56f7953
+    clipboard_release_delay_remove(rel->self, rel->selection, true);
56f7953
+
56f7953
+    return G_SOURCE_REMOVE;
56f7953
+}
56f7953
+
56f7953
+/*
56f7953
+ * The agents send release between two grabs. This may trigger
56f7953
+ * clipboard managers trying to grab the clipboard. We end up with two
56f7953
+ * sides, client and remote, racing for the clipboard grab, and
56f7953
+ * believing each other is the owner.
56f7953
+ *
56f7953
+ * Workaround this problem by delaying the release event by 0.5 sec.
56f7953
+ * FIXME: protocol change to solve the conflict and set client priority.
56f7953
+ */
56f7953
+#define CLIPBOARD_RELEASE_DELAY 500 /* ms */
56f7953
+
56f7953
+static void clipboard_release_delay(SpiceMainChannel *main, guint selection,
56f7953
+                                    gpointer user_data)
56f7953
+{
56f7953
+    SpiceGtkSession *self = SPICE_GTK_SESSION(user_data);
56f7953
+    SpiceGtkSessionPrivate *s = self->priv;
56f7953
+    GtkClipboard* clipboard = get_clipboard_from_selection(s, selection);
56f7953
+    SpiceGtkClipboardRelease *rel;
56f7953
+
56f7953
+    if (!clipboard)
56f7953
+        return;
56f7953
+
56f7953
+    clipboard_release_delay_remove(self, selection, true);
56f7953
+
56f7953
+    rel = g_new0(SpiceGtkClipboardRelease, 1);
56f7953
+    rel->self = self;
56f7953
+    rel->selection = selection;
56f7953
+    s->clipboard_release_delay[selection] =
56f7953
+        g_timeout_add_full(G_PRIORITY_DEFAULT, CLIPBOARD_RELEASE_DELAY,
56f7953
+                           clipboard_release_timeout, rel, g_free);
56f7953
+
56f7953
+}
56f7953
+
56f7953
 static void channel_new(SpiceSession *session, SpiceChannel *channel,
56f7953
                         gpointer user_data)
56f7953
 {
56f7953
@@ -1088,7 +1152,7 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel,
56f7953
         g_signal_connect(channel, "main-clipboard-selection-request",
56f7953
                          G_CALLBACK(clipboard_request), self);
56f7953
         g_signal_connect(channel, "main-clipboard-selection-release",
56f7953
-                         G_CALLBACK(clipboard_release), self);
56f7953
+                         G_CALLBACK(clipboard_release_delay), self);
56f7953
     }
56f7953
     if (SPICE_IS_INPUTS_CHANNEL(channel)) {
56f7953
         spice_g_signal_connect_object(channel, "inputs-modifiers",
56f7953
-- 
56f7953
2.23.0
56f7953