From 1ded834e33c9cb9f8e20d6a0a8738693ae81f851 Mon Sep 17 00:00:00 2001 From: HuntedByTheIRS Date: Mon, 29 Jun 2026 02:41:38 -0400 Subject: [PATCH] Add live reloading to the rest of the config --- include/ipc_socket.h | 1 + src/peachwm.c | 134 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/include/ipc_socket.h b/include/ipc_socket.h index 4b87a02..a75f627 100644 --- a/include/ipc_socket.h +++ b/include/ipc_socket.h @@ -820,6 +820,7 @@ ipc_handle_command(struct ipc_client *client, const char *payload, quit(NULL); success = 1; } else if (!strcmp(cmd, "reload")) { + do_reload(); success = 1; } } diff --git a/src/peachwm.c b/src/peachwm.c index cf553cb..b440a75 100644 --- a/src/peachwm.c +++ b/src/peachwm.c @@ -418,6 +418,7 @@ static void virtualpointer(struct wl_listener *listener, void *data); static Monitor *xytomon(double x, double y); static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); +static void do_reload(void); /* variables */ static pid_t child_pid = -1; @@ -524,6 +525,7 @@ static struct wlr_xwayland *xwayland; static Config cfg; static struct wl_event_source *cfg_watch_src; static const char *custom_cfg_path; +static char config_path[1024]; /* attempt to encapsulate suck into one file */ #include "client.h" @@ -2899,13 +2901,118 @@ static void reapply_input_config(const Config *newcfg) { } } +/* Re-apply monitor configuration from global cfg to existing monitors */ + +static void +reapply_monitor_config(void) +{ + Monitor *m; + wl_list_for_each(m, &mons, link) { + for (int ri = 0; ri < cfg.nmonitors; ri++) { + const CfgMonitorRule *r = &cfg.monitors[ri]; + if (!r->name[0] || strstr(m->wlr_output->name, r->name)) { + m->mfact = r->mfact; + m->nmaster = r->nmaster; + /* Map layout name */ + m->lt[0] = &layouts[0]; + for (int li = 0; li < (int)LENGTH(layouts); li++) { + if (layouts[li].symbol && !strcmp(r->layout, layouts[li].symbol)) { + m->lt[0] = &layouts[li]; + break; + } + if (!strcmp(r->layout, "dwindle") && layouts[li].arrange == dwindle) { + m->lt[0] = &layouts[li]; + break; + } + if (!strcmp(r->layout, "master") && layouts[li].arrange == master) { + m->lt[0] = &layouts[li]; + break; + } + if (!strcmp(r->layout, "monocle") && layouts[li].arrange == monocle) { + m->lt[0] = &layouts[li]; + break; + } + } + m->lt[1] = &layouts[LENGTH(layouts) > 1 && m->lt[0] != &layouts[1]]; + /* Apply scale and transform */ + struct wlr_output_state state; + wlr_output_state_init(&state); + wlr_output_state_set_scale(&state, r->scale); + wlr_output_state_set_transform(&state, r->transform); + wlr_output_commit_state(m->wlr_output, &state); + wlr_output_state_finish(&state); + /* Update position */ + if (r->x != -1 && r->y != -1) + wlr_output_layout_add(output_layout, m->wlr_output, r->x, r->y); + break; + } + } + } +} + +/* Re-apply appearance settings to root background, fullscreen backgrounds, + * and all client borders */ + +static void +reapply_client_appearance(void) +{ + Client *c; + Monitor *m; + wlr_scene_rect_set_color(root_bg, cfg.appearance.root_color); + wl_list_for_each(m, &mons, link) { + wlr_scene_rect_set_color(m->fullscreen_bg, cfg.appearance.fullscreen_bg); + } + wl_list_for_each(c, &clients, link) { + c->bw = !c->isfullscreen ? cfg.appearance.border_px : 0; + if (!client_is_unmanaged(c)) { + float *color = c->isurgent ? cfg.appearance.urgent_color + : c == focustop(c->mon) ? cfg.appearance.focus_color + : cfg.appearance.border_color; + for (int i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], color); + } + } +} + +/* Re-apply window rules from global cfg to all existing clients */ + +static void +reapply_client_rules(void) +{ + Client *c; + wl_list_for_each(c, &clients, link) { + if (client_is_unmanaged(c)) + continue; + const char *appid = client_get_appid(c); + const char *title = client_get_title(c); + for (int ri = 0; ri < cfg.nrules; ri++) { + const CfgRule *r = &cfg.rules[ri]; + if ((!r->title[0] || strstr(title, r->title)) && + (!r->app_id[0] || strstr(appid, r->app_id))) { + c->isfloating = r->floating | client_is_float_type(c); + if (r->tags) { + dwindle_remove_client(c); + master_remove_client(c); + c->tags = r->tags; + } + break; + } + } + } +} + /* Config hot reload callback is fired by the inotify watcher */ -static void on_config_reload(const Config *newcfg, void *ud) { +static void +on_config_reload(const Config *newcfg, void *ud) +{ Monitor *m; (void)ud; reapply_input_config(newcfg); cfg = *newcfg; + reapply_monitor_config(); + reapply_client_appearance(); + reapply_client_rules(); wl_list_for_each(m, &mons, link) { apply_workspace_layout(m, current_tag_idx(m)); arrange(m); @@ -2913,6 +3020,30 @@ static void on_config_reload(const Config *newcfg, void *ud) { printstatus(); } +/* Triggered by the IPC 'reload' command - re-reads config from disk */ + +static void +do_reload(void) +{ + Config fresh; + if (config_load(config_path, &fresh) == 0) { + fprintf(stderr, "peachwm: config reloaded via IPC\n"); + reapply_input_config(&fresh); + cfg = fresh; + reapply_monitor_config(); + reapply_client_appearance(); + reapply_client_rules(); + Monitor *m; + wl_list_for_each(m, &mons, link) { + apply_workspace_layout(m, current_tag_idx(m)); + arrange(m); + } + printstatus(); + } else { + fprintf(stderr, "peachwm: IPC config reload failed\n"); + } +} + void setup(void) { int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; @@ -2937,6 +3068,7 @@ void setup(void) { die("failed to load config from '%s'", path); if (debug_override) cfg.log_level = WLR_DEBUG; + strncpy(config_path, path, sizeof(config_path) - 1); } wlr_log_init(cfg.log_level, NULL);