From b319618af15b5afd9d0f63271bd09b4a4a27ad52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 23 Jul 2024 09:33:18 +0200 Subject: [PATCH] notify: XDG token is now expected to be prefixed with xdgtoken= This patch modifies our stdout reader to consume input as we go, instead of all at once when stdout is closed. This will make it easier to add support for reading e.g. the daemon assigned notification ID in the future, and also ensures we see the XDG activation token "as soon as possible". Furthermore, to be more future proof, require the XDG activation token to be prefixed with 'xdgtoken=', and ignore other lines. Thus, instead of treating *all* of stdout as the XDG activation token, parse stdout line-by-line, and ignore everything that does not begin with 'xdgtoken='. Everything (on that line) following 'xdgtoken=' is treated as the activation token. --- doc/foot.ini.5.scd | 13 +++++---- notify.c | 73 ++++++++++++++++++++++++++++++++-------------- notify.h | 18 ++++++++++-- 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index e6b554bb..5135e080 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -463,11 +463,14 @@ Note: do not set *TERM* here; use the *term* option in the main has been configured. For this to work, foot needs an XDG activation token. To this - end, foot will read the command's stdout; everything printed - there, not including trailing newlines, are assumed to be part - of the activation token. There is no harm in printing - something else on stdout - it will simply result in the - activation failing (i.e. the window will not be focused). + end, foot will read the command's stdout; a line prefixed with + *xdgtoken=* will be recognized as containing the XDG + activation token: + + xdgtoken=18179adf579a7a904ce73754964b1ec3 + + The expected format of stdout may change at any time. Please + read the changelog when upgrading foot. *Note*: notify-send does not, out of the box, support reporting the XDG activation token in any way. This means diff --git a/notify.c b/notify.c index 043f41a5..d2ff9d07 100644 --- a/notify.c +++ b/notify.c @@ -28,6 +28,40 @@ notify_free(struct terminal *term, struct notification *notif) free(notif->body); free(notif->icon); free(notif->xdg_token); + free(notif->stdout); +} + +static void +consume_stdout(struct notification *notif, bool eof) +{ + char *data = notif->stdout; + const char *line = data; + size_t left = notif->stdout_sz; + + /* Process stdout, line-by-line */ + while (left > 0) { + line = data; + size_t len = left; + char *eol = memchr(line, '\n', left); + + if (eol != NULL) { + *eol = '\0'; + len = strlen(line); + data = eol + 1; + } else if (!eof) + break; + + /* Check for 'xdgtoken=xyz' */ + if (len > 9 && memcmp(line, "xdgtoken=", 9) == 0) { + notif->xdg_token = xstrndup(&line[9], len - 9); + LOG_DBG("XDG token: \"%s\"", notif->xdg_token); + } + + left -= len + (eol != NULL ? 1 : 0); + } + + memmove(notif->stdout, data, left); + notif->stdout_sz = left; } static bool @@ -36,6 +70,7 @@ fdm_notify_stdout(struct fdm *fdm, int fd, int events, void *data) const struct terminal *term = data; struct notification *notif = NULL; + /* Find notification */ tll_foreach(term->notifications, it) { if (it->item.stdout_fd == fd) { @@ -56,34 +91,25 @@ fdm_notify_stdout(struct fdm *fdm, int fd, int events, void *data) return false; } - if (count > 0) { - buf[count - 1] = '\0'; - - if (notif != NULL) { - if (notif->xdg_token == NULL) { - notif->xdg_token = xstrdup(buf); - } else { - char *new_token = xstrjoin(notif->xdg_token, buf); - free(notif->xdg_token); - notif->xdg_token = new_token; - } + if (count > 0 && notif != NULL) { + if (notif->stdout == NULL) { + xassert(notif->stdout_sz == 0); + notif->stdout = xmemdup(buf, count); + } else { + notif->stdout = xrealloc(notif->stdout, notif->stdout_sz + count); + memcpy(¬if->stdout[notif->stdout_sz], buf, count); } + + notif->stdout_sz += count; + consume_stdout(notif, false); } } if (events & EPOLLHUP) { fdm_del(fdm, fd); - if (notif != NULL) + if (notif != NULL) { notif->stdout_fd = -1; - - /* Strip trailing newlines */ - if (notif != NULL && notif->xdg_token != NULL) { - size_t len = strlen(notif->xdg_token); - - while (len > 0 && notif->xdg_token[len - 1] == '\n') - len--; - - notif->xdg_token[len] = '\0'; + consume_stdout(notif, true); } } @@ -130,6 +156,7 @@ notify_notify(const struct terminal *term, struct notification *notif) xassert(notif->xdg_token == NULL); xassert(notif->pid == 0); xassert(notif->stdout_fd == 0); + xassert(notif->stdout == NULL); notif->pid = -1; notif->stdout_fd = -1; @@ -187,7 +214,9 @@ notify_notify(const struct terminal *term, struct notification *notif) LOG_DBG(" argv[%zu] = \"%s\"", i, argv[i]); int stdout_fds[2] = {-1, -1}; - if (notif->focus && pipe2(stdout_fds, O_CLOEXEC | O_NONBLOCK) < 0) { + if ((notif->focus || notif->report) && + pipe2(stdout_fds, O_CLOEXEC | O_NONBLOCK) < 0) + { LOG_WARN("failed to create stdout pipe"); /* Non-fatal */ } diff --git a/notify.h b/notify.h index 6c43e294..cc34ff74 100644 --- a/notify.h +++ b/notify.h @@ -23,18 +23,30 @@ enum notify_urgency { }; struct notification { + /* + * Set by caller of notify_notify() + */ char *id; char *title; char *body; char *icon; - char *xdg_token; + enum notify_when when; enum notify_urgency urgency; bool focus; bool report; - pid_t pid; - int stdout_fd; + /* + * Used internally by notify + */ + + char *xdg_token; /* XDG activation token, from daemon */ + + pid_t pid; /* Notifier command PID */ + int stdout_fd; /* Notifier command's stdout */ + + char *stdout; /* Data we've reado from command's stdout */ + size_t stdout_sz; }; bool notify_notify(const struct terminal *term, struct notification *notif);