[spice-gtk,3/3] clipboard: implement CAP_CLIPBOARD_GRAB_SERIAL

Submitted by marcandre.lureau@redhat.com on March 22, 2019, 2:20 p.m.

Details

Message ID 20190322142014.3330-4-marcandre.lureau@redhat.com
State New
Headers show
Series "Clipboard improvements" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

marcandre.lureau@redhat.com March 22, 2019, 2:20 p.m.
From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 src/channel-main.c      | 32 +++++++++++++++++++++++++++++++-
 src/spice-gtk-session.c |  1 -
 2 files changed, 31 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/channel-main.c b/src/channel-main.c
index e359e8d..ced037e 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -111,6 +111,7 @@  struct _SpiceMainChannelPrivate  {
     guint                       migrate_delayed_id;
     spice_migrate               *migrate_data;
     int                         max_clipboard;
+    uint32_t                    clipboard_serial[256];
 
     gboolean                    agent_volume_playback_sync;
     gboolean                    agent_volume_record_sync;
@@ -223,6 +224,7 @@  static const char *agent_caps[] = {
     [ VD_AGENT_CAP_MONITORS_CONFIG_POSITION ] = "monitors config position",
     [ VD_AGENT_CAP_FILE_XFER_DISABLED ] = "file transfer disabled",
     [ VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB ] = "no release on re-grab",
+    [ VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL ] = "clipboard grab serial",
 };
 #define NAME(_a, _i) ((_i) < SPICE_N_ELEMENTS(_a) ? (_a[(_i)] ?: "?") : "?")
 
@@ -412,6 +414,7 @@  static void spice_main_channel_reset_agent(SpiceMainChannel *channel)
 
     spice_main_channel_reset_all_xfer_operations(channel);
     file_xfer_flushed(channel, FALSE);
+    memset(c->clipboard_serial, 0, sizeof(c->clipboard_serial));
 }
 
 /* main or coroutine context */
@@ -1335,6 +1338,7 @@  static void agent_announce_caps(SpiceMainChannel *channel)
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG_POSITION);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB);
+    VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL);
 
     agent_msg_queue(channel, VD_AGENT_ANNOUNCE_CAPABILITIES, size, caps);
     g_free(caps);
@@ -1365,6 +1369,10 @@  static void agent_clipboard_grab(SpiceMainChannel *channel, guint selection,
         return;
     }
 
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
+        size += sizeof(uint32_t);
+    }
+
     msg = g_alloca(size);
     memset(msg, 0, size);
 
@@ -1372,7 +1380,13 @@  static void agent_clipboard_grab(SpiceMainChannel *channel, guint selection,
 
     if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msg[0] = selection;
-        grab = (VDAgentClipboardGrab *)(msg + 4);
+        grab = (void *)grab + 4;
+    }
+
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
+        guint32 *serial = (guint32 *)grab;
+        *serial = GUINT32_TO_LE(c->clipboard_serial[selection]++);
+        grab = (void *)grab + sizeof(uint32_t);
     }
 
     for (i = 0; i < ntypes; i++) {
@@ -1974,6 +1988,7 @@  static void main_agent_handle_msg(SpiceChannel *channel,
     SpiceMainChannel *self = SPICE_MAIN_CHANNEL(channel);
     SpiceMainChannelPrivate *c = self->priv;
     guint8 selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
+    guint32 serial;
 
     g_return_if_fail(msg->protocol == VD_AGENT_PROTOCOL);
 
@@ -2045,6 +2060,21 @@  static void main_agent_handle_msg(SpiceChannel *channel,
     case VD_AGENT_CLIPBOARD_GRAB:
     {
         gboolean ret;
+
+        if (test_agent_cap(self, VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
+            serial = GUINT32_FROM_LE(*((guint32 *)payload));
+            payload = ((guint8*)payload) + sizeof(uint32_t);
+            msg->size -= sizeof(uint32_t);
+
+            if (serial == c->clipboard_serial[selection]) {
+                c->clipboard_serial[selection]++;
+            } else {
+                CHANNEL_DEBUG(channel, "grab discard, serial:%u != c->serial:%u",
+                              serial, c->clipboard_serial[selection]);
+                break;
+            }
+        }
+
         g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_SELECTION_GRAB], 0, selection,
                           (guint8*)payload, msg->size / sizeof(uint32_t), &ret);
         if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
index 7a7ebb7..5b2c27c 100644
--- a/src/spice-gtk-session.c
+++ b/src/spice-gtk-session.c
@@ -1103,7 +1103,6 @@  static gboolean clipboard_release_timeout(gpointer user_data)
  *
  * Workaround this problem by delaying the release event by 0.5 sec,
  * unless the no-release-on-regrab capability is present.
- * FIXME: protocol change to solve the conflict and set client priority.
  */
 #define CLIPBOARD_RELEASE_DELAY 500 /* ms */