config.def.h | 6 +++++ x.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
diff --git a/config.def.h b/config.def.h index 87ebdbb..265a4ff 100644 --- a/config.def.h +++ b/config.def.h @@ -467,3 +467,9 @@ static char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; + +/* + * plumber_cmd is run on mouse button 3 click, with argument set to + * current selection and with cwd set to the cwd of the active shell + */ +static char *plumber_cmd = "plumb"; diff --git a/x.c b/x.c index 4345892..f319129 100644 --- a/x.c +++ b/x.c @@ -5,6 +5,9 @@ #include <locale.h> #include <signal.h> #include <sys/select.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <dirent.h> #include <time.h> #include <unistd.h> #include <libgen.h> @@ -644,6 +647,77 @@ xsetsel(char *str) setsel(str, CurrentTime); } +char * +subprocwd() +{ + struct dirent* dent; + DIR* srcdir = opendir("/proc/self/task"); + char path[PATH_MAX]; + FILE *fp; + int chpid; + + if (srcdir == NULL) + { + return NULL; + } + + while((dent = readdir(srcdir)) != NULL) + { + struct stat st; + char newdir[PATH_MAX]; + + if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + if (snprintf(newdir, PATH_MAX, "%s/%s", "/proc/self/task", dent->d_name) < 0) + return NULL; + if (stat(newdir, &st) < 0) + continue; + + if (S_ISDIR(st.st_mode)) break; + } + closedir(srcdir); + if (snprintf(path, PATH_MAX, "/proc/self/task/%s/children", dent->d_name) < 0) + return NULL; + if (!(fp = fopen(path, "r"))) + return NULL; + if (fscanf(fp, "%d", &chpid) != 1) { + fclose(fp); + return NULL; + } + fclose(fp); + if (snprintf(path, PATH_MAX, "/proc/%d/cwd", chpid) < 0) + return NULL; + return realpath(path, NULL); +} + +void +plumb(char *sel) { + if (sel == NULL) + return; + char *cwd; + char *cmd; + pid_t child; + cwd = subprocwd(); + if (cwd == NULL) + return; + + switch(child = fork()) { + case -1: + return; + case 0: + if (cwd == NULL) + exit(1); + cmd = malloc(PATH_MAX+100); + if (snprintf(cmd, PATH_MAX+100, "(cd %s ; %s %s)", cwd, plumber_cmd, sel) < 0) + exit(1); + free(cwd); + execvp("sh", (char *const []){"sh", "-c", cmd, 0}); + exit(0); + default: + waitpid(child, NULL, 0); + } +} + void brelease(XEvent *e) { @@ -656,6 +730,8 @@ brelease(XEvent *e) selpaste(NULL); else if (e->xbutton.button == Button1) mousesel(e, 1); + else if (e->xbutton.button == Button3) + plumb(xsel.primary); } void