[client] wayland: make clipboard writes asynchronous

This allows multiple Wayland clients to stream data from looking glass
without blocking the looking glass main thread.
This commit is contained in:
Quantum 2021-02-11 04:02:08 -05:00 committed by Geoffrey McRae
parent db16efe68b
commit 98a327e99e

View File

@ -41,6 +41,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "app.h" #include "app.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/locking.h" #include "common/locking.h"
#include "common/countedbuffer.h"
#include "wayland-xdg-shell-client-protocol.h" #include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
@ -128,8 +129,7 @@ struct WaylandDSState
struct WCBTransfer struct WCBTransfer
{ {
void * data; struct CountedBuffer * data;
size_t size;
const char ** mimetypes; const char ** mimetypes;
}; };
@ -1332,6 +1332,38 @@ static bool waylandCBInit(void)
return true; return true;
} }
struct ClipboardWrite
{
int fd;
size_t pos;
struct CountedBuffer * buffer;
};
static void clipboardWriteCallback(uint32_t events, void * opaque)
{
struct ClipboardWrite * data = opaque;
if (events & EPOLLERR)
goto error;
ssize_t written = write(data->fd, data->buffer->data + data->pos, data->buffer->size - data->pos);
if (written < 0)
{
if (errno != EPIPE)
DEBUG_ERROR("Failed to write clipboard data: %s", strerror(errno));
goto error;
}
data->pos += written;
if (data->pos < data->buffer->size)
return;
error:
waylandEpollUnregister(data->fd);
close(data->fd);
countedBufferRelease(&data->buffer);
free(data);
}
static void dataSourceHandleSend(void * data, struct wl_data_source * source, static void dataSourceHandleSend(void * data, struct wl_data_source * source,
const char * mimetype, int fd) const char * mimetype, int fd)
{ {
@ -1343,19 +1375,19 @@ static void dataSourceHandleSend(void * data, struct wl_data_source * source,
// wl-copy also stalls like this, but it's not necessary. // wl-copy also stalls like this, but it's not necessary.
fcntl(fd, F_SETFL, 0); fcntl(fd, F_SETFL, 0);
size_t pos = 0; struct ClipboardWrite * data = malloc(sizeof(struct ClipboardWrite));
while (pos < transfer->size) if (!data)
{ {
ssize_t written = write(fd, transfer->data + pos, transfer->size - pos); DEBUG_ERROR("Out of memory trying to allocate ClipboardWrite");
if (written < 0)
{
if (errno != EPIPE)
DEBUG_ERROR("Failed to write clipboard data: %s", strerror(errno));
goto error; goto error;
} }
pos += written; data->fd = fd;
} data->pos = 0;
data->buffer = transfer->data;
countedBufferAddRef(transfer->data);
waylandEpollRegister(fd, clipboardWriteCallback, data, EPOLLOUT);
return;
} }
error: error:
@ -1366,7 +1398,7 @@ static void dataSourceHandleCancelled(void * data,
struct wl_data_source * source) struct wl_data_source * source)
{ {
struct WCBTransfer * transfer = (struct WCBTransfer *) data; struct WCBTransfer * transfer = (struct WCBTransfer *) data;
free(transfer->data); countedBufferRelease(&transfer->data);
free(transfer); free(transfer);
wl_data_source_destroy(source); wl_data_source_destroy(source);
} }
@ -1380,13 +1412,21 @@ static void waylandCBReplyFn(void * opaque, LG_ClipboardData type,
uint8_t * data, uint32_t size) uint8_t * data, uint32_t size)
{ {
struct WCBTransfer * transfer = malloc(sizeof(struct WCBTransfer)); struct WCBTransfer * transfer = malloc(sizeof(struct WCBTransfer));
void * dataCopy = malloc(size); if (!transfer)
memcpy(dataCopy, data, size); {
*transfer = (struct WCBTransfer) { DEBUG_ERROR("Out of memory when allocating WCBTransfer");
.data = dataCopy, return;
.size = size, }
.mimetypes = cbTypeToMimetypes(type),
}; transfer->mimetypes = cbTypeToMimetypes(type);
transfer->data = countedBufferNew(size);
if (!transfer->data)
{
DEBUG_ERROR("Out of memory when allocating clipboard buffer");
free(transfer);
return;
}
memcpy(transfer->data->data, data, size);
struct wl_data_source * source = struct wl_data_source * source =
wl_data_device_manager_create_data_source(wm.dataDeviceManager); wl_data_device_manager_create_data_source(wm.dataDeviceManager);