From 620017860ee3de5c777d440d67155f6c302609b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 29 Dec 2018 16:24:22 +0100 Subject: [PATCH] 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. --- particle.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/particle.c b/particle.c index 987fe1e..46a25df 100644 --- a/particle.c +++ b/particle.c @@ -2,10 +2,13 @@ #include #include +#include #include +#include + #define LOG_MODULE "particle" -#define LOG_ENABLE_DBG 1 +#define LOG_ENABLE_DBG 0 #include "log.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, 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) - bar->set_cursor(bar, "left_ptr"); - else - bar->set_cursor(bar, "hand2"); + /* If this is a mouse click, and we have a handler, execute it */ + if (exposable->on_click != NULL && event == ON_MOUSE_CLICK) { + /* Need a writeable copy, whose scope *we* control */ + 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)"); + } + } }