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);