typedef struct { const char *id; const char *title; unsigned int tags; int isfloating; int isfullscreen; float scroller_proportion; const char *animation_type; int isnoborder; int monitor; unsigned int width; unsigned int height; } ConfigWinRule; typedef struct { const char *name; // 显示器名称 float mfact; // 主区域比例 int nmaster; // 主区域窗口数量 const char *layout; // 布局名称(字符串) int rr; // 旋转和翻转(假设为整数) float scale; // 显示器缩放比例 int x, y; // 显示器位置 } ConfigMonitorRule; typedef struct { uint32_t mod; xkb_keysym_t keysym; void (*func)(const Arg *); Arg arg; } KeyBinding; typedef struct { unsigned int mod; unsigned int button; void (*func)(const Arg *); Arg arg; } MouseBinding; typedef struct { unsigned int mod; unsigned int dir; void (*func)(const Arg *); Arg arg; } AxisBinding; typedef struct { int animations; char animation_type[10]; char animation_fade_in; float zoom_initial_ratio; float fadein_begin_opacity; uint32_t animation_duration_move; uint32_t animation_duration_open; uint32_t animation_duration_tag; double animation_curve[4]; int scroller_structs; float scroller_default_proportion; int scoller_focus_center; float scroller_proportion_preset[3]; unsigned int new_is_master; float default_mfact; unsigned int default_nmaster; unsigned int hotarea_size; unsigned int enable_hotarea; unsigned int ov_tab_mode; int overviewgappi; int overviewgappo; unsigned int axis_bind_apply_timeout; unsigned int focus_on_activate; unsigned int numlockon; int bypass_surface_visibility; int sloppyfocus; int warpcursor; int smartgaps; unsigned int gappih; unsigned int gappiv; unsigned int gappoh; unsigned int gappov; unsigned int borderpx; int rootcolor; int bordercolor; int focuscolor; int maxmizescreencolor; int urgentcolor; int scratchpadcolor; int globalcolor; char autostart[3][256]; struct { int id; char name[256]; } tags[9]; ConfigWinRule *window_rules; int window_rules_count; ConfigMonitorRule *monitor_rules; // 动态数组 int monitor_rules_count; // 条数 KeyBinding *key_bindings; int key_bindings_count; MouseBinding *mouse_bindings; int mouse_bindings_count; AxisBinding *axis_bindings; int axis_bindings_count; } Config; long int parse_color(const char *hex_str) { char *endptr; long int hex_num = strtol(hex_str, &endptr, 16); if (*endptr != '\0') { return -1; } return hex_num; } uint32_t parse_mod(const char *mod_str) { uint32_t mod = 0; if (strstr(mod_str, "SUPER")) mod |= WLR_MODIFIER_LOGO; if (strstr(mod_str, "CTRL")) mod |= WLR_MODIFIER_CTRL; if (strstr(mod_str, "SHIFT")) mod |= WLR_MODIFIER_SHIFT; if (strstr(mod_str, "ALT")) mod |= WLR_MODIFIER_ALT; return mod; } xkb_keysym_t parse_keysym(const char *keysym_str) { return xkb_keysym_from_name(keysym_str, XKB_KEYSYM_CASE_INSENSITIVE); } typedef void (*FuncType)(const Arg *); FuncType parse_func_name(char *func_name,Arg *arg, char *arg_value) { FuncType func = NULL; (*arg).v = NULL; if (strcmp(func_name, "focusstack") == 0) { func = focusstack; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "focusdir") == 0) { func = focusdir; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "incnmaster") == 0) { func = incnmaster; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "setmfact") == 0) { func = setmfact; (*arg).f = atof(arg_value); } else if (strcmp(func_name, "zoom") == 0) { func = zoom; } else if (strcmp(func_name, "exchange_client") == 0) { func = exchange_client; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "toggleglobal") == 0) { func = toggleglobal; } else if (strcmp(func_name, "toggleoverview") == 0) { func = toggleoverview; } else if (strcmp(func_name, "set_proportion") == 0) { func = set_proportion; (*arg).f = atof(arg_value); } else if (strcmp(func_name, "switch_proportion_preset") == 0) { func = switch_proportion_preset; } else if (strcmp(func_name, "viewtoleft") == 0) { func = viewtoleft; } else if (strcmp(func_name, "viewtoright") == 0) { func = viewtoright; } else if (strcmp(func_name, "tagtoleft") == 0) { func = tagtoleft; } else if (strcmp(func_name, "tagtoright") == 0) { func = tagtoright; } else if (strcmp(func_name, "killclient") == 0) { func = killclient; } else if (strcmp(func_name, "setlayout") == 0) { func = setlayout; } else if (strcmp(func_name, "switch_layout") == 0) { func = switch_layout; } else if (strcmp(func_name, "togglefloating") == 0) { func = togglefloating; } else if (strcmp(func_name, "togglefullscreen") == 0) { func = togglefullscreen; } else if (strcmp(func_name, "minized") == 0) { func = minized; } else if (strcmp(func_name, "restore_minized") == 0) { func = restore_minized; } else if (strcmp(func_name, "toggle_scratchpad") == 0) { func = toggle_scratchpad; } else if (strcmp(func_name, "focusmon") == 0) { func = focusmon; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "tagmon") == 0) { func = tagmon; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "incgaps") == 0) { func = incgaps; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "togglegaps") == 0) { func = togglegaps; } else if (strcmp(func_name, "chvt") == 0) { func = chvt; (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "spawn") == 0) { func = spawn; (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "quit") == 0) { func = quit; } else if (strcmp(func_name, "moveresize") == 0) { func = moveresize; (*arg).ui = atoi(arg_value); } else if (strcmp(func_name, "togglemaxmizescreen") == 0) { func = togglemaxmizescreen; } else if (strcmp(func_name, "viewtoleft_have_client") == 0) { func = viewtoleft_have_client; } else if (strcmp(func_name, "viewtoright_have_client") == 0) { func = viewtoright_have_client; } else { return NULL; } return func; } void parse_config_line(Config *config, const char *line) { char key[256], value[256]; if (sscanf(line, "%[^=]=%[^\n]", key, value) != 2) { fprintf(stderr, "Error: Invalid line format: %s\n", line); return; } if (strcmp(key, "animations") == 0) { config->animations = atoi(value); } else if (strcmp(key, "animation_type") == 0) { strncpy(config->animation_type, value, sizeof(config->animation_type)); } else if (strcmp(key, "animation_fade_in") == 0) { config->animation_fade_in = atoi(value); } else if (strcmp(key, "zoom_initial_ratio") == 0) { config->zoom_initial_ratio = atof(value); } else if (strcmp(key, "fadein_begin_opacity") == 0) { config->fadein_begin_opacity = atof(value); } else if (strcmp(key, "animation_duration_move") == 0) { config->animation_duration_move = atoi(value); } else if (strcmp(key, "animation_duration_open") == 0) { config->animation_duration_open = atoi(value); } else if (strcmp(key, "animation_duration_tag") == 0) { config->animation_duration_tag = atoi(value); } else if (strcmp(key, "animation_curve") == 0) { if (sscanf(value, "%lf,%lf,%lf,%lf", &config->animation_curve[0], &config->animation_curve[1], &config->animation_curve[2], &config->animation_curve[3]) != 4) { fprintf(stderr, "Error: Invalid animation_curve format: %s\n", value); } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); } else if (strcmp(key, "scroller_default_proportion") == 0) { config->scroller_default_proportion = atof(value); } 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); } } 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); } else if (strcmp(key, "default_nmaster") == 0) { config->default_nmaster = atoi(value); } else if (strcmp(key, "hotarea_size") == 0) { config->hotarea_size = atoi(value); } else if (strcmp(key, "enable_hotarea") == 0) { config->enable_hotarea = atoi(value); } else if (strcmp(key, "ov_tab_mode") == 0) { config->ov_tab_mode = atoi(value); } else if (strcmp(key, "overviewgappi") == 0) { config->overviewgappi = atoi(value); } else if (strcmp(key, "overviewgappo") == 0) { config->overviewgappo = atoi(value); } else if (strcmp(key, "axis_bind_apply_timeout") == 0) { config->axis_bind_apply_timeout = atoi(value); } else if (strcmp(key, "focus_on_activate") == 0) { config->focus_on_activate = atoi(value); } else if (strcmp(key, "numlockon") == 0) { config->numlockon = atoi(value); } else if (strcmp(key, "bypass_surface_visibility") == 0) { config->bypass_surface_visibility = atoi(value); } else if (strcmp(key, "sloppyfocus") == 0) { config->sloppyfocus = atoi(value); } else if (strcmp(key, "warpcursor") == 0) { config->warpcursor = atoi(value); } else if (strcmp(key, "smartgaps") == 0) { config->smartgaps = atoi(value); } else if (strcmp(key, "gappih") == 0) { config->gappih = atoi(value); } else if (strcmp(key, "gappiv") == 0) { config->gappiv = atoi(value); } else if (strcmp(key, "gappoh") == 0) { config->gappoh = atoi(value); } else if (strcmp(key, "gappov") == 0) { config->gappov = atoi(value); } else if (strcmp(key, "borderpx") == 0) { config->borderpx = atoi(value); } else if (strcmp(key, "rootcolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid rootcolor format: %s\n", value); } else { config->rootcolor = color; } } else if (strcmp(key, "bordercolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid bordercolor format: %s\n", value); } else { config->bordercolor = color; } } else if (strcmp(key, "focuscolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid focuscolor format: %s\n", value); } else { config->focuscolor = color; } } else if (strcmp(key, "maxmizescreencolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid maxmizescreencolor format: %s\n", value); } else { config->maxmizescreencolor = color; } } else if (strcmp(key, "urgentcolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid urgentcolor format: %s\n", value); } else { config->urgentcolor = color; } } else if (strcmp(key, "scratchpadcolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid scratchpadcolor format: %s\n", value); } else { config->scratchpadcolor = color; } } else if (strcmp(key, "globalcolor") == 0) { long int color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid globalcolor format: %s\n", value); } else { config->globalcolor = color; } } else if (strcmp(key, "autostart") == 0) { if (sscanf(value, "%[^,],%[^,],%[^,]", config->autostart[0], config->autostart[1], config->autostart[2]) != 3) { fprintf(stderr, "Error: Invalid autostart format: %s\n", value); } } else if (strcmp(key, "tags") == 0) { int id; char name[256]; if (sscanf(value, "id:%d,name:%255[^\n]", &id, name) == 2) { if (id >= 1 && id <= 9) { config->tags[id - 1].id = id; strncpy(config->tags[id - 1].name, name, sizeof(config->tags[id - 1].name)); } else { fprintf(stderr, "Error: Invalid tag id: %d\n", id); } } else { fprintf(stderr, "Error: Invalid tags format: %s\n", value); } } else if (strcmp(key, "windowrule") == 0) { config->window_rules = realloc(config->window_rules, (config->window_rules_count + 1) * sizeof(ConfigWinRule)); if (!config->window_rules) { fprintf(stderr, "Error: Failed to allocate memory for window rules\n"); return; } ConfigWinRule *rule = &config->window_rules[config->window_rules_count]; memset(rule, 0, sizeof(ConfigWinRule)); char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); if (colon != NULL) { *colon = '\0'; char *key = token; char *val = colon + 1; if (strcmp(key, "isfloating") == 0) { rule->isfloating = atoi(val); } else if (strcmp(key, "title") == 0) { rule->title = strdup(val); } else if (strcmp(key, "appid") == 0) { rule->id = strdup(val); } else if (strcmp(key, "animation_type") == 0) { rule->animation_type = strdup(val); } else if (strcmp(key, "tags") == 0) { rule->tags = atoi(val); } else if (strcmp(key, "monitor") == 0) { rule->monitor = atoi(val); } else if (strcmp(key, "width") == 0) { rule->width = atoi(val); } else if (strcmp(key, "height") == 0) { rule->height = atoi(val); } else if (strcmp(key, "isnoborder") == 0) { rule->isnoborder = atoi(val); } else if (strcmp(key, "scroller_proportion") == 0) { rule->scroller_proportion = atof(val); } else if (strcmp(key, "isfullscreen") == 0) { rule->isfullscreen = atoi(val); } } token = strtok(NULL, ","); } config->window_rules_count++; } else if (strcmp(key, "monitorrule") == 0) { config->monitor_rules = realloc(config->monitor_rules, (config->monitor_rules_count + 1) * sizeof(ConfigMonitorRule)); if (!config->monitor_rules) { fprintf(stderr, "Error: Failed to allocate memory for monitor rules\n"); return; } ConfigMonitorRule *rule = &config->monitor_rules[config->monitor_rules_count]; memset(rule, 0, sizeof(ConfigMonitorRule)); char layout[256], name[256]; int parsed = sscanf(value, "%255[^,],%f,%d,%255[^,],%d,%f,%d,%d", name, &rule->mfact, &rule->nmaster, layout, &rule->rr, &rule->scale, &rule->x, &rule->y); if (parsed == 8) { rule->name = strdup(name); rule->layout = strdup(layout); if (!rule->name || !rule->layout) { if (rule->name) free((void *)rule->name); if (rule->layout) free((void *)rule->layout); fprintf(stderr, "Error: Failed to allocate memory for monitor rule\n"); return; } config->monitor_rules_count++; } else { fprintf(stderr, "Error: Invalid monitorrule format: %s\n", value); } } else if (strncmp(key, "bind", 4) == 0) { config->key_bindings = realloc(config->key_bindings, (config->key_bindings_count + 1) * sizeof(KeyBinding)); if (!config->key_bindings) { fprintf(stderr, "Error: Failed to allocate memory for key bindings\n"); return; } KeyBinding *binding = &config->key_bindings[config->key_bindings_count]; memset(binding, 0, sizeof(KeyBinding)); char mod_str[256], keysym_str[256], func_name[256], arg_value[256] = "none"; if (sscanf(value, "%[^,],%[^,],%[^,],%[^\n]", mod_str, keysym_str, func_name, arg_value) < 3) { fprintf(stderr, "Error: Invalid bind format: %s\n", value); return; } binding->mod = parse_mod(mod_str); binding->keysym = parse_keysym(keysym_str); binding->arg.v = NULL; binding->func = parse_func_name(func_name, &binding->arg, arg_value); if (!binding->func){ fprintf(stderr, "Error: Unknown function in bind: %s\n", func_name); } else { config->key_bindings_count++; } } else if (strncmp(key, "mousebind", 9) == 0) { config->mouse_bindings = realloc(config->mouse_bindings, (config->mouse_bindings_count + 1) * sizeof(MouseBinding)); if (!config->mouse_bindings) { fprintf(stderr, "Error: Failed to allocate memory for mouse bindings\n"); return; } MouseBinding *binding = &config->mouse_bindings[config->mouse_bindings_count]; memset(binding, 0, sizeof(MouseBinding)); char mod_str[256], button_str[256], func_name[256], arg_value[256] = "none"; if (sscanf(value, "%[^,],%[^,],%[^,],%[^\n]", mod_str, button_str, func_name, arg_value) < 3) { fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); return; } binding->mod = parse_mod(mod_str); binding->button = atoi(button_str); binding->arg.v = NULL; binding->func = parse_func_name(func_name, &binding->arg, arg_value); if (!binding->func){ fprintf(stderr, "Error: Unknown function in mousebind: %s\n", func_name); } else { config->mouse_bindings_count++; } } else if (strncmp(key, "axisbind", 8) == 0) { config->axis_bindings = realloc(config->axis_bindings, (config->axis_bindings_count + 1) * sizeof(AxisBinding)); if (!config->axis_bindings) { fprintf(stderr, "Error: Failed to allocate memory for axis bindings\n"); return; } AxisBinding *binding = &config->axis_bindings[config->axis_bindings_count]; memset(binding, 0, sizeof(AxisBinding)); char mod_str[256], dir_str[256], func_name[256], arg_value[256] = "none"; if (sscanf(value, "%[^,],%[^,],%[^,],%[^\n]", mod_str, dir_str, func_name, arg_value) < 3) { fprintf(stderr, "Error: Invalid axisbind format: %s\n", value); return; } binding->mod = parse_mod(mod_str); binding->dir = atoi(dir_str); binding->arg.v = NULL; binding->func = parse_func_name(func_name, &binding->arg, arg_value); if (!binding->func){ fprintf(stderr, "Error: Unknown function in axisbind: %s\n", func_name); } else { config->axis_bindings_count++; } } else { fprintf(stderr, "Error: Unknown key: %s\n", key); } } void parse_config_file(Config *config, const char *file_path) { FILE *file = fopen(file_path, "r"); if (!file) { perror("Error opening file"); return; } char line[512]; while (fgets(line, sizeof(line), file)) { if (line[0] == '#' || line[0] == '\n') continue; parse_config_line(config, line); } fclose(file); }