[PATCH 4/4] ui/vnc: notify client of clipboard peer status

Lukasz Kornicki <[email protected]>
Newsgroups org.nongnu.qemu-devel
Message-ID <[email protected]>
Introduce a new vnc message (VNC_MSG_SERVER_QEMU_CLIPBOARD_STATUS) and
the corresponding feature/encoding.

When a client requests this feature, the server will inform the client
whether a guest clipboard peer is present. The server will repeat the
notification each time availability of a guest clipboard peer changes.

This change enables the VNC client to determine if a guest side
clipboard peer is available for clipboard exchange and react to
changes of its availability.

Until now the VNC clipboard peer was only registered when
VNC_FEATURE_CLIPBOARD_EXT was enabled. With this change the VNC peer
can be registered just for the purpose of receiving peer status
updates. This requires introducing a VNC_FEATURE_CLIPBOARD_EXT guard
before the QEMU_CLIPBOARD_UPDATE_INFO handler which previously only ran
if VNC_FEATURE_CLIPBOARD_EXT was enabled.

Change-Id: Id0897a24fae103288c399f73e808ed6c07018359
Signed-off-by: Lukasz Kornicki <[email protected]>
---
 ui/trace-events    |  1 +
 ui/vnc-clipboard.c | 31 ++++++++++++++++++++++++++++++-
 ui/vnc.c           |  6 ++++++
 ui/vnc.h           |  8 ++++++++
 4 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/ui/trace-events b/ui/trace-events
index 917d116d90..d2fe153b7d 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -48,6 +48,7 @@ vnc_msg_server_ext_desktop_resize(void *state, void *ioc, int width, int height,
 vnc_msg_client_audio_enable(void *state, void *ioc) "VNC client msg audio enable state=%p ioc=%p"
 vnc_msg_client_audio_disable(void *state, void *ioc) "VNC client msg audio disable state=%p ioc=%p"
 vnc_msg_client_audio_format(void *state, void *ioc, int fmt, int channels, int freq) "VNC client msg audio format state=%p ioc=%p fmt=%d channels=%d freq=%d"
+vnc_clipboard_peer_status_send(void *state, bool present) "VNC server clipboard peer status state=%p present=%d"
 vnc_msg_client_cut_text(void *state, void *ioc, int len) "VNC client msg cut text state=%p ioc=%p len=%u"
 vnc_msg_client_cut_text_ext(void *state, void *ioc, int len, int flags) "VNC client msg cut text state=%p ioc=%p len=%u flags=%u"
 vnc_msg_client_ext_key_event(void *state, void *ioc, int down, int sym, int keycode) "VNC client msg ext key event state=%p ioc=%p down=%u sym=%u keycode=%u"
diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c
index 67f710f6ed..4ecc4489e4 100644
--- a/ui/vnc-clipboard.c
+++ b/ui/vnc-clipboard.c
@@ -26,6 +26,7 @@
 #include "qemu/error-report.h"
 #include "vnc.h"
 #include "vnc-jobs.h"
+#include "trace.h"
 
 static uint8_t *inflate_buffer(uint8_t *in, uint32_t in_len, uint32_t *size)
 {
@@ -224,6 +225,23 @@ static void vnc_clipboard_update_info(VncState *vs, QemuClipboardInfo *info)
     }
 }
 
+void vnc_clipboard_peer_status_send(VncState *vs, bool present)
+{
+    if (!vnc_has_feature(vs, VNC_FEATURE_CLIPBOARD_STATUS)) {
+        return;
+    }
+
+    trace_vnc_clipboard_peer_status_send(vs, present);
+
+    vnc_lock_output(vs);
+    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_CLIPBOARD_STATUS);
+    vnc_write_u16(vs, present ? VNC_CLIPBOARD_PEER_PRESENT
+                              : VNC_CLIPBOARD_PEER_ABSENT);
+    vnc_unlock_output(vs);
+    vnc_flush(vs);
+}
+
 static void vnc_clipboard_notify(Notifier *notifier, void *data)
 {
     VncState *vs = container_of(notifier, VncState, cbpeer.notifier);
@@ -231,13 +249,24 @@ static void vnc_clipboard_notify(Notifier *notifier, void *data)
 
     switch (notify->type) {
     case QEMU_CLIPBOARD_UPDATE_INFO:
+        /* ignore the update if client does not want ext messages */
+        if (!vnc_has_feature(vs, VNC_FEATURE_CLIPBOARD_EXT)) {
+            return;
+        }
+
         vnc_clipboard_update_info(vs, notify->info);
         return;
     case QEMU_CLIPBOARD_RESET_SERIAL:
         /* ignore */
         return;
     case QEMU_CLIPBOARD_PEER_UPDATE:
-        /* ignore */
+        /* only guest side peers affect the status we relay to the client */
+        if (!notify->peer_update.peer->guest) {
+            return;
+        }
+
+        vnc_clipboard_peer_status_send(vs,
+            qemu_clipboard_guest_peer_present());
         return;
     }
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index 656768f9c9..9e44a20311 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2191,6 +2191,12 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
             vnc_set_feature(vs, VNC_FEATURE_CLIPBOARD_EXT);
             vnc_server_cut_text_caps(vs);
             break;
+        case VNC_ENCODING_CLIPBOARD_STATUS:
+            vnc_set_feature(vs, VNC_FEATURE_CLIPBOARD_STATUS);
+            vnc_clipboard_peer_register(vs);
+            vnc_clipboard_peer_status_send(vs,
+                qemu_clipboard_guest_peer_present());
+            break;
         case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
             vc->worker.tight.compression = (enc & 0x0F);
             break;
diff --git a/ui/vnc.h b/ui/vnc.h
index d8b0070396..6e8fa66e9c 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -422,6 +422,7 @@ enum {
 #define VNC_ENCODING_DESKTOP_RESIZE_EXT   0XFFFFFECC /* -308 */
 #define VNC_ENCODING_XVP                  0XFFFFFECB /* -309 */
 #define VNC_ENCODING_ALPHA_CURSOR         0XFFFFFEC6 /* -314 */
+#define VNC_ENCODING_CLIPBOARD_STATUS     0XFFFFFEC5 /* -315 */
 #define VNC_ENCODING_WMVi                 0x574D5669
 #define VNC_ENCODING_CLIPBOARD_EXT        0xc0a1e5ce
 
@@ -466,6 +467,7 @@ enum VncFeatures {
     VNC_FEATURE_LED_STATE,
     VNC_FEATURE_XVP,
     VNC_FEATURE_CLIPBOARD_EXT,
+    VNC_FEATURE_CLIPBOARD_STATUS,
     VNC_FEATURE_AUDIO,
 };
 
@@ -507,6 +509,7 @@ enum VncFeatures {
 
 /* QEMU server -> client message IDs */
 #define VNC_MSG_SERVER_QEMU_AUDIO                 1
+#define VNC_MSG_SERVER_QEMU_CLIPBOARD_STATUS      2
 
 
 
@@ -541,6 +544,10 @@ enum VncFeatures {
 #define VNC_CLIPBOARD_NOTIFY   (1 << 27)
 #define VNC_CLIPBOARD_PROVIDE  (1 << 28)
 
+/* guest side clipboard peer status */
+#define VNC_CLIPBOARD_PEER_ABSENT  0
+#define VNC_CLIPBOARD_PEER_PRESENT 1
+
 VncDisplay *vnc_display_new(const char *id, Error **errp);
 void vnc_display_free(VncDisplay *vd);
 
@@ -637,6 +644,7 @@ void vnc_zrle_clear(VncWorker *worker);
 
 /* vnc-clipboard.c */
 void vnc_clipboard_peer_register(VncState *vs);
+void vnc_clipboard_peer_status_send(VncState *vs, bool present);
 void vnc_server_cut_text_caps(VncState *vs);
 void vnc_client_cut_text(VncState *vs, size_t len, uint8_t *text);
 void vnc_client_cut_text_ext(VncState *vs, int32_t len, uint32_t flags, uint8_t *data);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.