2
0
Fork 0
mirror of https://github.com/lbonn/rofi synced 2025-03-01 05:37:08 +00:00

Initial clipboard support for wayland

Using wl_data and primary_selection protocols
This commit is contained in:
lbonn 2021-09-06 14:50:54 +02:00
parent cfc3be4a5d
commit 2a68677b6a
7 changed files with 193 additions and 3 deletions

View file

@ -48,6 +48,7 @@ typedef struct _display_proxy {
void (*set_input_focus)(guint window);
void (*revert_input_focus)(void);
char *(*get_clipboard_data)(int type);
guint (*scale)(void);

View file

@ -122,4 +122,11 @@ void display_revert_input_focus(void);
guint display_scale(void);
enum clipboard_type {
CLIPBOARD_DEFAULT,
CLIPBOARD_PRIMARY,
};
char *display_get_clipboard_data(enum clipboard_type);
#endif

View file

@ -40,8 +40,9 @@ typedef struct {
struct wl_registry *registry;
uint32_t global_names[_WAYLAND_GLOBAL_SIZE];
struct wl_compositor *compositor;
struct zww_launcher_menu_v1 *launcher_menu;
struct zww_window_switcher_v1 *window_switcher;
struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
struct zwlr_layer_shell_v1 *layer_shell;
@ -67,6 +68,9 @@ typedef struct {
int32_t scale;
NkBindingsSeat *bindings_seat;
char *clipboard_default_data;
char *clipboard_primary_data;
uint32_t layer_width;
uint32_t layer_height;
} wayland_stuff;
@ -85,6 +89,10 @@ struct _wayland_seat {
uint32_t serial;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;
struct wl_data_device *data_device;
struct zwp_primary_selection_device_v1 *primary_selection_device;
widget_button_event button;
widget_motion_event motion;
struct {

View file

@ -1,5 +1,5 @@
project('rofi', 'c',
version: '1.7.0-wayland',
version: '1.7.0-wayland-dev',
meson_version: '>=0.47.0',
license: [ 'MIT' ],
default_options: [
@ -232,6 +232,7 @@ if get_option('wayland').enabled()
wayland_scanner = find_program('wayland-scanner')
protocols = files(
wayland_sys_protocols_dir + '/stable/xdg-shell/xdg-shell.xml',
wayland_sys_protocols_dir + '/unstable/primary-selection/primary-selection-unstable-v1.xml',
'protocols/wlr-layer-shell-unstable-v1.xml',
)
proto_srcs = []

View file

@ -41,3 +41,7 @@ void display_startup_notification(RofiHelperExecuteContext *context,
}
guint display_scale(void) { return proxy->scale(); }
char *display_get_clipboard_data(enum clipboard_type type) {
return proxy->get_clipboard_data(type);
}

View file

@ -627,6 +627,11 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
XCB_ATOM_PRIMARY, xcb->ewmh.UTF8_STRING,
xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
xcb_flush(xcb->connection);
} else { // config.backend == DISPLAY_WAYLAND
char *d = display_get_clipboard_data(CLIPBOARD_PRIMARY);
if (d != NULL) {
rofi_view_handle_text(current_active_menu, d);
}
}
break;
case PASTE_SECONDARY:
@ -635,6 +640,11 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
netatoms[CLIPBOARD], xcb->ewmh.UTF8_STRING,
xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
xcb_flush(xcb->connection);
} else { // config.backend == DISPLAY_WAYLAND
char *d = display_get_clipboard_data(CLIPBOARD_DEFAULT);
if (d != NULL) {
rofi_view_handle_text(current_active_menu, d);
}
}
break;
case SCREENSHOT:

View file

@ -55,6 +55,7 @@
#include "display.h"
#include "wayland-internal.h"
#include "primary-selection-unstable-v1-protocol.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
typedef struct _display_buffer_pool wayland_buffer_pool;
@ -724,6 +725,129 @@ static void wayland_keyboard_release(wayland_seat *self) {
self->keyboard = NULL;
}
static char *clipboard_read_data(int fds[2]) {
size_t read_bs = 1024;
char *new_clipboard_data = g_malloc(read_bs);
if (new_clipboard_data == NULL) {
close(fds[0]);
return NULL;
}
size_t k = 0;
// TODO: do this outside of the wayland loop
while (1) {
ssize_t n = read(fds[0], new_clipboard_data + k, read_bs);
if (n <= 0) {
new_clipboard_data[k] = '\0';
break;
}
k += n;
new_clipboard_data = g_realloc(new_clipboard_data, k + read_bs);
if (new_clipboard_data == NULL) {
close(fds[0]);
return NULL;
}
}
close(fds[0]);
return new_clipboard_data;
}
static void data_offer_handle_offer(void *data, struct wl_data_offer *offer,
const char *mime_type) {}
static const struct wl_data_offer_listener data_offer_listener = {
.offer = data_offer_handle_offer,
};
static void data_device_handle_data_offer(void *data,
struct wl_data_device *data_device,
struct wl_data_offer *offer) {
wl_data_offer_add_listener(offer, &data_offer_listener, NULL);
}
static void data_device_handle_selection(void *data,
struct wl_data_device *data_device,
struct wl_data_offer *offer) {
if (offer == NULL) {
// clipboard is empty
return;
}
int fds[2];
if (pipe(fds) < 0) {
return;
}
wl_data_offer_receive(offer, "text/plain", fds[1]);
close(fds[1]);
wl_display_roundtrip(wayland->display);
char *new_clipboard_data = clipboard_read_data(fds);
if (wayland->clipboard_default_data != NULL) {
g_free(wayland->clipboard_default_data);
}
wayland->clipboard_default_data = new_clipboard_data;
wl_data_offer_destroy(offer);
}
static const struct wl_data_device_listener data_device_listener = {
.data_offer = data_device_handle_data_offer,
.selection = data_device_handle_selection,
};
static void
primary_selection_handle_offer(void *data,
struct zwp_primary_selection_offer_v1 *offer,
const char *mime_type) {}
static const struct zwp_primary_selection_offer_v1_listener
primary_selection_offer_listener = {
.offer = primary_selection_handle_offer,
};
static void primary_selection_device_handle_data_offer(
void *data, struct zwp_primary_selection_device_v1 *data_device,
struct zwp_primary_selection_offer_v1 *offer) {
zwp_primary_selection_offer_v1_add_listener(
offer, &primary_selection_offer_listener, NULL);
}
static void primary_selection_device_handle_selection(
void *data, struct zwp_primary_selection_device_v1 *data_device,
struct zwp_primary_selection_offer_v1 *offer) {
if (offer == NULL) {
// clipboard is empty
return;
}
int fds[2];
if (pipe(fds) < 0) {
return;
}
zwp_primary_selection_offer_v1_receive(offer, "text/plain", fds[1]);
close(fds[1]);
wl_display_roundtrip(wayland->display);
char *new_clipboard_data = clipboard_read_data(fds);
if (wayland->clipboard_primary_data != NULL) {
g_free(wayland->clipboard_primary_data);
}
wayland->clipboard_primary_data = new_clipboard_data;
zwp_primary_selection_offer_v1_destroy(offer);
}
static const struct zwp_primary_selection_device_v1_listener
primary_selection_device_listener = {
.data_offer = primary_selection_device_handle_data_offer,
.selection = primary_selection_device_handle_selection,
};
static void wayland_pointer_release(wayland_seat *self) {
if (self->pointer == NULL) {
return;
@ -774,6 +898,21 @@ static void wayland_seat_capabilities(void *data, struct wl_seat *seat,
(self->pointer != NULL)) {
wayland_pointer_release(self);
}
if (wayland->data_device_manager != NULL) {
self->data_device = wl_data_device_manager_get_data_device(
wayland->data_device_manager, seat);
wl_data_device_add_listener(self->data_device, &data_device_listener, NULL);
}
if (wayland->primary_selection_device_manager != NULL) {
self->primary_selection_device =
zwp_primary_selection_device_manager_v1_get_device(
wayland->primary_selection_device_manager, seat);
zwp_primary_selection_device_v1_add_listener(
self->primary_selection_device, &primary_selection_device_listener,
NULL);
}
}
static void wayland_seat_name(void *data, struct wl_seat *seat,
@ -872,6 +1011,14 @@ static void wayland_registry_handle_global(void *data,
g_hash_table_insert(wayland->outputs, output->output, output);
wl_output_add_listener(output->output, &wayland_output_listener, output);
} else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
wayland->data_device_manager =
wl_registry_bind(registry, name, &wl_data_device_manager_interface, 3);
} else if (strcmp(interface,
zwp_primary_selection_device_manager_v1_interface.name) ==
0) {
wayland->primary_selection_device_manager = wl_registry_bind(
registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
}
}
@ -1172,6 +1319,17 @@ static const struct _view_proxy *wayland_display_view_proxy(void) {
static guint wayland_display_scale(void) { return wayland->scale; }
static char *wayland_get_clipboard_data(int type) {
switch (type) {
case CLIPBOARD_DEFAULT:
return wayland->clipboard_default_data;
case CLIPBOARD_PRIMARY:
return wayland->clipboard_primary_data;
}
return NULL;
}
static display_proxy display_ = {
.setup = wayland_display_setup,
.late_setup = wayland_display_late_setup,
@ -1183,6 +1341,7 @@ static display_proxy display_ = {
.set_input_focus = wayland_display_set_input_focus,
.revert_input_focus = wayland_display_revert_input_focus,
.scale = wayland_display_scale,
.get_clipboard_data = wayland_get_clipboard_data,
.view = wayland_display_view_proxy,
};