From 85a6bb6ba81de493c0ceb9a8d4c2f78eb5d1567f Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Wed, 2 Dec 2020 17:54:35 -0800 Subject: [PATCH] Add support for plumbing via right click --- config.def.h | 5 ++++ st.c | 79 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/config.def.h b/config.def.h index 49ca50b..a63d2be 100644 --- a/config.def.h +++ b/config.def.h @@ -460,3 +460,8 @@ static char ascii_printable[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; +/* + * plumb_cmd is run on mouse button 3 click, with first NULL set to + * current selection and with cwd set to the cwd of the active shell + */ +static char *plumb_cmd[] = {"plumb", NULL, NULL}; diff --git a/st.c b/st.c index 20a3c3c..914fdd5 100644 --- a/st.c +++ b/st.c @@ -44,6 +44,9 @@ char *argv0; #elif defined(__FreeBSD__) || defined(__DragonFly__) #include #endif +#if defined(__OpenBSD__) + #include +#endif /* Arbitrary sizes */ @@ -558,6 +561,8 @@ static void *xmalloc(size_t); static void *xrealloc(void *, size_t); static char *xstrdup(char *); +static int subprocwd(char *, size_t); + static void usage(void); static struct wl_registry_listener reglistener = { regglobal, regglobalremove }; @@ -579,6 +584,7 @@ static struct wl_data_source_listener datasrclistener = { datasrctarget, datasrcsend, datasrccancelled }; /* Globals */ +static int plumbsel; static DC dc; static Wayland wl; static WLD wld; @@ -763,6 +769,21 @@ utf8validate(Rune *u, size_t i) return i; } +int +subprocwd(char *path, size_t len) +{ +#if defined(__linux__) + if (snprintf(path, len, "/proc/%d/cwd", pid) < 0) + return -1; + return 0; +#elif defined(__OpenBSD__) + int name[3] = {CTL_KERN, KERN_PROC_CWD, pid}; + if (sysctl(name, 3, path, &len, 0, 0) == -1) + return -1; + return 0; +#endif +} + void selinit(void) { @@ -1165,6 +1186,29 @@ wlsetsel(char *str, uint32_t serial) wl_data_device_set_selection(wl.datadev, sel.source, serial); } +void +plumbinit(void) +{ + for (plumbsel = 0; plumb_cmd[plumbsel]; ++plumbsel) + ; +} + +void +plumb(char *sel) +{ + char cwd[PATH_MAX]; + + if (!sel || subprocwd(cwd, sizeof(cwd)) != 0) + return; + plumb_cmd[plumbsel] = sel; + + if (fork() == 0) { + if (chdir(cwd) == 0) + execvp(plumb_cmd[0], plumb_cmd); + _exit(1); + } +} + void die(const char *errstr, ...) { @@ -1227,15 +1271,18 @@ sigchld(int a) int stat; pid_t p; - if ((p = waitpid(pid, &stat, WNOHANG)) < 0) - die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); - - if (pid != p) - return; - - if (!WIFEXITED(stat) || WEXITSTATUS(stat)) - die("child finished with error '%d'\n", stat); - exit(0); + for (;;) { + p = waitpid(-1, &stat, WNOHANG); + if (p == 0) + break; + if (p < 0) + die("waitpid: %s\n", strerror(errno)); + if (pid == p) { + if (!WIFEXITED(stat) || WEXITSTATUS(stat)) + die("child finished with error '%d'\n", stat); + exit(0); + } + } } @@ -4224,16 +4271,23 @@ ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, switch (state) { case WL_POINTER_BUTTON_STATE_RELEASED: - if (button == BTN_MIDDLE) { + switch (button) { + case BTN_MIDDLE: selpaste(NULL); - } else if (button == BTN_LEFT) { + break; + case BTN_LEFT: if (sel.mode == SEL_READY) { getbuttoninfo(); selcopy(serial); - } else + } else { selclear(); + } sel.mode = SEL_IDLE; tsetdirt(sel.nb.y, sel.ne.y); + break; + case BTN_RIGHT: + plumb(sel.primary); + break; } break; @@ -4557,6 +4611,7 @@ main(int argc, char *argv[]) } ARGEND; run: + plumbinit(); if (argc > 0) { /* eat all remaining arguments */ opt_cmd = argv; -- 2.37.3