From 341cdabdd236543d4cb3191b4a54dcd05f99cf4a Mon Sep 17 00:00:00 2001 From: wreald Date: Wed, 18 Sep 2024 18:40:26 +1000 Subject: [PATCH] Implement live-reload of config colors on SIGUSR1. --- config.c | 18 ++++++++++++++++++ config.h | 2 ++ main.c | 24 ++++++++++++++++++++++++ server.c | 14 ++++++++++++++ server.h | 1 + terminal.c | 25 +++++++++++++++++++++++++ terminal.h | 3 +++ 7 files changed, 87 insertions(+) diff --git a/config.c b/config.c index a8cdb34a..574ee6e2 100644 --- a/config.c +++ b/config.c @@ -3276,6 +3276,7 @@ config_load(struct config *conf, const char *conf_path, enum fcft_capabilities fcft_caps = fcft_capabilities(); *conf = (struct config) { + .path = NULL, .term = xstrdup(FOOT_DEFAULT_TERM), .shell = get_shell(), .title = xstrdup("foot"), @@ -3517,6 +3518,8 @@ config_load(struct config *conf, const char *conf_path, if (conf_file.path && conf_file.fd >= 0) { LOG_INFO("loading configuration from %s", conf_file.path); + conf->path = xstrdup(conf_file.path); + FILE *f = fdopen(conf_file.fd, "r"); if (f == NULL) { LOG_AND_NOTIFY_ERRNO("%s: failed to open", conf_file.path); @@ -3788,6 +3791,20 @@ config_clone(const struct config *old) return conf; } +void +config_reload_colors(struct config *conf) +{ + user_notifications_t notifications = tll_init(); + config_override_t overrides = tll_init(); + struct config new_conf = {NULL}; + config_load(&new_conf, conf->path, ¬ifications, &overrides, false, false); + + // TODO: should we do something with any notifications that come from + // loading the config? + + conf->colors = new_conf.colors; +} + UNITTEST { struct config original; @@ -3816,6 +3833,7 @@ UNITTEST void config_free(struct config *conf) { + free(conf->path); free(conf->term); free(conf->shell); free(conf->title); diff --git a/config.h b/config.h index a08fae31..f023d0b9 100644 --- a/config.h +++ b/config.h @@ -132,6 +132,7 @@ struct custom_regex { }; struct config { + char *path; char *term; char *shell; char *title; @@ -423,6 +424,7 @@ bool config_load( bool as_server); void config_free(struct config *conf); struct config *config_clone(const struct config *old); +void config_reload_colors(struct config *conf); bool config_font_parse(const char *pattern, struct config_font *font); void config_font_list_destroy(struct config_font_list *font_list); diff --git a/main.c b/main.c index b9404503..d0f25f9b 100644 --- a/main.c +++ b/main.c @@ -45,6 +45,20 @@ fdm_sigint(struct fdm *fdm, int signo, void *data) return true; } +static bool +fdm_sigusr1_server(struct fdm *fdm, int signo, void *data) +{ + server_hard_reload_config_colors(data); + return true; +} + +static bool +fdm_sigusr1_term(struct fdm *fdm, int signo, void *data) +{ + term_hard_reload_config_colors(data); + return true; +} + static void print_usage(const char *prog_name) { @@ -608,6 +622,15 @@ main(int argc, char *const *argv) goto out; } + bool ok = as_server ? + fdm_signal_add(fdm, SIGUSR1, fdm_sigusr1_server, server) + : fdm_signal_add(fdm, SIGUSR1, fdm_sigusr1_term, term); + if (!ok) { + LOG_WARN("failed to set SIGUSR1 handler"); + goto out; + } + LOG_INFO("added USR1 handler"); + struct sigaction sig_ign = {.sa_handler = SIG_IGN}; sigemptyset(&sig_ign.sa_mask); if (sigaction(SIGHUP, &sig_ign, NULL) < 0 || @@ -645,6 +668,7 @@ out: reaper_destroy(reaper); fdm_signal_del(fdm, SIGTERM); fdm_signal_del(fdm, SIGINT); + fdm_signal_del(fdm, SIGUSR1); fdm_destroy(fdm); config_free(&conf); diff --git a/server.c b/server.c index 22dd473b..40a92d43 100644 --- a/server.c +++ b/server.c @@ -591,6 +591,20 @@ err: return NULL; } +/* Reload configured colors from disk. */ +void +server_hard_reload_config_colors(struct server *server) { + config_reload_colors((struct config *)server->conf); + + tll_foreach(server->wayl->terms, it) { + struct terminal *term = it->item; + + ((struct config *)term->conf)->colors = server->conf->colors; + + term_soft_reload_config_colors(term); + } +} + void server_destroy(struct server *server) { diff --git a/server.h b/server.h index 50797540..7eae2aa0 100644 --- a/server.h +++ b/server.h @@ -9,3 +9,4 @@ struct server; struct server *server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, struct wayland *wayl); void server_destroy(struct server *server); +void server_hard_reload_config_colors(struct server *server); diff --git a/terminal.c b/terminal.c index ae1adb1a..e6beecc8 100644 --- a/terminal.c +++ b/terminal.c @@ -4693,3 +4693,28 @@ term_send_size_notification(struct terminal *term) term->rows, term->cols, height, width); term_to_slave(term, buf, n); } + +/* Reload configured colors from disk. */ +void +term_hard_reload_config_colors(struct terminal *term) { + config_reload_colors((struct config *)term->conf); + term_soft_reload_config_colors(term); +} + +/* Reset colors to the in-memory config values. Does not reload the config from + disk. */ +void +term_soft_reload_config_colors(struct terminal *term) { + term->colors.fg = term->conf->colors.fg; + term->colors.bg = term->conf->colors.bg; + term->colors.alpha = term->conf->colors.alpha; + term->colors.cursor_fg = term->conf->cursor.color.text; + term->colors.cursor_bg = term->conf->cursor.color.cursor; + term->colors.selection_fg = term->conf->colors.selection_fg; + term->colors.selection_bg = term->conf->colors.selection_bg; + + memcpy(term->colors.table, term->conf->colors.table, sizeof(term->colors.table)); + + term_damage_all(term); + render_refresh(term); +} diff --git a/terminal.h b/terminal.h index 518e36ef..028581ed 100644 --- a/terminal.h +++ b/terminal.h @@ -982,6 +982,9 @@ void term_enable_size_notifications(struct terminal *term); void term_disable_size_notifications(struct terminal *term); void term_send_size_notification(struct terminal *term); +void term_hard_reload_config_colors(struct terminal *term); +void term_soft_reload_config_colors(struct terminal *term); + static inline void term_reset_grapheme_state(struct terminal *term) { #if defined(FOOT_GRAPHEME_CLUSTERING)