From 318965b71597b0617a893739d958e153a08faa00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 24 Sep 2020 14:32:39 +0200 Subject: [PATCH 1/2] module/clock: internally use either minutes or seconds granularity --- modules/clock.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/modules/clock.c b/modules/clock.c index 0599e9a..2ff4f28 100644 --- a/modules/clock.c +++ b/modules/clock.c @@ -4,7 +4,10 @@ #include #include +#include +#define LOG_MODULE "clock" +#include "../log.h" #include "../bar/bar.h" #include "../config.h" #include "../config-verify.h" @@ -12,6 +15,10 @@ struct private { struct particle *label; + enum { + UPDATE_GRANULARITY_SECONDS, + UPDATE_GRANULARITY_MINUTES, + } update_granularity; char *date_format; char *time_format; }; @@ -55,20 +62,56 @@ content(struct module *mod) static int run(struct module *mod) { + const struct private *m = mod->private; const struct bar *bar = mod->bar; bar->refresh(bar); while (true) { - time_t now = time(NULL); - time_t now_no_secs = now / 60 * 60; - assert(now_no_secs % 60 == 0); + struct timespec _now; + clock_gettime(CLOCK_REALTIME, &_now); - time_t next_min = now_no_secs + 60; - time_t timeout = next_min - now; - assert(timeout >= 0 && timeout <= 60); + const struct timeval now = { + .tv_sec = _now.tv_sec, + .tv_usec = _now.tv_nsec / 1000, + }; + + int timeout_ms; + + switch (m->update_granularity) { + case UPDATE_GRANULARITY_SECONDS: { + const struct timeval next_second = { + .tv_sec = now.tv_sec + 1, + .tv_usec = 0}; + + struct timeval _timeout; + timersub(&next_second, &now, &_timeout); + + assert(_timeout.tv_sec == 0 || + (_timeout.tv_sec == 1 && _timeout.tv_usec == 0)); + timeout_ms = _timeout.tv_usec / 1000; + break; + } + + case UPDATE_GRANULARITY_MINUTES: { + const struct timeval next_minute = { + .tv_sec = now.tv_sec / 60 * 60 + 60, + .tv_usec = 0, + }; + + struct timeval _timeout; + timersub(&next_minute, &now, &_timeout); + timeout_ms = _timeout.tv_sec * 1000 + _timeout.tv_usec / 1000; + } + } + + /* Add 1ms to account for rounding errors */ + timeout_ms++; + + LOG_DBG("now: %lds %ldµs -> timeout: %dms", + now.tv_sec, now.tv_usec, timeout_ms); struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; - poll(fds, 1, timeout * 1000); + poll(fds, 1, timeout_ms); if (fds[0].revents & POLLIN) break; @@ -86,6 +129,7 @@ clock_new(struct particle *label, const char *date_format, const char *time_form m->label = label; m->date_format = strdup(date_format); m->time_format = strdup(time_format); + m->update_granularity = UPDATE_GRANULARITY_MINUTES; struct module *mod = module_common_new(); mod->private = m; From 0cde404d2a5145d2fd91e049e5b0b874cd199ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 24 Sep 2020 15:59:46 +0200 Subject: [PATCH 2/2] module/clock: detect when we need to update every second Closes #12 --- CHANGELOG.md | 2 ++ modules/clock.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a95f16..e42b0fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ * YAML parsing error messages being replaced with a generic _“unknown error”_. * Memory leak when a YAML parsing error was encountered. +* clock: update every second when necessary + (https://codeberg.org/dnkl/yambar/issues/12). ### Security diff --git a/modules/clock.c b/modules/clock.c index 2ff4f28..6c0cb56 100644 --- a/modules/clock.c +++ b/modules/clock.c @@ -7,6 +7,7 @@ #include #define LOG_MODULE "clock" +#define LOG_ENABLE_DBG 0 #include "../log.h" #include "../bar/bar.h" #include "../config.h" @@ -129,8 +130,32 @@ clock_new(struct particle *label, const char *date_format, const char *time_form m->label = label; m->date_format = strdup(date_format); m->time_format = strdup(time_format); + + static const char *const seconds_formatters[] = { + "%c", + "%s", + "%S", + "%T", + "%r", + "%X", + }; + m->update_granularity = UPDATE_GRANULARITY_MINUTES; + for (size_t i = 0; + i < sizeof(seconds_formatters) / sizeof(seconds_formatters[0]); + i++) + { + if (strstr(time_format, seconds_formatters[i]) != NULL) { + m->update_granularity = UPDATE_GRANULARITY_SECONDS; + break; + } + } + + LOG_DBG("using %s update granularity", + (m->update_granularity == UPDATE_GRANULARITY_MINUTES + ? "minutes" : "seconds")); + struct module *mod = module_common_new(); mod->private = m; mod->run = &run;