[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.
This commit is contained in:
Quantum 2021-02-07 05:22:29 -05:00 committed by Geoffrey McRae
parent 0c9ecdfcb5
commit a450e0f8f5

View File

@ -117,8 +117,8 @@ struct WCBState
char * stashedMimetype; char * stashedMimetype;
uint8_t * stashedContents; uint8_t * stashedContents;
ssize_t stashedSize; ssize_t stashedSize;
bool isReceiving;
bool isSelfCopy; bool isSelfCopy;
char lgMimetype[64];
bool haveRequest; bool haveRequest;
LG_ClipboardData type; LG_ClipboardData type;
@ -1005,6 +1005,9 @@ static void dataOfferHandleOffer(void * data, struct wl_data_offer * offer,
free(wcb.stashedMimetype); free(wcb.stashedMimetype);
wcb.stashedMimetype = strdup(mimetype); wcb.stashedMimetype = strdup(mimetype);
} }
if (!strcmp(mimetype, wcb.lgMimetype))
wcb.isSelfCopy = true;
} }
static void dataOfferHandleSourceActions(void * data, static void dataOfferHandleSourceActions(void * data,
@ -1029,13 +1032,14 @@ static void dataDeviceHandleDataOffer(void * data,
struct wl_data_device * dataDevice, struct wl_data_offer * offer) struct wl_data_device * dataDevice, struct wl_data_offer * offer)
{ {
wcb.stashedType = LG_CLIPBOARD_DATA_NONE; wcb.stashedType = LG_CLIPBOARD_DATA_NONE;
wcb.isSelfCopy = false;
wl_data_offer_add_listener(offer, &dataOfferListener, NULL); wl_data_offer_add_listener(offer, &dataOfferListener, NULL);
} }
static void dataDeviceHandleSelection(void * data, static void dataDeviceHandleSelection(void * data,
struct wl_data_device * dataDevice, struct wl_data_offer * offer) 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; return;
int fds[2]; int fds[2];
@ -1045,8 +1049,6 @@ static void dataDeviceHandleSelection(void * data,
abort(); abort();
} }
wcb.isReceiving = true;
wcb.isSelfCopy = false;
wl_data_offer_receive(offer, wcb.stashedMimetype, fds[1]); wl_data_offer_receive(offer, wcb.stashedMimetype, fds[1]);
close(fds[1]); close(fds[1]);
free(wcb.stashedMimetype); free(wcb.stashedMimetype);
@ -1093,13 +1095,10 @@ static void dataDeviceHandleSelection(void * data,
wcb.stashedSize = numRead; wcb.stashedSize = numRead;
wcb.stashedContents = buf; wcb.stashedContents = buf;
wcb.isReceiving = false;
close(fds[0]); close(fds[0]);
wl_data_offer_destroy(offer); wl_data_offer_destroy(offer);
app_clipboardNotify(wcb.stashedType, 0);
if (!wcb.isSelfCopy)
app_clipboardNotify(wcb.stashedType, 0);
} }
static const struct wl_data_device_listener dataDeviceListener = { static const struct wl_data_device_listener dataDeviceListener = {
@ -1121,6 +1120,9 @@ static bool waylandCBInit(void)
wcb.stashedType = LG_CLIPBOARD_DATA_NONE; wcb.stashedType = LG_CLIPBOARD_DATA_NONE;
wl_data_device_add_listener(wm.dataDevice, &dataDeviceListener, NULL); 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; return true;
} }
@ -1128,9 +1130,7 @@ static void dataSourceHandleSend(void * data, struct wl_data_source * source,
const char * mimetype, int fd) const char * mimetype, int fd)
{ {
struct WCBTransfer * transfer = (struct WCBTransfer *) data; struct WCBTransfer * transfer = (struct WCBTransfer *) data;
if (wcb.isReceiving) if (containsMimetype(transfer->mimetypes, mimetype))
wcb.isSelfCopy = true;
else if (containsMimetype(transfer->mimetypes, mimetype))
{ {
// Consider making this do non-blocking sends to not stall the Wayland // 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 // 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); wl_data_source_add_listener(source, &dataSourceListener, transfer);
for (const char ** mimetype = transfer->mimetypes; *mimetype; mimetype++) for (const char ** mimetype = transfer->mimetypes; *mimetype; mimetype++)
wl_data_source_offer(source, *mimetype); wl_data_source_offer(source, *mimetype);
wl_data_source_offer(source, wcb.lgMimetype);
wl_data_device_set_selection(wm.dataDevice, source, wl_data_device_set_selection(wm.dataDevice, source,
wm.keyboardEnterSerial); wm.keyboardEnterSerial);