diff --git a/src/config.c b/src/config.c index 2e27904..05a8992 100644 --- a/src/config.c +++ b/src/config.c @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include #include @@ -17,11 +15,50 @@ #include "config.h" #include "wm.h" +static const KeybindFunctionCommand __wm_keybind_commands[] = { + (KeybindFunctionCommand) { + .command = "spawn", + .function = &wm_kb_spawn + }, + (KeybindFunctionCommand) { + .command = "focus", + .function = &wm_kb_focus_dir + }, + (KeybindFunctionCommand) { + .command = "move", + .function = &wm_kb_move_dir + }, + (KeybindFunctionCommand) { + .command = "switch_ws", + .function = &wm_kb_switch_ws + }, + (KeybindFunctionCommand) { + .command = "move_to_ws", + .function = &wm_kb_move_client_ws + }, + (KeybindFunctionCommand) { + .command = "quit", + .function = &wm_kb_exit + }, + (KeybindFunctionCommand) { + .command = "quit_client", + .function = &wm_kb_kill + }, + (KeybindFunctionCommand) { + .command = "split_vertical", + .function = &wm_kb_switch_split_mode + }, + (KeybindFunctionCommand) { + .command = "split_horizontal", + .function = &wm_kb_switch_split_mode + }, +}; + void wm_cfg_init_def(Config *config) { config->ms_p = 0.5; - config->border_col = "#222222"; - config->focused_border_col = "#444444"; + strncpy(config->border_col, "#222222", CONFIG_COLOR_MAX); + strncpy(config->focused_border_col, "#444444", CONFIG_COLOR_MAX); config->border_width = 2; config->focus_on_motion = true; @@ -165,6 +202,14 @@ void wm_keybinds_init_def(Config *config) memcpy(config->keybinds, k, size); } +void wm_keybinds_free(Config *config) +{ + for (size_t i = 0; i < config->kb_count; i++) { + if (config->keybinds[i].function == &wm_kb_spawn) + free(config->keybinds[i].args.sl); + } +} + void wm_configfile_init(ConfigFile *config, const char *filename) { assert(config); @@ -175,23 +220,23 @@ void wm_configfile_init(ConfigFile *config, const char *filename) ConfigCommand commands[] = { (ConfigCommand) {.string = "border_color", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, border_col), - .argc = 0}, + .argc = 0, .arg_type = TYPE_STRING}, (ConfigCommand) {.string = "focused_border_color", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, focused_border_col), - .argc = 0}, + .argc = 0, .arg_type = TYPE_STRING}, (ConfigCommand) {.string = "border_width", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, border_width), - .argc = 0}, + .argc = 0, .arg_type = TYPE_UNSIGNED_INTEGER}, (ConfigCommand) {.string = "keybind", .arg_count = 0, .cfg_var_offset[0] = -1, - .argc = 0}, + .argc = 0, .arg_type = TYPE_KEYBIND}, (ConfigCommand) {.string = "focus_on_motion", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, focus_on_motion), - .argc = 0}, + .argc = 0, .arg_type = TYPE_BOOL}, }; config->command_count = sizeof(commands) / sizeof (commands[0]); @@ -210,6 +255,8 @@ void wm_configfile_free(ConfigFile *config) for (size_t i = 0; i < config->command_count; i++) { wm_configcommand_free(&config->available_commands[i]); } + + free(config->available_commands); } void wm_configfile_read(ConfigFile *cfile, Config *config) @@ -253,31 +300,31 @@ void wm_config_apply_command(Config *config, ConfigCommand *command) switch (command->arg_type) { case TYPE_INTEGER: for (size_t i = 0; i < command->argc; i++) { - *(int*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].i; + *(int*)(((char*)config) + (command->cfg_var_offset[i])) = command->args[i].i; } return; case TYPE_UNSIGNED_INTEGER: for (size_t i = 0; i < command->argc; i++) { - *(unsigned int*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].ui; + *(unsigned int*)(((char*)config) + (command->cfg_var_offset[i])) = command->args[i].ui; } return; case TYPE_BOOL: for (size_t i = 0; i < command->argc; i++) { - *(bool*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].i; + *(bool*)(((char*)config) + (command->cfg_var_offset[i])) = command->args[i].i; } return; case TYPE_KEYBIND: - // TODO - wm_config_parse_bind_command(command); + wm_config_replace_keybind(config, &command->keybind); + return; case TYPE_STRING: for (size_t i = 0; i < command->argc; i++) { size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX); - memcpy((char*)(config + (command->cfg_var_offset)[i]), command->argv[i], len); + memcpy(((char*)(config) + (command->cfg_var_offset)[i]), command->argv[i], len); } return; case TYPE_FLOAT: for (size_t i = 0; i < command->argc; i++) { - *(float*)((char*)config + (command->cfg_var_offset[i])) = atof(command->argv[i]); + *(float*)(((char*)config) + (command->cfg_var_offset[i])) = atof(command->argv[i]); } return; } @@ -298,6 +345,9 @@ ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config, if (line[0] == '\n') return (ParserResult) {.success = true, .message = ""}; + if (!token) + return (ParserResult) {.success = true, .message = ""}; + // try to match command for (size_t i = 0; i < cfile->command_count; i++) { if (strncmp(cfile->available_commands[i].string, token, @@ -333,12 +383,15 @@ ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config, CONFIG_ARGC_MAX); } - if (command->argc > command->arg_count) { + if (command->argc > command->arg_count && command->arg_type != TYPE_KEYBIND) { PARSER_RETURN(result, false, "Too many arguments to command %s\n", command->string); } strncpy(command->argv[command->argc-1], token, CONFIG_ARGLEN_MAX); + char *arg = command->argv[command->argc-1]; + for (size_t i = 0; i < strnlen(arg, CONFIG_ARGLEN_MAX); i++) + if (arg[i] == '\n') arg[i] = '\0'; } // end of args @@ -419,8 +472,8 @@ void wm_configcommand_argv_parse(ConfigCommand *command) } return; case TYPE_KEYBIND: - // todo - wm_config_parse_bind_command(command); + command->keybind = wm_config_parse_bind_command(command); + return; case TYPE_STRING: for (size_t i = 0; i < command->argc; i++) { size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX); @@ -474,6 +527,99 @@ bool atobool(char *arr) return false; } +Arg wm_keybind_argv_to_args(Keybind kb, ConfigCommand command) +{ + DEBUG_PRINT("%s\n", __func__); + Arg ret; + + if (kb.function == &wm_kb_spawn) { + ret.sl = calloc(command.argc - 2, sizeof(char*)); + for (size_t i = 2; i < command.argc; i++) { + ret.sl[i] = calloc(CONFIG_ARGLEN_MAX, 1); + strncpy(ret.sl[i], command.argv[i], CONFIG_ARGLEN_MAX); + } + + return ret; + } + + if (kb.function == &wm_kb_focus_dir) { + assert(command.argc == 3); + ret.i = wm_string_to_direction(command.argv[command.argc - 1]); + + return ret; + } + + if (kb.function == &wm_kb_move_dir) { + assert(command.argc == 3); + ret.i = wm_string_to_direction(command.argv[command.argc - 1]); + + return ret; + } + + if (kb.function == &wm_kb_switch_ws) { + assert(command.argc == 3); + ret.i = atoi(command.argv[command.argc - 1]); + + return ret; + } + + if (kb.function == &wm_kb_move_client_ws) { + assert(command.argc == 3); + ret.i = atoi(command.argv[command.argc - 1]); + + return ret; + } + + if (kb.function == &wm_kb_switch_split_mode) { + // TODO + } + + assert(false); +} + +int wm_string_to_direction(const char *str) +{ + int ret; + char lower[CONFIG_ARGLEN_MAX]; + strncpy(lower, str, CONFIG_ARGLEN_MAX); + + for (char *c = lower; *c; c++) *c = tolower(*c); + + ret = strncmp(lower, "right", CONFIG_ARGLEN_MAX); + if (ret == 0) return RIGHT; + + ret = strncmp(lower, "left", CONFIG_ARGLEN_MAX); + if (ret == 0) return LEFT; + + ret = strncmp(lower, "up", CONFIG_ARGLEN_MAX); + if (ret == 0) return UP; + + ret = strncmp(lower, "down", CONFIG_ARGLEN_MAX); + if (ret == 0) return DOWN; + + fprintf(stderr, "wm: encountered invalid direction \"%s\"\n. exiting.", + str); + abort(); +} + +KeybindFunction wm_str_to_keybindfunction(const char* str) +{ + DEBUG_PRINT("%s %s\n", __func__, str); + char lower[CONFIG_ARGLEN_MAX]; + strncpy(lower, str, CONFIG_ARGLEN_MAX); + + for (char *c = lower; *c; c++) *c = tolower(*c); + + for (size_t i = 0; i < sizeof(__wm_keybind_commands) / sizeof(__wm_keybind_commands[0]); i++) { + if (strncmp(lower, __wm_keybind_commands[i].command, CONFIG_ARGLEN_MAX) == 0) + return __wm_keybind_commands[i].function; + } + + fprintf(stderr, "wm: encountered invalid keybind command \"%s\"\n. exiting.", + str); + abort(); +} + unsigned int wm_string_to_mask(const char* str) { int ret; @@ -504,12 +650,12 @@ unsigned int wm_string_to_mask(const char* str) ret = strncmp(str, "Super", CONFIG_ARGLEN_MAX); if (ret == 0) return Mod4Mask; - fprintf(stderr, "wm: encountered invalid modifier token %s\n. exiting.", + fprintf(stderr, "wm: encountered invalid modifier token \"%s\"\n. exiting.", str); abort(); } -KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv) +KeySym* wm_keybind_string_to_mask_keysym(const char* kb_argv) { KeySym *ret = calloc(2, sizeof(KeySym)); char* str = strdup(kb_argv); @@ -531,7 +677,7 @@ KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv) token = strtok(NULL, "+"); } - DEBUG_PRINT("str: %s token count: %d\n", kb_argv, token_count); + DEBUG_PRINT("str: %s, str[0]: %d, token count: %d\n", kb_argv, kb_argv[0], token_count); ret[0] = wm_string_to_mask(tokens[0]); @@ -541,7 +687,7 @@ KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv) KeySym keysym = XStringToKeysym(tokens[token_count - 1]); if (keysym == NoSymbol) { - fprintf(stderr, "wm: encountered invalid keybind token %s\n. exiting.", + fprintf(stderr, "wm: encountered invalid keybind token \"%s\"\n. exiting.", tokens[token_count-1]); abort(); } @@ -553,8 +699,27 @@ KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv) return ret; } -// TODO Keybind wm_config_parse_bind_command(ConfigCommand *command) { + DEBUG_PRINT("%s\n", __func__); + Keybind ret; + KeySym *keysyms = wm_keybind_string_to_mask_keysym(command->argv[0]); + ret.mask = keysyms[0]; + ret.keysym = keysyms[1]; + free(keysyms); + + ret.function = wm_str_to_keybindfunction(command->argv[1]); + ret.args = wm_keybind_argv_to_args(ret, *command); + + return ret; +} + +void wm_config_replace_keybind(Config *config, const Keybind *keybind) +{ + for (size_t i = 0; i < config->kb_count; i++) + if (config->keybinds[i].function == keybind->function) { + config->keybinds[i] = *keybind; + return; + } } diff --git a/src/config.h b/src/config.h index 4f1f3f7..f568587 100644 --- a/src/config.h +++ b/src/config.h @@ -11,6 +11,7 @@ #define CONFIG_PARSERRESULT_MAX 1024 #define CONFIG_ARGC_MAX 16 #define CONFIG_ARGLEN_MAX 256 +#define CONFIG_COLOR_MAX 16 #define PARSER_RETURN(result, _success, fmt, ...) \ do { (result).success = (_success); \ @@ -42,6 +43,11 @@ struct Keybind { Arg args; }; +typedef struct { + const char command[CONFIG_ARGLEN_MAX]; + const KeybindFunction function; +} KeybindFunctionCommand; + typedef enum { TYPE_INTEGER, TYPE_UNSIGNED_INTEGER, @@ -64,6 +70,7 @@ typedef struct { size_t argc; char **argv; Arg *args; + Keybind keybind; } ConfigCommand; typedef struct { @@ -74,8 +81,8 @@ typedef struct { typedef struct { float ms_p; - char *border_col; - char *focused_border_col; + char border_col[CONFIG_COLOR_MAX]; + char focused_border_col[CONFIG_COLOR_MAX]; unsigned int border_width; Keybind *keybinds; int kb_count; @@ -85,6 +92,7 @@ typedef struct { void wm_cfg_init_def(Config *config); void wm_keybinds_init_def(Config *config); +void wm_keybinds_free(Config *config); void wm_configfile_init(ConfigFile *config, const char *path); void wm_configfile_free(ConfigFile *config); void wm_configfile_read(ConfigFile *cfile, Config *config); @@ -97,13 +105,23 @@ void wm_configcommand_argv_parse(ConfigCommand *command); void wm_configcommand_free(ConfigCommand *command); bool atobool(char *arr); +Arg wm_keybind_argv_to_args(Keybind kb, ConfigCommand command); + +int wm_string_to_direction(const char *str); + +KeybindFunction wm_string_to_keybindfunction(const char* str); + /* Converts string to Key mask (see X.h:218-228). */ unsigned int wm_string_to_mask(const char* str); /* The first element is the mask, the second element is the * key. The returned array needs to be freed. */ -KeySym* wm_keybind_str_to_mask_keysym(const char* kb_argv); +KeySym* wm_keybind_string_to_mask_keysym(const char* kb_argv); Keybind wm_config_parse_bind_command(ConfigCommand *command); +/* Finds a keybind matching the function of the keybind parameter, and + * replaces it. */ +void wm_config_replace_keybind(Config *config, const Keybind *keybind); + #endif // CONFIG_H