[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 "common/debug.h"
#include "common/locking.h"
#include "common/countedbuffer.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
@ -128,8 +129,7 @@ struct WaylandDSState
struct WCBTransfer
{
void * data;
size_t size;
struct CountedBuffer * data;
const char ** mimetypes;
};
@ -1332,6 +1332,38 @@ static bool waylandCBInit(void)
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,
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.
fcntl(fd, F_SETFL, 0);
size_t pos = 0;
while (pos < transfer->size)
struct ClipboardWrite * data = malloc(sizeof(struct ClipboardWrite));
if (!data)
{
ssize_t written = write(fd, transfer->data + pos, transfer->size - pos);
if (written < 0)
{
if (errno != EPIPE)
DEBUG_ERROR("Failed to write clipboard data: %s", strerror(errno));
goto error;
}
pos += written;
DEBUG_ERROR("Out of memory trying to allocate ClipboardWrite");
goto error;
}
data->fd = fd;
data->pos = 0;
data->buffer = transfer->data;
countedBufferAddRef(transfer->data);
waylandEpollRegister(fd, clipboardWriteCallback, data, EPOLLOUT);
return;
}
error:
@ -1366,7 +1398,7 @@ static void dataSourceHandleCancelled(void * data,
struct wl_data_source * source)
{
struct WCBTransfer * transfer = (struct WCBTransfer *) data;
free(transfer->data);
countedBufferRelease(&transfer->data);
free(transfer);
wl_data_source_destroy(source);
}
@ -1380,13 +1412,21 @@ static void waylandCBReplyFn(void * opaque, LG_ClipboardData type,
uint8_t * data, uint32_t size)
{
struct WCBTransfer * transfer = malloc(sizeof(struct WCBTransfer));
void * dataCopy = malloc(size);
memcpy(dataCopy, data, size);
*transfer = (struct WCBTransfer) {
.data = dataCopy,
.size = size,
.mimetypes = cbTypeToMimetypes(type),
};
if (!transfer)
{
DEBUG_ERROR("Out of memory when allocating WCBTransfer");
return;
}
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 =
wl_data_device_manager_create_data_source(wm.dataDeviceManager);