From de3af1e8c66d52946d8a7b9ddcf7dbb502cb71b3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 28 Feb 2025 12:55:02 +0800 Subject: [PATCH] feat: limit circle switch layout --- config.conf | 4 ++ maomao.c | 48 +++++++++++++--- parse_config.h | 149 +++++++++++++++++++++++++++++++++++++++++++++--- preset_config.h | 1 - 4 files changed, 184 insertions(+), 18 deletions(-) diff --git a/config.conf b/config.conf index 12b1104..e5ccb7c 100644 --- a/config.conf +++ b/config.conf @@ -65,6 +65,10 @@ urgentcolor=0xad401fff scratchpadcolor=0x516c93ff globalcolor=0xb153a7ff +# layout circle limit +# if not set, it will circle all layout +# circle_layout=spiral,scroller + # tags rule # layout support: tile,scroller,grid,monocle,spiral,dwindle tags=id:1,layout_name:tile diff --git a/maomao.c b/maomao.c index bb03185..692a98c 100644 --- a/maomao.c +++ b/maomao.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -4405,7 +4406,38 @@ setlayout(const Arg *arg) { void switch_layout(const Arg *arg) { - int jk; + int jk,ji; + char *target_layout_name=NULL; + size_t len; + + if(config.circle_layout_count != 0) { + for(jk = 0; jk < config.circle_layout_count; jk++) { + + len = MAX(strlen(config.circle_layout[jk]), strlen(selmon->pertag->ltidxs[selmon->pertag->curtag]->name)); + + if(strncmp(config.circle_layout[jk], selmon->pertag->ltidxs[selmon->pertag->curtag]->name,len) == 0) { + target_layout_name = jk == config.circle_layout_count - 1 ? config.circle_layout[0] : config.circle_layout[jk + 1]; + break; + } + } + + if(!target_layout_name) { + target_layout_name = config.circle_layout[0]; + } + + for (ji = 0; ji < LENGTH(layouts); ji++) { + len = MAX(strlen(layouts[ji].name), strlen(target_layout_name)); + if (strncmp(layouts[ji].name,target_layout_name,len) == 0) { + selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji]; + break; + } + } + + arrange(selmon, false); + printstatus(); + return; + } + for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, selmon->pertag->ltidxs[selmon->pertag->curtag]->name) == 0) { @@ -5338,26 +5370,26 @@ void overview_restore(Client *c, const Arg *arg) { void switch_proportion_preset(const Arg *arg) { float target_proportion = 0; - if (LENGTH(scroller_proportion_preset) == 0) { + if (config.scroller_proportion_preset_count == 0) { return; } if (selmon->sel) { - for (int i = 0; i < LENGTH(scroller_proportion_preset); i++) { - if (scroller_proportion_preset[i] == selmon->sel->scroller_proportion) { - if (i == LENGTH(scroller_proportion_preset) - 1) { - target_proportion = scroller_proportion_preset[0]; + for (int i = 0; i < config.scroller_proportion_preset_count; i++) { + if (config.scroller_proportion_preset[i] == selmon->sel->scroller_proportion) { + if (i == config.scroller_proportion_preset_count - 1) { + target_proportion = config.scroller_proportion_preset[0]; break; } else { - target_proportion = scroller_proportion_preset[i + 1]; + target_proportion = config.scroller_proportion_preset[i + 1]; break; } } } if (target_proportion == 0) { - target_proportion = scroller_proportion_preset[0]; + target_proportion = config.scroller_proportion_preset[0]; } unsigned int max_client_width = diff --git a/parse_config.h b/parse_config.h index cc811b8..14226f2 100644 --- a/parse_config.h +++ b/parse_config.h @@ -81,7 +81,11 @@ typedef struct { int scroller_structs; float scroller_default_proportion; int scoller_focus_center; - float scroller_proportion_preset[3]; + float *scroller_proportion_preset; + int scroller_proportion_preset_count; + + char **circle_layout; + int circle_layout_count; unsigned int new_is_master; float default_mfact; @@ -154,6 +158,17 @@ typedef struct { typedef void (*FuncType)(const Arg *); Config config; +// 清理字符串中的不可见字符(包括 \r, \n, 空格等) +char* sanitize_string(char *str) { + // 去除首部不可见字符 + while (*str != '\0' && !isprint((unsigned char)*str)) str++; + // 去除尾部不可见字符 + char *end = str + strlen(str) - 1; + while (end > str && !isprint((unsigned char)*end)) end--; + *(end + 1) = '\0'; + return str; +} + int parse_circle_direction(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; @@ -478,13 +493,109 @@ void parse_config_line(Config *config, const char *line) { } else if (strcmp(key, "scoller_focus_center") == 0) { config->scoller_focus_center = atoi(value); } else if (strcmp(key, "scroller_proportion_preset") == 0) { - if (sscanf(value, "%f,%f,%f", &config->scroller_proportion_preset[0], - &config->scroller_proportion_preset[1], - &config->scroller_proportion_preset[2]) != 3) { - fprintf(stderr, "Error: Invalid scroller_proportion_preset format: %s\n", - value); + // 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数 + int count = 0; // 初始化为 0 + for (const char *p = value; *p; p++) { + if (*p == ',') count++; } - } else if (strcmp(key, "new_is_master") == 0) { + int float_count = count + 1; // 浮点数的数量是逗号数量加 1 + + // 2. 动态分配内存,存储浮点数 + config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float)); + if (!config->scroller_proportion_preset) { + fprintf(stderr, "Error: Memory allocation failed\n"); + return; + } + + // 3. 解析 value 中的浮点数 + char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串 + char *token = strtok(value_copy, ","); + int i = 0; + + while (token != NULL && i < float_count) { + if (sscanf(token, "%f", &config->scroller_proportion_preset[i]) != 1) { + fprintf(stderr, "Error: Invalid float value in scroller_proportion_preset: %s\n", token); + free(value_copy); + free(config->scroller_proportion_preset); // 释放已分配的内存 + config->scroller_proportion_preset = NULL; // 防止野指针 + return; + } + token = strtok(NULL, ","); + i++; + } + + // 4. 检查解析的浮点数数量是否匹配 + if (i != float_count) { + fprintf(stderr, "Error: Invalid scroller_proportion_preset format: %s\n", value); + free(value_copy); + free(config->scroller_proportion_preset); // 释放已分配的内存 + config->scroller_proportion_preset = NULL; // 防止野指针 + config->scroller_proportion_preset_count = 0; + return; + } + config->scroller_proportion_preset_count = float_count; + + // 5. 释放临时复制的字符串 + free(value_copy); + } else if (strcmp(key, "circle_layout") == 0) { + // 1. 统计 value 中有多少个逗号,确定需要解析的字符串个数 + int count = 0; // 初始化为 0 + for (const char *p = value; *p; p++) { + if (*p == ',') count++; + } + int string_count = count + 1; // 字符串的数量是逗号数量加 1 + + // 2. 动态分配内存,存储字符串指针 + config->circle_layout = (char **)malloc(string_count * sizeof(char *)); + memset(config->circle_layout, 0, string_count * sizeof(char *)); + if (!config->circle_layout) { + fprintf(stderr, "Error: Memory allocation failed\n"); + return; + } + + // 3. 解析 value 中的字符串 + char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串 + char *token = strtok(value_copy, ","); + int i = 0; + char *cleaned_token; + while (token != NULL && i < string_count) { + // 为每个字符串分配内存并复制内容 + cleaned_token = sanitize_string(token); + config->circle_layout[i] = strdup(cleaned_token); + if (!config->circle_layout[i]) { + fprintf(stderr, "Error: Memory allocation failed for string: %s\n", token); + // 释放之前分配的内存 + for (int j = 0; j < i; j++) { + free(config->circle_layout[j]); + } + free(config->circle_layout); + free(value_copy); + config->circle_layout = NULL; // 防止野指针 + config->circle_layout_count = 0; + return; + } + token = strtok(NULL, ","); + i++; + } + + // 4. 检查解析的字符串数量是否匹配 + if (i != string_count) { + fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value); + // 释放之前分配的内存 + for (int j = 0; j < i; j++) { + free(config->circle_layout[j]); + } + free(config->circle_layout); + free(value_copy); + config->circle_layout = NULL; // 防止野指针 + config->circle_layout_count = 0; + return; + } + config->circle_layout_count = string_count; + + // 5. 释放临时复制的字符串 + free(value_copy); + } else if (strcmp(key, "new_is_master") == 0) { config->new_is_master = atoi(value); } else if (strcmp(key, "default_mfact") == 0) { config->default_mfact = atof(value); @@ -836,6 +947,22 @@ void parse_config_file(Config *config, const char *file_path) { fclose(file); } +void free_circle_layout(Config *config) { + if (config->circle_layout) { + // 释放每个字符串 + for (int i = 0; i < config->circle_layout_count; i++) { + if (config->circle_layout[i]) { + free(config->circle_layout[i]); // 释放单个字符串 + config->circle_layout[i] = NULL; // 防止野指针 + } + } + // 释放 circle_layout 数组本身 + free(config->circle_layout); + config->circle_layout = NULL; // 防止野指针 + } + config->circle_layout_count = 0; // 重置计数 +} + void free_config(void) { // 释放内存 int i; @@ -882,6 +1009,12 @@ void free_config(void) { } } free(config.axis_bindings); + + free(config.scroller_proportion_preset); + config.scroller_proportion_preset = NULL; + config.scroller_proportion_preset_count = 0; + + free_circle_layout(&config); } void override_config(void) { @@ -898,8 +1031,6 @@ void override_config(void) { // 复制数组类型的变量 memcpy(animation_curve, config.animation_curve, sizeof(animation_curve)); - memcpy(scroller_proportion_preset, config.scroller_proportion_preset, - sizeof(scroller_proportion_preset)); scroller_structs = config.scroller_structs; scroller_default_proportion = config.scroller_default_proportion; diff --git a/preset_config.h b/preset_config.h index f7990d4..5322836 100644 --- a/preset_config.h +++ b/preset_config.h @@ -40,7 +40,6 @@ unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ int scroller_structs = 20; float scroller_default_proportion = 0.9; int scoller_focus_center = 0; -float scroller_proportion_preset[] = {0.5, 0.9, 1.0}; int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's