From 4ca5d2d18009f812abb41f3b58983aeae1147b19 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Thu, 19 Oct 2023 00:17:04 -0700 Subject: launch: interpolate arguments This borrows from vmon.c to support argument interpolation. The only interpolation supported right now is %W for a hex windowid of the focused window. When no window is focused, the id of the root window is supplied. This is a preparatory commit for rmd integration --- src/launch.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) (limited to 'src/launch.c') diff --git a/src/launch.c b/src/launch.c index 3a30eca..9c481a1 100644 --- a/src/launch.c +++ b/src/launch.c @@ -17,6 +17,8 @@ */ /* launching of external processes / X clients */ +#include +#include #include #include #include @@ -26,21 +28,141 @@ #include "launch.h" #include "vwm.h" +#include "window.h" +#include "xwindow.h" #define LAUNCHED_RELATIVE_PRIORITY 10 /* the wm priority plus this is used as the priority of launched processes */ + +/* return an interpolated copy of arg */ +static char * arg_interpolate(const vwm_t *vwm, const char *arg) +{ + FILE *memfp; + char *xarg = NULL; + size_t xarglen; + int fmt = 0; + + assert(vwm); + assert(arg); + + /* this came from vmon.c, it'd be nice if they could share */ + + memfp = open_memstream(&xarg, &xarglen); + if (!memfp) { + VWM_PERROR("unable to create memstream"); + return NULL; + } + + for (size_t i = 0; arg[i]; i++) { + char c = arg[i]; + + if (!fmt) { + if (c == '%') + fmt = 1; + else + fputc(c, memfp); + + continue; + } + + switch (c) { + case 'W': { /* focused X window id in hex, root window if nothing focused */ + vwm_window_t *vwin; + Window winid; + + vwin = vwm_win_get_focused(vwm); + if (vwin) + winid = vwin->xwindow->id; + else + winid = VWM_XROOT(vwm); + + fprintf(memfp, "%#x", (unsigned)winid); + break; + } + + case '%': /* literal % */ + fputc(c, memfp); + break; + + default: + VWM_ERROR("Unrecognized specifier \'%c\'", c); + goto _err; + } + + fmt = 0; + } + + fclose(memfp); + + return xarg; + +_err: + fclose(memfp); + free(xarg); + + return NULL; +} + + +static char ** args_interpolate(vwm_t *vwm, char **argv) +{ + char **args; + int n_args; + + assert(vwm); + assert(argv); + + for (n_args = 0; argv[n_args]; n_args++); + + args = calloc(n_args + 1, sizeof(*args)); + if (!args) + return NULL; + + for (int i = 0; i < n_args; i++) { + args[i] = arg_interpolate(vwm, argv[i]); + if (!args[i]) { + for (int j = 0; j < n_args; j++) + free(args[j]); + free(args); + + return NULL; + } + } + + return args; +} + + +static void args_free(char **args) +{ + assert(args); + + for (int i = 0; args[i]; i++) + free(args[i]); + free(args); +} + + /* launch a child command specified in argv, mode decides if we wait for the child to exit before returning. */ void vwm_launch(vwm_t *vwm, char **argv, vwm_launch_mode_t mode) { + char **args; + + args = args_interpolate(vwm, argv); + if (!args) + return; + /* XXX: in BG mode I double fork and let init inherit the orphan so I don't have to collect the return status */ if (mode == VWM_LAUNCH_MODE_FG || !fork()) { if (!fork()) { /* child */ setpriority(PRIO_PROCESS, getpid(), vwm->priority + LAUNCHED_RELATIVE_PRIORITY); - execvp(argv[0], argv); + execvp(args[0], args); } if (mode == VWM_LAUNCH_MODE_BG) exit(0); } wait(NULL); /* TODO: could wait for the specific pid, particularly in FG mode ... */ + + args_free(args); } -- cgit v1.2.3