From a450e0f8f53112b94086fa50262c548d82ee3e92 Mon Sep 17 00:00:00 2001 From: Quantum Date: Sun, 7 Feb 2021 05:22:29 -0500 Subject: [PATCH] [client] wayland: better self-copy detection This new implementation uses a special mimetype to tag data copied from the guest, instead of using flags. This should make it easier to implement asynchronous transfers in the future. Also, it's simpler to understand and less error-prone. The pid is included in the mimetype in order to distinguish between different instances of looking glass: you might want to copy between two different VMs, for example. --- client/displayservers/Wayland/wayland.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index ab912541..31a6d018 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -117,8 +117,8 @@ struct WCBState char * stashedMimetype; uint8_t * stashedContents; ssize_t stashedSize; - bool isReceiving; bool isSelfCopy; + char lgMimetype[64]; bool haveRequest; LG_ClipboardData type; @@ -1005,6 +1005,9 @@ static void dataOfferHandleOffer(void * data, struct wl_data_offer * offer, free(wcb.stashedMimetype); wcb.stashedMimetype = strdup(mimetype); } + + if (!strcmp(mimetype, wcb.lgMimetype)) + wcb.isSelfCopy = true; } static void dataOfferHandleSourceActions(void * data, @@ -1029,13 +1032,14 @@ static void dataDeviceHandleDataOffer(void * data, struct wl_data_device * dataDevice, struct wl_data_offer * offer) { wcb.stashedType = LG_CLIPBOARD_DATA_NONE; + wcb.isSelfCopy = false; wl_data_offer_add_listener(offer, &dataOfferListener, NULL); } static void dataDeviceHandleSelection(void * data, struct wl_data_device * dataDevice, struct wl_data_offer * offer) { - if (wcb.stashedType == LG_CLIPBOARD_DATA_NONE || !offer) + if (wcb.stashedType == LG_CLIPBOARD_DATA_NONE || wcb.isSelfCopy || !offer) return; int fds[2]; @@ -1045,8 +1049,6 @@ static void dataDeviceHandleSelection(void * data, abort(); } - wcb.isReceiving = true; - wcb.isSelfCopy = false; wl_data_offer_receive(offer, wcb.stashedMimetype, fds[1]); close(fds[1]); free(wcb.stashedMimetype); @@ -1093,13 +1095,10 @@ static void dataDeviceHandleSelection(void * data, wcb.stashedSize = numRead; wcb.stashedContents = buf; - wcb.isReceiving = false; close(fds[0]); wl_data_offer_destroy(offer); - - if (!wcb.isSelfCopy) - app_clipboardNotify(wcb.stashedType, 0); + app_clipboardNotify(wcb.stashedType, 0); } static const struct wl_data_device_listener dataDeviceListener = { @@ -1121,6 +1120,9 @@ static bool waylandCBInit(void) wcb.stashedType = LG_CLIPBOARD_DATA_NONE; wl_data_device_add_listener(wm.dataDevice, &dataDeviceListener, NULL); + snprintf(wcb.lgMimetype, sizeof(wcb.lgMimetype), + "application/x-looking-glass-copy;pid=%d", getpid()); + return true; } @@ -1128,9 +1130,7 @@ static void dataSourceHandleSend(void * data, struct wl_data_source * source, const char * mimetype, int fd) { struct WCBTransfer * transfer = (struct WCBTransfer *) data; - if (wcb.isReceiving) - wcb.isSelfCopy = true; - else if (containsMimetype(transfer->mimetypes, mimetype)) + if (containsMimetype(transfer->mimetypes, mimetype)) { // Consider making this do non-blocking sends to not stall the Wayland // event loop if it becomes a problem. This is "fine" in the sense that @@ -1187,6 +1187,7 @@ static void waylandCBReplyFn(void * opaque, LG_ClipboardData type, wl_data_source_add_listener(source, &dataSourceListener, transfer); for (const char ** mimetype = transfer->mimetypes; *mimetype; mimetype++) wl_data_source_offer(source, *mimetype); + wl_data_source_offer(source, wcb.lgMimetype); wl_data_device_set_selection(wm.dataDevice, source, wm.keyboardEnterSerial);