From 66e067082b76530abad2ffe8e548d4d5c81a7f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 11 Jul 2019 17:34:52 +0200 Subject: [PATCH] selection: implement copy *to* primary --- input.c | 2 +- selection.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++---- selection.h | 2 +- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/input.c b/input.c index db348887..6e0d907d 100644 --- a/input.c +++ b/input.c @@ -369,7 +369,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, if (button == BTN_LEFT && term->selection.end.col == -1) selection_cancel(term); else - selection_finalize(term); + selection_finalize(term, serial); term->mouse.button = 0; /* For motion events */ term_mouse_up(term, button, term->mouse.row, term->mouse.col, diff --git a/selection.c b/selection.c index 7bc1df3a..2e7f79da 100644 --- a/selection.c +++ b/selection.c @@ -133,8 +133,10 @@ selection_update(struct terminal *term, int col, int row) grid_render(term); } +static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener; + void -selection_finalize(struct terminal *term) +selection_finalize(struct terminal *term, uint32_t serial) { if (!selection_enabled(term)) return; @@ -145,11 +147,43 @@ selection_finalize(struct terminal *term) assert(term->selection.start.row != -1); assert(term->selection.end.row != -1); - /* Kill old primary selection */ - free(term->selection.primary.text); + /* TODO: somehow share code with the clipboard equivalent */ + if (term->selection.primary.data_source != NULL) { + /* Kill previous data source */ + struct primary *primary = &term->selection.primary; - /* TODO: primary data source */ - term->selection.primary.text = extract_selection(term); + assert(primary->serial != 0); + zwp_primary_selection_device_v1_set_selection( + term->wl.primary_selection_device, NULL, primary->serial); + zwp_primary_selection_source_v1_destroy(primary->data_source); + free(primary->text); + + primary->data_source = NULL; + primary->serial = 0; + } + + struct primary *primary = &term->selection.primary; + + primary->data_source + = zwp_primary_selection_device_manager_v1_create_source( + term->wl.primary_selection_device_manager); + + if (primary->data_source == NULL) { + LOG_ERR("failed to create clipboard data source"); + return; + } + + /* Get selection as a string */ + primary->text = extract_selection(term); + + /* Configure source */ + zwp_primary_selection_source_v1_offer(primary->data_source, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_add_listener(primary->data_source, &primary_selection_source_listener, term); + zwp_primary_selection_device_v1_set_selection(term->wl.primary_selection_device, primary->data_source, serial); + zwp_primary_selection_source_v1_set_user_data(primary->data_source, primary); + + /* Needed when sending the selection to other client */ + primary->serial = serial; } void @@ -251,6 +285,56 @@ static const struct wl_data_source_listener data_source_listener = { .action = &action, }; +static void +primary_send(void *data, + struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1, + const char *mime_type, int32_t fd) +{ + const struct primary *primary + = zwp_primary_selection_source_v1_get_user_data(zwp_primary_selection_source_v1); + + assert(primary != NULL); + assert(primary->text != NULL); + + size_t left = strlen(primary->text); + size_t idx = 0; + + while (left > 0) { + ssize_t ret = write(fd, &primary->text[idx], left); + + if (ret == -1 && errno != EINTR) { + LOG_ERRNO("failed to write to clipboard"); + break; + } + + left -= ret; + idx += ret; + } + + close(fd); +} + +static void +primary_cancelled(void *data, + struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1) +{ + struct primary *primary = zwp_primary_selection_source_v1_get_user_data( + zwp_primary_selection_source_v1); + //assert(primary->data_source == zwp_primary_selection_source_v1); + + zwp_primary_selection_source_v1_destroy(primary->data_source); + primary->data_source = NULL; + primary->serial = 0; + + free(primary->text); + primary->text = NULL; +} + +static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = { + .send = &primary_send, + .cancelled = &primary_cancelled, +}; + void selection_to_clipboard(struct terminal *term, uint32_t serial) { @@ -341,7 +425,6 @@ selection_from_clipboard(struct terminal *term, uint32_t serial) void selection_from_primary(struct terminal *term) { - LOG_WARN("selection from PRIMARY"); struct primary *primary = &term->selection.primary; if (primary->data_offer == NULL) return; diff --git a/selection.h b/selection.h index 62b5eb44..f6edfd5f 100644 --- a/selection.h +++ b/selection.h @@ -9,7 +9,7 @@ extern const struct zwp_primary_selection_device_v1_listener primary_selection_d void selection_start(struct terminal *term, int col, int row); void selection_update(struct terminal *term, int col, int row); -void selection_finalize(struct terminal *term); +void selection_finalize(struct terminal *term, uint32_t serial); void selection_cancel(struct terminal *term); void selection_to_clipboard(struct terminal *term, uint32_t serial);