maomaowm/src/config/parse_config.h
2025-09-28 18:39:41 +08:00

2916 lines
91 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <ctype.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifndef SYSCONFDIR
#define SYSCONFDIR "/etc"
#endif
// 整数版本 - 截断小数部分
#define CLAMP_INT(x, min, max) \
((int)(x) < (int)(min) ? (int)(min) \
: ((int)(x) > (int)(max) ? (int)(max) : (int)(x)))
// 浮点数版本 - 保留小数部分
#define CLAMP_FLOAT(x, min, max) \
((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
enum { NUM_TYPE_MINUS, NUM_TYPE_PLUS, NUM_TYPE_DEFAULT };
enum { KEY_TYPE_SYM, KEY_TYPE_CODE };
typedef struct {
xkb_keysym_t keysym;
uint32_t keycode;
int type;
} KeySymCode;
typedef struct {
uint32_t mod;
KeySymCode keysymcode;
void (*func)(const Arg *);
Arg arg;
} KeyBinding;
typedef struct {
const char *id;
const char *title;
unsigned int tags;
int isfloating;
int isfullscreen;
float scroller_proportion;
const char *animation_type_open;
const char *animation_type_close;
const char *layer_animation_type_open;
const char *layer_animation_type_close;
int isnoborder;
int isopensilent;
int istagsilent;
int isnamedscratchpad;
int isunglobal;
int isglobal;
int isoverlay;
int ignore_maximize;
int ignore_minimize;
int isnosizehint;
const char *monitor;
int offsetx;
int offsety;
int width;
int height;
int nofadein;
int nofadeout;
int no_force_center;
int isterm;
int noswallow;
int noblur;
float focused_opacity;
float unfocused_opacity;
uint32_t passmod;
xkb_keysym_t keysym;
KeyBinding globalkeybinding;
} ConfigWinRule;
typedef struct {
const char *name; // 显示器名称
float mfact; // 主区域比例
int nmaster; // 主区域窗口数量
const char *layout; // 布局名称(字符串)
int rr; // 旋转和翻转(假设为整数)
float scale; // 显示器缩放比例
int x, y; // 显示器位置
int width, height; // 显示器分辨率
float refresh; // 刷新率
} ConfigMonitorRule;
// 修改后的宏定义
#define CHVT(n) \
{ \
WLR_MODIFIER_CTRL | WLR_MODIFIER_ALT, \
{.keysym = XKB_KEY_XF86Switch_VT_##n, .type = KEY_TYPE_SYM}, chvt, \
{ \
.ui = (n) \
} \
}
// 默认按键绑定数组
KeyBinding default_key_bindings[] = {CHVT(1), CHVT(2), CHVT(3), CHVT(4),
CHVT(5), CHVT(6), CHVT(7), CHVT(8),
CHVT(9), CHVT(10), CHVT(11), CHVT(12)};
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 {
unsigned int fold;
void (*func)(const Arg *);
Arg arg;
} SwitchBinding;
typedef struct {
unsigned int mod;
unsigned int motion;
unsigned int fingers_count;
void (*func)(const Arg *);
Arg arg;
} GestureBinding;
typedef struct {
int id; // 标签ID (1-9)
char *layout_name; // 布局名称
char *monitor_name;
int no_render_border;
int no_hide;
} ConfigTagRule;
typedef struct {
char *layer_name; // 布局名称
char *animation_type_open;
char *animation_type_close;
int noblur;
int noanim;
int noshadow;
} ConfigLayerRule;
typedef struct {
int animations;
int layer_animations;
char animation_type_open[10];
char animation_type_close[10];
char layer_animation_type_open[10];
char layer_animation_type_close[10];
int animation_fade_in;
int animation_fade_out;
int tag_animation_direction;
float zoom_initial_ratio;
float zoom_end_ratio;
float fadein_begin_opacity;
float fadeout_begin_opacity;
uint32_t animation_duration_move;
uint32_t animation_duration_open;
uint32_t animation_duration_tag;
uint32_t animation_duration_close;
double animation_curve_move[4];
double animation_curve_open[4];
double animation_curve_tag[4];
double animation_curve_close[4];
int scroller_structs;
float scroller_default_proportion;
float scroller_default_proportion_single;
int scroller_focus_center;
int scroller_prefer_center;
int edge_scroller_pointer_focus;
int focus_cross_monitor;
int exchange_cross_monitor;
int scratchpad_cross_monitor;
int focus_cross_tag;
int view_current_to_back;
int no_border_when_single;
int no_radius_when_single;
int snap_distance;
int enable_floating_snap;
int drag_tile_to_tile;
unsigned int swipe_min_threshold;
float focused_opacity;
float unfocused_opacity;
float *scroller_proportion_preset;
int scroller_proportion_preset_count;
char **circle_layout;
int circle_layout_count;
unsigned int new_is_master;
float default_mfact;
float default_smfact;
unsigned int default_nmaster;
int center_master_overspread;
int center_when_single_slave;
unsigned int hotarea_size;
unsigned int enable_hotarea;
unsigned int ov_tab_mode;
int overviewgappi;
int overviewgappo;
unsigned int cursor_hide_timeout;
unsigned int axis_bind_apply_timeout;
unsigned int focus_on_activate;
int inhibit_regardless_of_visibility;
int sloppyfocus;
int warpcursor;
/* keyboard */
int repeat_rate;
int repeat_delay;
unsigned int numlockon;
/* Trackpad */
int disable_trackpad;
int tap_to_click;
int tap_and_drag;
int drag_lock;
int mouse_natural_scrolling;
int trackpad_natural_scrolling;
int disable_while_typing;
int left_handed;
int middle_button_emulation;
unsigned int accel_profile;
double accel_speed;
unsigned int scroll_method;
unsigned int scroll_button;
unsigned int click_method;
unsigned int send_events_mode;
unsigned int button_map;
int blur;
int blur_layer;
int blur_optimized;
int border_radius;
struct blur_data blur_params;
int shadows;
int shadow_only_floating;
int layer_shadows;
unsigned int shadows_size;
float shadows_blur;
int shadows_position_x;
int shadows_position_y;
float shadowscolor[4];
int smartgaps;
unsigned int gappih;
unsigned int gappiv;
unsigned int gappoh;
unsigned int gappov;
unsigned int borderpx;
float scratchpad_width_ratio;
float scratchpad_height_ratio;
float rootcolor[4];
float bordercolor[4];
float focuscolor[4];
float maxmizescreencolor[4];
float urgentcolor[4];
float scratchpadcolor[4];
float globalcolor[4];
float overlaycolor[4];
char autostart[3][256];
ConfigTagRule *tag_rules; // 动态数组
int tag_rules_count; // 数量
ConfigLayerRule *layer_rules; // 动态数组
int layer_rules_count; // 数量
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;
SwitchBinding *switch_bindings;
int switch_bindings_count;
GestureBinding *gesture_bindings;
int gesture_bindings_count;
char **exec;
int exec_count;
char **exec_once;
int exec_once_count;
char *cursor_theme;
unsigned int cursor_size;
int single_scratchpad;
int xwayland_persistence;
int syncobj_enable;
int adaptive_sync;
struct xkb_rule_names xkb_rules;
} Config;
typedef void (*FuncType)(const Arg *);
Config config;
void parse_config_file(Config *config, const char *file_path);
// Helper function to trim whitespace from start and end of a string
void trim_whitespace(char *str) {
if (str == NULL || *str == '\0')
return;
// Trim leading space
char *start = str;
while (isspace((unsigned char)*start)) {
start++;
}
// Trim trailing space
char *end = str + strlen(str) - 1;
while (end > start && isspace((unsigned char)*end)) {
end--;
}
// Null-terminate the trimmed string
*(end + 1) = '\0';
// Move the trimmed part to the beginning if needed
if (start != str) {
memmove(str, start, end - start + 2); // +2 to include null terminator
}
}
int parse_double_array(const char *input, double *output, int max_count) {
char *dup = strdup(input); // 复制一份用于修改
char *token;
int count = 0;
token = strtok(dup, ",");
while (token != NULL && count < max_count) {
trim_whitespace(token); // 对每一个分割后的 token 去除前后空格
char *endptr;
double val = strtod(token, &endptr);
if (endptr == token || *endptr != '\0') {
fprintf(stderr, "Error: Invalid number in array: %s\n", token);
free(dup);
return -1; // 解析失败
}
output[count++] = val;
token = strtok(NULL, ",");
}
free(dup);
return count;
}
// 清理字符串中的不可见字符(包括 \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];
int i = 0;
while (str[i] && i < 9) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
// 根据转换后的小写字符串返回对应的枚举值
if (strcmp(lowerStr, "next") == 0) {
return 1;
} else {
return -1;
}
}
int parse_direction(const char *str) {
// 将输入字符串转换为小写
char lowerStr[10];
int i = 0;
while (str[i] && i < 9) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
// 根据转换后的小写字符串返回对应的枚举值
if (strcmp(lowerStr, "up") == 0) {
return UP;
} else if (strcmp(lowerStr, "down") == 0) {
return DOWN;
} else if (strcmp(lowerStr, "left") == 0) {
return LEFT;
} else if (strcmp(lowerStr, "right") == 0) {
return RIGHT;
} else {
return UNDIR;
}
}
int parse_fold_state(const char *str) {
// 将输入字符串转换为小写
char lowerStr[10];
int i = 0;
while (str[i] && i < 9) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
// 根据转换后的小写字符串返回对应的枚举值
if (strcmp(lowerStr, "fold") == 0) {
return FOLD;
} else if (strcmp(lowerStr, "unfold") == 0) {
return UNFOLD;
} else {
return INVALIDFOLD;
}
}
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;
}
xkb_keysym_t normalize_keysym(xkb_keysym_t sym) {
// 首先转换为小写(主要影响字母键)
sym = xkb_keysym_to_lower(sym);
// 将数字小键盘键转换为普通数字键
switch (sym) {
// 小键盘数字转换
case XKB_KEY_KP_0:
return XKB_KEY_0;
case XKB_KEY_KP_1:
return XKB_KEY_1;
case XKB_KEY_KP_2:
return XKB_KEY_2;
case XKB_KEY_KP_3:
return XKB_KEY_3;
case XKB_KEY_KP_4:
return XKB_KEY_4;
case XKB_KEY_KP_5:
return XKB_KEY_5;
case XKB_KEY_KP_6:
return XKB_KEY_6;
case XKB_KEY_KP_7:
return XKB_KEY_7;
case XKB_KEY_KP_8:
return XKB_KEY_8;
case XKB_KEY_KP_9:
return XKB_KEY_9;
// 将 Shift+数字 的符号转换回基础数字
case XKB_KEY_exclam:
return XKB_KEY_1; // !
case XKB_KEY_at:
return XKB_KEY_2; // @
case XKB_KEY_numbersign:
return XKB_KEY_3; // #
case XKB_KEY_dollar:
return XKB_KEY_4; // $
case XKB_KEY_percent:
return XKB_KEY_5; // %
case XKB_KEY_asciicircum:
return XKB_KEY_6; // ^
case XKB_KEY_ampersand:
return XKB_KEY_7; // &
case XKB_KEY_asterisk:
return XKB_KEY_8; // *
case XKB_KEY_parenleft:
return XKB_KEY_9; // (
case XKB_KEY_parenright:
return XKB_KEY_0; // )
default:
return sym;
}
}
// 辅助函数:检查字符串是否以指定的前缀开头(忽略大小写)
static bool starts_with_ignore_case(const char *str, const char *prefix) {
while (*prefix) {
if (tolower(*str) != tolower(*prefix)) {
return false;
}
str++;
prefix++;
}
return true;
}
uint32_t parse_mod(const char *mod_str) {
if (!mod_str || !*mod_str) {
return 0;
}
uint32_t mod = 0;
char input_copy[256];
char *token;
char *saveptr = NULL;
// 复制并转换为小写
strncpy(input_copy, mod_str, sizeof(input_copy) - 1);
input_copy[sizeof(input_copy) - 1] = '\0';
for (char *p = input_copy; *p; p++) {
*p = tolower(*p);
}
// 分割处理每个部分
token = strtok_r(input_copy, "+", &saveptr);
while (token != NULL) {
// 去除空白
while (*token == ' ' || *token == '\t')
token++;
if (strncmp(token, "code:", 5) == 0) {
// 处理 code: 形式
char *endptr;
long keycode = strtol(token + 5, &endptr, 10);
if (endptr != token + 5 && (*endptr == '\0' || *endptr == ' ')) {
switch (keycode) {
case 133:
case 134:
mod |= WLR_MODIFIER_LOGO;
break;
case 37:
case 105:
mod |= WLR_MODIFIER_CTRL;
break;
case 50:
case 62:
mod |= WLR_MODIFIER_SHIFT;
break;
case 64:
case 108:
mod |= WLR_MODIFIER_ALT;
break;
}
}
} else {
// 完整的 modifier 检查(保留原始所有检查项)
if (strstr(token, "super") || strstr(token, "super_l") ||
strstr(token, "super_r")) {
mod |= WLR_MODIFIER_LOGO;
}
if (strstr(token, "ctrl") || strstr(token, "ctrl_l") ||
strstr(token, "ctrl_r")) {
mod |= WLR_MODIFIER_CTRL;
}
if (strstr(token, "shift") || strstr(token, "shift_l") ||
strstr(token, "shift_r")) {
mod |= WLR_MODIFIER_SHIFT;
}
if (strstr(token, "alt") || strstr(token, "alt_l") ||
strstr(token, "alt_r")) {
mod |= WLR_MODIFIER_ALT;
}
if (strstr(token, "hyper") || strstr(token, "hyper_l") ||
strstr(token, "hyper_r")) {
mod |= WLR_MODIFIER_MOD3;
}
}
token = strtok_r(NULL, "+", &saveptr);
}
return mod;
}
KeySymCode parse_key(const char *key_str) {
KeySymCode kc;
// 处理 code: 前缀的情况
if (strncmp(key_str, "code:", 5) == 0) {
char *endptr;
xkb_keycode_t keycode = (xkb_keycode_t)strtol(key_str + 5, &endptr, 10);
kc.type = KEY_TYPE_CODE;
kc.keycode = keycode;
return kc;
}
// 普通键名直接转换
xkb_keysym_t sym = xkb_keysym_from_name(key_str, XKB_KEYSYM_NO_FLAGS);
kc.type = KEY_TYPE_SYM;
kc.keycode = 0;
kc.keysym = sym;
return kc;
}
int parse_button(const char *str) {
// 将输入字符串转换为小写
char lowerStr[20];
int i = 0;
while (str[i] && i < 19) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0'; // 确保字符串正确终止
// 根据转换后的小写字符串返回对应的按钮编号
if (strcmp(lowerStr, "btn_left") == 0) {
return BTN_LEFT;
} else if (strcmp(lowerStr, "btn_right") == 0) {
return BTN_RIGHT;
} else if (strcmp(lowerStr, "btn_middle") == 0) {
return BTN_MIDDLE;
} else if (strcmp(lowerStr, "btn_side") == 0) {
return BTN_SIDE;
} else if (strcmp(lowerStr, "btn_extra") == 0) {
return BTN_EXTRA;
} else if (strcmp(lowerStr, "btn_forward") == 0) {
return BTN_FORWARD;
} else if (strcmp(lowerStr, "btn_back") == 0) {
return BTN_BACK;
} else if (strcmp(lowerStr, "btn_task") == 0) {
return BTN_TASK;
} else {
return 0;
}
}
int parse_mouse_action(const char *str) {
// 将输入字符串转换为小写
char lowerStr[20];
int i = 0;
while (str[i] && i < 19) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0'; // 确保字符串正确终止
// 根据转换后的小写字符串返回对应的按钮编号
if (strcmp(lowerStr, "curmove") == 0) {
return CurMove;
} else if (strcmp(lowerStr, "curresize") == 0) {
return CurResize;
} else if (strcmp(lowerStr, "curnormal") == 0) {
return CurNormal;
} else if (strcmp(lowerStr, "curpressed") == 0) {
return CurPressed;
} else {
return 0;
}
}
void convert_hex_to_rgba(float *color, unsigned long int hex) {
color[0] = ((hex >> 24) & 0xFF) / 255.0f;
color[1] = ((hex >> 16) & 0xFF) / 255.0f;
color[2] = ((hex >> 8) & 0xFF) / 255.0f;
color[3] = (hex & 0xFF) / 255.0f;
}
unsigned int parse_num_type(char *str) {
switch (str[0]) {
case '-':
return NUM_TYPE_MINUS;
case '+':
return NUM_TYPE_PLUS;
default:
return NUM_TYPE_DEFAULT;
}
}
FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
char *arg_value2, char *arg_value3, char *arg_value4,
char *arg_value5) {
FuncType func = NULL;
(*arg).v = NULL;
(*arg).v2 = NULL;
(*arg).v3 = NULL;
if (strcmp(func_name, "focusstack") == 0) {
func = focusstack;
(*arg).i = parse_circle_direction(arg_value);
} else if (strcmp(func_name, "focusdir") == 0) {
func = focusdir;
(*arg).i = parse_direction(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, "setsmfact") == 0) {
func = setsmfact;
(*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 = parse_direction(arg_value);
} else if (strcmp(func_name, "exchange_stack_client") == 0) {
func = exchange_stack_client;
(*arg).i = parse_circle_direction(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, "increase_proportion") == 0) {
func = increase_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;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "viewtoright") == 0) {
func = viewtoright;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "tagsilent") == 0) {
func = tagsilent;
(*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "tagtoleft") == 0) {
func = tagtoleft;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "tagtoright") == 0) {
func = tagtoright;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "killclient") == 0) {
func = killclient;
} else if (strcmp(func_name, "centerwin") == 0) {
func = centerwin;
} else if (strcmp(func_name, "focuslast") == 0) {
func = focuslast;
} else if (strcmp(func_name, "toggle_trackpad_enable") == 0) {
func = toggle_trackpad_enable;
} else if (strcmp(func_name, "setlayout") == 0) {
func = setlayout;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "switch_layout") == 0) {
func = switch_layout;
} else if (strcmp(func_name, "switch_keyboard_layout") == 0) {
func = switch_keyboard_layout;
} else if (strcmp(func_name, "togglefloating") == 0) {
func = togglefloating;
} else if (strcmp(func_name, "togglefullscreen") == 0) {
func = togglefullscreen;
} else if (strcmp(func_name, "togglefakefullscreen") == 0) {
func = togglefakefullscreen;
} else if (strcmp(func_name, "toggleoverlay") == 0) {
func = toggleoverlay;
} else if (strcmp(func_name, "minimized") == 0) {
func = minimized;
} else if (strcmp(func_name, "restore_minimized") == 0) {
func = restore_minimized;
} else if (strcmp(func_name, "toggle_scratchpad") == 0) {
func = toggle_scratchpad;
} else if (strcmp(func_name, "toggle_render_border") == 0) {
func = toggle_render_border;
} else if (strcmp(func_name, "focusmon") == 0) {
func = focusmon;
(*arg).i = parse_direction(arg_value);
if ((*arg).i == UNDIR) {
(*arg).v = strdup(arg_value);
}
} else if (strcmp(func_name, "tagmon") == 0) {
func = tagmon;
(*arg).i = parse_direction(arg_value);
(*arg).ui = atoi(arg_value2);
if ((*arg).i == UNDIR) {
(*arg).v = strdup(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).ui = atoi(arg_value);
} else if (strcmp(func_name, "spawn") == 0) {
func = spawn;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "spawn_shell") == 0) {
func = spawn_shell;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "spawn_on_empty") == 0) {
func = spawn_on_empty;
(*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存
(*arg).ui = 1 << (atoi(arg_value2) - 1);
} else if (strcmp(func_name, "quit") == 0) {
func = quit;
} else if (strcmp(func_name, "create_virtual_output") == 0) {
func = create_virtual_output;
} else if (strcmp(func_name, "destroy_all_virtual_output") == 0) {
func = destroy_all_virtual_output;
} else if (strcmp(func_name, "moveresize") == 0) {
func = moveresize;
(*arg).ui = parse_mouse_action(arg_value);
} else if (strcmp(func_name, "togglemaxmizescreen") == 0) {
func = togglemaxmizescreen;
} else if (strcmp(func_name, "viewtoleft_have_client") == 0) {
func = viewtoleft_have_client;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "viewtoright_have_client") == 0) {
func = viewtoright_have_client;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "reload_config") == 0) {
func = reload_config;
} else if (strcmp(func_name, "tag") == 0) {
func = tag;
(*arg).ui = 1 << (atoi(arg_value) - 1);
(*arg).i = atoi(arg_value2);
} else if (strcmp(func_name, "view") == 0) {
func = bind_to_view;
(*arg).ui = 1 << (atoi(arg_value) - 1);
(*arg).i = atoi(arg_value2);
} else if (strcmp(func_name, "toggletag") == 0) {
func = toggletag;
(*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "toggleview") == 0) {
func = toggleview;
(*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "comboview") == 0) {
func = comboview;
(*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "smartmovewin") == 0) {
func = smartmovewin;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "smartresizewin") == 0) {
func = smartresizewin;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "resizewin") == 0) {
func = resizewin;
(*arg).ui = parse_num_type(arg_value);
(*arg).ui2 = parse_num_type(arg_value2);
(*arg).i = (*arg).ui == NUM_TYPE_DEFAULT ? atoi(arg_value)
: atoi(arg_value + 1);
(*arg).i2 = (*arg).ui2 == NUM_TYPE_DEFAULT ? atoi(arg_value2)
: atoi(arg_value2 + 1);
} else if (strcmp(func_name, "movewin") == 0) {
func = movewin;
(*arg).ui = parse_num_type(arg_value);
(*arg).ui2 = parse_num_type(arg_value2);
(*arg).i = (*arg).ui == NUM_TYPE_DEFAULT ? atoi(arg_value)
: atoi(arg_value + 1);
(*arg).i2 = (*arg).ui2 == NUM_TYPE_DEFAULT ? atoi(arg_value2)
: atoi(arg_value2 + 1);
} else if (strcmp(func_name, "toggle_named_scratchpad") == 0) {
func = toggle_named_scratchpad;
(*arg).v = strdup(arg_value);
(*arg).v2 = strdup(arg_value2);
(*arg).v3 = strdup(arg_value3);
} else {
return NULL;
}
return func;
}
void run_exec() {
Arg arg;
for (int i = 0; i < config.exec_count; i++) {
arg.v = config.exec[i];
spawn_shell(&arg);
}
}
void run_exec_once() {
Arg arg;
for (int i = 0; i < config.exec_once_count; i++) {
arg.v = config.exec_once[i];
spawn_shell(&arg);
}
}
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;
}
// Then trim each part separately
trim_whitespace(key);
trim_whitespace(value);
if (strcmp(key, "animations") == 0) {
config->animations = atoi(value);
} else if (strcmp(key, "layer_animations") == 0) {
config->layer_animations = atoi(value);
} else if (strcmp(key, "animation_type_open") == 0) {
snprintf(config->animation_type_open,
sizeof(config->animation_type_open), "%.9s",
value); // string limit to 9 char
} else if (strcmp(key, "animation_type_close") == 0) {
snprintf(config->animation_type_close,
sizeof(config->animation_type_close), "%.9s",
value); // string limit to 9 char
} else if (strcmp(key, "layer_animation_type_open") == 0) {
snprintf(config->layer_animation_type_open,
sizeof(config->layer_animation_type_open), "%.9s",
value); // string limit to 9 char
} else if (strcmp(key, "layer_animation_type_close") == 0) {
snprintf(config->layer_animation_type_close,
sizeof(config->layer_animation_type_close), "%.9s",
value); // string limit to 9 char
} else if (strcmp(key, "animation_fade_in") == 0) {
config->animation_fade_in = atoi(value);
} else if (strcmp(key, "animation_fade_out") == 0) {
config->animation_fade_out = atoi(value);
} else if (strcmp(key, "tag_animation_direction") == 0) {
config->tag_animation_direction = atoi(value);
} else if (strcmp(key, "zoom_initial_ratio") == 0) {
config->zoom_initial_ratio = atof(value);
} else if (strcmp(key, "zoom_end_ratio") == 0) {
config->zoom_end_ratio = atof(value);
} else if (strcmp(key, "fadein_begin_opacity") == 0) {
config->fadein_begin_opacity = atof(value);
} else if (strcmp(key, "fadeout_begin_opacity") == 0) {
config->fadeout_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_duration_close") == 0) {
config->animation_duration_close = atoi(value);
} else if (strcmp(key, "animation_curve_move") == 0) {
int num = parse_double_array(value, config->animation_curve_move, 4);
if (num != 4) {
fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n",
value);
}
} else if (strcmp(key, "animation_curve_open") == 0) {
int num = parse_double_array(value, config->animation_curve_open, 4);
if (num != 4) {
fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n",
value);
}
} else if (strcmp(key, "animation_curve_tag") == 0) {
int num = parse_double_array(value, config->animation_curve_tag, 4);
if (num != 4) {
fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n",
value);
}
} else if (strcmp(key, "animation_curve_close") == 0) {
int num = parse_double_array(value, config->animation_curve_close, 4);
if (num != 4) {
fprintf(stderr,
"Error: Failed to parse animation_curve_close: %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, "scroller_default_proportion_single") == 0) {
config->scroller_default_proportion_single = atof(value);
} else if (strcmp(key, "scroller_focus_center") == 0) {
config->scroller_focus_center = atoi(value);
} else if (strcmp(key, "scroller_prefer_center") == 0) {
config->scroller_prefer_center = atoi(value);
} else if (strcmp(key, "edge_scroller_pointer_focus") == 0) {
config->edge_scroller_pointer_focus = atoi(value);
} else if (strcmp(key, "focus_cross_monitor") == 0) {
config->focus_cross_monitor = atoi(value);
} else if (strcmp(key, "exchange_cross_monitor") == 0) {
config->exchange_cross_monitor = atoi(value);
} else if (strcmp(key, "scratchpad_cross_monitor") == 0) {
config->scratchpad_cross_monitor = atoi(value);
} else if (strcmp(key, "focus_cross_tag") == 0) {
config->focus_cross_tag = atoi(value);
} else if (strcmp(key, "view_current_to_back") == 0) {
config->view_current_to_back = atoi(value);
} else if (strcmp(key, "blur") == 0) {
config->blur = atoi(value);
} else if (strcmp(key, "blur_layer") == 0) {
config->blur_layer = atoi(value);
} else if (strcmp(key, "blur_optimized") == 0) {
config->blur_optimized = atoi(value);
} else if (strcmp(key, "border_radius") == 0) {
config->border_radius = atoi(value);
} else if (strcmp(key, "blur_params_num_passes") == 0) {
config->blur_params.num_passes = atoi(value);
} else if (strcmp(key, "blur_params_radius") == 0) {
config->blur_params.radius = atoi(value);
} else if (strcmp(key, "blur_params_noise") == 0) {
config->blur_params.noise = atof(value);
} else if (strcmp(key, "blur_params_brightness") == 0) {
config->blur_params.brightness = atof(value);
} else if (strcmp(key, "blur_params_contrast") == 0) {
config->blur_params.contrast = atof(value);
} else if (strcmp(key, "blur_params_saturation") == 0) {
config->blur_params.saturation = atof(value);
} else if (strcmp(key, "shadows") == 0) {
config->shadows = atoi(value);
} else if (strcmp(key, "shadow_only_floating") == 0) {
config->shadow_only_floating = atoi(value);
} else if (strcmp(key, "layer_shadows") == 0) {
config->layer_shadows = atoi(value);
} else if (strcmp(key, "shadows_size") == 0) {
config->shadows_size = atoi(value);
} else if (strcmp(key, "shadows_blur") == 0) {
config->shadows_blur = atof(value);
} else if (strcmp(key, "shadows_position_x") == 0) {
config->shadows_position_x = atoi(value);
} else if (strcmp(key, "shadows_position_y") == 0) {
config->shadows_position_y = atoi(value);
} else if (strcmp(key, "single_scratchpad") == 0) {
config->single_scratchpad = atoi(value);
} else if (strcmp(key, "xwayland_persistence") == 0) {
config->xwayland_persistence = atoi(value);
} else if (strcmp(key, "syncobj_enable") == 0) {
config->syncobj_enable = atoi(value);
} else if (strcmp(key, "adaptive_sync") == 0) {
config->adaptive_sync = atoi(value);
} else if (strcmp(key, "no_border_when_single") == 0) {
config->no_border_when_single = atoi(value);
} else if (strcmp(key, "no_radius_when_single") == 0) {
config->no_radius_when_single = atoi(value);
} else if (strcmp(key, "snap_distance") == 0) {
config->snap_distance = atoi(value);
} else if (strcmp(key, "enable_floating_snap") == 0) {
config->enable_floating_snap = atoi(value);
} else if (strcmp(key, "drag_tile_to_tile") == 0) {
config->drag_tile_to_tile = atoi(value);
} else if (strcmp(key, "swipe_min_threshold") == 0) {
config->swipe_min_threshold = atoi(value);
} else if (strcmp(key, "focused_opacity") == 0) {
config->focused_opacity = atof(value);
} else if (strcmp(key, "unfocused_opacity") == 0) {
config->unfocused_opacity = atof(value);
} else if (strcmp(key, "xkb_rules_rules") == 0) {
strncpy(xkb_rules_rules, value, sizeof(xkb_rules_rules) - 1);
xkb_rules_rules[sizeof(xkb_rules_rules) - 1] =
'\0'; // 确保字符串以 null 结尾
} else if (strcmp(key, "xkb_rules_model") == 0) {
strncpy(xkb_rules_model, value, sizeof(xkb_rules_model) - 1);
xkb_rules_model[sizeof(xkb_rules_model) - 1] =
'\0'; // 确保字符串以 null 结尾
} else if (strcmp(key, "xkb_rules_layout") == 0) {
strncpy(xkb_rules_layout, value, sizeof(xkb_rules_layout) - 1);
xkb_rules_layout[sizeof(xkb_rules_layout) - 1] =
'\0'; // 确保字符串以 null 结尾
} else if (strcmp(key, "xkb_rules_variant") == 0) {
strncpy(xkb_rules_variant, value, sizeof(xkb_rules_variant) - 1);
xkb_rules_variant[sizeof(xkb_rules_variant) - 1] =
'\0'; // 确保字符串以 null 结尾
} else if (strcmp(key, "xkb_rules_options") == 0) {
strncpy(xkb_rules_options, value, sizeof(xkb_rules_options) - 1);
xkb_rules_options[sizeof(xkb_rules_options) - 1] =
'\0'; // 确保字符串以 null 结尾
} else if (strcmp(key, "scroller_proportion_preset") == 0) {
// 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数
int count = 0; // 初始化为 0
for (const char *p = value; *p; p++) {
if (*p == ',')
count++;
}
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;
float value_set;
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);
free(value_copy);
free(config->scroller_proportion_preset);
config->scroller_proportion_preset = NULL;
return;
}
// Clamp the value between 0.0 and 1.0 (or your desired range)
config->scroller_proportion_preset[i] =
CLAMP_FLOAT(value_set, 0.1f, 1.0f);
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);
} else if (strcmp(key, "default_smfact") == 0) {
config->default_smfact = atof(value);
} else if (strcmp(key, "default_nmaster") == 0) {
config->default_nmaster = atoi(value);
} else if (strcmp(key, "center_master_overspread") == 0) {
config->center_master_overspread = atoi(value);
} else if (strcmp(key, "center_when_single_slave") == 0) {
config->center_when_single_slave = 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, "cursor_hide_timeout") == 0) {
config->cursor_hide_timeout = 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, "inhibit_regardless_of_visibility") == 0) {
config->inhibit_regardless_of_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, "repeat_rate") == 0) {
config->repeat_rate = atoi(value);
} else if (strcmp(key, "repeat_delay") == 0) {
config->repeat_delay = atoi(value);
} else if (strcmp(key, "disable_trackpad") == 0) {
config->disable_trackpad = atoi(value);
} else if (strcmp(key, "tap_to_click") == 0) {
config->tap_to_click = atoi(value);
} else if (strcmp(key, "tap_and_drag") == 0) {
config->tap_and_drag = atoi(value);
} else if (strcmp(key, "drag_lock") == 0) {
config->drag_lock = atoi(value);
} else if (strcmp(key, "mouse_natural_scrolling") == 0) {
config->mouse_natural_scrolling = atoi(value);
} else if (strcmp(key, "trackpad_natural_scrolling") == 0) {
config->trackpad_natural_scrolling = atoi(value);
} else if (strcmp(key, "cursor_size") == 0) {
config->cursor_size = atoi(value);
} else if (strcmp(key, "cursor_theme") == 0) {
config->cursor_theme = strdup(value);
} else if (strcmp(key, "disable_while_typing") == 0) {
config->disable_while_typing = atoi(value);
} else if (strcmp(key, "left_handed") == 0) {
config->left_handed = atoi(value);
} else if (strcmp(key, "middle_button_emulation") == 0) {
config->middle_button_emulation = atoi(value);
} else if (strcmp(key, "accel_profile") == 0) {
config->accel_profile = atoi(value);
} else if (strcmp(key, "accel_speed") == 0) {
config->accel_speed = atof(value);
} else if (strcmp(key, "scroll_method") == 0) {
config->scroll_method = atoi(value);
} else if (strcmp(key, "scroll_button") == 0) {
config->scroll_button = atoi(value);
} else if (strcmp(key, "click_method") == 0) {
config->click_method = atoi(value);
} else if (strcmp(key, "send_events_mode") == 0) {
config->send_events_mode = atoi(value);
} else if (strcmp(key, "button_map") == 0) {
config->button_map = 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, "scratchpad_width_ratio") == 0) {
config->scratchpad_width_ratio = atof(value);
} else if (strcmp(key, "scratchpad_height_ratio") == 0) {
config->scratchpad_height_ratio = atof(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 {
convert_hex_to_rgba(config->rootcolor, color);
}
} else if (strcmp(key, "shadowscolor") == 0) {
long int color = parse_color(value);
if (color == -1) {
fprintf(stderr, "Error: Invalid shadowscolor format: %s\n", value);
} else {
convert_hex_to_rgba(config->shadowscolor, 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 {
convert_hex_to_rgba(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 {
convert_hex_to_rgba(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 {
convert_hex_to_rgba(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 {
convert_hex_to_rgba(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 {
convert_hex_to_rgba(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 {
convert_hex_to_rgba(config->globalcolor, color);
}
} else if (strcmp(key, "overlaycolor") == 0) {
long int color = parse_color(value);
if (color == -1) {
fprintf(stderr, "Error: Invalid overlaycolor format: %s\n", value);
} else {
convert_hex_to_rgba(config->overlaycolor, 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);
}
trim_whitespace(config->autostart[0]);
trim_whitespace(config->autostart[1]);
trim_whitespace(config->autostart[2]);
} 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;
}
ConfigTagRule *rule = &config->tag_rules[config->tag_rules_count];
memset(rule, 0, sizeof(ConfigTagRule));
// 设置默认值
rule->id = 0;
rule->layout_name = NULL;
rule->monitor_name = NULL;
char *token = strtok(value, ",");
while (token != NULL) {
char *colon = strchr(token, ':');
if (colon != NULL) {
*colon = '\0';
char *key = token;
char *val = colon + 1;
trim_whitespace(key);
trim_whitespace(val);
if (strcmp(key, "id") == 0) {
rule->id = CLAMP_INT(atoi(val), 0, LENGTH(tags));
} else if (strcmp(key, "layout_name") == 0) {
rule->layout_name = strdup(val);
} else if (strcmp(key, "monitor_name") == 0) {
rule->monitor_name = strdup(val);
} else if (strcmp(key, "no_render_border") == 0) {
rule->no_render_border = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "no_hide") == 0) {
rule->no_hide = CLAMP_INT(atoi(val), 0, 1);
}
}
token = strtok(NULL, ",");
}
config->tag_rules_count++;
} 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;
}
ConfigLayerRule *rule = &config->layer_rules[config->layer_rules_count];
memset(rule, 0, sizeof(ConfigLayerRule));
// 设置默认值
rule->layer_name = NULL;
rule->animation_type_open = NULL;
rule->animation_type_close = NULL;
rule->noblur = 0;
rule->noanim = 0;
rule->noshadow = 0;
char *token = strtok(value, ",");
while (token != NULL) {
char *colon = strchr(token, ':');
if (colon != NULL) {
*colon = '\0';
char *key = token;
char *val = colon + 1;
trim_whitespace(key);
trim_whitespace(val);
if (strcmp(key, "layer_name") == 0) {
rule->layer_name = strdup(val);
} else if (strcmp(key, "animation_type_open") == 0) {
rule->animation_type_open = strdup(val);
} else if (strcmp(key, "animation_type_close") == 0) {
rule->animation_type_close = strdup(val);
} else if (strcmp(key, "noblur") == 0) {
rule->noblur = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "noanim") == 0) {
rule->noanim = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "noshadow") == 0) {
rule->noshadow = CLAMP_INT(atoi(val), 0, 1);
}
}
token = strtok(NULL, ",");
}
// 如果没有指定布局名称,则使用默认值
if (rule->layer_name == NULL) {
rule->layer_name = strdup("default");
}
config->layer_rules_count++;
} 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));
// int rule value, relay to a client property
rule->isfloating = -1;
rule->isfullscreen = -1;
rule->isnoborder = -1;
rule->isopensilent = -1;
rule->istagsilent = -1;
rule->isnamedscratchpad = -1;
rule->isunglobal = -1;
rule->isglobal = -1;
rule->isoverlay = -1;
rule->ignore_maximize = -1;
rule->ignore_minimize = -1;
rule->isnosizehint = -1;
rule->isterm = -1;
rule->noswallow = -1;
rule->noblur = -1;
rule->nofadein = -1;
rule->nofadeout = -1;
rule->no_force_center = -1;
// string rule value, relay to a client property
rule->animation_type_open = NULL;
rule->animation_type_close = NULL;
// float rule value, relay to a client property
rule->focused_opacity = 0;
rule->unfocused_opacity = 0;
rule->scroller_proportion = 0;
// special rule value,not directly set to client property
rule->tags = 0;
rule->offsetx = 0;
rule->offsety = 0;
rule->width = 0;
rule->height = 0;
rule->monitor = NULL;
rule->id = NULL;
rule->title = NULL;
rule->globalkeybinding = (KeyBinding){0};
char *token = strtok(value, ",");
while (token != NULL) {
char *colon = strchr(token, ':');
if (colon != NULL) {
*colon = '\0';
char *key = token;
char *val = colon + 1;
trim_whitespace(key);
trim_whitespace(val);
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_open") == 0) {
rule->animation_type_open = strdup(val);
} else if (strcmp(key, "animation_type_close") == 0) {
rule->animation_type_close = strdup(val);
} else if (strcmp(key, "tags") == 0) {
rule->tags = 1 << (atoi(val) - 1);
} else if (strcmp(key, "monitor") == 0) {
rule->monitor = strdup(val);
} else if (strcmp(key, "offsetx") == 0) {
rule->offsetx = atoi(val);
} else if (strcmp(key, "offsety") == 0) {
rule->offsety = atoi(val);
} else if (strcmp(key, "nofadein") == 0) {
rule->nofadein = atoi(val);
} else if (strcmp(key, "nofadeout") == 0) {
rule->nofadeout = atoi(val);
} else if (strcmp(key, "no_force_center") == 0) {
rule->no_force_center = 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, "isopensilent") == 0) {
rule->isopensilent = atoi(val);
} else if (strcmp(key, "istagsilent") == 0) {
rule->istagsilent = atoi(val);
} else if (strcmp(key, "isnamedscratchpad") == 0) {
rule->isnamedscratchpad = atoi(val);
} else if (strcmp(key, "isunglobal") == 0) {
rule->isunglobal = atoi(val);
} else if (strcmp(key, "isglobal") == 0) {
rule->isglobal = atoi(val);
} else if (strcmp(key, "unfocused_opacity") == 0) {
rule->unfocused_opacity = atof(val);
} else if (strcmp(key, "focused_opacity") == 0) {
rule->focused_opacity = atof(val);
} else if (strcmp(key, "isoverlay") == 0) {
rule->isoverlay = atoi(val);
} else if (strcmp(key, "ignore_maximize") == 0) {
rule->ignore_maximize = atoi(val);
} else if (strcmp(key, "ignore_minimize") == 0) {
rule->ignore_minimize = atoi(val);
} else if (strcmp(key, "isnosizehint") == 0) {
rule->isnosizehint = atoi(val);
} else if (strcmp(key, "isterm") == 0) {
rule->isterm = atoi(val);
} else if (strcmp(key, "noswallow") == 0) {
rule->noswallow = atoi(val);
} else if (strcmp(key, "noblur") == 0) {
rule->noblur = atoi(val);
} else if (strcmp(key, "scroller_proportion") == 0) {
rule->scroller_proportion = atof(val);
} else if (strcmp(key, "isfullscreen") == 0) {
rule->isfullscreen = atoi(val);
} else if (strcmp(key, "globalkeybinding") == 0) {
char mod_str[256], keysym_str[256];
sscanf(val, "%[^-]-%[a-zA-Z]", mod_str, keysym_str);
trim_whitespace(mod_str);
trim_whitespace(keysym_str);
rule->globalkeybinding.mod = parse_mod(mod_str);
rule->globalkeybinding.keysymcode = parse_key(keysym_str);
}
}
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 raw_name[256], raw_layout[256];
char raw_mfact[256], raw_nmaster[256], raw_rr[256];
char raw_scale[256], raw_x[256], raw_y[256], raw_width[256],
raw_height[256], raw_refresh[256];
// 先读取所有字段为字符串
int parsed =
sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255["
"^,],%255[^,],%255[^,],%255[^,],%255[^,],%255s",
raw_name, raw_mfact, raw_nmaster, raw_layout, raw_rr,
raw_scale, raw_x, raw_y, raw_width, raw_height, raw_refresh);
if (parsed == 11) {
// 修剪每个字段的空格
trim_whitespace(raw_name);
trim_whitespace(raw_mfact);
trim_whitespace(raw_nmaster);
trim_whitespace(raw_layout);
trim_whitespace(raw_rr);
trim_whitespace(raw_scale);
trim_whitespace(raw_x);
trim_whitespace(raw_y);
trim_whitespace(raw_width);
trim_whitespace(raw_height);
trim_whitespace(raw_refresh);
// 转换修剪后的字符串为特定类型
rule->name = strdup(raw_name);
rule->layout = strdup(raw_layout);
rule->mfact = atof(raw_mfact);
rule->nmaster = atoi(raw_nmaster);
rule->rr = atoi(raw_rr);
rule->scale = atof(raw_scale);
rule->x = atoi(raw_x);
rule->y = atoi(raw_y);
rule->width = atoi(raw_width);
rule->height = atoi(raw_height);
rule->refresh = atof(raw_refresh);
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, "env", 3) == 0) {
char env_type[256], env_value[256];
if (sscanf(value, "%[^,],%[^\n]", env_type, env_value) < 2) {
fprintf(stderr, "Error: Invalid bind format: %s\n", value);
return;
}
trim_whitespace(env_type);
trim_whitespace(env_value);
setenv(env_type, env_value, 1);
} else if (strncmp(key, "exec", 9) == 0) {
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;
}
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;
}
config->exec_count++;
} else if (strncmp(key, "exec-once", 9) == 0) {
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;
}
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;
}
config->exec_once_count++;
} 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] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\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;
}
trim_whitespace(mod_str);
trim_whitespace(keysym_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
trim_whitespace(arg_value5);
binding->mod = parse_mod(mod_str);
binding->keysymcode = parse_key(keysym_str);
binding->arg.v = NULL;
binding->arg.v2 = NULL;
binding->arg.v3 = NULL;
binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5);
if (!binding->func) {
if (binding->arg.v) {
free(binding->arg.v);
binding->arg.v = NULL;
}
if (binding->arg.v2) {
free(binding->arg.v2);
binding->arg.v2 = NULL;
}
if (binding->arg.v3) {
free(binding->arg.v3);
binding->arg.v3 = NULL;
}
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] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\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;
}
trim_whitespace(mod_str);
trim_whitespace(button_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
trim_whitespace(arg_value5);
binding->mod = parse_mod(mod_str);
binding->button = parse_button(button_str);
binding->arg.v = NULL;
binding->arg.v2 = NULL;
binding->arg.v3 = NULL;
binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5);
if (!binding->func) {
if (binding->arg.v) {
free(binding->arg.v);
binding->arg.v = NULL;
}
if (binding->arg.v2) {
free(binding->arg.v2);
binding->arg.v2 = NULL;
}
if (binding->arg.v3) {
free(binding->arg.v3);
binding->arg.v3 = NULL;
}
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] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\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;
}
trim_whitespace(mod_str);
trim_whitespace(dir_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
trim_whitespace(arg_value5);
binding->mod = parse_mod(mod_str);
binding->dir = parse_direction(dir_str);
binding->arg.v = NULL;
binding->arg.v2 = NULL;
binding->arg.v3 = NULL;
binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5);
if (!binding->func) {
if (binding->arg.v) {
free(binding->arg.v);
binding->arg.v = NULL;
}
if (binding->arg.v2) {
free(binding->arg.v2);
binding->arg.v2 = NULL;
}
if (binding->arg.v3) {
free(binding->arg.v3);
binding->arg.v3 = NULL;
}
fprintf(stderr, "Error: Unknown function in axisbind: %s\n",
func_name);
} else {
config->axis_bindings_count++;
}
} else if (strncmp(key, "switchbind", 10) == 0) {
config->switch_bindings = realloc(config->switch_bindings,
(config->switch_bindings_count + 1) *
sizeof(SwitchBinding));
if (!config->switch_bindings) {
fprintf(stderr,
"Error: Failed to allocate memory for switch bindings\n");
return;
}
SwitchBinding *binding =
&config->switch_bindings[config->switch_bindings_count];
memset(binding, 0, sizeof(SwitchBinding));
char fold_str[256], func_name[256],
arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0";
if (sscanf(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;
}
trim_whitespace(fold_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
trim_whitespace(arg_value5);
binding->fold = parse_fold_state(fold_str);
binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5);
if (!binding->func) {
if (binding->arg.v) {
free(binding->arg.v);
binding->arg.v = NULL;
}
if (binding->arg.v2) {
free(binding->arg.v2);
binding->arg.v2 = NULL;
}
if (binding->arg.v3) {
free(binding->arg.v3);
binding->arg.v3 = NULL;
}
fprintf(stderr, "Error: Unknown function in switchbind: %s\n",
func_name);
} else {
config->switch_bindings_count++;
}
} else if (strncmp(key, "gesturebind", 11) == 0) {
config->gesture_bindings = realloc(
config->gesture_bindings,
(config->gesture_bindings_count + 1) * sizeof(GestureBinding));
if (!config->gesture_bindings) {
fprintf(stderr,
"Error: Failed to allocate memory for axis gesturebind\n");
return;
}
GestureBinding *binding =
&config->gesture_bindings[config->gesture_bindings_count];
memset(binding, 0, sizeof(GestureBinding));
char mod_str[256], motion_str[256], fingers_count_str[256],
func_name[256], arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0";
if (sscanf(value,
"%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\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;
}
trim_whitespace(mod_str);
trim_whitespace(motion_str);
trim_whitespace(fingers_count_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
trim_whitespace(arg_value5);
binding->mod = parse_mod(mod_str);
binding->motion = parse_direction(motion_str);
binding->fingers_count = atoi(fingers_count_str);
binding->arg.v = NULL;
binding->arg.v2 = NULL;
binding->arg.v3 = NULL;
binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5);
if (!binding->func) {
if (binding->arg.v) {
free(binding->arg.v);
binding->arg.v = NULL;
}
if (binding->arg.v2) {
free(binding->arg.v2);
binding->arg.v2 = NULL;
}
if (binding->arg.v3) {
free(binding->arg.v3);
binding->arg.v3 = NULL;
}
fprintf(stderr, "Error: Unknown function in axisbind: %s\n",
func_name);
} else {
config->gesture_bindings_count++;
}
} else if (strncmp(key, "source", 6) == 0) {
parse_config_file(config, value);
} else {
fprintf(stderr, "Error: Unknown key: %s\n", key);
}
}
void parse_config_file(Config *config, const char *file_path) {
FILE *file;
// 检查路径是否以 ~/ 开头
if (file_path[0] == '~' && (file_path[1] == '/' || file_path[1] == '\0')) {
const char *home = getenv("HOME");
if (!home) {
fprintf(stderr, "Error: HOME environment variable not set.\n");
return;
}
// 构建完整路径(家目录 + / + 原路径去掉 ~
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1);
file = fopen(full_path, "r");
if (!file) {
perror("Error opening file");
return;
}
} else {
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);
}
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_baked_points(void) {
if (baked_points_move) {
free(baked_points_move);
baked_points_move = NULL;
}
if (baked_points_open) {
free(baked_points_open);
baked_points_open = NULL;
}
if (baked_points_close) {
free(baked_points_close);
baked_points_close = NULL;
}
if (baked_points_tag) {
free(baked_points_tag);
baked_points_tag = NULL;
}
}
void free_config(void) {
// 释放内存
int i;
// 释放 window_rules
if (config.window_rules) {
for (int i = 0; i < config.window_rules_count; i++) {
ConfigWinRule *rule = &config.window_rules[i];
if (rule->id)
free((void *)rule->id);
if (rule->title)
free((void *)rule->title);
if (rule->animation_type_open)
free((void *)rule->animation_type_open);
if (rule->animation_type_close)
free((void *)rule->animation_type_close);
if (rule->monitor)
free((void *)rule->monitor);
rule->id = NULL;
rule->title = NULL;
rule->animation_type_open = NULL;
rule->animation_type_close = NULL;
rule->monitor = NULL;
// 释放 globalkeybinding 的 arg.v如果动态分配
if (rule->globalkeybinding.arg.v) {
free((void *)rule->globalkeybinding.arg.v);
}
}
free(config.window_rules);
config.window_rules = NULL;
config.window_rules_count = 0;
}
// 释放 monitor_rules
if (config.monitor_rules) {
for (int i = 0; i < config.monitor_rules_count; i++) {
ConfigMonitorRule *rule = &config.monitor_rules[i];
free((void *)rule->name);
free((void *)rule->layout);
}
free(config.monitor_rules);
config.monitor_rules = NULL;
config.monitor_rules_count = 0;
}
// 释放 key_bindings
if (config.key_bindings) {
for (i = 0; i < config.key_bindings_count; i++) {
if (config.key_bindings[i].arg.v) {
free((void *)config.key_bindings[i].arg.v);
config.key_bindings[i].arg.v = NULL;
}
if (config.key_bindings[i].arg.v2) {
free((void *)config.key_bindings[i].arg.v2);
config.key_bindings[i].arg.v2 = NULL;
}
if (config.key_bindings[i].arg.v3) {
free((void *)config.key_bindings[i].arg.v3);
config.key_bindings[i].arg.v3 = NULL;
}
}
free(config.key_bindings);
config.key_bindings = NULL;
config.key_bindings_count = 0;
}
// 释放 mouse_bindings
if (config.mouse_bindings) {
for (i = 0; i < config.mouse_bindings_count; i++) {
if (config.mouse_bindings[i].arg.v) {
free((void *)config.mouse_bindings[i].arg.v);
config.mouse_bindings[i].arg.v = NULL;
}
if (config.mouse_bindings[i].arg.v2) {
free((void *)config.mouse_bindings[i].arg.v2);
config.mouse_bindings[i].arg.v2 = NULL;
}
if (config.mouse_bindings[i].arg.v3) {
free((void *)config.mouse_bindings[i].arg.v3);
config.mouse_bindings[i].arg.v3 = NULL;
}
}
free(config.mouse_bindings);
config.mouse_bindings = NULL;
config.mouse_bindings_count = 0;
}
// 释放 axis_bindings
if (config.axis_bindings) {
for (i = 0; i < config.axis_bindings_count; i++) {
if (config.axis_bindings[i].arg.v) {
free((void *)config.axis_bindings[i].arg.v);
config.axis_bindings[i].arg.v = NULL;
}
if (config.axis_bindings[i].arg.v2) {
free((void *)config.axis_bindings[i].arg.v2);
config.axis_bindings[i].arg.v2 = NULL;
}
if (config.axis_bindings[i].arg.v3) {
free((void *)config.axis_bindings[i].arg.v3);
config.axis_bindings[i].arg.v3 = NULL;
}
}
free(config.axis_bindings);
config.axis_bindings = NULL;
config.axis_bindings_count = 0;
}
// 释放 switch_bindings
if (config.switch_bindings) {
for (i = 0; i < config.switch_bindings_count; i++) {
if (config.switch_bindings[i].arg.v) {
free((void *)config.switch_bindings[i].arg.v);
config.switch_bindings[i].arg.v = NULL;
}
if (config.switch_bindings[i].arg.v2) {
free((void *)config.switch_bindings[i].arg.v2);
config.switch_bindings[i].arg.v2 = NULL;
}
if (config.switch_bindings[i].arg.v3) {
free((void *)config.switch_bindings[i].arg.v3);
config.switch_bindings[i].arg.v3 = NULL;
}
}
free(config.switch_bindings);
config.switch_bindings = NULL;
config.switch_bindings_count = 0;
}
// 释放 gesture_bindings
if (config.gesture_bindings) {
for (i = 0; i < config.gesture_bindings_count; i++) {
if (config.gesture_bindings[i].arg.v) {
free((void *)config.gesture_bindings[i].arg.v);
config.gesture_bindings[i].arg.v = NULL;
}
if (config.gesture_bindings[i].arg.v2) {
free((void *)config.gesture_bindings[i].arg.v2);
config.gesture_bindings[i].arg.v2 = NULL;
}
if (config.gesture_bindings[i].arg.v3) {
free((void *)config.gesture_bindings[i].arg.v3);
config.gesture_bindings[i].arg.v3 = NULL;
}
}
free(config.gesture_bindings);
config.gesture_bindings = NULL;
config.gesture_bindings_count = 0;
}
// 释放 tag_rules
if (config.tag_rules) {
for (int i = 0; i < config.tag_rules_count; i++) {
if (config.tag_rules[i].layout_name)
free((void *)config.tag_rules[i].layout_name);
if (config.tag_rules[i].monitor_name)
free((void *)config.tag_rules[i].monitor_name);
}
free(config.tag_rules);
config.tag_rules = NULL;
config.tag_rules_count = 0;
}
// 释放 layer_rules
if (config.layer_rules) {
for (int i = 0; i < config.layer_rules_count; i++) {
if (config.layer_rules[i].layer_name)
free((void *)config.layer_rules[i].layer_name);
if (config.layer_rules[i].animation_type_open)
free((void *)config.layer_rules[i].animation_type_open);
if (config.layer_rules[i].animation_type_close)
free((void *)config.layer_rules[i].animation_type_close);
}
free(config.layer_rules);
config.layer_rules = NULL;
config.layer_rules_count = 0;
}
// 释放 exec
if (config.exec) {
for (i = 0; i < config.exec_count; i++) {
free(config.exec[i]);
}
free(config.exec);
config.exec = NULL;
config.exec_count = 0;
}
// 释放 exec_once
if (config.exec_once) {
for (i = 0; i < config.exec_once_count; i++) {
free(config.exec_once[i]);
}
free(config.exec_once);
config.exec_once = NULL;
config.exec_once_count = 0;
}
// 释放 scroller_proportion_preset
if (config.scroller_proportion_preset) {
free(config.scroller_proportion_preset);
config.scroller_proportion_preset = NULL;
config.scroller_proportion_preset_count = 0;
}
if (config.cursor_theme) {
free(config.cursor_theme);
config.cursor_theme = NULL;
}
// 释放 circle_layout
free_circle_layout(&config);
// 释放动画资源
free_baked_points();
}
void override_config(void) {
// 动画启用
animations = CLAMP_INT(config.animations, 0, 1);
layer_animations = CLAMP_INT(config.layer_animations, 0, 1);
// 标签动画方向
tag_animation_direction = CLAMP_INT(config.tag_animation_direction, 0, 1);
// 动画淡入淡出设置
animation_fade_in = CLAMP_INT(config.animation_fade_in, 0, 1);
animation_fade_out = CLAMP_INT(config.animation_fade_out, 0, 1);
zoom_initial_ratio = CLAMP_FLOAT(config.zoom_initial_ratio, 0.1f, 1.0f);
zoom_end_ratio = CLAMP_FLOAT(config.zoom_end_ratio, 0.1f, 1.0f);
fadein_begin_opacity = CLAMP_FLOAT(config.fadein_begin_opacity, 0.0f, 1.0f);
fadeout_begin_opacity =
CLAMP_FLOAT(config.fadeout_begin_opacity, 0.0f, 1.0f);
// 打开关闭动画类型
animation_type_open = config.animation_type_open;
animation_type_close = config.animation_type_close;
// layer打开关闭动画类型
layer_animation_type_open = config.layer_animation_type_open;
layer_animation_type_close = config.layer_animation_type_close;
// 动画时间限制在合理范围(1-50000ms)
animation_duration_move =
CLAMP_INT(config.animation_duration_move, 1, 50000);
animation_duration_open =
CLAMP_INT(config.animation_duration_open, 1, 50000);
animation_duration_tag = CLAMP_INT(config.animation_duration_tag, 1, 50000);
animation_duration_close =
CLAMP_INT(config.animation_duration_close, 1, 50000);
// 滚动布局设置
scroller_default_proportion =
CLAMP_FLOAT(config.scroller_default_proportion, 0.1f, 1.0f);
scroller_default_proportion_single =
CLAMP_FLOAT(config.scroller_default_proportion_single, 0.1f, 1.0f);
scroller_focus_center = CLAMP_INT(config.scroller_focus_center, 0, 1);
scroller_prefer_center = CLAMP_INT(config.scroller_prefer_center, 0, 1);
edge_scroller_pointer_focus =
CLAMP_INT(config.edge_scroller_pointer_focus, 0, 1);
scroller_structs = CLAMP_INT(config.scroller_structs, 0, 1000);
// 主从布局设置
default_mfact = CLAMP_FLOAT(config.default_mfact, 0.1f, 0.9f);
default_smfact = CLAMP_FLOAT(config.default_smfact, 0.1f, 0.9f);
default_nmaster = CLAMP_INT(config.default_nmaster, 1, 1000);
center_master_overspread = CLAMP_INT(config.center_master_overspread, 0, 1);
center_when_single_slave = CLAMP_INT(config.center_when_single_slave, 0, 1);
new_is_master = CLAMP_INT(config.new_is_master, 0, 1);
// 概述模式设置
hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000);
enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1);
ov_tab_mode = CLAMP_INT(config.ov_tab_mode, 0, 1);
overviewgappi = CLAMP_INT(config.overviewgappi, 0, 1000);
overviewgappo = CLAMP_INT(config.overviewgappo, 0, 1000);
// 杂项设置
xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1);
axis_bind_apply_timeout =
CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000);
focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1);
inhibit_regardless_of_visibility =
CLAMP_INT(config.inhibit_regardless_of_visibility, 0, 1);
sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1);
warpcursor = CLAMP_INT(config.warpcursor, 0, 1);
focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1);
exchange_cross_monitor = CLAMP_INT(config.exchange_cross_monitor, 0, 1);
scratchpad_cross_monitor = CLAMP_INT(config.scratchpad_cross_monitor, 0, 1);
focus_cross_tag = CLAMP_INT(config.focus_cross_tag, 0, 1);
view_current_to_back = CLAMP_INT(config.view_current_to_back, 0, 1);
enable_floating_snap = CLAMP_INT(config.enable_floating_snap, 0, 1);
snap_distance = CLAMP_INT(config.snap_distance, 0, 99999);
cursor_size = CLAMP_INT(config.cursor_size, 4, 512);
no_border_when_single = CLAMP_INT(config.no_border_when_single, 0, 1);
no_radius_when_single = CLAMP_INT(config.no_radius_when_single, 0, 1);
cursor_hide_timeout =
CLAMP_INT(config.cursor_hide_timeout, 0, 36000); // 0-10小时
drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1);
single_scratchpad = CLAMP_INT(config.single_scratchpad, 0, 1);
// 键盘设置
repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
numlockon = CLAMP_INT(config.numlockon, 0, 1);
// 触控板设置
disable_trackpad = CLAMP_INT(config.disable_trackpad, 0, 1);
tap_to_click = CLAMP_INT(config.tap_to_click, 0, 1);
tap_and_drag = CLAMP_INT(config.tap_and_drag, 0, 1);
drag_lock = CLAMP_INT(config.drag_lock, 0, 1);
trackpad_natural_scrolling =
CLAMP_INT(config.trackpad_natural_scrolling, 0, 1);
disable_while_typing = CLAMP_INT(config.disable_while_typing, 0, 1);
left_handed = CLAMP_INT(config.left_handed, 0, 1);
middle_button_emulation = CLAMP_INT(config.middle_button_emulation, 0, 1);
swipe_min_threshold = CLAMP_INT(config.swipe_min_threshold, 1, 1000);
// 鼠标设置
mouse_natural_scrolling = CLAMP_INT(config.mouse_natural_scrolling, 0, 1);
accel_profile = CLAMP_INT(config.accel_profile, 0, 2);
accel_speed = CLAMP_FLOAT(config.accel_speed, -1.0f, 1.0f);
scroll_method = CLAMP_INT(config.scroll_method, 0, 4);
scroll_button = CLAMP_INT(config.scroll_button, 272, 276);
click_method = CLAMP_INT(config.click_method, 0, 2);
send_events_mode = CLAMP_INT(config.send_events_mode, 0, 2);
button_map = CLAMP_INT(config.button_map, 0, 1);
// 外观设置
gappih = CLAMP_INT(config.gappih, 0, 1000);
gappiv = CLAMP_INT(config.gappiv, 0, 1000);
gappoh = CLAMP_INT(config.gappoh, 0, 1000);
gappov = CLAMP_INT(config.gappov, 0, 1000);
scratchpad_width_ratio =
CLAMP_FLOAT(config.scratchpad_width_ratio, 0.1f, 1.0f);
scratchpad_height_ratio =
CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f);
borderpx = CLAMP_INT(config.borderpx, 0, 200);
smartgaps = CLAMP_INT(config.smartgaps, 0, 1);
blur = CLAMP_INT(config.blur, 0, 1);
blur_layer = CLAMP_INT(config.blur_layer, 0, 1);
blur_optimized = CLAMP_INT(config.blur_optimized, 0, 1);
border_radius = CLAMP_INT(config.border_radius, 0, 100);
blur_params.num_passes = CLAMP_INT(config.blur_params.num_passes, 0, 10);
blur_params.radius = CLAMP_INT(config.blur_params.radius, 0, 100);
blur_params.noise = CLAMP_FLOAT(config.blur_params.noise, 0, 1);
blur_params.brightness = CLAMP_FLOAT(config.blur_params.brightness, 0, 1);
blur_params.contrast = CLAMP_FLOAT(config.blur_params.contrast, 0, 1);
blur_params.saturation = CLAMP_FLOAT(config.blur_params.saturation, 0, 1);
shadows = CLAMP_INT(config.shadows, 0, 1);
shadow_only_floating = CLAMP_INT(config.shadow_only_floating, 0, 1);
layer_shadows = CLAMP_INT(config.layer_shadows, 0, 1);
shadows_size = CLAMP_INT(config.shadows_size, 0, 100);
shadows_blur = CLAMP_INT(config.shadows_blur, 0, 100);
shadows_position_x = CLAMP_INT(config.shadows_position_x, -1000, 1000);
shadows_position_y = CLAMP_INT(config.shadows_position_y, -1000, 1000);
focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
unfocused_opacity = CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
memcpy(shadowscolor, config.shadowscolor, sizeof(shadowscolor));
// 复制颜色数组
memcpy(rootcolor, config.rootcolor, sizeof(rootcolor));
memcpy(bordercolor, config.bordercolor, sizeof(bordercolor));
memcpy(focuscolor, config.focuscolor, sizeof(focuscolor));
memcpy(maxmizescreencolor, config.maxmizescreencolor,
sizeof(maxmizescreencolor));
memcpy(urgentcolor, config.urgentcolor, sizeof(urgentcolor));
memcpy(scratchpadcolor, config.scratchpadcolor, sizeof(scratchpadcolor));
memcpy(globalcolor, config.globalcolor, sizeof(globalcolor));
memcpy(overlaycolor, config.overlaycolor, sizeof(overlaycolor));
// 复制动画曲线
memcpy(animation_curve_move, config.animation_curve_move,
sizeof(animation_curve_move));
memcpy(animation_curve_open, config.animation_curve_open,
sizeof(animation_curve_open));
memcpy(animation_curve_tag, config.animation_curve_tag,
sizeof(animation_curve_tag));
memcpy(animation_curve_close, config.animation_curve_close,
sizeof(animation_curve_close));
}
void set_value_default() {
/* animaion */
config.animations = animations; // 是否启用动画
config.layer_animations = layer_animations; // 是否启用layer动画
config.animation_fade_in = animation_fade_in; // Enable animation fade in
config.animation_fade_out = animation_fade_out; // Enable animation fade out
config.tag_animation_direction = tag_animation_direction; // 标签动画方向
config.zoom_initial_ratio = zoom_initial_ratio; // 动画起始窗口比例
config.zoom_end_ratio = zoom_end_ratio; // 动画结束窗口比例
config.fadein_begin_opacity =
fadein_begin_opacity; // Begin opac window ratio for animations
config.fadeout_begin_opacity = fadeout_begin_opacity;
config.animation_duration_move =
animation_duration_move; // Animation move speed
config.animation_duration_open =
animation_duration_open; // Animation open speed
config.animation_duration_tag =
animation_duration_tag; // Animation tag speed
config.animation_duration_close =
animation_duration_close; // Animation tag speed
/* appearance */
config.axis_bind_apply_timeout =
axis_bind_apply_timeout; // 滚轮绑定动作的触发的时间间隔
config.focus_on_activate =
focus_on_activate; // 收到窗口激活请求是否自动跳转聚焦
config.new_is_master = new_is_master; // 新窗口是否插在头部
config.default_mfact = default_mfact; // master 窗口比例
config.default_smfact = default_smfact; // 第一个stack比例
config.default_nmaster = default_nmaster; // 默认master数量
config.center_master_overspread =
center_master_overspread; // 中心master时是否铺满
config.center_when_single_slave =
center_when_single_slave; // 单个slave时是否居中
config.numlockon = numlockon; // 是否打开右边小键盘
config.ov_tab_mode = ov_tab_mode; // alt tab切换模式
config.hotarea_size = hotarea_size; // 热区大小,10x10
config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区
config.smartgaps =
smartgaps; /* 1 means no outer gap when there is only one window */
config.sloppyfocus = sloppyfocus; /* focus follows mouse */
config.gappih = gappih; /* horiz inner gap between windows */
config.gappiv = gappiv; /* vert inner gap between windows */
config.gappoh =
gappoh; /* horiz outer gap between windows and screen edge */
config.gappov = gappov; /* vert outer gap between windows and screen edge */
config.scratchpad_width_ratio = scratchpad_width_ratio;
config.scratchpad_height_ratio = scratchpad_height_ratio;
config.scroller_structs = scroller_structs;
config.scroller_default_proportion = scroller_default_proportion;
config.scroller_default_proportion_single =
scroller_default_proportion_single;
config.scroller_focus_center = scroller_focus_center;
config.scroller_prefer_center = scroller_prefer_center;
config.edge_scroller_pointer_focus = edge_scroller_pointer_focus;
config.focus_cross_monitor = focus_cross_monitor;
config.exchange_cross_monitor = exchange_cross_monitor;
config.scratchpad_cross_monitor = scratchpad_cross_monitor;
config.focus_cross_tag = focus_cross_tag;
config.view_current_to_back = view_current_to_back;
config.single_scratchpad = single_scratchpad;
config.xwayland_persistence = xwayland_persistence;
config.syncobj_enable = syncobj_enable;
config.adaptive_sync = adaptive_sync;
config.no_border_when_single = no_border_when_single;
config.no_radius_when_single = no_radius_when_single;
config.snap_distance = snap_distance;
config.drag_tile_to_tile = drag_tile_to_tile;
config.enable_floating_snap = enable_floating_snap;
config.swipe_min_threshold = swipe_min_threshold;
config.inhibit_regardless_of_visibility =
inhibit_regardless_of_visibility; /* 1 means idle inhibitors will
disable idle tracking even if it's
surface isn't visible
*/
config.borderpx = borderpx;
config.overviewgappi = overviewgappi; /* overview时 窗口与边缘 缝隙大小 */
config.overviewgappo = overviewgappo; /* overview时 窗口与窗口 缝隙大小 */
config.cursor_hide_timeout = cursor_hide_timeout;
config.warpcursor = warpcursor; /* Warp cursor to focused client */
config.repeat_rate = repeat_rate;
config.repeat_delay = repeat_delay;
/* Trackpad */
config.disable_trackpad = disable_trackpad;
config.tap_to_click = tap_to_click;
config.tap_and_drag = tap_and_drag;
config.drag_lock = drag_lock;
config.mouse_natural_scrolling = mouse_natural_scrolling;
config.cursor_size = cursor_size;
config.trackpad_natural_scrolling = trackpad_natural_scrolling;
config.disable_while_typing = disable_while_typing;
config.left_handed = left_handed;
config.middle_button_emulation = middle_button_emulation;
config.accel_profile = accel_profile;
config.accel_speed = accel_speed;
config.scroll_method = scroll_method;
config.scroll_button = scroll_button;
config.click_method = click_method;
config.send_events_mode = send_events_mode;
config.button_map = button_map;
config.blur = blur;
config.blur_layer = blur_layer;
config.blur_optimized = blur_optimized;
config.border_radius = border_radius;
config.blur_params.num_passes = blur_params_num_passes;
config.blur_params.radius = blur_params_radius;
config.blur_params.noise = blur_params_noise;
config.blur_params.brightness = blur_params_brightness;
config.blur_params.contrast = blur_params_contrast;
config.blur_params.saturation = blur_params_saturation;
config.shadows = shadows;
config.shadow_only_floating = shadow_only_floating;
config.layer_shadows = layer_shadows;
config.shadows_size = shadows_size;
config.shadows_blur = shadows_blur;
config.shadows_position_x = shadows_position_x;
config.shadows_position_y = shadows_position_y;
config.focused_opacity = focused_opacity;
config.unfocused_opacity = unfocused_opacity;
memcpy(config.shadowscolor, shadowscolor, sizeof(shadowscolor));
memcpy(config.animation_curve_move, animation_curve_move,
sizeof(animation_curve_move));
memcpy(config.animation_curve_open, animation_curve_open,
sizeof(animation_curve_open));
memcpy(config.animation_curve_tag, animation_curve_tag,
sizeof(animation_curve_tag));
memcpy(config.animation_curve_close, animation_curve_close,
sizeof(animation_curve_close));
memcpy(config.rootcolor, rootcolor, sizeof(rootcolor));
memcpy(config.bordercolor, bordercolor, sizeof(bordercolor));
memcpy(config.focuscolor, focuscolor, sizeof(focuscolor));
memcpy(config.maxmizescreencolor, maxmizescreencolor,
sizeof(maxmizescreencolor));
memcpy(config.urgentcolor, urgentcolor, sizeof(urgentcolor));
memcpy(config.scratchpadcolor, scratchpadcolor, sizeof(scratchpadcolor));
memcpy(config.globalcolor, globalcolor, sizeof(globalcolor));
memcpy(config.overlaycolor, overlaycolor, sizeof(overlaycolor));
}
void set_default_key_bindings(Config *config) {
// 计算默认按键绑定的数量
size_t default_key_bindings_count =
sizeof(default_key_bindings) / sizeof(KeyBinding);
// 重新分配内存以容纳新的默认按键绑定
config->key_bindings =
realloc(config->key_bindings,
(config->key_bindings_count + default_key_bindings_count) *
sizeof(KeyBinding));
if (!config->key_bindings) {
return;
}
// 将默认按键绑定复制到配置的按键绑定数组中
for (size_t i = 0; i < default_key_bindings_count; i++) {
config->key_bindings[config->key_bindings_count + i] =
default_key_bindings[i];
}
// 更新按键绑定的总数
config->key_bindings_count += default_key_bindings_count;
}
void parse_config(void) {
char filename[1024];
free_config();
// 重置config结构体确保所有指针初始化为NULL
memset(&config, 0, sizeof(config));
// 初始化动态数组的指针为NULL避免野指针
config.window_rules = NULL;
config.window_rules_count = 0;
config.monitor_rules = NULL;
config.monitor_rules_count = 0;
config.key_bindings = NULL;
config.key_bindings_count = 0;
config.mouse_bindings = NULL;
config.mouse_bindings_count = 0;
config.axis_bindings = NULL;
config.axis_bindings_count = 0;
config.switch_bindings = NULL;
config.switch_bindings_count = 0;
config.gesture_bindings = NULL;
config.gesture_bindings_count = 0;
config.exec = NULL;
config.exec_count = 0;
config.exec_once = NULL;
config.exec_once_count = 0;
config.scroller_proportion_preset = NULL;
config.scroller_proportion_preset_count = 0;
config.circle_layout = NULL;
config.circle_layout_count = 0;
config.tag_rules = NULL;
config.tag_rules_count = 0;
config.cursor_theme = NULL;
// 获取 MANGOCONFIG 环境变量
const char *mangoconfig = getenv("MANGOCONFIG");
// 如果 MANGOCONFIG 环境变量不存在或为空,则使用 HOME 环境变量
if (!mangoconfig || mangoconfig[0] == '\0') {
// 获取当前用户家目录
const char *homedir = getenv("HOME");
if (!homedir) {
// 如果获取失败,则无法继续
return;
}
// 构建日志文件路径
snprintf(filename, sizeof(filename), "%s/.config/mango/config.conf",
homedir);
// 检查文件是否存在
if (access(filename, F_OK) != 0) {
// 如果文件不存在,则使用 /etc/mango/config.conf
snprintf(filename, sizeof(filename), "%s/mango/config.conf",
SYSCONFDIR);
}
} else {
// 使用 MANGOCONFIG 环境变量作为配置文件夹路径
snprintf(filename, sizeof(filename), "%s/config.conf", mangoconfig);
}
set_value_default();
parse_config_file(&config, filename);
set_default_key_bindings(&config);
override_config();
}
void reset_blur_params(void) {
if (blur) {
Monitor *m;
wl_list_for_each(m, &mons, link) {
if (m->blur != NULL) {
wlr_scene_node_destroy(&m->blur->node);
}
m->blur = wlr_scene_optimized_blur_create(&scene->tree, 0, 0);
wlr_scene_node_reparent(&m->blur->node, layers[LyrBlur]);
wlr_scene_optimized_blur_set_size(m->blur, m->m.width, m->m.height);
wlr_scene_set_blur_data(
scene, blur_params.num_passes, blur_params.radius,
blur_params.noise, blur_params.brightness, blur_params.contrast,
blur_params.saturation);
}
} else {
Monitor *m;
wl_list_for_each(m, &mons, link) {
if (m->blur) {
wlr_scene_node_destroy(&m->blur->node);
m->blur = NULL;
}
}
}
}
void reapply_monitor_rules(void) {
ConfigMonitorRule *mr;
Monitor *m;
int ji, jk;
struct wlr_output_state state;
struct wlr_output_mode *internal_mode = NULL;
wlr_output_state_init(&state);
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled) {
continue;
}
for (ji = 0; ji < config.monitor_rules_count; ji++) {
if (config.monitor_rules_count < 1)
break;
mr = &config.monitor_rules[ji];
if (!mr->name || regex_match(mr->name, m->wlr_output->name)) {
m->mfact = mr->mfact;
m->nmaster = mr->nmaster;
m->m.x = mr->x;
m->m.y = mr->y;
if (mr->layout) {
for (jk = 0; jk < LENGTH(layouts); jk++) {
if (strcmp(layouts[jk].name, mr->layout) == 0) {
m->lt = &layouts[jk];
}
}
}
if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) {
internal_mode = get_nearest_output_mode(
m->wlr_output, mr->width, mr->height, mr->refresh);
if (internal_mode) {
wlr_output_state_set_mode(&state, internal_mode);
} else if (wlr_output_is_headless(m->wlr_output)) {
wlr_output_state_set_custom_mode(
&state, mr->width, mr->height,
(int)roundf(mr->refresh * 1000));
}
}
wlr_output_state_set_scale(&state, mr->scale);
wlr_output_state_set_transform(&state, mr->rr);
wlr_output_layout_add(output_layout, m->wlr_output, mr->x,
mr->y);
}
}
if (adaptive_sync) {
enable_adaptive_sync(m, &state);
}
wlr_output_commit_state(m->wlr_output, &state);
wlr_output_state_finish(&state);
updatemons(NULL, NULL);
}
}
void reapply_border(void) {
Client *c;
// reset border width when config change
wl_list_for_each(c, &clients, link) {
if (c && !c->iskilling) {
if (c->bw && !c->isnoborder) {
c->bw = borderpx;
}
}
}
}
void reapply_keyboard(void) {
Keyboard *kb;
wl_list_for_each(kb, &keyboards, link) {
wlr_keyboard_set_repeat_info(kb->wlr_keyboard, repeat_rate,
repeat_delay);
}
}
void reapply_pointer(void) {
InputDevice *id;
struct libinput_device *device;
wl_list_for_each(id, &inputdevices, link) {
if (id->wlr_device->type != WLR_INPUT_DEVICE_POINTER) {
continue;
}
device = id->libinput_device;
if (wlr_input_device_is_libinput(id->wlr_device) && device) {
configure_pointer(device);
}
}
}
void reapply_master(void) {
int i;
Monitor *m;
for (i = 0; i <= LENGTH(tags); i++) {
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled) {
continue;
}
m->pertag->nmasters[i] = default_nmaster;
m->pertag->mfacts[i] = default_mfact;
m->pertag->smfacts[i] = default_smfact;
m->gappih = gappih;
m->gappiv = gappiv;
m->gappoh = gappoh;
m->gappov = gappov;
}
}
}
void reapply_tagrule(void) {
Monitor *m;
int i, jk;
char *rule_monitor_name = NULL;
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled) {
continue;
}
// apply tag rule
for (i = 1; i <= config.tag_rules_count; i++) {
rule_monitor_name = config.tag_rules[i - 1].monitor_name;
if (regex_match(rule_monitor_name, m->wlr_output->name) ||
!rule_monitor_name) {
for (jk = 0; jk < LENGTH(layouts); jk++) {
if (config.tag_rules_count > 0 &&
config.tag_rules[i - 1].layout_name &&
strcmp(layouts[jk].name,
config.tag_rules[i - 1].layout_name) == 0) {
m->pertag->ltidxs[config.tag_rules[i - 1].id] =
&layouts[jk];
m->pertag->no_hide[config.tag_rules[i - 1].id] =
config.tag_rules[i - 1].no_hide;
}
}
}
}
}
}
void reload_config(const Arg *arg) {
parse_config();
init_baked_points();
handlecursoractivity();
reset_keyboard_layout();
reset_blur_params();
run_exec();
reapply_border();
reapply_keyboard();
reapply_pointer();
reapply_master();
reapply_tagrule();
reapply_monitor_rules();
arrange(selmon, false);
}