selection: try to write selection data synchronously first

Only if we fail to write everything do we switch to asynchronous mode.
This commit is contained in:
Daniel Eklöf 2019-11-04 14:00:51 +01:00
parent 3081898caf
commit cebeb390e4
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

View file

@ -12,8 +12,10 @@
#define LOG_MODULE "selection" #define LOG_MODULE "selection"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "render.h"
#include "async.h"
#include "grid.h" #include "grid.h"
#include "render.h"
#include "vt.h" #include "vt.h"
#define min(x, y) ((x) < (y) ? (x) : (y)) #define min(x, y) ((x) < (y) ? (x) : (y))
@ -329,31 +331,23 @@ static bool
fdm_send(struct fdm *fdm, int fd, int events, void *data) fdm_send(struct fdm *fdm, int fd, int events, void *data)
{ {
struct clipboard_send *ctx = data; struct clipboard_send *ctx = data;
size_t left = ctx->len - ctx->idx;
while (left > 0) { assert(false);
ssize_t count = write(fd, &ctx->data[ctx->idx], left);
if (count < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return true;
/* switch (async_write(fd, ctx->data, ctx->len, &ctx->idx)) {
* Log error, but handle this as if it completed case ASYNC_WRITE_REMAIN:
* successfully - we don't want to terminate just because return true;
* the clipboard receiver cancelled
*/
LOG_ERRNO("failed to write to FD=%d", fd);
goto out;
}
LOG_DBG("async sent %zd bytes (of %zu, %zu left)", case ASYNC_WRITE_DONE:
count, left, left - count); break;
ctx->idx += count; case ASYNC_WRITE_ERR:
left -= count; LOG_ERRNO(
"failed to asynchronously write %zu of selection data to FD=%d",
ctx->len - ctx->idx, fd);
break;
} }
out:
fdm_del(fdm, fd); fdm_del(fdm, fd);
free(ctx->data); free(ctx->data);
free(ctx); free(ctx);
@ -370,6 +364,9 @@ send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
assert(clipboard != NULL); assert(clipboard != NULL);
assert(clipboard->text != NULL); assert(clipboard->text != NULL);
const char *selection = clipboard->text;
const size_t len = strlen(selection);
int flags; int flags;
if ((flags = fcntl(fd, F_GETFL)) < 0 || if ((flags = fcntl(fd, F_GETFL)) < 0 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
@ -378,15 +375,33 @@ send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
return; return;
} }
struct clipboard_send *ctx = malloc(sizeof(*ctx)); switch (async_write(fd, selection, len, &(size_t){0})) {
*ctx = (struct clipboard_send) { case ASYNC_WRITE_REMAIN: {
.data = strdup(clipboard->text), struct clipboard_send *ctx = malloc(sizeof(*ctx));
.len = strlen(clipboard->text), *ctx = (struct clipboard_send) {
.idx = 0, .data = strdup(selection),
}; .len = len,
.idx = 0,
};
if (fdm_add(wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
return;
if (!fdm_add(wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
free(ctx); free(ctx);
break;
}
case ASYNC_WRITE_DONE:
break;
case ASYNC_WRITE_ERR:
LOG_ERRNO(
"failed to write %zu bytes of clipboard selection data to FD=%d",
len, fd);
break;
}
close(fd);
} }
static void static void
@ -438,6 +453,9 @@ primary_send(void *data,
assert(primary != NULL); assert(primary != NULL);
assert(primary->text != NULL); assert(primary->text != NULL);
const char *selection = primary->text;
const size_t len = strlen(selection);
int flags; int flags;
if ((flags = fcntl(fd, F_GETFL)) < 0 || if ((flags = fcntl(fd, F_GETFL)) < 0 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
@ -446,15 +464,33 @@ primary_send(void *data,
return; return;
} }
struct clipboard_send *ctx = malloc(sizeof(*ctx)); switch (async_write(fd, selection, len, &(size_t){0})) {
*ctx = (struct clipboard_send) { case ASYNC_WRITE_REMAIN: {
.data = strdup(primary->text), struct clipboard_send *ctx = malloc(sizeof(*ctx));
.len = strlen(primary->text), *ctx = (struct clipboard_send) {
.idx = 0, .data = strdup(selection),
}; .len = len,
.idx = 0,
};
if (fdm_add(wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
return;
if (!fdm_add(wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
free(ctx); free(ctx);
break;
}
case ASYNC_WRITE_DONE:
break;
case ASYNC_WRITE_ERR:
LOG_ERRNO(
"failed to write %zu bytes of primary selection data to FD=%d",
len, fd);
break;
}
close(fd);
} }
static void static void
@ -505,7 +541,6 @@ text_to_clipboard(struct terminal *term, char *text, uint32_t serial)
clipboard->text = text; clipboard->text = text;
/* Configure source */ /* Configure source */
LOG_INFO("registering listener, term=%p", term);
wl_data_source_offer(clipboard->data_source, "text/plain;charset=utf-8"); wl_data_source_offer(clipboard->data_source, "text/plain;charset=utf-8");
wl_data_source_add_listener(clipboard->data_source, &data_source_listener, term->wl); wl_data_source_add_listener(clipboard->data_source, &data_source_listener, term->wl);
wl_data_device_set_selection(term->wl->data_device, clipboard->data_source, serial); wl_data_device_set_selection(term->wl->data_device, clipboard->data_source, serial);