mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-05 07:15:30 -04:00
selection: add support for pasting *from* primary
This commit is contained in:
parent
e56066feef
commit
703aeecb95
5 changed files with 124 additions and 6 deletions
29
main.c
29
main.c
|
|
@ -131,6 +131,11 @@ handle_global(void *data, struct wl_registry *registry,
|
||||||
term->wl.data_device_manager = wl_registry_bind(
|
term->wl.data_device_manager = wl_registry_bind(
|
||||||
term->wl.registry, name, &wl_data_device_manager_interface, 1);
|
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
|
static void
|
||||||
|
|
@ -403,12 +408,22 @@ main(int argc, char *const *argv)
|
||||||
"(wl_data_device_manager not implemented by server)");
|
"(wl_data_device_manager not implemented by server)");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (term.wl.primary_selection_device_manager == NULL) {
|
||||||
|
LOG_ERR("no primary selection available");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clipboard */
|
/* Clipboard */
|
||||||
term.wl.data_device = wl_data_device_manager_get_data_device(
|
term.wl.data_device = wl_data_device_manager_get_data_device(
|
||||||
term.wl.data_device_manager, term.wl.seat);
|
term.wl.data_device_manager, term.wl.seat);
|
||||||
wl_data_device_add_listener(term.wl.data_device, &data_device_listener, &term);
|
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 */
|
/* Cursor */
|
||||||
term.wl.pointer.surface = wl_compositor_create_surface(term.wl.compositor);
|
term.wl.pointer.surface = wl_compositor_create_surface(term.wl.compositor);
|
||||||
if (term.wl.pointer.surface == NULL) {
|
if (term.wl.pointer.surface == NULL) {
|
||||||
|
|
@ -623,11 +638,6 @@ out:
|
||||||
wl_surface_destroy(term.wl.pointer.surface);
|
wl_surface_destroy(term.wl.pointer.surface);
|
||||||
if (term.wl.keyboard != NULL)
|
if (term.wl.keyboard != NULL)
|
||||||
wl_keyboard_destroy(term.wl.keyboard);
|
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)
|
if (term.selection.clipboard.data_source != NULL)
|
||||||
wl_data_source_destroy(term.selection.clipboard.data_source);
|
wl_data_source_destroy(term.selection.clipboard.data_source);
|
||||||
if (term.selection.clipboard.data_offer != NULL)
|
if (term.selection.clipboard.data_offer != NULL)
|
||||||
|
|
@ -637,6 +647,15 @@ out:
|
||||||
wl_data_device_destroy(term.wl.data_device);
|
wl_data_device_destroy(term.wl.data_device);
|
||||||
if (term.wl.data_device_manager != NULL)
|
if (term.wl.data_device_manager != NULL)
|
||||||
wl_data_device_manager_destroy(term.wl.data_device_manager);
|
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)
|
if (term.wl.seat != NULL)
|
||||||
wl_seat_destroy(term.wl.seat);
|
wl_seat_destroy(term.wl.seat);
|
||||||
if (term.wl.surface != NULL)
|
if (term.wl.surface != NULL)
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ wl_proto_src = []
|
||||||
foreach prot : [
|
foreach prot : [
|
||||||
#'external/wlr-layer-shell-unstable-v1.xml',
|
#'external/wlr-layer-shell-unstable-v1.xml',
|
||||||
wayland_protocols_datadir + '/stable/xdg-shell/xdg-shell.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']
|
#wayland_protocols_datadir + '/unstable/xdg-output/xdg-output-unstable-v1.xml']
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
86
selection.c
86
selection.c
|
|
@ -342,6 +342,49 @@ void
|
||||||
selection_from_primary(struct terminal *term)
|
selection_from_primary(struct terminal *term)
|
||||||
{
|
{
|
||||||
LOG_WARN("selection from PRIMARY");
|
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
|
static void
|
||||||
|
|
@ -420,3 +463,46 @@ const struct wl_data_device_listener data_device_listener = {
|
||||||
.drop = &drop,
|
.drop = &drop,
|
||||||
.selection = &selection,
|
.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,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
extern const struct wl_data_device_listener data_device_listener;
|
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_start(struct terminal *term, int col, int row);
|
||||||
void selection_update(struct terminal *term, int col, int row);
|
void selection_update(struct terminal *term, int col, int row);
|
||||||
|
|
|
||||||
13
terminal.h
13
terminal.h
|
|
@ -8,9 +8,11 @@
|
||||||
|
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
#include <primary-selection-unstable-v1.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||||
|
|
||||||
|
|
||||||
#include "tllist.h"
|
#include "tllist.h"
|
||||||
|
|
||||||
#define likely(c) __builtin_expect(!!(c), 1)
|
#define likely(c) __builtin_expect(!!(c), 1)
|
||||||
|
|
@ -25,6 +27,8 @@ struct wayland {
|
||||||
struct wl_seat *seat;
|
struct wl_seat *seat;
|
||||||
struct wl_data_device_manager *data_device_manager;
|
struct wl_data_device_manager *data_device_manager;
|
||||||
struct wl_data_device *data_device;
|
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 wl_keyboard *keyboard;
|
||||||
struct {
|
struct {
|
||||||
struct wl_pointer *pointer;
|
struct wl_pointer *pointer;
|
||||||
|
|
@ -193,6 +197,13 @@ struct clipboard {
|
||||||
uint32_t serial;
|
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 {
|
struct terminal {
|
||||||
pid_t slave;
|
pid_t slave;
|
||||||
int ptmx;
|
int ptmx;
|
||||||
|
|
@ -240,8 +251,8 @@ struct terminal {
|
||||||
struct {
|
struct {
|
||||||
struct coord start;
|
struct coord start;
|
||||||
struct coord end;
|
struct coord end;
|
||||||
struct clipboard primary;
|
|
||||||
struct clipboard clipboard;
|
struct clipboard clipboard;
|
||||||
|
struct primary primary;
|
||||||
} selection;
|
} selection;
|
||||||
|
|
||||||
struct grid normal;
|
struct grid normal;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue