diff --git a/meson.build b/meson.build index d71eb59..0565609 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.11.0', + version : '0.12.0', ) subdir('protocols') diff --git a/src/config/parse_config.h b/src/config/parse_config.h index c345836..f7ce848 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -405,7 +405,10 @@ int32_t parse_double_array(const char *input, double *output, char *endptr; double val = strtod(token, &endptr); if (endptr == token || *endptr != '\0') { - fprintf(stderr, "Error: Invalid number in array: %s\n", token); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid number in array: %s\n", + token); free(dup); return -1; } @@ -457,7 +460,9 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { kb->ispassapply = true; break; default: - // 忽略其他字符或可根据需要处理错误 + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown bind flag: %c\n", + suffix[i]); break; } } @@ -547,13 +552,14 @@ static bool starts_with_ignore_case(const char *str, const char *prefix) { uint32_t parse_mod(const char *mod_str) { if (!mod_str || !*mod_str) { - return 0; + return UINT32_MAX; } uint32_t mod = 0; char input_copy[256]; char *token; char *saveptr = NULL; + bool match_success = false; // 复制并转换为小写 strncpy(input_copy, mod_str, sizeof(input_copy) - 1); @@ -591,35 +597,56 @@ uint32_t parse_mod(const char *mod_str) { case 108: mod |= WLR_MODIFIER_ALT; break; + default: + fprintf(stderr, + "unknown modifier keycode: \033[1m\033[31m%s\n", + token); + break; } } } else { // 完整的 modifier 检查(保留原始所有检查项) - if (strstr(token, "super") || strstr(token, "super_l") || - strstr(token, "super_r")) { + if (!strcmp(token, "super") || !strcmp(token, "super_l") || + !strcmp(token, "super_r")) { mod |= WLR_MODIFIER_LOGO; + match_success = true; } - if (strstr(token, "ctrl") || strstr(token, "ctrl_l") || - strstr(token, "ctrl_r")) { + if (!strcmp(token, "ctrl") || !strcmp(token, "ctrl_l") || + !strcmp(token, "ctrl_r")) { mod |= WLR_MODIFIER_CTRL; + match_success = true; } - if (strstr(token, "shift") || strstr(token, "shift_l") || - strstr(token, "shift_r")) { + if (!strcmp(token, "shift") || !strcmp(token, "shift_l") || + !strcmp(token, "shift_r")) { mod |= WLR_MODIFIER_SHIFT; + match_success = true; } - if (strstr(token, "alt") || strstr(token, "alt_l") || - strstr(token, "alt_r")) { + if (!strcmp(token, "alt") || !strcmp(token, "alt_l") || + !strcmp(token, "alt_r")) { mod |= WLR_MODIFIER_ALT; + match_success = true; } - if (strstr(token, "hyper") || strstr(token, "hyper_l") || - strstr(token, "hyper_r")) { + if (!strcmp(token, "hyper") || !strcmp(token, "hyper_l") || + !strcmp(token, "hyper_r")) { mod |= WLR_MODIFIER_MOD3; + match_success = true; + } + if (!strcmp(token, "none")) { + match_success = true; } } token = strtok_r(NULL, "+", &saveptr); } + if (!match_success) { + mod = UINT32_MAX; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown modifier: " + "\033[1m\033[31m%s\n", + mod_str); + } + return mod; } @@ -735,13 +762,17 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { // 无法解析的键名 kc.type = KEY_TYPE_SYM; kc.keysym = XKB_KEY_NoSymbol; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown key: \033[1m\033[31m%s\n", + key_str); // keycode 字段保持为0 } return kc; } -int32_t parse_button(const char *str) { +uint32_t parse_button(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; int32_t i = 0; @@ -769,7 +800,11 @@ int32_t parse_button(const char *str) { } else if (strcmp(lowerStr, "btn_task") == 0) { return BTN_TASK; } else { - return 0; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown button: " + "\033[1m\033[31m%s\n", + str); + return UINT32_MAX; } } @@ -1115,7 +1150,7 @@ void run_exec_once() { } } -void parse_option(Config *config, char *key, char *value) { +bool parse_option(Config *config, char *key, char *value) { if (strcmp(key, "keymode") == 0) { snprintf(config->keymode, sizeof(config->keymode), "%.27s", value); } else if (strcmp(key, "animations") == 0) { @@ -1166,53 +1201,70 @@ void parse_option(Config *config, char *key, char *value) { int32_t num = parse_double_array(value, config->animation_curve_move, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_move: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_open") == 0) { int32_t num = parse_double_array(value, config->animation_curve_open, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_open: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_tag") == 0) { int32_t num = parse_double_array(value, config->animation_curve_tag, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_tag: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_close") == 0) { int32_t num = parse_double_array(value, config->animation_curve_close, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_close: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_close: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_focus") == 0) { int32_t num = parse_double_array(value, config->animation_curve_focus, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_focus: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_focus: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_opafadein") == 0) { int32_t num = parse_double_array(value, config->animation_curve_opafadein, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_opafadein: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_opafadein: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_opafadeout") == 0) { int32_t num = parse_double_array(value, config->animation_curve_opafadeout, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_opafadeout: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_opafadeout: %s\n", value); + return false; } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); @@ -1333,8 +1385,10 @@ void parse_option(Config *config, char *key, char *value) { config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float)); if (!config->scroller_proportion_preset) { - fprintf(stderr, "Error: Memory allocation failed\n"); - return; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n"); + return false; } // 3. 解析 value 中的浮点数 @@ -1346,14 +1400,15 @@ void parse_option(Config *config, char *key, char *value) { while (token != NULL && i < float_count) { if (sscanf(token, "%f", &value_set) != 1) { - fprintf(stderr, - "Error: Invalid float value in " - "scroller_proportion_preset: %s\n", - token); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid float value in " + "scroller_proportion_preset: %s\n", + token); free(value_copy); free(config->scroller_proportion_preset); config->scroller_proportion_preset = NULL; - return; + return false; } // Clamp the value between 0.0 and 1.0 (or your desired range) @@ -1367,13 +1422,14 @@ void parse_option(Config *config, char *key, char *value) { // 4. 检查解析的浮点数数量是否匹配 if (i != float_count) { fprintf(stderr, - "Error: Invalid scroller_proportion_preset format: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m 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; + return false; } config->scroller_proportion_preset_count = float_count; @@ -1392,8 +1448,10 @@ void parse_option(Config *config, char *key, char *value) { 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; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n"); + return false; } // 3. 解析 value 中的字符串 @@ -1408,7 +1466,9 @@ void parse_option(Config *config, char *key, char *value) { config->circle_layout[i] = strdup(cleaned_token); if (!config->circle_layout[i]) { fprintf(stderr, - "Error: Memory allocation failed for string: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation " + "failed for " + "string: %s\n", token); // 释放之前分配的内存 for (int32_t j = 0; j < i; j++) { @@ -1418,7 +1478,7 @@ void parse_option(Config *config, char *key, char *value) { free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return; + return false; } token = strtok(NULL, ","); i++; @@ -1426,7 +1486,10 @@ void parse_option(Config *config, char *key, char *value) { // 4. 检查解析的字符串数量是否匹配 if (i != string_count) { - fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid circle_layout " + "format: %s\n", + value); // 释放之前分配的内存 for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); @@ -1435,7 +1498,7 @@ void parse_option(Config *config, char *key, char *value) { free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return; + return false; } config->circle_layout_count = string_count; @@ -1542,7 +1605,11 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "rootcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid rootcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor format: " + "%s\n", + value); + return false; } else { convert_hex_to_rgba(config->rootcolor, color); } @@ -1550,58 +1617,89 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "shadowscolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid shadowscolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid shadowscolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->shadowscolor, color); } } else if (strcmp(key, "bordercolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid bordercolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bordercolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->bordercolor, color); } } else if (strcmp(key, "focuscolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid focuscolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid focuscolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->focuscolor, color); } } else if (strcmp(key, "maximizescreencolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid maximizescreencolor format: %s\n", - value); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid maximizescreencolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->maximizescreencolor, color); } } else if (strcmp(key, "urgentcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid urgentcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid urgentcolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->urgentcolor, color); } } else if (strcmp(key, "scratchpadcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid scratchpadcolor format: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid scratchpadcolor " + "format: %s\n", value); + return false; } else { convert_hex_to_rgba(config->scratchpadcolor, color); } } else if (strcmp(key, "globalcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid globalcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid globalcolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->globalcolor, color); } } else if (strcmp(key, "overlaycolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid overlaycolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid overlaycolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->overlaycolor, color); } @@ -1611,8 +1709,9 @@ void parse_option(Config *config, char *key, char *value) { sizeof(ConfigMonitorRule)); if (!config->monitor_rules) { fprintf(stderr, - "Error: Failed to allocate memory for monitor rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for monitor rules\n"); + return false; } ConfigMonitorRule *rule = @@ -1630,6 +1729,7 @@ void parse_option(Config *config, char *key, char *value) { rule->refresh = 0.0f; rule->vrr = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1659,19 +1759,29 @@ void parse_option(Config *config, char *key, char *value) { rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); } else if (strcmp(key, "vrr") == 0) { rule->vrr = CLAMP_INT(atoi(val), 0, 1); + } else { + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown monitor rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->monitor_rules_count++; + return !parse_error; } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, (config->tag_rules_count + 1) * sizeof(ConfigTagRule)); if (!config->tag_rules) { - fprintf(stderr, "Error: Failed to allocate memory for tag rules\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for tag rules\n"); + return false; } ConfigTagRule *rule = &config->tag_rules[config->tag_rules_count]; @@ -1686,6 +1796,7 @@ void parse_option(Config *config, char *key, char *value) { rule->no_render_border = 0; rule->no_hide = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1711,20 +1822,28 @@ void parse_option(Config *config, char *key, char *value) { rule->nmaster = CLAMP_INT(atoi(val), 1, 99); } else if (strcmp(key, "mfact") == 0) { rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown tag rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->tag_rules_count++; + return !parse_error; } else if (strcmp(key, "layerrule") == 0) { config->layer_rules = realloc(config->layer_rules, (config->layer_rules_count + 1) * sizeof(ConfigLayerRule)); if (!config->layer_rules) { fprintf(stderr, - "Error: Failed to allocate memory for layer rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for layer rules\n"); + return false; } ConfigLayerRule *rule = &config->layer_rules[config->layer_rules_count]; @@ -1738,6 +1857,7 @@ void parse_option(Config *config, char *key, char *value) { rule->noanim = 0; rule->noshadow = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1761,6 +1881,13 @@ void parse_option(Config *config, char *key, char *value) { rule->noanim = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noshadow") == 0) { rule->noshadow = CLAMP_INT(atoi(val), 0, 1); + } else { + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown layer rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); @@ -1772,14 +1899,16 @@ void parse_option(Config *config, char *key, char *value) { } config->layer_rules_count++; + return !parse_error; } 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; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for window rules\n"); + return false; } ConfigWinRule *rule = &config->window_rules[config->window_rules_count]; @@ -1835,6 +1964,7 @@ void parse_option(Config *config, char *key, char *value) { rule->globalkeybinding = (KeyBinding){0}; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1934,17 +2064,37 @@ void parse_option(Config *config, char *key, char *value) { rule->globalkeybinding.mod = parse_mod(mod_str); rule->globalkeybinding.keysymcode = parse_key(keysym_str, false); + if (rule->globalkeybinding.mod == UINT32_MAX) { + return false; + } + if (rule->globalkeybinding.keysymcode.type == + KEY_TYPE_SYM && + rule->globalkeybinding.keysymcode.keysym == + XKB_KEY_NoSymbol) { + return false; + } + } else { + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown window rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->window_rules_count++; + return !parse_error; } else if (strncmp(key, "env", 3) == 0) { char env_type[256], env_value[256]; if (sscanf(value, "%255[^,],%255[^\n]", env_type, env_value) < 2) { - fprintf(stderr, "Error: Invalid bind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " + "\033[1m\033[31m%s\n", + value); + return false; } trim_whitespace(env_type); trim_whitespace(env_value); @@ -1959,8 +2109,9 @@ void parse_option(Config *config, char *key, char *value) { free(env->type); free(env->value); free(env); - fprintf(stderr, "Error: Failed to allocate memory for env\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " + "allocate memory for env\n"); + return false; } config->env[config->env_count] = env; @@ -1970,15 +2121,18 @@ void parse_option(Config *config, char *key, char *value) { char **new_exec = realloc(config->exec, (config->exec_count + 1) * sizeof(char *)); if (!new_exec) { - fprintf(stderr, "Error: Failed to allocate memory for exec\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for exec\n"); + return false; } config->exec = new_exec; config->exec[config->exec_count] = strdup(value); if (!config->exec[config->exec_count]) { - fprintf(stderr, "Error: Failed to duplicate exec string\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " + "duplicate exec string\n"); + return false; } config->exec_count++; @@ -1988,15 +2142,19 @@ void parse_option(Config *config, char *key, char *value) { char **new_exec_once = realloc( config->exec_once, (config->exec_once_count + 1) * sizeof(char *)); if (!new_exec_once) { - fprintf(stderr, "Error: Failed to allocate memory for exec_once\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for exec_once\n"); + return false; } config->exec_once = new_exec_once; config->exec_once[config->exec_once_count] = strdup(value); if (!config->exec_once[config->exec_once_count]) { - fprintf(stderr, "Error: Failed to duplicate exec_once string\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to duplicate " + "exec_once string\n"); + return false; } config->exec_once_count++; @@ -2007,8 +2165,9 @@ void parse_option(Config *config, char *key, char *value) { (config->key_bindings_count + 1) * sizeof(KeyBinding)); if (!config->key_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for key bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for key bindings\n"); + return false; } KeyBinding *binding = &config->key_bindings[config->key_bindings_count]; @@ -2023,8 +2182,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid bind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " + "\033[1m\033[31m%s\n", + value); + return false; } trim_whitespace(mod_str); trim_whitespace(keysym_str); @@ -2057,7 +2219,9 @@ void parse_option(Config *config, char *key, char *value) { binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX || + (binding->keysymcode.type == KEY_TYPE_SYM && + binding->keysymcode.keysym == XKB_KEY_NoSymbol)) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2070,7 +2234,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in bind: %s\n", func_name); + if (!binding->func) + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in bind: " + "\033[1m\033[31m%s\n", + func_name); + return false; } else { config->key_bindings_count++; } @@ -2081,8 +2251,9 @@ void parse_option(Config *config, char *key, char *value) { (config->mouse_bindings_count + 1) * sizeof(MouseBinding)); if (!config->mouse_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for mouse bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for mouse bindings\n"); + return false; } MouseBinding *binding = @@ -2098,8 +2269,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^\n]", mod_str, button_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind format: " + "%s\n", + value); + return false; } trim_whitespace(mod_str); trim_whitespace(button_str); @@ -2118,7 +2292,8 @@ void parse_option(Config *config, char *key, char *value) { binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX || + binding->button == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2131,8 +2306,12 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in mousebind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "mousebind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->mouse_bindings_count++; } @@ -2142,8 +2321,9 @@ void parse_option(Config *config, char *key, char *value) { (config->axis_bindings_count + 1) * sizeof(AxisBinding)); if (!config->axis_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for axis bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for axis bindings\n"); + return false; } AxisBinding *binding = @@ -2159,8 +2339,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^\n]", mod_str, dir_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid axisbind format: %s\n", value); - return; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind format: %s\n", + value); + return false; } trim_whitespace(mod_str); @@ -2181,7 +2364,7 @@ void parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2194,8 +2377,12 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in axisbind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "axisbind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->axis_bindings_count++; } @@ -2206,8 +2393,9 @@ void parse_option(Config *config, char *key, char *value) { sizeof(SwitchBinding)); if (!config->switch_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for switch bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for switch bindings\n"); + return false; } SwitchBinding *binding = @@ -2223,8 +2411,11 @@ void parse_option(Config *config, char *key, char *value) { "^\n]", fold_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid switchbind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid switchbind " + "format: %s\n", + value); + return false; } trim_whitespace(fold_str); trim_whitespace(func_name); @@ -2252,8 +2443,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in switchbind: %s\n", + + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "switchbind: " + "\033[1m\033[31m%s\n", func_name); + return false; } else { config->switch_bindings_count++; } @@ -2264,8 +2460,9 @@ void parse_option(Config *config, char *key, char *value) { (config->gesture_bindings_count + 1) * sizeof(GestureBinding)); if (!config->gesture_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for axis gesturebind\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for axis gesturebind\n"); + return false; } GestureBinding *binding = @@ -2281,8 +2478,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^,],%255[^\n]", mod_str, motion_str, fingers_count_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 4) { - fprintf(stderr, "Error: Invalid gesturebind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid gesturebind " + "format: %s\n", + value); + return false; } trim_whitespace(mod_str); @@ -2305,7 +2505,7 @@ void parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2318,8 +2518,12 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in axisbind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "axisbind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->gesture_bindings_count++; } @@ -2327,22 +2531,30 @@ void parse_option(Config *config, char *key, char *value) { } else if (strncmp(key, "source", 6) == 0) { parse_config_file(config, value); } else { - fprintf(stderr, "Error: Unknown key: %s\n", key); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: " + "\033[1m\033[31m%s\n", + key); + return false; } + + return true; } -void parse_config_line(Config *config, const char *line) { +bool parse_config_line(Config *config, const char *line) { char key[256], value[256]; if (sscanf(line, "%255[^=]=%255[^\n]", key, value) != 2) { - // fprintf(stderr, "Error: Invalid line format: %s\n", line); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid line format: %s", + line); + return false; } // Then trim each part separately trim_whitespace(key); trim_whitespace(value); - parse_option(config, key, value); + return parse_option(config, key, value); } void parse_config_file(Config *config, const char *file_path) { @@ -2361,7 +2573,9 @@ void parse_config_file(Config *config, const char *file_path) { } else { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m HOME environment " + "variable not set.\n"); return; } snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, @@ -2375,7 +2589,8 @@ void parse_config_file(Config *config, const char *file_path) { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " + "variable not set.\n"); return; } snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); @@ -2392,11 +2607,21 @@ void parse_config_file(Config *config, const char *file_path) { } char line[512]; + bool parse_correct = true; + uint32_t line_count = 0; while (fgets(line, sizeof(line), file)) { + line_count++; if (line[0] == '#' || line[0] == '\n') { continue; } - parse_config_line(config, line); + parse_correct = parse_config_line(config, line); + if (!parse_correct) { + fprintf(stderr, + "\033[1;31m╰─\033[1;33m[Index]\033[0m " + "\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n" + " \033[1;36m╰─\033[0;33m%s\033[0m\n\n", + file_path, line_count, line); + } } fclose(file); @@ -3198,6 +3423,8 @@ void reapply_monitor_rules(void) { if (vrr) { enable_adaptive_sync(m, &state); + } else { + wlr_output_state_set_adaptive_sync_enabled(&state, false); } wlr_output_state_set_scale(&state, mr->scale); diff --git a/src/config/preset.h b/src/config/preset.h index 3d05161..ae4424f 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -108,7 +108,8 @@ int32_t drag_warp_cursor = 1; int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t syncobj_enable = 0; int32_t allow_lock_transparent = 0; -double drag_refresh_interval = 16.0; +double drag_tile_refresh_interval = 16.0; +double drag_floating_refresh_interval = 8.0; int32_t allow_tearing = TEARING_DISABLED; int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index f27ed67..c0e51dc 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1444,9 +1444,14 @@ int32_t viewcrossmon(const Arg *arg) { } int32_t tagcrossmon(const Arg *arg) { - if (!selmon->sel) + if (!selmon || !selmon->sel) return 0; + if (regex_match(selmon->wlr_output->name, arg->v)) { + tag_client(arg, selmon->sel); + return 0; + } + tagmon(&(Arg){.ui = arg->ui, .i = UNDIR, .v = arg->v}); return 0; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 6ff1dd2..3721364 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -210,7 +210,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_tile_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -367,7 +367,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_tile_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -548,7 +548,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_tile_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } diff --git a/src/mango.c b/src/mango.c index a32be83..f5583c3 100644 --- a/src/mango.c +++ b/src/mango.c @@ -480,6 +480,7 @@ typedef struct { char *animation_type_open; char *animation_type_close; bool need_output_flush; + bool being_unmapped; } LayerSurface; typedef struct { @@ -592,7 +593,7 @@ static void cursorwarptohint(void); static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); -static void destroylayersurfacenotify(struct wl_listener *listener, void *data); +static void destroylayernodenotify(struct wl_listener *listener, void *data); static void destroylock(SessionLock *lock, int32_t unlocked); static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); @@ -1521,6 +1522,9 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, !layer_surface->initialized) continue; + if (l->being_unmapped) + continue; + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, @@ -2337,6 +2341,15 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { return; } + // 检查surface是否有buffer + // 空buffer,只是隐藏,不改变mapped状态 + if (l->mapped && !layer_surface->surface->buffer) { + wlr_scene_node_set_enabled(&l->scene->node, false); + return; + } else { + wlr_scene_node_set_enabled(&l->scene->node, true); + } + get_layer_target_geometry(l, &box); if (animations && layer_animations && !l->noanim && l->mapped && @@ -2633,8 +2646,6 @@ void createlayersurface(struct wl_listener *listener, void *data) { LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); - LISTEN(&layer_surface->events.destroy, &l->destroy, - destroylayersurfacenotify); l->layer_surface = layer_surface; l->mon = layer_surface->output->data; @@ -2647,6 +2658,8 @@ void createlayersurface(struct wl_listener *listener, void *data) { : scene_layer); l->scene->node.data = l->popups->node.data = l; + LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify); + wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link); wlr_surface_send_enter(surface, layer_surface->output); } @@ -2777,6 +2790,8 @@ void createmon(struct wl_listener *listener, void *data) { if (vrr) { enable_adaptive_sync(m, &state); + } else { + wlr_output_state_set_adaptive_sync_enabled(&state, false); } wlr_output_state_set_scale(&state, r->scale); @@ -2958,9 +2973,14 @@ void configure_pointer(struct libinput_device *device) { if (libinput_device_config_send_events_get_modes(device)) libinput_device_config_send_events_set_mode(device, send_events_mode); - if (libinput_device_config_accel_is_available(device)) { + if (accel_profile && libinput_device_config_accel_is_available(device)) { libinput_device_config_accel_set_profile(device, accel_profile); libinput_device_config_accel_set_speed(device, accel_speed); + } else { + // profile cannot be directly applied to 0, need to set to 1 first + libinput_device_config_accel_set_profile(device, 1); + libinput_device_config_accel_set_profile(device, 0); + libinput_device_config_accel_set_speed(device, 0); } } @@ -3105,7 +3125,7 @@ void destroyidleinhibitor(struct wl_listener *listener, void *data) { free(listener); } -void destroylayersurfacenotify(struct wl_listener *listener, void *data) { +void destroylayernodenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, destroy); wl_list_remove(&l->link); @@ -3113,7 +3133,6 @@ void destroylayersurfacenotify(struct wl_listener *listener, void *data) { wl_list_remove(&l->map.link); wl_list_remove(&l->unmap.link); wl_list_remove(&l->surface_commit.link); - wlr_scene_node_destroy(&l->scene->node); wlr_scene_node_destroy(&l->popups->node); free(l); } @@ -4124,7 +4143,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, if (grabc->isfloating) { grabc->iscustomsize = 1; if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_floating_refresh_interval) { resize_floating_window(grabc); last_apply_drap_time = time; } @@ -5547,6 +5566,7 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, unmap); l->mapped = 0; + l->being_unmapped = true; init_fadeout_layers(l); @@ -5558,6 +5578,9 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { if (l->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); + l->being_unmapped = false; + wlr_scene_node_destroy(&l->shadow->node); + l->shadow = NULL; } void unmapnotify(struct wl_listener *listener, void *data) { @@ -6137,17 +6160,22 @@ int32_t main(int32_t argc, char *argv[]) { char *startup_cmd = NULL; int32_t c; - while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { - if (c == 's') + while ((c = getopt(argc, argv, "s:c:hdvp")) != -1) { + if (c == 's') { startup_cmd = optarg; - else if (c == 'd') + } else if (c == 'd') { log_level = WLR_DEBUG; - else if (c == 'v') - die("mango " VERSION); - else if (c == 'c') + } else if (c == 'v') { + printf("mango " VERSION "\n"); + return EXIT_SUCCESS; + } else if (c == 'c') { cli_config_path = optarg; - else + } else if (c == 'p') { + parse_config(); + return EXIT_SUCCESS; + } else { goto usage; + } } if (optind < argc) goto usage; @@ -6161,7 +6189,14 @@ int32_t main(int32_t argc, char *argv[]) { run(startup_cmd); cleanup(); return EXIT_SUCCESS; - usage: - die("Usage: %s [-v] [-d] [-c config file] [-s startup command]", argv[0]); + printf("Usage: mango [OPTIONS]\n" + "\n" + "Options:\n" + " -v Show mango version\n" + " -d Enable debug log\n" + " -c Use custom configuration file\n" + " -s Execute startup command\n" + " -p Check configuration file error\n"); + return EXIT_SUCCESS; }