From dd44bc56abf6354aa1839a8ac419741c729b303f Mon Sep 17 00:00:00 2001 From: speedie Date: Sat, 22 Jul 2023 04:04:23 +0200 Subject: [PATCH] Add clipboard support for Wayland This commit adds clipboard support for Wayland. The implementation is quite ugly though, as it requires the use of an external program and shell (wl-clipboard). It doesn't add a hard dependency though, as if the user doesn't want pasting the dependency is not required. --- PKGBUILD | 4 ++++ README.md | 3 +++ libs/arg.c | 8 +++++++- libs/wl/wayland.c | 38 ++++++++++++++++++++++++++++++++++++++ libs/wl/wayland.h | 2 ++ spmenu.c | 2 +- 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 99928ac..07be5bc 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -27,6 +27,10 @@ makedepends=( ninja ) +optdepends=( + 'wl-clipboard: Clipboard support on Wayland' +) + provides=($pkgname) conflicts=($pkgname) source=( diff --git a/README.md b/README.md index 401ec16..7784900 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,9 @@ can be themed to look identical to dmenu. - For Wayland support, which is optional. - wayland-protocols - For Wayland support, which is optional. +- wl-clipboard + - For Wayland support, which is optional. + - Only required at runtime, and only if pasting is desired. - xkbcommon - For Wayland support, which is optional. - libX11 diff --git a/libs/arg.c b/libs/arg.c index 894ca2f..afcee69 100644 --- a/libs/arg.c +++ b/libs/arg.c @@ -188,10 +188,16 @@ void moveend(Arg *arg) { } void paste(Arg *arg) { +#if USEWAYLAND + if (protocol) { + paste_wl(); + } else { #if USEX - if (!protocol) { paste_x11(arg->i); +#endif } +#elif USEX + paste_x11(arg->i); #endif } diff --git a/libs/wl/wayland.c b/libs/wl/wayland.c index d2a0266..c3d5089 100644 --- a/libs/wl/wayland.c +++ b/libs/wl/wayland.c @@ -74,6 +74,44 @@ int is_correct_modifier(struct state *state, char *modifier) { return 1; } +/* This function is pretty garbage. However I don't feel like implementing all the garbage necessary to paste properly. + * If anyone wants to do it, feel free to pull request. + */ +char *wl_clipboard(void) { + FILE *fp; + char output_text[1024]; + char *clipboard = malloc(sizeof(output_text)); + clipboard[0] = '\0'; + + fp = popen("which wl-paste > /dev/null && wl-paste -t text/plain", "r"); + + if (fp == NULL) { + fprintf(stderr, "spmenu: Failed to open command\n"); + return NULL; + } + + while (fgets(output_text, sizeof(output_text), fp) != NULL) { + strcat(clipboard, output_text); + } + + pclose(fp); + + return clipboard; +} + +void paste_wl(void) { + char *p, *q; + + fprintf(stderr, "gentoo"); + + p = wl_clipboard(); + + insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); // insert selection + + // draw the menu + drawmenu(); +} + void keypress_wl(struct state *state, enum wl_keyboard_key_state key_state, xkb_keysym_t sym) { int i = 0; char buf[8]; diff --git a/libs/wl/wayland.h b/libs/wl/wayland.h index 6f41c30..51746bf 100644 --- a/libs/wl/wayland.h +++ b/libs/wl/wayland.h @@ -149,6 +149,8 @@ static int set_exclusive_zone(struct state *state, unsigned int val); static int set_keyboard(struct state *state, int interactivity); static int add_layer_listener(struct state *state); static int set_visible_layer(struct state *state); +static char *wl_clipboard(void); +static void paste_wl(void); struct wl_buffer *create_buffer(struct state *state); /* Set to 0 if the connection was successful diff --git a/spmenu.c b/spmenu.c index 45b7e0f..81eaff4 100644 --- a/spmenu.c +++ b/spmenu.c @@ -257,7 +257,7 @@ static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp; static char *(*fstrstr)(const char *, const char *) = cistrstr; #if USEX -static void pastesel(void); // TODO: wayland clipboard +static void pastesel(void); static void grabfocus(void); // focus doesn't need to be grabbed on wayland #endif