particle: handle ON_MOUSE_CLICK

If a particle has an on-click handler, execute it when we receive an
ON_MOUSE_CLICK event.

This is done by first tokenizing the command string. We currently
handle one level of quotes, but no escape characters.

Then, fork(). Main process waits for child to finish. Child daemonizes
and then execvp() the tokenized argument vector.
This commit is contained in:
Daniel Eklöf 2018-12-29 16:24:22 +01:00
parent abc4ff0402
commit 620017860e

View file

@ -2,10 +2,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <assert.h> #include <assert.h>
#include <sys/wait.h>
#define LOG_MODULE "particle" #define LOG_MODULE "particle"
#define LOG_ENABLE_DBG 1 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "bar.h" #include "bar.h"
@ -59,10 +62,56 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
LOG_DBG("on_mouse: exposable=%p, event=%s, x=%d, y=%d", exposable, LOG_DBG("on_mouse: exposable=%p, event=%s, x=%d, y=%d", exposable,
event == ON_MOUSE_MOTION ? "motion" : "click", x, y); event == ON_MOUSE_MOTION ? "motion" : "click", x, y);
assert(exposable->particle != NULL); /* If we have a handler, change cursor to a hand */
bar->set_cursor(bar, exposable->on_click == NULL ? "left_ptr" : "hand2");
if (exposable->on_click == NULL) /* If this is a mouse click, and we have a handler, execute it */
bar->set_cursor(bar, "left_ptr"); if (exposable->on_click != NULL && event == ON_MOUSE_CLICK) {
else /* Need a writeable copy, whose scope *we* control */
bar->set_cursor(bar, "hand2"); char *cmd = strdup(exposable->on_click);
const char *end = cmd + strlen(cmd);
char *argv[1024];
size_t tokens = 0;
/* Tokenize the command string */
for (char *ctx, *tok = strtok_r(cmd, " ", &ctx);
tok != NULL;
/*tok = strtok_r(NULL, " ", &ctx)*/)
{
argv[tokens++] = tok;
/* Is the beginning of the next token a quote? */
bool next_is_quoted = &tok[strlen(tok) + 1] < end &&
tok[strlen(tok) + 1] == '"';
tok = strtok_r(NULL, next_is_quoted ? "\"" : " ", &ctx);
}
/* NULL-terminate list (for execvp) */
argv[tokens] = NULL;
pid_t pid = fork();
if (pid == -1)
LOG_ERRNO("failed to run on_click handler (fork)");
else if (pid > 0) {
/* Parent */
free(cmd);
if (waitpid(pid, NULL, 0) == -1)
LOG_ERRNO("failed to wait for on_click handler");
} else {
LOG_DBG("ARGV:");
for (size_t i = 0; i < tokens; i++)
LOG_DBG(" #%zu: \"%s\" ", i, argv[i]);
LOG_DBG("daemonizing on-click handler");
daemon(0, 0);
LOG_DBG("executing on-click handler: %s", cmd);
execvp(argv[0], argv);
LOG_ERRNO("failed to run on_click handler (exec)");
}
}
} }