selection: add support for pasting *from* primary

This commit is contained in:
Daniel Eklöf 2019-07-11 17:02:21 +02:00
parent e56066feef
commit 703aeecb95
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 124 additions and 6 deletions

29
main.c
View file

@ -131,6 +131,11 @@ handle_global(void *data, struct wl_registry *registry,
term->wl.data_device_manager = wl_registry_bind(
term->wl.registry, name, &wl_data_device_manager_interface, 1);
}
else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
term->wl.primary_selection_device_manager = wl_registry_bind(
term->wl.registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
}
}
static void
@ -403,12 +408,22 @@ main(int argc, char *const *argv)
"(wl_data_device_manager not implemented by server)");
goto out;
}
if (term.wl.primary_selection_device_manager == NULL) {
LOG_ERR("no primary selection available");
goto out;
}
/* Clipboard */
term.wl.data_device = wl_data_device_manager_get_data_device(
term.wl.data_device_manager, term.wl.seat);
wl_data_device_add_listener(term.wl.data_device, &data_device_listener, &term);
/* Primary selection */
term.wl.primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
term.wl.primary_selection_device_manager, term.wl.seat);
zwp_primary_selection_device_v1_add_listener(
term.wl.primary_selection_device, &primary_selection_device_listener, &term);
/* Cursor */
term.wl.pointer.surface = wl_compositor_create_surface(term.wl.compositor);
if (term.wl.pointer.surface == NULL) {
@ -623,11 +638,6 @@ out:
wl_surface_destroy(term.wl.pointer.surface);
if (term.wl.keyboard != NULL)
wl_keyboard_destroy(term.wl.keyboard);
if (term.selection.primary.data_source != NULL)
wl_data_source_destroy(term.selection.primary.data_source);
if (term.selection.primary.data_offer != NULL)
wl_data_offer_destroy(term.selection.primary.data_offer);
free(term.selection.primary.text);
if (term.selection.clipboard.data_source != NULL)
wl_data_source_destroy(term.selection.clipboard.data_source);
if (term.selection.clipboard.data_offer != NULL)
@ -637,6 +647,15 @@ out:
wl_data_device_destroy(term.wl.data_device);
if (term.wl.data_device_manager != NULL)
wl_data_device_manager_destroy(term.wl.data_device_manager);
if (term.selection.primary.data_source != NULL)
zwp_primary_selection_source_v1_destroy(term.selection.primary.data_source);
if (term.selection.primary.data_offer != NULL)
zwp_primary_selection_offer_v1_destroy(term.selection.primary.data_offer);
free(term.selection.primary.text);
if (term.wl.primary_selection_device != NULL)
zwp_primary_selection_device_v1_destroy(term.wl.primary_selection_device);
if (term.wl.primary_selection_device_manager != NULL)
zwp_primary_selection_device_manager_v1_destroy(term.wl.primary_selection_device_manager);
if (term.wl.seat != NULL)
wl_seat_destroy(term.wl.seat);
if (term.wl.surface != NULL)

View file

@ -40,6 +40,7 @@ wl_proto_src = []
foreach prot : [
#'external/wlr-layer-shell-unstable-v1.xml',
wayland_protocols_datadir + '/stable/xdg-shell/xdg-shell.xml',
wayland_protocols_datadir + '/unstable/primary-selection/primary-selection-unstable-v1.xml',
#wayland_protocols_datadir + '/unstable/xdg-output/xdg-output-unstable-v1.xml']
]

View file

@ -342,6 +342,49 @@ void
selection_from_primary(struct terminal *term)
{
LOG_WARN("selection from PRIMARY");
struct primary *primary = &term->selection.primary;
if (primary->data_offer == NULL)
return;
/* Prepare a pipe the other client can write its selection to us */
int fds[2];
if (pipe2(fds, O_CLOEXEC) == -1) {
LOG_ERRNO("failed to create pipe");
return;
}
int read_fd = fds[0];
int write_fd = fds[1];
/* Give write-end of pipe to other client */
zwp_primary_selection_offer_v1_receive(
primary->data_offer, "text/plain;charset=utf-8", write_fd);
wl_display_roundtrip(term->wl.display);
/* Don't keep our copy of the write-end open (or we'll never get EOF) */
close(write_fd);
if (term->bracketed_paste)
write(term->ptmx, "\033[200~", 6);
/* Read until EOF */
while (true) {
char text[256];
ssize_t amount = read(read_fd, text, sizeof(text));
if (amount == -1) {
LOG_ERRNO("failed to read clipboard data: %d", errno);
break;
} else if (amount == 0)
break;
write(term->ptmx, text, amount);
}
if (term->bracketed_paste)
write(term->ptmx, "\033[201~", 6);
close(read_fd);
}
static void
@ -420,3 +463,46 @@ const struct wl_data_device_listener data_device_listener = {
.drop = &drop,
.selection = &selection,
};
static void
primary_offer(void *data,
struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer,
const char *mime_type)
{
}
static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = {
.offer = &primary_offer,
};
static void
primary_data_offer(void *data,
struct zwp_primary_selection_device_v1 *zwp_primary_selection_device,
struct zwp_primary_selection_offer_v1 *offer)
{
}
static void
primary_selection(void *data,
struct zwp_primary_selection_device_v1 *zwp_primary_selection_device,
struct zwp_primary_selection_offer_v1 *id)
{
/* Selection offer from other client, for primary */
struct terminal *term = data;
struct primary *primary = &term->selection.primary;
if (primary->data_offer != NULL)
zwp_primary_selection_offer_v1_destroy(primary->data_offer);
primary->data_offer = id;
if (id != NULL) {
zwp_primary_selection_offer_v1_add_listener(
id, &primary_selection_offer_listener, term);
}
}
const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
.data_offer = &primary_data_offer,
.selection = &primary_selection,
};

View file

@ -5,6 +5,7 @@
#include "terminal.h"
extern const struct wl_data_device_listener data_device_listener;
extern const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener;
void selection_start(struct terminal *term, int col, int row);
void selection_update(struct terminal *term, int col, int row);

View file

@ -8,9 +8,11 @@
#include <cairo.h>
#include <wayland-client.h>
#include <primary-selection-unstable-v1.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-keysyms.h>
#include "tllist.h"
#define likely(c) __builtin_expect(!!(c), 1)
@ -25,6 +27,8 @@ struct wayland {
struct wl_seat *seat;
struct wl_data_device_manager *data_device_manager;
struct wl_data_device *data_device;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
struct zwp_primary_selection_device_v1 *primary_selection_device;
struct wl_keyboard *keyboard;
struct {
struct wl_pointer *pointer;
@ -193,6 +197,13 @@ struct clipboard {
uint32_t serial;
};
struct primary {
struct zwp_primary_selection_source_v1 *data_source;
struct zwp_primary_selection_offer_v1 *data_offer;
char *text;
uint32_t serial;
};
struct terminal {
pid_t slave;
int ptmx;
@ -240,8 +251,8 @@ struct terminal {
struct {
struct coord start;
struct coord end;
struct clipboard primary;
struct clipboard clipboard;
struct primary primary;
} selection;
struct grid normal;