From: Lukasz Kornicki <[email protected]> Adds support for vnc ClipboardAvailability pseudo-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. Signed-off-by: Lukasz Kornicki <[email protected]> Reviewed-by: Marc-André Lureau <[email protected]> Message-ID: <[email protected]> --- tools/qemu-vnc/qemu-vnc.c | 7 ++++++- ui/trace-events | 1 + ui/vnc-clipboard.c | 34 +++++++++++++++++++++++++++++++++- ui/vnc.c | 9 +++++++++ ui/vnc.h | 8 ++++++++ 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/tools/qemu-vnc/qemu-vnc.c b/tools/qemu-vnc/qemu-vnc.c index 5c2ba3b7a564..c915589ca7e1 100644 --- a/tools/qemu-vnc/qemu-vnc.c +++ b/tools/qemu-vnc/qemu-vnc.c @@ -95,6 +95,7 @@ on_manager_ready(GObject *source_object, g_autoptr(GPtrArray) console_paths = NULL; bool found = false; Error *local_err = NULL; + VncDisplay *vd; manager = G_DBUS_OBJECT_MANAGER( g_dbus_object_manager_client_new_finish(res, &err)); @@ -145,13 +146,17 @@ on_manager_ready(GObject *source_object, * Create the VNC display now that consoles exist, so that the * display change listener is registered against a valid console. */ - if (!vnc_display_new("default", &local_err)) { + vd = vnc_display_new("default", &local_err); + if (!vd) { error_report("Failed to create VNC display: %s", error_get_pretty(local_err)); g_assert_not_reached(); return; } + /* guest clipboard peer presence is not exposed over D-Bus */ + vd->clipboard_availability = false; + vnc_dbus_setup(state->bus); clipboard_setup(manager, state->bus); diff --git a/ui/trace-events b/ui/trace-events index 917d116d90e1..f5f82c75db0b 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -45,6 +45,7 @@ vnc_msg_server_audio_end(void *state, void *ioc) "VNC server msg audio end state vnc_msg_server_audio_data(void *state, void *ioc, const void *buf, size_t len) "VNC server msg audio data state=%p ioc=%p buf=%p len=%zd" vnc_msg_server_desktop_resize(void *state, void *ioc, int width, int height) "VNC server msg ext resize state=%p ioc=%p size=%dx%d" vnc_msg_server_ext_desktop_resize(void *state, void *ioc, int width, int height, int reason) "VNC server msg ext resize state=%p ioc=%p size=%dx%d reason=%d" +vnc_msg_server_clipboard_availability(void *state, void *ioc, bool available) "VNC server msg clipboard availability state=%p ioc=%p available=%d" 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" diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c index 67f710f6ed80..7c5bd94cb62d 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,26 @@ static void vnc_clipboard_update_info(VncState *vs, QemuClipboardInfo *info) } } +void vnc_clipboard_availability_send(VncState *vs, bool available) +{ + if (!vnc_has_feature(vs, VNC_FEATURE_CLIPBOARD_AVAILABILITY)) { + return; + } + + trace_vnc_msg_server_clipboard_availability(vs, vs->ioc, available); + + vnc_lock_output(vs); + vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); + vnc_framebuffer_update(vs, 0, 0, 0, 0, + VNC_ENCODING_CLIPBOARD_AVAILABILITY); + vnc_write_u8(vs, available ? VNC_CLIPBOARD_AVAILABLE + : VNC_CLIPBOARD_UNAVAILABLE); + 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 +252,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_availability_send(vs, + qemu_clipboard_guest_peer_present()); return; } } diff --git a/ui/vnc.c b/ui/vnc.c index 656768f9c998..8b1d03ef2434 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2191,6 +2191,14 @@ 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_AVAILABILITY: + if (vs->vd->clipboard_availability) { + vnc_set_feature(vs, VNC_FEATURE_CLIPBOARD_AVAILABILITY); + vnc_clipboard_peer_register(vs); + vnc_clipboard_availability_send(vs, + qemu_clipboard_guest_peer_present()); + } + break; case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9: vc->worker.tight.compression = (enc & 0x0F); break; @@ -3459,6 +3467,7 @@ VncDisplay *vnc_display_new(const char *id, Error **errp) vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; vd->connections_limit = 32; + vd->clipboard_availability = true; vnc_start_worker_thread(vd); diff --git a/ui/vnc.h b/ui/vnc.h index d8b0070396dc..8eae550c96d6 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -171,6 +171,7 @@ struct VncDisplay bool lossy; bool non_adaptive; bool power_control; + bool clipboard_availability; QCryptoTLSCreds *tlscreds; char *tlsauthzid; #ifdef CONFIG_VNC_SASL @@ -422,6 +423,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_AVAILABILITY 0XFFFFFEC2 /* -318 */ #define VNC_ENCODING_WMVi 0x574D5669 #define VNC_ENCODING_CLIPBOARD_EXT 0xc0a1e5ce @@ -466,6 +468,7 @@ enum VncFeatures { VNC_FEATURE_LED_STATE, VNC_FEATURE_XVP, VNC_FEATURE_CLIPBOARD_EXT, + VNC_FEATURE_CLIPBOARD_AVAILABILITY, VNC_FEATURE_AUDIO, }; @@ -541,6 +544,10 @@ enum VncFeatures { #define VNC_CLIPBOARD_NOTIFY (1 << 27) #define VNC_CLIPBOARD_PROVIDE (1 << 28) +/* ClipboardAvailability pseudo-encoding values */ +#define VNC_CLIPBOARD_UNAVAILABLE 0 +#define VNC_CLIPBOARD_AVAILABLE 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_availability_send(VncState *vs, bool available); 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.56.0.116.g6de20f6092dc
