#include "config.h" #include "wm.h" #include #include #include #include #include #include #include #include #include #include void wm_cfg_init_def(Config *config) { config->ms_p = 0.5; config->border_col = "#222222"; config->focused_border_col = "#444444"; config->border_width = 2; config->focus_on_motion = true; wm_keybinds_init_def(config); } void wm_keybinds_init_def(Config *config) { char *st[] = {"st", NULL}; char **sth = malloc(sizeof(st)); memcpy(sth, st, sizeof(st)); char *dmenu[] = {"i3-dmenu-desktop", NULL}; char **dmenuh = malloc(sizeof(dmenu)); memcpy(dmenuh, dmenu, sizeof(dmenu)); int size; Keybind k[] = { (Keybind) {Mod4Mask, XK_Return, *wm_kb_spawn, (Arg) {.sl = sth, .count = 2}}, (Keybind) {Mod4Mask | ShiftMask, XK_q, *wm_kb_exit, (Arg) {0}}, (Keybind) {Mod4Mask, XK_d, *wm_kb_spawn, (Arg) {.sl = dmenuh, .count = 2}}, (Keybind) {Mod4Mask, XK_c, *wm_kb_kill, (Arg) {.c = NULL}}, (Keybind) {Mod4Mask, XK_1, *wm_kb_switch_ws, (Arg) {.i = 0}}, (Keybind) {Mod4Mask, XK_2, *wm_kb_switch_ws, (Arg) {.i = 1}}, (Keybind) {Mod4Mask, XK_3, *wm_kb_switch_ws, (Arg) {.i = 2}}, (Keybind) {Mod4Mask, XK_4, *wm_kb_switch_ws, (Arg) {.i = 3}}, (Keybind) {Mod4Mask, XK_5, *wm_kb_switch_ws, (Arg) {.i = 4}}, (Keybind) {Mod4Mask, XK_6, *wm_kb_switch_ws, (Arg) {.i = 5}}, (Keybind) {Mod4Mask, XK_7, *wm_kb_switch_ws, (Arg) {.i = 6}}, (Keybind) {Mod4Mask, XK_8, *wm_kb_switch_ws, (Arg) {.i = 7}}, (Keybind) {Mod4Mask, XK_9, *wm_kb_switch_ws, (Arg) {.i = 8}}, (Keybind) {Mod4Mask | ShiftMask, XK_1, *wm_kb_move_client_ws, (Arg) {.i = 0}}, (Keybind) {Mod4Mask | ShiftMask, XK_2, *wm_kb_move_client_ws, (Arg) {.i = 1}}, (Keybind) {Mod4Mask | ShiftMask, XK_3, *wm_kb_move_client_ws, (Arg) {.i = 2}}, (Keybind) {Mod4Mask | ShiftMask, XK_4, *wm_kb_move_client_ws, (Arg) {.i = 3}}, (Keybind) {Mod4Mask | ShiftMask, XK_5, *wm_kb_move_client_ws, (Arg) {.i = 4}}, (Keybind) {Mod4Mask | ShiftMask, XK_6, *wm_kb_move_client_ws, (Arg) {.i = 5}}, (Keybind) {Mod4Mask | ShiftMask, XK_7, *wm_kb_move_client_ws, (Arg) {.i = 6}}, (Keybind) {Mod4Mask | ShiftMask, XK_8, *wm_kb_move_client_ws, (Arg) {.i = 7}}, (Keybind) {Mod4Mask | ShiftMask, XK_9, *wm_kb_move_client_ws, (Arg) {.i = 8}}, (Keybind) {Mod4Mask, XK_h, *wm_kb_focus_dir, (Arg) {.i = LEFT}}, (Keybind) {Mod4Mask, XK_j, *wm_kb_focus_dir, (Arg) {.i = DOWN}}, (Keybind) {Mod4Mask, XK_k, *wm_kb_focus_dir, (Arg) {.i = UP}}, (Keybind) {Mod4Mask, XK_l, *wm_kb_focus_dir, (Arg) {.i = RIGHT}}, (Keybind) {Mod4Mask | ShiftMask, XK_h, *wm_kb_move_dir, (Arg) {.i = LEFT}}, (Keybind) {Mod4Mask | ShiftMask, XK_j, *wm_kb_move_dir, (Arg) {.i = DOWN}}, (Keybind) {Mod4Mask | ShiftMask, XK_k, *wm_kb_move_dir, (Arg) {.i = UP}}, (Keybind) {Mod4Mask | ShiftMask, XK_l, *wm_kb_move_dir, (Arg) {.i = RIGHT}}, (Keybind) {Mod4Mask, XK_b, *wm_kb_switch_split_mode, (Arg) {.i = SPLIT_VERTICAL}}, (Keybind) {Mod4Mask, XK_v, *wm_kb_switch_split_mode, (Arg) {.i = SPLIT_HORIZ}}, (Keybind) {Mod4Mask, XK_t, *wm_kb_switch_split_mode, (Arg) {.i = SPLIT_TAB}}, }; size = sizeof(k); config->kb_count = size / sizeof(Keybind); DEBUG_PRINT("sizeof k: %d\n", size); config->keybinds = malloc(size); memcpy(config->keybinds, k, size); } void wm_configfile_init(ConfigFile *config, const char *filename) { assert(config); assert(filename); strncpy(config->file_path, filename, PATH_MAX); ConfigCommand commands[] = { (ConfigCommand) {.string = "border_color", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, border_col), .argc = 0}, (ConfigCommand) {.string = "focused_border_color", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, focused_border_col), .argc = 0}, (ConfigCommand) {.string = "border_width", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, border_width), .argc = 0}, (ConfigCommand) {.string = "keybind", .arg_count = 0, .cfg_var_offset[0] = -1, .argc = 0}, (ConfigCommand) {.string = "focus_on_motion", .arg_count = 1, .cfg_var_offset[0] = offsetof(Config, focus_on_motion), .argc = 0}, }; config->command_count = sizeof(commands) / sizeof (commands[0]); DEBUG_PRINT("command_count: %ld\n", config->command_count); for (size_t i = 0; i < config->command_count; i++) { wm_configcommand_init(&commands[i]); } config->available_commands = calloc(config->command_count, sizeof(ConfigCommand)); memcpy(config->available_commands, commands, sizeof(commands)); } void wm_configfile_free(ConfigFile *config) { for (size_t i = 0; i < config->command_count; i++) { wm_configcommand_free(&config->available_commands[i]); } } void wm_configfile_read(ConfigFile *cfile, Config *config) { assert(config); assert(cfile); FILE *fp = fopen(cfile->file_path, "r"); if (!fp) { fprintf(stderr, "wm: could not open config file: %s\n", strerror(errno)); return; } const int max_line_len = 8192; char line[max_line_len]; size_t line_index = 0; ConfigCommand command = {0}; wm_configcommand_init(&command); while(fgets(line, max_line_len, fp) != NULL) { line_index++; ParserResult result = wm_configfile_parse_line(cfile, config, line, &command); if (!result.success) { fprintf(stderr, "wm: could not parse line %ld of config file %s: %s\n", line_index, cfile->file_path, result.message); continue; } wm_configcommand_argv_parse(&command); wm_config_apply_command(config, &command); } fclose(fp); wm_configcommand_free(&command); } 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; } 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; } 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; } return; case TYPE_KEYBIND: // TODO wm_config_parse_bind_command(command); 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); } 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]); } return; } } ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config, char* line, ConfigCommand *command) { char *token = strtok(line, " "); bool matched_command = false; ParserResult result; // comment if (line[0] == '#') return (ParserResult) {.success = true, .message = ""}; // empty line if (line[0] == '\n') 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, CONFIG_COMMAND_MAX_LEN) == 0) { wm_configcommand_copy(command, &cfile->available_commands[i]); matched_command = true; } } if (!matched_command) { PARSER_RETURN(result, false, "Unknown config command: %s\n", token); } DEBUG_PRINT("matched command: %s\n", command->string); // read arguments while (true) { token = strtok(NULL, " "); DEBUG_PRINT("token: %s\n", token); if (token != NULL) { command->argc++; if (strnlen(token, CONFIG_ARGLEN_MAX) == CONFIG_ARGLEN_MAX) { PARSER_RETURN(result, false, "Argument length exceeded maximum of %d characters\n", CONFIG_ARGLEN_MAX); } if (command->argc >= CONFIG_ARGC_MAX) { PARSER_RETURN(result, false, "Maximum number of arguments (%d) exceeded\n", CONFIG_ARGC_MAX); } if (command->argc > command->arg_count) { PARSER_RETURN(result, false, "Too many arguments to command %s\n", command->string); } strncpy(command->argv[command->argc-1], token, CONFIG_ARGLEN_MAX); } // end of args if (token == NULL) { if (command->argc < command->arg_count) { PARSER_RETURN(result, false, "Missing arguments from command %s\n", command->string); } break; } }; return (ParserResult) {.success = true, .message = ""}; } void wm_configcommand_init(ConfigCommand *command) { assert(command); command->argv = calloc(CONFIG_ARGC_MAX, sizeof(void*)); command->args = calloc(CONFIG_ARGC_MAX, sizeof(Arg)); for (size_t i = 0; i < CONFIG_ARGC_MAX; i++) { command->argv[i] = calloc(CONFIG_ARGLEN_MAX, 1); command->args[i].s = calloc(CONFIG_ARGLEN_MAX, 1); command->args[i].sl = calloc(CONFIG_ARGC_MAX, sizeof(char*)); for (size_t j = 0; j < CONFIG_ARGC_MAX; j++) { command->args[i].sl[j] = calloc(CONFIG_ARGLEN_MAX, 1); } } } void wm_configcommand_copy(ConfigCommand *dest, const ConfigCommand *src) { assert(dest); assert(src); memcpy(dest->string, src->string, CONFIG_COMMAND_MAX_LEN); dest->arg_count = src->arg_count; memcpy(dest->cfg_var_offset, src->cfg_var_offset, CONFIG_ARGC_MAX*sizeof(off_t)); dest->arg_type = src->arg_type; dest->argc = src->argc; for (size_t i = 0; i < CONFIG_ARGC_MAX; i++) { memcpy(dest->argv[i], src->argv[i], CONFIG_ARGLEN_MAX); memcpy(dest->args[i].s, src->args[i].s, CONFIG_ARGLEN_MAX); for (size_t j = 0; j < CONFIG_ARGC_MAX; j++) { memcpy(dest->args[i].sl[j], src->args[i].sl[j], CONFIG_ARGLEN_MAX); } } } void wm_configcommand_argv_parse(ConfigCommand *command) { switch (command->arg_type) { case TYPE_INTEGER: for (size_t i = 0; i < command->argc; i++) { command->args[i].i = atoi(command->argv[i]); } return; case TYPE_UNSIGNED_INTEGER: for (size_t i = 0; i < command->argc; i++) { command->args[i].ui = atoi(command->argv[i]); } return; case TYPE_BOOL: for (size_t i = 0; i < command->argc; i++) { command->args[i].i = atobool(command->argv[i]); } return; case TYPE_KEYBIND: // todo wm_config_parse_bind_command(command); case TYPE_STRING: for (size_t i = 0; i < command->argc; i++) { size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX); command->args[i].count = len; memcpy(command->args[i].s, command->argv[i], len); } return; case TYPE_FLOAT: for (size_t i = 0; i < command->argc; i++) { command->args[i].f = atof(command->argv[i]); } return; } } void wm_configcommand_free(ConfigCommand *command) { assert(command); command->argc = 0; for (size_t i = 0; i < CONFIG_ARGC_MAX; i++) { free(command->argv[i]); free(command->args[i].s); for (size_t j = 0; j < CONFIG_ARGC_MAX; j++) { free(command->args[i].sl[j]); } free(command->args[i].sl); } free(command->argv); free(command->args); } bool atobool(char *arr) { for (size_t i = 0; i