From 16b41429618985e4ab8c597fbd0c5cca5cf7b3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 21 Mar 2019 13:21:33 +0100 Subject: [PATCH 1/6] clipboard: do not release between client grabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the client side, whenever the grab owner changes (and the clipboard was previously grabbed), spice-gtk sends a clipboard release followed immediately by a new grab. But some clipboard managers on the remote side react to clipboard release events by taking a clipboard grab, presumably to avoid empty clipboards. The two grabs, coming from the client and from the remote sides, will race in both directions, which may confuse the client & remote side, as both believe the other side is the current grab owner, and thus further clipboard data requests are likely to fail. Let's avoid sending a release event when re-grabing. The race described above may still happen in other rare circunstances, and will require a protocol change. To avoid the conflict, a discussed solution could use a clipboard serial number. Tested with current linux & windows vdagent. Looking at earlier version of the code, it doesn't seem like subsequent grabs will be treated as an error. Signed-off-by: Marc-André Lureau --- src/spice-gtk-session.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c index 60399d0..cb00fa5 100644 --- a/src/spice-gtk-session.c +++ b/src/spice-gtk-session.c @@ -577,8 +577,7 @@ static void clipboard_get_targets(GtkClipboard *clipboard, g_return_if_fail(selection != -1); if (s->clip_grabbed[selection]) { - SPICE_DEBUG("Clipboard is already grabbed, ignoring %d atoms", n_atoms); - return; + SPICE_DEBUG("Clipboard is already grabbed, re-grab: %d atoms", n_atoms); } /* Set all Atoms that matches our current protocol implementation */ @@ -660,18 +659,14 @@ static void clipboard_owner_change(GtkClipboard *clipboard, return; } - /* In case we sent a grab to the agent, we need to release it now as - * previous clipboard data should not be reachable anymore */ - if (s->clip_grabbed[selection]) { - s->clip_grabbed[selection] = FALSE; - if (spice_main_channel_agent_test_capability(s->main, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) { - spice_main_channel_clipboard_selection_release(s->main, selection); - } - } - - /* We are mostly interested when owner has changed in which case - * we would like to let agent know about new clipboard data. */ if (event->reason != GDK_OWNER_CHANGE_NEW_OWNER) { + if (s->clip_grabbed[selection]) { + /* grab was sent to the agent, so release it */ + s->clip_grabbed[selection] = FALSE; + if (spice_main_channel_agent_test_capability(s->main, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) { + spice_main_channel_clipboard_selection_release(s->main, selection); + } + } s->clip_hasdata[selection] = FALSE; return; } -- 2.23.0