summaryrefslogtreecommitdiff
path: root/src/launch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/launch.c')
-rw-r--r--src/launch.c124
1 files changed, 123 insertions, 1 deletions
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 <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
@@ -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);
}
© All Rights Reserved