diff options
Diffstat (limited to 'patches/ttym-notify-2.0.diff')
| -rw-r--r-- | patches/ttym-notify-2.0.diff | 232 |
1 files changed, 0 insertions, 232 deletions
diff --git a/patches/ttym-notify-2.0.diff b/patches/ttym-notify-2.0.diff deleted file mode 100644 index a80eef3..0000000 --- a/patches/ttym-notify-2.0.diff +++ /dev/null @@ -1,232 +0,0 @@ -diff -ruN a/config.def.h b/config.def.h ---- a/config.def.h 2026-05-20 12:03:30.597867999 +0200 -+++ b/config.def.h 2026-05-20 12:03:30.597867999 +0200 -@@ -3,3 +3,16 @@ - /* progress bar glyphs (ASCII default) */ - static const char *const BAR_FILL = ">"; - static const char *const BAR_EMPTY = "-"; -+ -+/* desktop notification on countdown completion. -+ * Tokens are split on whitespace; placeholders {title} and {msg} are expanded. -+ * Set NULL or "" to disable. -+ */ -+static const char *const TITLE = "Timer"; -+static const char *const NOTIFY_CMD = "notify-send -u critical {title} {msg}"; -+ -+/* sound on countdown completion. If SOUND_CMD is "" the binary autodetects -+ * a player (paplay/aplay/mpv/ffplay) and plays a default freedesktop sound. -+ * SOUND_CMD is split on whitespace; same token rules as NOTIFY_CMD. -+ */ -+static const char *const SOUND_CMD = ""; -diff -ruN a/ttym.c b/ttym.c ---- a/ttym.c 2026-05-20 12:03:30.597867999 +0200 -+++ b/ttym.c 2026-05-20 12:03:53.438340036 +0200 -@@ -12,6 +12,7 @@ - #include <stdlib.h> - #include <string.h> - #include <sys/ioctl.h> -+#include <sys/wait.h> - #include <termios.h> - #include <time.h> - #include <unistd.h> -@@ -23,6 +24,10 @@ - typedef struct { - int quiet; /* -q: suppress completion bell */ - int silent; /* -s: no bell, no extras */ -+ const char *title; -+ const char *notify_cmd; -+ const char *sound_cmd; -+ char msg[1024]; - } Config; - - static struct termios oldtios; -@@ -226,6 +231,142 @@ - fflush(stdout); - } - -+/* ===== subprocess + placeholder expansion ===== -+ * Tokens split on whitespace; {title} and {msg} expanded within each token. -+ * No shell involved — argv stays argv. -+ */ -+ -+static int -+build_argv(const char *cmd, const Config *c, char ***out) -+{ -+ char buf[2048]; -+ snprintf(buf, sizeof(buf), "%s", cmd); -+ char **argv = calloc(64, sizeof(char *)); -+ if (!argv) return -1; -+ int argc = 0; -+ char *p = buf; -+ while (*p && argc < 63) { -+ while (*p && isspace((unsigned char)*p)) p++; -+ if (!*p) break; -+ char *start = p; -+ while (*p && !isspace((unsigned char)*p)) p++; -+ if (*p) *p++ = '\0'; -+ char tok[2048]; size_t oi = 0; -+ for (char *q = start; *q && oi < sizeof(tok) - 1; ) { -+ const char *sub = NULL; size_t skip = 0; -+ if (!strncmp(q, "{msg}", 5)) { sub = c->msg; skip = 5; } -+ else if (!strncmp(q, "{title}", 7)) { sub = c->title; skip = 7; } -+ if (sub) { -+ size_t sl = strlen(sub); -+ if (oi + sl >= sizeof(tok)) sl = sizeof(tok) - 1 - oi; -+ memcpy(tok + oi, sub, sl); -+ oi += sl; q += skip; -+ } else { tok[oi++] = *q++; } -+ } -+ tok[oi] = '\0'; -+ argv[argc++] = strdup(tok); -+ } -+ argv[argc] = NULL; -+ *out = argv; -+ return argc; -+} -+ -+static void -+free_argv(char **argv) -+{ -+ if (!argv) return; -+ for (int i = 0; argv[i]; i++) free(argv[i]); -+ free(argv); -+} -+ -+static void -+spawn_bg(char *const argv[]) -+{ -+ pid_t pid = fork(); -+ if (pid == 0) { -+ setsid(); -+ int devnull = open("/dev/null", O_RDWR); -+ if (devnull >= 0) { -+ dup2(devnull, 0); dup2(devnull, 1); dup2(devnull, 2); -+ if (devnull > 2) close(devnull); -+ } -+ execvp(argv[0], argv); -+ _exit(127); -+ } -+ (void)pid; -+} -+ -+static int -+command_exists(const char *name) -+{ -+ const char *path = getenv("PATH"); -+ if (!path) return 0; -+ char buf[512]; -+ const char *p = path; -+ while (*p) { -+ const char *e = strchr(p, ':'); -+ size_t len = e ? (size_t)(e - p) : strlen(p); -+ if (len > 0 && len + strlen(name) + 2 < sizeof(buf)) { -+ snprintf(buf, sizeof(buf), "%.*s/%s", (int)len, p, name); -+ if (access(buf, X_OK) == 0) return 1; -+ } -+ if (!e) break; -+ p = e + 1; -+ } -+ return 0; -+} -+ -+static const char * -+detect_sound_player(void) -+{ -+ static const char *cands[] = { "paplay", "aplay", "mpv", "ffplay", NULL }; -+ for (int i = 0; cands[i]; i++) -+ if (command_exists(cands[i])) return cands[i]; -+ return NULL; -+} -+ -+static const char * -+default_sound_path(void) -+{ -+ static const char *paths[] = { -+ "/usr/share/sounds/freedesktop/stereo/complete.oga", -+ "/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga", -+ "/usr/share/sounds/alsa/Front_Center.wav", -+ NULL -+ }; -+ for (int i = 0; paths[i]; i++) -+ if (access(paths[i], R_OK) == 0) return paths[i]; -+ return NULL; -+} -+ -+static void -+notify_and_sound(const Config *c) -+{ -+ if (c->notify_cmd && c->notify_cmd[0] && command_exists("notify-send")) { -+ char **a; -+ if (build_argv(c->notify_cmd, c, &a) > 0) { -+ spawn_bg(a); -+ free_argv(a); -+ } -+ } -+ if (!c->quiet) { -+ if (c->sound_cmd && c->sound_cmd[0]) { -+ char **a; -+ if (build_argv(c->sound_cmd, c, &a) > 0) { -+ spawn_bg(a); -+ free_argv(a); -+ } -+ } else { -+ const char *pl = detect_sound_player(); -+ const char *sp = default_sound_path(); -+ if (pl && sp) { -+ char *a[] = { (char *)pl, (char *)sp, NULL }; -+ spawn_bg(a); -+ } -+ } -+ } -+} -+ - /* ===== usage ===== - * Patches MUST update this in lockstep with new flags so -h always - * reflects the build. -@@ -236,8 +377,8 @@ - { - fprintf(f, - "usage:\n" --" timer [FLAGS] DURATION countdown\n" --" timer [FLAGS] stopwatch\n" -+" timer [FLAGS] DURATION [MESSAGE...] countdown\n" -+" timer [FLAGS] stopwatch\n" - "\n" - "DURATION: 25m | 90s | 2h | 1h30m | 01:30:00 | 25:00\n" - "FLAGS:\n" -@@ -370,6 +511,7 @@ - printf("\r\033[32mDONE %s 100%%%*s\033[0m\n", tb, 20, ""); - else - printf("DONE %s 100%%\n", tb); -+ if (!cfg->silent) notify_and_sound(cfg); - if (!cfg->silent && !cfg->quiet && out_tty) { - fputc('\a', stdout); - fflush(stdout); -@@ -387,6 +529,10 @@ - main(int argc, char **argv) - { - Config cfg = {0}; -+ cfg.title = TITLE; -+ cfg.notify_cmd = NOTIFY_CMD; -+ cfg.sound_cmd = SOUND_CMD; -+ snprintf(cfg.msg, sizeof(cfg.msg), "%s", "Time is up"); - - /* Pre-strip long-form flags before getopt. Stop at "--". */ - int new_argc = 0; -@@ -424,6 +570,16 @@ - free(new_argv); - return 1; - } -+ if (rem_argc > 1) { -+ size_t off = 0; -+ cfg.msg[0] = '\0'; -+ for (int i = 1; i < rem_argc && off < sizeof(cfg.msg) - 2; i++) { -+ int n = snprintf(cfg.msg + off, sizeof(cfg.msg) - off, -+ "%s%s", (i > 1 ? " " : ""), rem_argv[i]); -+ if (n < 0) break; -+ off += (size_t)n; -+ } -+ } - } - - int rc = run(total, stopwatch, &cfg); |
