From 8cc5579e16e8222cd87ce203c64afd3cb204938d Mon Sep 17 00:00:00 2001 From: Gerry Hernandez Date: Thu, 5 Mar 2026 23:59:06 -0800 Subject: [PATCH] Make number of tags configurable (tag_count) --- mmsg/mmsg.c | 14 ++++++------ src/config/parse_config.h | 15 ++++++++----- src/config/preset.h | 4 +--- src/dispatch/bind_define.h | 4 ++-- src/ext-protocol/dwl-ipc.h | 4 ++-- src/ext-protocol/ext-workspace.h | 18 ++++++++++------ src/fetch/monitor.h | 12 +++++------ src/mango.c | 37 +++++++++++++++++++++----------- 8 files changed, 64 insertions(+), 44 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 4e0e1d8c..7a361a13 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -85,9 +85,9 @@ static void noop_scale(void *data, struct wl_output *wl_output, static void noop_description(void *data, struct wl_output *wl_output, const char *description) {} -// 将 n 转换为 9 位二进制字符串,结果存入 buf(至少长度 10) -void bin_str_9bits(char *buf, uint32_t n) { - for (int32_t i = 8; i >= 0; i--) { +// Convert n to an N-bit binary string, store result in buf (minimum length bits+1) +void bin_str_nbits(char *buf, uint32_t n, int32_t bits) { + for (int32_t i = bits - 1; i >= 0; i--) { *buf++ = ((n >> i) & 1) ? '1' : '0'; } *buf = '\0'; // 字符串结尾 @@ -395,11 +395,11 @@ static void dwl_ipc_output_frame(void *data, printf("%s clients %u\n", output_name, total_clients); - char occ_str[10], seltags_str[10], urg_str[10]; + char occ_str[tagcount + 1], seltags_str[tagcount + 1], urg_str[tagcount + 1]; - bin_str_9bits(occ_str, occ); - bin_str_9bits(seltags_str, seltags); - bin_str_9bits(urg_str, urg); + bin_str_nbits(occ_str, occ, tagcount); + bin_str_nbits(seltags_str, seltags, tagcount); + bin_str_nbits(urg_str, urg, tagcount); printf("%s tags %u %u %u\n", output_name, occ, seltags, urg); printf("%s tags %s %s %s\n", output_name, occ_str, seltags_str, urg_str); diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ce5db532..2a3330b7 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -359,6 +359,8 @@ typedef struct { int32_t allow_shortcuts_inhibit; int32_t allow_lock_transparent; + int32_t tag_count; + struct xkb_rule_names xkb_rules; char keymode[28]; @@ -1111,7 +1113,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, while (token != NULL) { int32_t num = atoi(token); - if (num > 0 && num <= LENGTH(tags)) { + if (num > 0 && num <= tag_count) { mask |= (1 << (num - 1)); } token = strtok_r(NULL, "|", &saveptr); @@ -1573,6 +1575,8 @@ bool parse_option(Config *config, char *key, char *value) { config->default_mfact = atof(value); } else if (strcmp(key, "default_nmaster") == 0) { config->default_nmaster = atoi(value); + } else if (strcmp(key, "tag_count") == 0) { + config->tag_count = CLAMP_INT(atoi(value), 1, 32); } else if (strcmp(key, "center_master_overspread") == 0) { config->center_master_overspread = atoi(value); } else if (strcmp(key, "center_when_single_stack") == 0) { @@ -1893,7 +1897,7 @@ bool parse_option(Config *config, char *key, char *value) { trim_whitespace(val); if (strcmp(key, "id") == 0) { - rule->id = CLAMP_INT(atoi(val), 0, LENGTH(tags)); + rule->id = CLAMP_INT(atoi(val), 0, tag_count); } else if (strcmp(key, "layout_name") == 0) { rule->layout_name = strdup(val); } else if (strcmp(key, "monitor_name") == 0) { @@ -3288,6 +3292,7 @@ void set_value_default() { config.new_is_master = new_is_master; // 新窗口是否插在头部 config.default_mfact = default_mfact; // master 窗口比例 config.default_nmaster = default_nmaster; // 默认master数量 + config.tag_count = tag_count; config.center_master_overspread = center_master_overspread; // 中心master时是否铺满 config.center_when_single_stack = @@ -3731,7 +3736,7 @@ void reapply_master(void) { int32_t i; Monitor *m = NULL; - for (i = 0; i <= LENGTH(tags); i++) { + for (i = 0; i <= tag_count; i++) { wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) { continue; @@ -3752,7 +3757,7 @@ void parse_tagrule(Monitor *m) { Client *c = NULL; bool match_rule = false; - for (i = 0; i <= LENGTH(tags); i++) { + for (i = 0; i <= tag_count; i++) { m->pertag->nmasters[i] = default_nmaster; m->pertag->mfacts[i] = default_mfact; } @@ -3810,7 +3815,7 @@ void parse_tagrule(Monitor *m) { } } - for (i = 1; i <= LENGTH(tags); i++) { + for (i = 1; i <= tag_count; i++) { wl_list_for_each(c, &clients, link) { if ((c->tags & (1 << (i - 1)) & TAGMASK) && ISTILED(c)) { if (m->pertag->mfacts[i] > 0.0f) diff --git a/src/config/preset.h b/src/config/preset.h index d9824588..e8b244bb 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -207,9 +207,7 @@ enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT -static const char *tags[] = { - "1", "2", "3", "4", "5", "6", "7", "8", "9", -}; +int32_t tag_count = 9; float focused_opacity = 1.0; float unfocused_opacity = 1.0; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 5cf41d6c..d6678708 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1515,10 +1515,10 @@ int32_t viewtoright_have_client(const Arg *arg) { return 0; } - if (current >= LENGTH(tags)) + if (current >= tag_count) return 0; - for (n = current + 1; n <= LENGTH(tags); n++) { + for (n = current + 1; n <= tag_count; n++) { if (get_tag_status(n, selmon)) { found = true; break; diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index ab0bdb8d..23934807 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -55,7 +55,7 @@ void dwl_ipc_manager_bind(struct wl_client *client, void *data, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy); - zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags)); + zdwl_ipc_manager_v2_send_tags(manager_resource, tag_count); for (uint32_t i = 0; i < LENGTH(layouts); i++) zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); @@ -118,7 +118,7 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { focused = focustop(monitor); zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); - for (tag = 0; tag < LENGTH(tags); tag++) { + for (tag = 0; tag < tag_count; tag++) { numclients = state = focused_client = 0; tagmask = 1 << tag; if ((tagmask & monitor->tagset[monitor->seltags]) != 0) diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 28aaeeeb..fa07b1ca 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -69,10 +69,13 @@ static void handle_ext_workspace_deactivate(struct wl_listener *listener, wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); } -static const char *get_name_from_tag(uint32_t tag) { - static const char *names[] = {"overview", "1", "2", "3", "4", - "5", "6", "7", "8", "9"}; - return (tag < sizeof(names) / sizeof(names[0])) ? names[tag] : NULL; +static const char *get_name_from_tag(uint32_t tag, char *buf, size_t len) { + if (tag == 0) + return "overview"; + if (tag > (uint32_t)tag_count) + return NULL; + snprintf(buf, len, "%u", tag); + return buf; } void destroy_workspace(struct workspace *workspace) { @@ -103,7 +106,8 @@ static void remove_workspace_by_tag(uint32_t tag, Monitor *m) { } static void add_workspace_by_tag(int32_t tag, Monitor *m) { - const char *name = get_name_from_tag(tag); + char name_buf[4]; + const char *name = get_name_from_tag(tag, name_buf, sizeof(name_buf)); struct workspace *workspace = ecalloc(1, sizeof(*workspace)); wl_list_append(&workspaces, &workspace->link); @@ -165,13 +169,13 @@ void refresh_monitors_workspaces_status(Monitor *m) { int32_t i; if (m->isoverview) { - for (i = 1; i <= LENGTH(tags); i++) { + for (i = 1; i <= tag_count; i++) { remove_workspace_by_tag(i, m); } add_workspace_by_tag(0, m); } else { remove_workspace_by_tag(0, m); - for (i = 1; i <= LENGTH(tags); i++) { + for (i = 1; i <= tag_count; i++) { add_workspace_by_tag(i, m); } } diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index d2b4fe62..6c1e8a24 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -57,14 +57,14 @@ uint32_t get_tags_first_tag_num(uint32_t source_tags) { return selmon->pertag->curtag; } - for (i = 0; !(tag & 1) && source_tags != 0 && i < LENGTH(tags); i++) { + for (i = 0; !(tag & 1) && source_tags != 0 && i < tag_count; i++) { tag = source_tags >> i; } if (i == 1) { return 1; - } else if (i > 9) { - return 9; + } else if (i > tag_count) { + return tag_count; } else { return i; } @@ -79,14 +79,14 @@ uint32_t get_tags_first_tag(uint32_t source_tags) { return selmon->pertag->curtag; } - for (i = 0; !(tag & 1) && source_tags != 0 && i < LENGTH(tags); i++) { + for (i = 0; !(tag & 1) && source_tags != 0 && i < tag_count; i++) { tag = source_tags >> i; } if (i == 1) { return 1; - } else if (i > 9) { - return 1 << 8; + } else if (i > tag_count) { + return 1 << (tag_count - 1); } else { return 1 << (i - 1); } diff --git a/src/mango.c b/src/mango.c index 3ae5ccc9..3e0ea8f6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -117,7 +117,7 @@ ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TAGMASK (tag_count == 32 ? ~0u : ((1u << tag_count) - 1)) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define ISFULLSCREEN(A) \ ((A)->isfullscreen || (A)->ismaximizescreen || \ @@ -925,13 +925,12 @@ static struct { #include "config/preset.h" struct Pertag { - uint32_t curtag, prevtag; /* current and previous tag */ - int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ - float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ - bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ - bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */ - const Layout - *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ + uint32_t curtag, prevtag; /* current and previous tag */ + int32_t *nmasters; /* number of windows in master area */ + float *mfacts; /* mfacts per tag */ + bool *no_hide; /* no_hide per tag */ + bool *no_render_border; /* no_render_border per tag */ + const Layout **ltidxs; /* matrix of tags and layouts indexes */ }; static struct wl_signal mango_print_status; @@ -2292,6 +2291,11 @@ void cleanupmon(struct wl_listener *listener, void *data) { m->skip_frame_timeout = NULL; } m->wlr_output->data = NULL; + free(m->pertag->nmasters); + free(m->pertag->mfacts); + free(m->pertag->no_hide); + free(m->pertag->no_render_border); + free(m->pertag->ltidxs); free(m->pertag); free(m); } @@ -3025,6 +3029,14 @@ void createmon(struct wl_listener *listener, void *data) { wl_list_insert(&mons, &m->link); m->pertag = calloc(1, sizeof(Pertag)); + m->pertag->nmasters = calloc(tag_count + 1, sizeof(int32_t)); + m->pertag->mfacts = calloc(tag_count + 1, sizeof(float)); + m->pertag->no_hide = calloc(tag_count + 1, sizeof(bool)); + m->pertag->no_render_border = calloc(tag_count + 1, sizeof(bool)); + m->pertag->ltidxs = calloc(tag_count + 1, sizeof(const Layout *)); + if (!m->pertag->nmasters || !m->pertag->mfacts || !m->pertag->no_hide || + !m->pertag->no_render_border || !m->pertag->ltidxs) + die("pertag calloc failed"); if (chvt_backup_tag && regex_match(chvt_backup_selmon, m->wlr_output->name)) { m->tagset[0] = m->tagset[1] = (1 << (chvt_backup_tag - 1)) & TAGMASK; @@ -3036,7 +3048,7 @@ void createmon(struct wl_listener *listener, void *data) { m->pertag->curtag = m->pertag->prevtag = 1; } - for (i = 0; i <= LENGTH(tags); i++) { + for (i = 0; i <= tag_count; i++) { m->pertag->nmasters[i] = default_nmaster; m->pertag->mfacts[i] = default_mfact; m->pertag->ltidxs[i] = &layouts[0]; @@ -3077,7 +3089,7 @@ void createmon(struct wl_listener *listener, void *data) { ext_manager, EXT_WORKSPACE_ENABLE_CAPS); wlr_ext_workspace_group_handle_v1_output_enter(m->ext_group, m->wlr_output); - for (i = 1; i <= LENGTH(tags); i++) { + for (i = 1; i <= tag_count; i++) { add_workspace_by_tag(i, m); } @@ -5444,6 +5456,7 @@ void setup(void) { setenv("XDG_CURRENT_DESKTOP", "mango", 1); parse_config(); + tag_count = config.tag_count; init_baked_points(); int32_t drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; @@ -6259,10 +6272,10 @@ void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, if (arg->ui == (~0 & TAGMASK)) m->pertag->curtag = 0; else { - for (i = 0; !(arg->ui & 1 << i) && i < LENGTH(tags) && arg->ui != 0; + for (i = 0; !(arg->ui & 1 << i) && i < tag_count && arg->ui != 0; i++) ; - m->pertag->curtag = i >= LENGTH(tags) ? LENGTH(tags) : i + 1; + m->pertag->curtag = i >= tag_count ? tag_count : i + 1; } m->pertag->prevtag =