From 667dad864a3f5ace47c08ab411211b948d82a0c3 Mon Sep 17 00:00:00 2001 From: HuntedByTheIRS Date: Sun, 28 Jun 2026 19:41:21 -0400 Subject: [PATCH] Add workspace starting layouts --- example/config.lua | 9 +++++++++ parser/parser.c | 31 +++++++++++++++++++++++++++++++ parser/parser.h | 3 +++ src/peachwm.c | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/example/config.lua b/example/config.lua index 2db51e4..9d6a3f1 100644 --- a/example/config.lua +++ b/example/config.lua @@ -47,6 +47,15 @@ monitors = { -- layout = "dwindle", x = -1, y = -1 }, } +-- Per-workspace default layouts (overrides the monitor layout for a given workspace) +-- workspaces = { +-- layouts = { +-- [1] = { layout = "dwindle" }, +-- [2] = { layout = "master" }, +-- [3] = { layout = "monocle" }, +-- }, +-- } + -- autostart: it starts stuff in sequence autostart = { "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_SESSION_TYPE XDG_CURRENT_DESKTOP", diff --git a/parser/parser.c b/parser/parser.c index 9b85f78..4735b45 100644 --- a/parser/parser.c +++ b/parser/parser.c @@ -559,6 +559,36 @@ parse_scrolls(lua_State *L, Config *cfg) lua_pop(L, 1); /* scrolls table */ } +static void +parse_workspace_layouts(lua_State *L, Config *cfg) +{ + lua_getglobal(L, "workspaces"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return; + } + + lua_getfield(L, -1, "layouts"); + if (!lua_istable(L, -1)) { + lua_pop(L, 2); + return; + } + + /* Iterate over array-like entries; the numeric key is the workspace number */ + int n = (int)lua_rawlen(L, -1); + for (int ws = 1; ws <= n && ws <= 9; ws++) { + lua_rawgeti(L, -1, ws); + if (!lua_istable(L, -1)) { lua_pop(L, 1); continue; } + + lua_get_string(L, "layout", cfg->workspace_layouts[ws - 1], + sizeof(cfg->workspace_layouts[ws - 1])); + + lua_pop(L, 1); /* entry table */ + } + + lua_pop(L, 2); /* layouts + workspaces */ +} + static void parse_autostart(lua_State *L, Config *cfg) { @@ -648,6 +678,7 @@ config_load(const char *path, Config *cfg) parse_input (L, &cfg->input); parse_rules (L, cfg); parse_monitors (L, cfg); + parse_workspace_layouts(L, cfg); parse_keybinds (L, cfg); parse_buttons (L, cfg); parse_scrolls (L, cfg); diff --git a/parser/parser.h b/parser/parser.h index 63a1070..c093ca4 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -134,6 +134,9 @@ typedef struct { CfgAutostart autostart[CFG_MAX_AUTOSTART]; int nautostart; + + /* Per-workspace (tag) default layouts, indexed by tag index 0-8 */ + char workspace_layouts[9][CFG_MAX_STRLEN]; } Config; /* Public API */ diff --git a/src/peachwm.c b/src/peachwm.c index 119a654..713eae9 100644 --- a/src/peachwm.c +++ b/src/peachwm.c @@ -523,6 +523,36 @@ static const char *custom_cfg_path; #include "ipc.h" /* function implementations */ + +/* Apply a workspace default layout for the given tag index (0-based) on monitor + * m */ +static void apply_workspace_layout(Monitor *m, int tag_idx) { + if (tag_idx < 0 || tag_idx >= TAGCOUNT) + return; + const char *layout_name = cfg.workspace_layouts[tag_idx]; + if (!layout_name[0]) + return; + + for (int li = 0; li < (int)LENGTH(layouts); li++) { + if (layouts[li].symbol && !strcmp(layout_name, layouts[li].symbol)) { + m->lt[m->sellt] = &layouts[li]; + break; + } + if (!strcmp(layout_name, "dwindle") && layouts[li].arrange == dwindle) { + m->lt[m->sellt] = &layouts[li]; + break; + } + if (!strcmp(layout_name, "master") && layouts[li].arrange == master) { + m->lt[m->sellt] = &layouts[li]; + break; + } + if (!strcmp(layout_name, "monocle") && layouts[li].arrange == monocle) { + m->lt[m->sellt] = &layouts[li]; + break; + } + } +} + void applybounds(Client *c, struct wlr_box *bbox) { /* set minimum possible */ c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); @@ -1194,6 +1224,8 @@ void createmon(struct wl_listener *listener, void *data) { } } m->lt[1] = &layouts[LENGTH(layouts) > 1 && m->lt[0] != &layouts[1]]; + /* Apply per-workspace default for the initial tag (workspace 1) */ + apply_workspace_layout(m, 0); strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); wlr_output_state_set_scale(&state, r->scale); wlr_output_state_set_transform(&state, r->transform); @@ -2780,7 +2812,10 @@ static void on_config_reload(const Config *newcfg, void *ud) { Monitor *m; (void)ud; cfg = *newcfg; - wl_list_for_each(m, &mons, link) arrange(m); + wl_list_for_each(m, &mons, link) { + apply_workspace_layout(m, current_tag_idx(m)); + arrange(m); + } printstatus(); } @@ -3642,6 +3677,8 @@ void toggleview(const Arg *arg) { return; selmon->tagset[selmon->seltags] = newtagset; + /* Apply per-workspace default layout if configured */ + apply_workspace_layout(selmon, current_tag_idx(selmon)); focusclient(focustop(selmon), 1); arrange(selmon); printstatus(); @@ -3816,6 +3853,8 @@ void view(const Arg *arg) { selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + /* Apply per-workspace default layout if configured */ + apply_workspace_layout(selmon, current_tag_idx(selmon)); focusclient(focustop(selmon), 1); arrange(selmon); printstatus();