From 54991cb6386a828aa721ab4d923285578f847b9d Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 6 Mar 2020 20:51:05 +0100 Subject: [PATCH 01/13] Unify parsing of config file --- keybinding.c | 80 +++++++- keybinding.h | 9 + parse.c | 537 +++++++++++++++++++++++++-------------------------- 3 files changed, 351 insertions(+), 275 deletions(-) diff --git a/keybinding.c b/keybinding.c index 2d5abdf..45a0021 100644 --- a/keybinding.c +++ b/keybinding.c @@ -54,12 +54,19 @@ find_keybinding(const struct keybinding_list *list, } void -keybinding_free(struct keybinding *keybinding) { +keybinding_free(struct keybinding *keybinding, bool recursive) { switch(keybinding->action) { + case KEYBINDING_DEFINEMODE: case KEYBINDING_RUN_COMMAND: if(keybinding->data.c != NULL) { free(keybinding->data.c); } + break; + case KEYBINDING_DEFINEKEY: + if(keybinding->data.kb != NULL && recursive) { + keybinding_free(keybinding->data.kb, true); + } + break; default: break; } @@ -79,7 +86,7 @@ keybinding_list_push(struct keybinding_list *list, * exist*/ struct keybinding **found_keybinding = find_keybinding(list, keybinding); if(found_keybinding != NULL) { - keybinding_free(*found_keybinding); + keybinding_free(*found_keybinding,true); *found_keybinding = keybinding; wlr_log(WLR_DEBUG, "A keybinding was found twice in the config file."); } else { @@ -101,7 +108,7 @@ keybinding_list_init() { void keybinding_list_free(struct keybinding_list *list) { for(unsigned int i = 0; i < list->length; ++i) { - keybinding_free(list->keybindings[i]); + keybinding_free(list->keybindings[i], true); } free(list->keybindings); free(list); @@ -634,6 +641,7 @@ keybinding_show_time(struct cg_server *server) { msg[strcspn(msg, "\n")] = '\0'; /* Remove the newline */ message_printf(server->curr_output, "%s", msg); + free(msg); } void @@ -670,6 +678,60 @@ keybinding_move_view_to_next_output(struct cg_server *server) { } } +void +keybinding_set_nws(struct cg_server *server, int nws) { + struct cg_output *output; + wl_list_for_each(output, &server->outputs, link) { + for(unsigned int i = nws; i < server->nws; ++i) { + workspace_free(output->workspaces[i]); + } + struct cg_workspace **new_workspaces = realloc( + output->workspaces, nws * sizeof(struct cg_workspace *)); + if(new_workspaces == NULL) { + wlr_log(WLR_ERROR, "Error reallocating memory for workspaces."); + return; + } + output->workspaces = new_workspaces; + for(int i = server->nws; i < nws; ++i) { + output->workspaces[i] = full_screen_workspace(output); + wl_list_init(&output->workspaces[i]->views); + wl_list_init(&output->workspaces[i]->unmanaged_views); + } + + if(output->curr_workspace >= nws) { + output->curr_workspace = nws-1; + } + } + server->nws = nws; +} + +void +keybinding_definemode(struct cg_server *server, char* mode) { + int length = 0; + while(server->modes[length++] != NULL); + char **tmp = realloc(server->modes, (length + 1) * sizeof(char *)); + if(tmp == NULL) { + wlr_log(WLR_ERROR, "Could not allocate memory for storing modes."); + return; + } + server->modes = tmp; + server->modes[length] = NULL; + + server->modes[length - 1] = strdup(mode); +} + +void +keybinding_definekey(struct cg_server *server, struct keybinding *kb) { + keybinding_list_push(server->keybindings,kb); +} + +void +keybinding_set_background(struct cg_server *server, float* bg) { + server->bg_color[0] = bg[0]; + server->bg_color[1] = bg[1]; + server->bg_color[2] = bg[2]; +} + void keybinding_move_view_to_workspace(struct cg_server *server, uint32_t ws) { struct cg_view *view = @@ -808,6 +870,18 @@ run_action(enum keybinding_action action, struct cg_server *server, keybinding_move_view_to_next_output(server); break; } + case KEYBINDING_DEFINEKEY: + keybinding_definekey(server,data.kb); + break; + case KEYBINDING_BACKGROUND: + keybinding_set_background(server, data.color); + break; + case KEYBINDING_DEFINEMODE: + keybinding_definemode(server, data.c); + break; + case KEYBINDING_WORKSPACES: + keybinding_set_nws(server, data.i); + break; default: { wlr_log(WLR_ERROR, "run_action was called with a value not present in \"enum " diff --git a/keybinding.h b/keybinding.h index d06bbbb..42ad114 100644 --- a/keybinding.h +++ b/keybinding.h @@ -43,6 +43,11 @@ enum keybinding_action { KEYBINDING_FOCUS_RIGHT, KEYBINDING_FOCUS_TOP, KEYBINDING_FOCUS_BOTTOM, + + KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition + KEYBINDING_BACKGROUND, //data.color is the background color + KEYBINDING_DEFINEMODE, //data.c is the mode name + KEYBINDING_WORKSPACES, //data.i is the number of workspaces }; union keybinding_params { @@ -50,6 +55,8 @@ union keybinding_params { uint32_t u; int32_t i; bool b; + float color[3]; + struct keybinding* kb; }; struct keybinding { @@ -82,5 +89,7 @@ keybinding_list_init(); int run_action(enum keybinding_action action, struct cg_server *server, union keybinding_params data); +void +keybinding_free(struct keybinding *keybinding, bool recursive); #endif /* end of include guard KEYBINDINGS_H */ diff --git a/parse.c b/parse.c index e8c7b15..7e09fce 100644 --- a/parse.c +++ b/parse.c @@ -10,167 +10,6 @@ #include "server.h" #include "workspace.h" -int -parse_action(struct cg_server *server, struct keybinding *keybinding, - char **saveptr) { - char *action = strtok_r(NULL, " ", saveptr); - if(action == NULL) { - wlr_log( - WLR_ERROR, - "Not enough parameters to \"bind\". Expected action to execute"); - return -1; - } - keybinding->data = (union keybinding_params){.c = NULL}; - if(strcmp(action, "vsplit") == 0) { - keybinding->action = KEYBINDING_SPLIT_VERTICAL; - } else if(strcmp(action, "hsplit") == 0) { - keybinding->action = KEYBINDING_SPLIT_HORIZONTAL; - } else if(strcmp(action, "quit") == 0) { - keybinding->action = KEYBINDING_QUIT; - } else if(strcmp(action, "focus") == 0) { - keybinding->action = KEYBINDING_CYCLE_TILES; - keybinding->data.b = false; - } else if(strcmp(action, "focusprev") == 0) { - keybinding->action = KEYBINDING_CYCLE_TILES; - keybinding->data.b = true; - } else if(strcmp(action, "next") == 0) { - keybinding->action = KEYBINDING_CYCLE_VIEWS; - keybinding->data.b = false; - } else if(strcmp(action, "prev") == 0) { - keybinding->action = KEYBINDING_CYCLE_VIEWS; - keybinding->data.b = true; - } else if(strcmp(action, "only") == 0) { - keybinding->action = KEYBINDING_LAYOUT_FULLSCREEN; - } else if(strcmp(action, "abort") == 0) { - keybinding->action = KEYBINDING_NOOP; - } else if(strcmp(action, "time") == 0) { - keybinding->action = KEYBINDING_SHOW_TIME; - } else if(strcmp(action, "nextscreen") == 0) { - keybinding->action = KEYBINDING_CYCLE_OUTPUT; - keybinding->data.b = false; - } else if(strcmp(action, "prevscreen") == 0) { - keybinding->action = KEYBINDING_CYCLE_OUTPUT; - keybinding->data.b = true; - } else if(strcmp(action, "exec") == 0) { - keybinding->action = KEYBINDING_RUN_COMMAND; - if(*saveptr == NULL) { - wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected " - "string to execute."); - return -1; - } - keybinding->data.c = strdup(*saveptr); - } else if(strcmp(action, "resizeleft") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; - keybinding->data.i = -10; - } else if(strcmp(action, "resizeright") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; - keybinding->data.i = 10; - } else if(strcmp(action, "resizedown") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; - keybinding->data.i = 10; - } else if(strcmp(action, "resizeup") == 0) { - keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; - keybinding->data.i = -10; - } else if(strcmp(action, "workspace") == 0) { - keybinding->action = KEYBINDING_SWITCH_WORKSPACE; - char *nws_str = strtok_r(NULL, " ", saveptr); - if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspace\" action, got none."); - return -1; - } - - long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { - wlr_log(WLR_ERROR, - "Requested binding for workspace %li, but have %u", ws, - server->nws); - return -1; - } - keybinding->data.u = ws - 1; - } else if(strcmp(action, "movetoworkspace") == 0) { - keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; - char *nws_str = strtok_r(NULL, " ", saveptr); - if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspace\" action, got none."); - return -1; - } - - long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { - wlr_log( - WLR_ERROR, - "Requested binding for moving to workspace %li, but have %u", - ws, server->nws); - return -1; - } - keybinding->data.u = ws - 1; - } else if(strcmp(action, "exchangeleft") == 0) { - keybinding->action = KEYBINDING_SWAP_LEFT; - } else if(strcmp(action, "exchangeright") == 0) { - keybinding->action = KEYBINDING_SWAP_RIGHT; - } else if(strcmp(action, "exchangeup") == 0) { - keybinding->action = KEYBINDING_SWAP_TOP; - } else if(strcmp(action, "exchangedown") == 0) { - keybinding->action = KEYBINDING_SWAP_BOTTOM; - } else if(strcmp(action, "focusleft") == 0) { - keybinding->action = KEYBINDING_FOCUS_LEFT; - } else if(strcmp(action, "focusright") == 0) { - keybinding->action = KEYBINDING_FOCUS_RIGHT; - } else if(strcmp(action, "focusup") == 0) { - keybinding->action = KEYBINDING_FOCUS_TOP; - } else if(strcmp(action, "focusdown") == 0) { - keybinding->action = KEYBINDING_FOCUS_BOTTOM; - } else if(strcmp(action, "movetonextscreen") == 0) { - keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT; - } else if(strcmp(action, "switchvt") == 0) { - keybinding->action = KEYBINDING_CHANGE_TTY; - char *ntty = strtok_r(NULL, " ", saveptr); - if(ntty == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"switchvt\" command, got none."); - return -1; - } - long tty = strtol(ntty, NULL, 10); - keybinding->data.u = tty; - } else if(strcmp(action, "mode") == 0) { - keybinding->action = KEYBINDING_SWITCH_MODE; - char *mode = strtok_r(NULL, " ", saveptr); - if(mode == NULL) { - wlr_log(WLR_ERROR, - "Expected mode after \"switch_mode\". Got nothing."); - return -1; - } - int mode_idx = get_mode_index_from_name(server->modes, mode); - if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode); - return -1; - } - keybinding->data.u = (unsigned int)mode_idx; - } else if(strcmp(action, "setmode") == 0) { - keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE; - char *mode = strtok_r(NULL, " ", saveptr); - if(mode == NULL) { - wlr_log( - WLR_ERROR, - "Expected mode after \"switch_default_mode\". Got nothing."); - return -1; - } - int mode_idx = get_mode_index_from_name(server->modes, mode); - if(mode_idx == -1) { - wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode", - mode); - return -1; - } - keybinding->data.u = (unsigned int)mode_idx; - } else { - wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action); - return -1; - } - return 0; -} - /* parses a key definition (e.g. "S-Tab") and sets key and modifiers in * keybinding respectivly */ int @@ -218,6 +57,9 @@ parse_key(struct keybinding *keybinding, const char *key_def) { return 0; } +int +parse_command(struct cg_server *server, struct keybinding *keybinding, char *saveptr); + /* Parse a keybinding definition and return it if successful, else return NULL */ struct keybinding * @@ -229,188 +71,339 @@ parse_keybinding(struct cg_server *server, char **saveptr) { free(keybinding); return NULL; } - if(parse_action(server, keybinding, saveptr) != 0) { + if(parse_command(server, keybinding, *saveptr) != 0) { free(keybinding); return NULL; } return keybinding; } -int -parse_bind(struct cg_server *server, struct keybinding_list *list, - char **saveptr) { +struct keybinding * +parse_bind(struct cg_server *server, char **saveptr) { struct keybinding *keybinding = parse_keybinding(server, saveptr); if(keybinding == NULL) { wlr_log(WLR_ERROR, "Could not parse keybinding for \"bind\"."); - return -1; + return NULL; } keybinding->mode = 1; - keybinding_list_push(list, keybinding); - return 0; + return keybinding; } -int -parse_definekey(struct cg_server *server, struct keybinding_list *list, - char **saveptr) { +struct keybinding * +parse_definekey(struct cg_server *server, char **saveptr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { wlr_log(WLR_ERROR, "Too few arguments to \"definekey\". Expected mode"); - return -1; + return NULL; } int mode_idx = get_mode_index_from_name(server->modes, mode); if(mode_idx == -1) { wlr_log(WLR_ERROR, "Unknown mode \"%s\"", mode); - return -1; + return NULL; } struct keybinding *keybinding = parse_keybinding(server, saveptr); if(keybinding == NULL) { wlr_log(WLR_ERROR, "Could not parse keybinding for \"definekey\""); - return -1; + return NULL; } keybinding->mode = mode_idx; - keybinding_list_push(list, keybinding); - return 0; + return keybinding; } int -parse_and_run_exec(char **saveptr) { - return run_action(KEYBINDING_RUN_COMMAND, NULL, - (union keybinding_params){.c = *saveptr}); -} - -int -parse_background(struct cg_server *server, char **saveptr) { +parse_background(struct cg_server *server, float *color, char **saveptr) { /* Read rgb numbers */ for(unsigned int i = 0; i < 3; ++i) { - char *nstr = strtok_r(NULL, " ", saveptr); - if(nstr == NULL) { + char *nstr = strtok_r(NULL, " \n", saveptr); + int nstrlen; + if(nstr == NULL||(nstrlen = strlen(nstr))== 0) { wlr_log(WLR_ERROR, "Expected three space-separated numbers (rgb) for " "background color setting. Got %d.", i); return -1; } + if(nstr[nstrlen-1] == '\n') { + nstr[nstrlen-1] = '\0'; + --nstrlen; + } char *endptr = NULL; float nval = strtof(nstr, &endptr); - if(endptr == nstr) { + if(endptr != nstr+nstrlen) { wlr_log( WLR_ERROR, - "Could not parse number \"%s\" für background color setting.", + "Could not parse number \"%s\" for background color setting.", nstr); return -1; } - server->bg_color[i] = nval; + if(nval<0||nval>1) { + wlr_log(WLR_ERROR, "Expected a number between 0 and 1 for setting of background color. Got %f.",nval); + return -1; + } + color[i] = nval; } return 0; } -int -parse_escape(struct keybinding_list *list, char **saveptr) { +struct keybinding * +parse_escape(char **saveptr) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); char *key = strtok_r(NULL, " ", saveptr); if(parse_key(keybinding, key) != 0) { wlr_log(WLR_ERROR, "Could not parse key definition \"%s\" for \"escape\"", key); free(keybinding); - return -1; + return NULL; } keybinding->mode = 0; //"top" mode keybinding->action = KEYBINDING_SWITCH_MODE; keybinding->data.u = 1; //"root" mode - keybinding_list_push(list, keybinding); - return 0; + return keybinding; } -int -parse_definemode(char ***modes, char **saveptr) { - int length = 0; - while((*modes)[length++] != NULL) - ; - char **tmp = realloc(*modes, (length + 1) * sizeof(char *)); - if(tmp == NULL) { - wlr_log(WLR_ERROR, "Could not allocate memory for storing modes."); - return -1; - } - *modes = tmp; - (*modes)[length] = NULL; - +char* +parse_definemode(char **saveptr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { wlr_log(WLR_ERROR, "Expected mode to succeed \"definemode\" keyword."); + return NULL; + } + return strdup(mode); +} + +int +parse_workspaces(char **saveptr) { + char *nws_str = strtok_r(NULL, " ", saveptr); + if(nws_str == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"workspaces\" command, got none."); + return -1; + } + long nws = strtol(nws_str, NULL, 10); + if(!(1 <= nws && nws <= 30)) { + wlr_log(WLR_ERROR, + "More than 30 workspaces are not supported. Received %li", + nws); + return -1; + } + return nws; +} + +int +parse_command(struct cg_server *server, struct keybinding *keybinding, + char *saveptr) { + char *action = strtok_r(NULL, " ", &saveptr); + if(action == NULL) { + wlr_log( + WLR_ERROR, + "Expected an action to parse, got none."); + return -1; + } + keybinding->data = (union keybinding_params){.c = NULL}; + if(strcmp(action, "vsplit") == 0) { + keybinding->action = KEYBINDING_SPLIT_VERTICAL; + } else if(strcmp(action, "hsplit") == 0) { + keybinding->action = KEYBINDING_SPLIT_HORIZONTAL; + } else if(strcmp(action, "quit") == 0) { + keybinding->action = KEYBINDING_QUIT; + } else if(strcmp(action, "focus") == 0) { + keybinding->action = KEYBINDING_CYCLE_TILES; + keybinding->data.b = false; + } else if(strcmp(action, "focusprev") == 0) { + keybinding->action = KEYBINDING_CYCLE_TILES; + keybinding->data.b = true; + } else if(strcmp(action, "next") == 0) { + keybinding->action = KEYBINDING_CYCLE_VIEWS; + keybinding->data.b = false; + } else if(strcmp(action, "prev") == 0) { + keybinding->action = KEYBINDING_CYCLE_VIEWS; + keybinding->data.b = true; + } else if(strcmp(action, "only") == 0) { + keybinding->action = KEYBINDING_LAYOUT_FULLSCREEN; + } else if(strcmp(action, "abort") == 0) { + keybinding->action = KEYBINDING_NOOP; + } else if(strcmp(action, "time") == 0) { + keybinding->action = KEYBINDING_SHOW_TIME; + } else if(strcmp(action, "nextscreen") == 0) { + keybinding->action = KEYBINDING_CYCLE_OUTPUT; + keybinding->data.b = false; + } else if(strcmp(action, "prevscreen") == 0) { + keybinding->action = KEYBINDING_CYCLE_OUTPUT; + keybinding->data.b = true; + } else if(strcmp(action, "exec") == 0) { + keybinding->action = KEYBINDING_RUN_COMMAND; + if(saveptr == NULL) { + wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected " + "string to execute."); + return -1; + } + keybinding->data.c = strdup(saveptr); + } else if(strcmp(action, "resizeleft") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; + keybinding->data.i = -10; + } else if(strcmp(action, "resizeright") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL; + keybinding->data.i = 10; + } else if(strcmp(action, "resizedown") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; + keybinding->data.i = 10; + } else if(strcmp(action, "resizeup") == 0) { + keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; + keybinding->data.i = -10; + } else if(strcmp(action, "workspace") == 0) { + keybinding->action = KEYBINDING_SWITCH_WORKSPACE; + char *nws_str = strtok_r(NULL, " ", &saveptr); + if(nws_str == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"workspace\" action, got none."); + return -1; + } + + long ws = strtol(nws_str, NULL, 10); + if(!(1 <= ws && ws <= server->nws)) { + wlr_log(WLR_ERROR, + "Requested binding for workspace %li, but have %u", ws, + server->nws); + return -1; + } + keybinding->data.u = ws - 1; + } else if(strcmp(action, "movetoworkspace") == 0) { + keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; + char *nws_str = strtok_r(NULL, " ", &saveptr); + if(nws_str == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"workspace\" action, got none."); + return -1; + } + + long ws = strtol(nws_str, NULL, 10); + if(!(1 <= ws && ws <= server->nws)) { + wlr_log( + WLR_ERROR, + "Requested binding for moving to workspace %li, but have %u", + ws, server->nws); + return -1; + } + keybinding->data.u = ws - 1; + } else if(strcmp(action, "exchangeleft") == 0) { + keybinding->action = KEYBINDING_SWAP_LEFT; + } else if(strcmp(action, "exchangeright") == 0) { + keybinding->action = KEYBINDING_SWAP_RIGHT; + } else if(strcmp(action, "exchangeup") == 0) { + keybinding->action = KEYBINDING_SWAP_TOP; + } else if(strcmp(action, "exchangedown") == 0) { + keybinding->action = KEYBINDING_SWAP_BOTTOM; + } else if(strcmp(action, "focusleft") == 0) { + keybinding->action = KEYBINDING_FOCUS_LEFT; + } else if(strcmp(action, "focusright") == 0) { + keybinding->action = KEYBINDING_FOCUS_RIGHT; + } else if(strcmp(action, "focusup") == 0) { + keybinding->action = KEYBINDING_FOCUS_TOP; + } else if(strcmp(action, "focusdown") == 0) { + keybinding->action = KEYBINDING_FOCUS_BOTTOM; + } else if(strcmp(action, "movetonextscreen") == 0) { + keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT; + } else if(strcmp(action, "switchvt") == 0) { + keybinding->action = KEYBINDING_CHANGE_TTY; + char *ntty = strtok_r(NULL, " ", &saveptr); + if(ntty == NULL) { + wlr_log(WLR_ERROR, + "Expected argument for \"switchvt\" command, got none."); + return -1; + } + long tty = strtol(ntty, NULL, 10); + keybinding->data.u = tty; + } else if(strcmp(action, "mode") == 0) { + keybinding->action = KEYBINDING_SWITCH_MODE; + char *mode = strtok_r(NULL, " ", &saveptr); + if(mode == NULL) { + wlr_log(WLR_ERROR, + "Expected mode after \"switch_mode\". Got nothing."); + return -1; + } + int mode_idx = get_mode_index_from_name(server->modes, mode); + if(mode_idx == -1) { + wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode); + return -1; + } + keybinding->data.u = (unsigned int)mode_idx; + } else if(strcmp(action, "setmode") == 0) { + keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE; + char *mode = strtok_r(NULL, " ", &saveptr); + if(mode == NULL) { + wlr_log( + WLR_ERROR, + "Expected mode after \"switch_default_mode\". Got nothing."); + return -1; + } + int mode_idx = get_mode_index_from_name(server->modes, mode); + if(mode_idx == -1) { + wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode", + mode); + return -1; + } + keybinding->data.u = (unsigned int)mode_idx; + } else if(strcmp(action, "bind") == 0) { + keybinding->action = KEYBINDING_DEFINEKEY; + keybinding->data.kb = parse_bind(server, &saveptr); + if(keybinding->data.kb == NULL) { + return -1; + } + } else if(strcmp(action, "definekey") == 0) { + keybinding->action = KEYBINDING_DEFINEKEY; + keybinding->data.kb = parse_definekey(server, &saveptr); + if(keybinding->data.kb == NULL) { + return -1; + } + } else if(strcmp(action, "background") == 0) { + keybinding->action = KEYBINDING_BACKGROUND; + if(parse_background(server, keybinding->data.color,&saveptr) != 0) { + return -1; + } + } else if(strcmp(action, "escape") == 0) { + keybinding->action = KEYBINDING_DEFINEKEY; + keybinding->data.kb = parse_escape(&saveptr); + if(keybinding->data.kb == NULL) { + return -1; + } + } else if(strcmp(action, "definemode") == 0) { + keybinding->action = KEYBINDING_DEFINEMODE; + keybinding->data.c = parse_definemode(&saveptr); + if(keybinding->data.c == NULL) { + return -1; + } + } else if(strcmp(action, "workspaces") == 0) { + keybinding->action = KEYBINDING_WORKSPACES; + keybinding->data.i=parse_workspaces(&saveptr); + if(keybinding->data.i<0) { + return -1; + } + } else { + wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action); return -1; } - (*modes)[length - 1] = strdup(mode); return 0; } int parse_rc_line(struct cg_server *server, char *line) { - char *saveptr = NULL; // Used internally by strtok_r - char *command = strtok_r(line, " ", &saveptr); - if(command == NULL) { - return 0; - } - if(strcmp(command, "bind") == 0) { - if(parse_bind(server, server->keybindings, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "definekey") == 0) { - if(parse_definekey(server, server->keybindings, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "background") == 0) { - if(parse_background(server, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "escape") == 0) { - if(parse_escape(server->keybindings, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "definemode") == 0) { - if(parse_definemode(&server->modes, &saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "exec") == 0) { - if(parse_and_run_exec(&saveptr) != 0) { - return -1; - } - } else if(strcmp(command, "workspaces") == 0) { - char *nws_str = strtok_r(NULL, " ", &saveptr); - if(nws_str == NULL) { - wlr_log(WLR_ERROR, - "Expected argument for \"workspaces\" command, got none."); - return -1; - } - long nws = strtol(nws_str, NULL, 10); - if(!(1 <= nws && nws <= 30)) { - wlr_log(WLR_ERROR, - "More than 30 workspaces are not supported. Received %li", - nws); - return -1; - } - struct cg_output *output; - wl_list_for_each(output, &server->outputs, link) { - for(unsigned int i = nws; i < server->nws; ++i) { - free(output->workspaces[i]); - } - struct cg_workspace **new_workspaces = realloc( - output->workspaces, nws * sizeof(struct cg_workspace *)); - if(new_workspaces == NULL) { - wlr_log(WLR_ERROR, "Error reallocating memory for workspaces."); - return -1; - } - output->workspaces = new_workspaces; - for(unsigned int i = server->nws; i < nws; ++i) { - output->workspaces[i] = full_screen_workspace(output); - wl_list_init(&output->workspaces[i]->views); - wl_list_init(&output->workspaces[i]->unmanaged_views); - } - } - server->nws = nws; - } else { - wlr_log(WLR_ERROR, "Unsupported command \"%s\" in config file", - command); + char *saveptr = strdup(line); // Used internally by strtok_r + + struct keybinding *keybinding = malloc(sizeof(struct keybinding)); + if(keybinding == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate memory for temporary keybinding struct."); + free(keybinding); + free(saveptr); return -1; } + if(parse_command(server, keybinding, saveptr) != 0) { + wlr_log(WLR_ERROR, "Error parsing config file."); + free(keybinding); + free(saveptr); + return -1; + } + run_action(keybinding->action, server, keybinding->data); + keybinding_free(keybinding, false); + free(saveptr); return 0; } From cb46e463a3f65b1a58086fc3ffbecc1bf494a9d6 Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 6 Mar 2020 21:04:29 +0100 Subject: [PATCH 02/13] Fix memory leaks --- message.c | 1 + workspace.c | 1 + 2 files changed, 2 insertions(+) diff --git a/message.c b/message.c index 66e09dd..c7b6b96 100644 --- a/message.c +++ b/message.c @@ -147,6 +147,7 @@ message_printf(struct cg_output *output, const char *fmt, ...) { message_set_output(output, buffer, box, CG_MESSAGE_TOP_RIGHT); free(buffer); + free(box); alarm(output->server->message_timeout); } diff --git a/workspace.c b/workspace.c index 8ed010e..7027710 100644 --- a/workspace.c +++ b/workspace.c @@ -51,6 +51,7 @@ workspace_focus_tile(struct cg_workspace *ws, struct cg_tile *tile) { box->x = tile->tile.x + tile->tile.width / 2; box->y = tile->tile.y + tile->tile.height / 2; message_printf_pos(ws->output, box, CG_MESSAGE_CENTER, "Current frame"); + free(box); } void From 56ee91d396ec181330008d6d3b0262ac503aae80 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:49:16 +0100 Subject: [PATCH 03/13] Cleanup cairo and pandoc structures on exit --- cagebreak.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cagebreak.c b/cagebreak.c index 4a71480..aeddf84 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -10,6 +10,9 @@ #include "config.h" +#include +#include +#include #include #include #include @@ -533,5 +536,10 @@ end: with a proper wl_display. */ wl_display_destroy(server.wl_display); wlr_output_layout_destroy(server.output_layout); + + pango_cairo_font_map_set_default(NULL); + cairo_debug_reset_static_data(); + FcFini(); + return ret; } From 0c7719011bf3db78be9545acb67c00ea118d8746 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:49:50 +0100 Subject: [PATCH 04/13] Add fontconfig as dependency --- meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meson.build b/meson.build index 6925b67..9904430 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,7 @@ xkbcommon = dependency('xkbcommon') cairo = dependency('cairo') pango = dependency('pango') pangocairo = dependency('pangocairo') +fontconfig = dependency('fontconfig') math = cc.find_library('m') wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') @@ -180,6 +181,7 @@ cagebreak_dependencies = [ wayland_cursor, wlroots, xkbcommon, + fontconfig, pixman, math, pango, From 3035866d78fb165aed8143d56c67eeee2f1b4cf2 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:50:42 +0100 Subject: [PATCH 05/13] Fix parsing bugs --- parse.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/parse.c b/parse.c index 7e09fce..5b0ac6e 100644 --- a/parse.c +++ b/parse.c @@ -58,7 +58,8 @@ parse_key(struct keybinding *keybinding, const char *key_def) { } int -parse_command(struct cg_server *server, struct keybinding *keybinding, char *saveptr); +parse_command(struct cg_server *server, struct keybinding *keybinding, + char *saveptr); /* Parse a keybinding definition and return it if successful, else return NULL */ @@ -116,28 +117,31 @@ parse_background(struct cg_server *server, float *color, char **saveptr) { for(unsigned int i = 0; i < 3; ++i) { char *nstr = strtok_r(NULL, " \n", saveptr); int nstrlen; - if(nstr == NULL||(nstrlen = strlen(nstr))== 0) { + if(nstr == NULL || (nstrlen = strlen(nstr)) == 0) { wlr_log(WLR_ERROR, "Expected three space-separated numbers (rgb) for " "background color setting. Got %d.", i); return -1; } - if(nstr[nstrlen-1] == '\n') { - nstr[nstrlen-1] = '\0'; + if(nstr[nstrlen - 1] == '\n') { + nstr[nstrlen - 1] = '\0'; --nstrlen; } char *endptr = NULL; float nval = strtof(nstr, &endptr); - if(endptr != nstr+nstrlen) { + if(endptr != nstr + nstrlen) { wlr_log( WLR_ERROR, "Could not parse number \"%s\" for background color setting.", nstr); return -1; } - if(nval<0||nval>1) { - wlr_log(WLR_ERROR, "Expected a number between 0 and 1 for setting of background color. Got %f.",nval); + if(nval < 0 || nval > 1) { + wlr_log(WLR_ERROR, + "Expected a number between 0 and 1 for setting of " + "background color. Got %f.", + nval); return -1; } color[i] = nval; @@ -161,7 +165,7 @@ parse_escape(char **saveptr) { return keybinding; } -char* +char * parse_definemode(char **saveptr) { char *mode = strtok_r(NULL, " ", saveptr); if(mode == NULL) { @@ -182,8 +186,7 @@ parse_workspaces(char **saveptr) { long nws = strtol(nws_str, NULL, 10); if(!(1 <= nws && nws <= 30)) { wlr_log(WLR_ERROR, - "More than 30 workspaces are not supported. Received %li", - nws); + "More than 30 workspaces are not supported. Received %li", nws); return -1; } return nws; @@ -191,12 +194,10 @@ parse_workspaces(char **saveptr) { int parse_command(struct cg_server *server, struct keybinding *keybinding, - char *saveptr) { + char *saveptr) { char *action = strtok_r(NULL, " ", &saveptr); if(action == NULL) { - wlr_log( - WLR_ERROR, - "Expected an action to parse, got none."); + wlr_log(WLR_ERROR, "Expected an action to parse, got none."); return -1; } keybinding->data = (union keybinding_params){.c = NULL}; @@ -260,10 +261,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { - wlr_log(WLR_ERROR, - "Requested binding for workspace %li, but have %u", ws, - server->nws); + if(ws < 1) { + wlr_log(WLR_ERROR, "Workspace number must be a integer number larger or equal to 1. Got %ld", ws); return -1; } keybinding->data.u = ws - 1; @@ -277,11 +276,9 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } long ws = strtol(nws_str, NULL, 10); - if(!(1 <= ws && ws <= server->nws)) { + if(ws < 1) { wlr_log( - WLR_ERROR, - "Requested binding for moving to workspace %li, but have %u", - ws, server->nws); + WLR_ERROR, "Workspace number must be an integer larger or equal to 1. Got %ld", ws); return -1; } keybinding->data.u = ws - 1; @@ -357,7 +354,7 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } } else if(strcmp(action, "background") == 0) { keybinding->action = KEYBINDING_BACKGROUND; - if(parse_background(server, keybinding->data.color,&saveptr) != 0) { + if(parse_background(server, keybinding->data.color, &saveptr) != 0) { return -1; } } else if(strcmp(action, "escape") == 0) { @@ -374,8 +371,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } } else if(strcmp(action, "workspaces") == 0) { keybinding->action = KEYBINDING_WORKSPACES; - keybinding->data.i=parse_workspaces(&saveptr); - if(keybinding->data.i<0) { + keybinding->data.i = parse_workspaces(&saveptr); + if(keybinding->data.i < 0) { return -1; } } else { @@ -391,7 +388,8 @@ parse_rc_line(struct cg_server *server, char *line) { struct keybinding *keybinding = malloc(sizeof(struct keybinding)); if(keybinding == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate memory for temporary keybinding struct."); + wlr_log(WLR_ERROR, + "Failed to allocate memory for temporary keybinding struct."); free(keybinding); free(saveptr); return -1; From f6240e9f687c2b101d4ae3754bd5ef9918995e9b Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:50:52 +0100 Subject: [PATCH 06/13] Fix potential double-free --- workspace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/workspace.c b/workspace.c index 7027710..8ed010e 100644 --- a/workspace.c +++ b/workspace.c @@ -51,7 +51,6 @@ workspace_focus_tile(struct cg_workspace *ws, struct cg_tile *tile) { box->x = tile->tile.x + tile->tile.width / 2; box->y = tile->tile.y + tile->tile.height / 2; message_printf_pos(ws->output, box, CG_MESSAGE_CENTER, "Current frame"); - free(box); } void From 8ffac22f1b4f175ccd9ff4b0f89c25e434bef829 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:51:05 +0100 Subject: [PATCH 07/13] Fix conventions for system include --- pango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pango.c b/pango.c index 035ac9b..ef3df10 100644 --- a/pango.c +++ b/pango.c @@ -1,4 +1,4 @@ -#include "cairo.h" +#include #include #include #include From b11e2409c6e7db5ca4fedd0392659b41e7f4f997 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:51:35 +0100 Subject: [PATCH 08/13] Add support for disabling messages when fuzzing --- message.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/message.c b/message.c index c7b6b96..c41e1a4 100644 --- a/message.c +++ b/message.c @@ -46,6 +46,12 @@ create_message_texture(const char *string, const struct cg_output *output) { cairo_surface_t *dummy_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); cairo_t *c = cairo_create(dummy_surface); + + // This occurs when we are fuzzing. In that case, do nothing + if(c == NULL) { + return NULL; + } + cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); @@ -147,7 +153,6 @@ message_printf(struct cg_output *output, const char *fmt, ...) { message_set_output(output, buffer, box, CG_MESSAGE_TOP_RIGHT); free(buffer); - free(box); alarm(output->server->message_timeout); } From 30bfa9b68928871b8a3f471d95f258ca27e1a27a Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 09:52:41 +0100 Subject: [PATCH 09/13] Fix bugs in keybinding execution --- keybinding.c | 111 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 33 deletions(-) diff --git a/keybinding.c b/keybinding.c index 45a0021..9bf5734 100644 --- a/keybinding.c +++ b/keybinding.c @@ -86,7 +86,7 @@ keybinding_list_push(struct keybinding_list *list, * exist*/ struct keybinding **found_keybinding = find_keybinding(list, keybinding); if(found_keybinding != NULL) { - keybinding_free(*found_keybinding,true); + keybinding_free(*found_keybinding, true); *found_keybinding = keybinding; wlr_log(WLR_DEBUG, "A keybinding was found twice in the config file."); } else { @@ -255,10 +255,27 @@ is_between_strict(int a, int b, int x) { return a < x && x < b; } +int +get_compl_coord(struct cg_tile *tile, int *(*get_coord)(struct cg_tile *tile)) { + return tile->tile.x + tile->tile.y - *get_coord(tile); +} + +int +get_compl_dim(struct cg_tile *tile, int *(*get_dim)(struct cg_tile *tile)) { + return tile->tile.width + tile->tile.height - *get_dim(tile); +} + bool -resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset, - int dim_offset, int *(*get_coord)(struct cg_tile *tile), - int *(*get_dim)(struct cg_tile *tile)) { +intervalls_intersect(int x1, int x2, int y1, int y2) { + return y2 > x1 && y1 < x2; +} + +bool +resize_allowed(struct cg_tile *tile, const struct cg_tile *parent, + int coord_offset, int dim_offset, + int *(*get_coord)(struct cg_tile *tile), + int *(*get_dim)(struct cg_tile *tile), struct cg_tile *orig) { + if(coord_offset == 0 && dim_offset == 0) { return true; } else if(*get_dim(tile) - coord_offset + dim_offset <= 0) { @@ -267,17 +284,25 @@ resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset, for(struct cg_tile *it = tile->next; it != tile && it != NULL; it = it->next) { - if(it == parent) { + if(it == parent || it == orig) { continue; } - if(it->tile.x == tile->tile.x + tile->tile.width) { - if(!resize_allowed(it, tile, dim_offset, -dim_offset, get_coord, - get_dim)) { - return false; - } - } else if(it->tile.x + it->tile.width == tile->tile.x) { - if(!resize_allowed(it, tile, 0, coord_offset, get_coord, get_dim)) { - return false; + if(intervalls_intersect( + get_compl_coord(tile, get_coord), + get_compl_coord(tile, get_coord) + get_compl_dim(tile, get_dim), + get_compl_coord(it, get_coord), + get_compl_coord(it, get_coord) + get_compl_dim(it, get_dim))) { + if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) { + if(!resize_allowed(it, tile, dim_offset + coord_offset, + -dim_offset - coord_offset, get_coord, + get_dim, orig)) { + return false; + } + } else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) { + if(!resize_allowed(it, tile, 0, coord_offset, get_coord, + get_dim, orig)) { + return false; + } } } } @@ -287,20 +312,27 @@ resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset, void resize(struct cg_tile *tile, const struct cg_tile *parent, int coord_offset, int dim_offset, int *(*get_coord)(struct cg_tile *tile), - int *(*get_dim)(struct cg_tile *tile)) { + int *(*get_dim)(struct cg_tile *tile), struct cg_tile *orig) { if(coord_offset == 0 && dim_offset == 0) { return; } for(struct cg_tile *it = tile->next; it != tile && it != NULL; it = it->next) { - if(it == parent) { + if(it == parent || it == orig) { continue; } - if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) { - resize(it, tile, dim_offset, -dim_offset, get_coord, get_dim); - } else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) { - resize(it, tile, 0, coord_offset, get_coord, get_dim); + if(intervalls_intersect( + get_compl_coord(tile, get_coord), + get_compl_coord(tile, get_coord) + get_compl_dim(tile, get_dim), + get_compl_coord(it, get_coord), + get_compl_coord(it, get_coord) + get_compl_dim(it, get_dim))) { + if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) { + resize(it, tile, dim_offset + coord_offset, + -dim_offset - coord_offset, get_coord, get_dim, orig); + } else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) { + resize(it, tile, 0, coord_offset, get_coord, get_dim, orig); + } } } @@ -342,26 +374,26 @@ bool resize_allowed_horizontal(struct cg_tile *tile, struct cg_tile *parent, int x_offset, int width_offset) { return resize_allowed(tile, parent, x_offset, width_offset, get_x, - get_width); + get_width, tile); } bool resize_allowed_vertical(struct cg_tile *tile, struct cg_tile *parent, int y_offset, int height_offset) { return resize_allowed(tile, parent, y_offset, height_offset, get_y, - get_height); + get_height, tile); } void resize_horizontal(struct cg_tile *tile, struct cg_tile *parent, int x_offset, int width_offset) { - resize(tile, parent, x_offset, width_offset, get_x, get_width); + resize(tile, parent, x_offset, width_offset, get_x, get_width, tile); } void resize_vertical(struct cg_tile *tile, struct cg_tile *parent, int y_offset, int height_offset) { - resize(tile, parent, y_offset, height_offset, get_y, get_height); + resize(tile, parent, y_offset, height_offset, get_y, get_height, tile); } /* hpixs: positiv -> right, negative -> left; vpixs: positiv -> down, negative @@ -615,9 +647,9 @@ keybinding_cycle_tiles(struct cg_server *server, bool reverse) { int keybinding_switch_ws(struct cg_server *server, uint32_t ws) { - if(ws > server->nws) { + if(ws >= server->nws) { wlr_log(WLR_ERROR, - "Requested workspace %u, but only have %u workspaces.", ws, + "Requested workspace %u, but only have %u workspaces.", ws+1, server->nws); return -1; } @@ -683,10 +715,21 @@ keybinding_set_nws(struct cg_server *server, int nws) { struct cg_output *output; wl_list_for_each(output, &server->outputs, link) { for(unsigned int i = nws; i < server->nws; ++i) { + struct cg_view *view, *tmp; + wl_list_for_each_safe(view,tmp, &output->workspaces[i]->views,link) { + wl_list_remove(&view->link); + wl_list_insert(&output->workspaces[nws-1]->views,&view->link); + view->workspace = output->workspaces[nws-1]; + } + wl_list_for_each_safe(view,tmp,&output->workspaces[i]->unmanaged_views,link) { + wl_list_remove(&view->link); + wl_list_insert(&output->workspaces[nws-1]->unmanaged_views,&view->link); + view->workspace = output->workspaces[nws-1]; + } workspace_free(output->workspaces[i]); } - struct cg_workspace **new_workspaces = realloc( - output->workspaces, nws * sizeof(struct cg_workspace *)); + struct cg_workspace **new_workspaces = + realloc(output->workspaces, nws * sizeof(struct cg_workspace *)); if(new_workspaces == NULL) { wlr_log(WLR_ERROR, "Error reallocating memory for workspaces."); return; @@ -699,16 +742,18 @@ keybinding_set_nws(struct cg_server *server, int nws) { } if(output->curr_workspace >= nws) { - output->curr_workspace = nws-1; + output->curr_workspace = nws - 1; } } server->nws = nws; + seat_set_focus(server->seat,server->curr_output->workspaces[server->curr_output->curr_workspace]->focused_tile->view); } void -keybinding_definemode(struct cg_server *server, char* mode) { +keybinding_definemode(struct cg_server *server, char *mode) { int length = 0; - while(server->modes[length++] != NULL); + while(server->modes[length++] != NULL) + ; char **tmp = realloc(server->modes, (length + 1) * sizeof(char *)); if(tmp == NULL) { wlr_log(WLR_ERROR, "Could not allocate memory for storing modes."); @@ -722,11 +767,11 @@ keybinding_definemode(struct cg_server *server, char* mode) { void keybinding_definekey(struct cg_server *server, struct keybinding *kb) { - keybinding_list_push(server->keybindings,kb); + keybinding_list_push(server->keybindings, kb); } void -keybinding_set_background(struct cg_server *server, float* bg) { +keybinding_set_background(struct cg_server *server, float *bg) { server->bg_color[0] = bg[0]; server->bg_color[1] = bg[1]; server->bg_color[2] = bg[2]; @@ -871,7 +916,7 @@ run_action(enum keybinding_action action, struct cg_server *server, break; } case KEYBINDING_DEFINEKEY: - keybinding_definekey(server,data.kb); + keybinding_definekey(server, data.kb); break; case KEYBINDING_BACKGROUND: keybinding_set_background(server, data.color); From 14a15feebbe676efd97c270597a91fabce2e108d Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 10:07:24 +0100 Subject: [PATCH 10/13] Ameliorate fuzzing process --- fuzz/execl_override.c | 28 ++- fuzz/fuzz-parse.c | 443 ++++++++++++++++++++++++++++++++++++++---- fuzz/meson.build | 1 + message.c | 6 +- 4 files changed, 428 insertions(+), 50 deletions(-) diff --git a/fuzz/execl_override.c b/fuzz/execl_override.c index 281282f..8ce707b 100644 --- a/fuzz/execl_override.c +++ b/fuzz/execl_override.c @@ -1,11 +1,29 @@ /* This file is used by the fuzzer in order to prevent executing shell commands. */ #define _GNU_SOURCE -#include - -struct tm *(*orig_localtime)(const time_t *timep); +#include +#include "../output.h" +#include +#include +#include int -execl(const char *pathname, const char *arg, ...) { - return 0; +fork() { + return 1; +} + +void wlr_texture_get_size(struct wlr_texture *texture, int *width, + int *height) { + if(width != NULL) { + *width=0; + } + + if(height != NULL) { + *height=0; + } +} + +cairo_surface_t* +cairo_image_surface_create(cairo_format_t fmt, int width, int height) { + return NULL; } diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 257f289..746e459 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -1,75 +1,410 @@ -#define _POSIX_C_SOURCE 200812L -#define FUZZING +/* + * Cagebreak: A Wayland tiling compositor. + * + * Copyright (C) 2018-2020 Jente Hidskes + * + * See the LICENSE file accompanying this file. + */ -#include "../keybinding.h" -#include "../parse.h" -#include "../seat.h" -#include "../server.h" -#include +#define _POSIX_C_SOURCE 200812L + +#include "config.h" + +#include +#include #include +#include #include #include #include #include + +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if CG_HAS_XWAYLAND +#include +#endif +#include +#include +#include +#include +#if CG_HAS_XWAYLAND +#include +#endif + +#include "idle_inhibit_v1.h" +#include "keybinding.h" +#include "message.h" +#include "output.h" +#include "workspace.h" +#include "parse.h" +#include "seat.h" +#include "server.h" +#include "view.h" +#include "xdg_shell.h" +#if CG_HAS_XWAYLAND +#include "xwayland.h" +#endif #ifndef WAIT_ANY #define WAIT_ANY -1 #endif -void -set_sig_handler(int sig) { - struct sigaction sa; - sa.sa_handler = SIG_IGN; // handle signal by ignoring - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if(sigaction(SIGCHLD, &sa, 0) == -1) { - perror(0); - exit(1); +static bool +drop_permissions(void) { + if(getuid() != geteuid() || getgid() != getegid()) { + if(setuid(getuid()) != 0 || setgid(getgid()) != 0) { + wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); + return false; + } } + + if(setuid(0) != -1) { + wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " + "restore it after setuid), refusing to start"); + return false; + } + + return true; } -struct cg_server server; +static bool +parse_args(struct cg_server *server, int argc, char *argv[]) { + server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; + server->debug_damage_tracking = false; + return true; +} + +struct cg_server server = {0}; +struct wlr_xwayland *xwayland = NULL; +#if CG_HAS_XWAYLAND +struct wlr_xcursor_manager *xcursor_manager = NULL; +#endif + +void +cleanup() { + server.running = false; +#if CG_HAS_XWAYLAND + if(xwayland != NULL) { + wlr_xwayland_destroy(xwayland); + } + if(xcursor_manager != NULL) { + wlr_xcursor_manager_destroy(xcursor_manager); + } +#endif + wl_display_destroy_clients(server.wl_display); + + for(unsigned int i = 0; server.modes[i] != NULL; ++i) { + free(server.modes[i]); + } + free(server.modes); + + keybinding_list_free(server.keybindings); + + seat_destroy(server.seat); + /* This function is not null-safe, but we only ever get here + with a proper wl_display. */ + wl_display_destroy(server.wl_display); + wlr_output_layout_destroy(server.output_layout); +} int LLVMFuzzerInitialize(int *argc, char ***argv) { - set_sig_handler(SIGCHLD); + struct wl_event_loop *event_loop = NULL; + struct wlr_backend *backend = NULL; + struct wlr_renderer *renderer = NULL; + struct wlr_compositor *compositor = NULL; + struct wlr_data_device_manager *data_device_manager = NULL; + struct wlr_server_decoration_manager *server_decoration_manager = NULL; + struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; + struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL; + struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; + struct wlr_xdg_output_manager_v1 *output_manager = NULL; + struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + struct wlr_xdg_shell *xdg_shell = NULL; + int ret = 0; - server.wl_display = NULL; - server.event_loop = NULL; + if(!parse_args(&server, *argc, *argv)) { + return 1; + } - server.seat = malloc(sizeof(struct cg_seat)); - server.seat->mode = 0; - server.seat->default_mode = 0; +#ifdef DEBUG + wlr_log_init(WLR_DEBUG, NULL); +#else + wlr_log_init(WLR_ERROR, NULL); +#endif - server.idle = NULL; - server.idle_inhibit_v1 = NULL; - /* new_idle_inhibitor_v1 */ - wl_list_init(&server.inhibitors); + /* Wayland requires XDG_RUNTIME_DIR to be set. */ + if(!getenv("XDG_RUNTIME_DIR")) { + wlr_log(WLR_ERROR, "XDG_RUNTIME_DIR is not set in the environment"); + return 1; + } - server.output_layout = NULL; - wl_list_init(&server.outputs); - server.curr_output = NULL; - - /* new_output */ - - /* xdg_toplevel_decoration */ - /* new_xdg_shell_surface */ - /* new_xwayland_surface */ - server.keybindings = keybinding_list_init(); - server.output_transform = 0; + server.wl_display = wl_display_create(); + if(!server.wl_display) { + wlr_log(WLR_ERROR, "Cannot allocate a Wayland display"); + return 1; + } server.running = true; - server.modes = malloc(sizeof(char *)); - server.modes[0] = NULL; + + server.modes = malloc(4 * sizeof(char *)); + server.modes[0] = strdup("top"); + server.modes[1] = strdup("root"); + server.modes[2] = strdup("resize"); + server.modes[3] = NULL; + server.nws = 1; - server.message_timeout = 0; + server.message_timeout = 2; + + event_loop = wl_display_get_event_loop(server.wl_display); + server.event_loop = event_loop; + + backend = wlr_backend_autocreate(server.wl_display, NULL); + if(!backend) { + wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); + ret = 1; + goto end; + } + server.backend = backend; + + if(!drop_permissions()) { + ret = 1; + goto end; + } + + server.keybindings = keybinding_list_init(); + if(server.keybindings == NULL || server.keybindings->keybindings == NULL) { + wlr_log(WLR_ERROR, "Unable to allocate keybindings"); + ret = 1; + goto end; + } + + renderer = wlr_backend_get_renderer(backend); + wlr_renderer_init_wl_display(renderer, server.wl_display); + server.bg_color = malloc(4 * sizeof(float)); server.bg_color[0] = 0; server.bg_color[1] = 0; server.bg_color[2] = 0; server.bg_color[3] = 1; + wl_list_init(&server.outputs); + server.output_layout = wlr_output_layout_create(); + if(!server.output_layout) { + wlr_log(WLR_ERROR, "Unable to create output layout"); + ret = 1; + goto end; + } + + compositor = wlr_compositor_create(server.wl_display, renderer); + if(!compositor) { + wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); + ret = 1; + goto end; + } + + data_device_manager = wlr_data_device_manager_create(server.wl_display); + if(!data_device_manager) { + wlr_log(WLR_ERROR, "Unable to create the data device manager"); + ret = 1; + goto end; + } + + /* Configure a listener to be notified when new outputs are + * available on the backend. We use this only to detect the + * first output and ignore subsequent outputs. */ + server.new_output.notify = handle_new_output; + wl_signal_add(&backend->events.new_output, &server.new_output); + + server.seat = seat_create(&server, backend); + if(!server.seat) { + wlr_log(WLR_ERROR, "Unable to create the seat"); + ret = 1; + goto end; + } + + server.idle = wlr_idle_create(server.wl_display); + if(!server.idle) { + wlr_log(WLR_ERROR, "Unable to create the idle tracker"); + ret = 1; + goto end; + } + + server.idle_inhibit_v1 = wlr_idle_inhibit_v1_create(server.wl_display); + if(!server.idle_inhibit_v1) { + wlr_log(WLR_ERROR, "Cannot create the idle inhibitor"); + ret = 1; + goto end; + } + server.new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1_new; + wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, + &server.new_idle_inhibitor_v1); + wl_list_init(&server.inhibitors); + + xdg_shell = wlr_xdg_shell_create(server.wl_display); + if(!xdg_shell) { + wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); + ret = 1; + goto end; + } + server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; + wl_signal_add(&xdg_shell->events.new_surface, + &server.new_xdg_shell_surface); + + xdg_decoration_manager = + wlr_xdg_decoration_manager_v1_create(server.wl_display); + if(!xdg_decoration_manager) { + wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager"); + ret = 1; + goto end; + } + wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, + &server.xdg_toplevel_decoration); + server.xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; + + server_decoration_manager = + wlr_server_decoration_manager_create(server.wl_display); + if(!server_decoration_manager) { + wlr_log(WLR_ERROR, "Unable to create the server decoration manager"); + ret = 1; + goto end; + } + wlr_server_decoration_manager_set_default_mode( + server_decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + + export_dmabuf_manager = + wlr_export_dmabuf_manager_v1_create(server.wl_display); + if(!export_dmabuf_manager) { + wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); + ret = 1; + goto end; + } + + screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); + if(!screencopy_manager) { + wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); + ret = 1; + goto end; + } + + output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, + server.output_layout); + if(!output_manager) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); + ret = 1; + goto end; + } + + gamma_control_manager = + wlr_gamma_control_manager_v1_create(server.wl_display); + if(!gamma_control_manager) { + wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); + ret = 1; + goto end; + } + +#if CG_HAS_XWAYLAND + xwayland = wlr_xwayland_create(server.wl_display, compositor, true); + if(!xwayland) { + wlr_log(WLR_ERROR, "Cannot create XWayland server"); + ret = 1; + goto end; + } + server.new_xwayland_surface.notify = handle_xwayland_surface_new; + wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); + + xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); + if(!xcursor_manager) { + wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); + ret = 1; + goto end; + } + + if(setenv("DISPLAY", xwayland->display_name, true) < 0) { + wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland.", + "Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, "XWayland is running on display %s", + xwayland->display_name); + } + + if(wlr_xcursor_manager_load(xcursor_manager, 1)) { + wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); + } + struct wlr_xcursor *xcursor = + wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); + if(xcursor) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, + image->hotspot_y); + } +#endif + + const char *socket = wl_display_add_socket_auto(server.wl_display); + if(!socket) { + wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket"); + ret = 1; + goto end; + } + + if(!wlr_backend_start(backend)) { + wlr_log(WLR_ERROR, "Unable to start the wlroots backend"); + ret = 1; + goto end; + } + + if(setenv("WAYLAND_DISPLAY", socket, true) < 0) { + wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.", + "Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, + "Cagebreak " CG_VERSION " is running on Wayland display %s", + socket); + } + +#if CG_HAS_XWAYLAND + wlr_xwayland_set_seat(xwayland, server.seat->seat); +#endif + + /* Place the cursor to the topl left of the output layout. */ + wlr_cursor_warp(server.seat->cursor, NULL, 0, 0); + atexit(cleanup); + return 0; +end: + cleanup(); + return ret; +} + +/* Parse config file. Lines longer than "max_line_size" are ignored */ +int +set_configuration(struct cg_server *server, char *content) { + char *line; + for(unsigned int line_num = 1; + (line = strtok_r(NULL, "\n", &content)) != NULL; ++line_num) { + line[strcspn(line, "\n")] = '\0'; + if(*line != '\0' && *line != '#') { + if(parse_rc_line(server, line) != 0) { + return -1; + } + } + } return 0; } @@ -78,9 +413,33 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *str = malloc(size * sizeof(char) + 1); strncpy(str, (char *)data, size); str[size] = 0; - parse_rc_line(&server, str); + set_configuration(&server, str); free(str); keybinding_list_free(server.keybindings); server.keybindings = keybinding_list_init(); + run_action(KEYBINDING_WORKSPACES, &server, + (union keybinding_params){.i = 1}); + run_action(KEYBINDING_LAYOUT_FULLSCREEN, &server, + (union keybinding_params){.c = NULL}); + wl_display_flush_clients(server.wl_display); + wl_display_destroy_clients(server.wl_display); + struct cg_output* output; + wl_list_for_each(output, &server.outputs, link) { + message_clear(output); + struct cg_view *view; + wl_list_for_each(view, &(*output->workspaces)->views, link) { + view_unmap(view); + view_destroy(view); + } + wl_list_for_each(view, &(*output->workspaces)->unmanaged_views, link) { + view_unmap(view); + view_destroy(view); + } + } + for(unsigned int i = 3; server.modes[i] != NULL; ++i) { + free(server.modes[i]); + } + server.modes[3] = NULL; + server.modes = realloc(server.modes, 4 * sizeof(char *)); return 0; } diff --git a/fuzz/meson.build b/fuzz/meson.build index 0266717..8ff982a 100644 --- a/fuzz/meson.build +++ b/fuzz/meson.build @@ -17,6 +17,7 @@ endif override_lib = shared_library('execl_override', [ 'execl_override.c' ], + dependencies: [ pixman,cairo,pango,pangocairo ], install: false ) diff --git a/message.c b/message.c index c41e1a4..40ac033 100644 --- a/message.c +++ b/message.c @@ -45,13 +45,13 @@ create_message_texture(const char *string, const struct cg_output *output) { // Therefore, we cannot use cairo_create(NULL). cairo_surface_t *dummy_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); - cairo_t *c = cairo_create(dummy_surface); - // This occurs when we are fuzzing. In that case, do nothing - if(c == NULL) { + if(dummy_surface == NULL) { return NULL; } + cairo_t *c = cairo_create(dummy_surface); + cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); From 9363a59b95d2a97f8451fa5a061d5a082d7ffad4 Mon Sep 17 00:00:00 2001 From: project-repo Date: Sat, 21 Mar 2020 14:31:06 +0100 Subject: [PATCH 11/13] Apply clang-format --- cagebreak.c | 4 ++-- fuzz/execl_override.c | 12 ++++++------ fuzz/fuzz-parse.c | 4 ++-- keybinding.c | 23 +++++++++++++++-------- keybinding.h | 10 +++++----- parse.c | 11 ++++++++--- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/cagebreak.c b/cagebreak.c index aeddf84..ba359e5 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -10,11 +10,11 @@ #include "config.h" +#include #include +#include #include #include -#include -#include #include #include #include diff --git a/fuzz/execl_override.c b/fuzz/execl_override.c index 8ce707b..316cf1e 100644 --- a/fuzz/execl_override.c +++ b/fuzz/execl_override.c @@ -1,10 +1,10 @@ /* This file is used by the fuzzer in order to prevent executing shell commands. */ #define _GNU_SOURCE -#include #include "../output.h" #include #include +#include #include int @@ -12,18 +12,18 @@ fork() { return 1; } -void wlr_texture_get_size(struct wlr_texture *texture, int *width, - int *height) { +void +wlr_texture_get_size(struct wlr_texture *texture, int *width, int *height) { if(width != NULL) { - *width=0; + *width = 0; } if(height != NULL) { - *height=0; + *height = 0; } } -cairo_surface_t* +cairo_surface_t * cairo_image_surface_create(cairo_format_t fmt, int width, int height) { return NULL; } diff --git a/fuzz/fuzz-parse.c b/fuzz/fuzz-parse.c index 746e459..24b15cf 100644 --- a/fuzz/fuzz-parse.c +++ b/fuzz/fuzz-parse.c @@ -51,11 +51,11 @@ #include "keybinding.h" #include "message.h" #include "output.h" -#include "workspace.h" #include "parse.h" #include "seat.h" #include "server.h" #include "view.h" +#include "workspace.h" #include "xdg_shell.h" #if CG_HAS_XWAYLAND #include "xwayland.h" @@ -423,7 +423,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { (union keybinding_params){.c = NULL}); wl_display_flush_clients(server.wl_display); wl_display_destroy_clients(server.wl_display); - struct cg_output* output; + struct cg_output *output; wl_list_for_each(output, &server.outputs, link) { message_clear(output); struct cg_view *view; diff --git a/keybinding.c b/keybinding.c index 9bf5734..f6f5eaf 100644 --- a/keybinding.c +++ b/keybinding.c @@ -649,7 +649,7 @@ int keybinding_switch_ws(struct cg_server *server, uint32_t ws) { if(ws >= server->nws) { wlr_log(WLR_ERROR, - "Requested workspace %u, but only have %u workspaces.", ws+1, + "Requested workspace %u, but only have %u workspaces.", ws + 1, server->nws); return -1; } @@ -716,15 +716,19 @@ keybinding_set_nws(struct cg_server *server, int nws) { wl_list_for_each(output, &server->outputs, link) { for(unsigned int i = nws; i < server->nws; ++i) { struct cg_view *view, *tmp; - wl_list_for_each_safe(view,tmp, &output->workspaces[i]->views,link) { + wl_list_for_each_safe(view, tmp, &output->workspaces[i]->views, + link) { wl_list_remove(&view->link); - wl_list_insert(&output->workspaces[nws-1]->views,&view->link); - view->workspace = output->workspaces[nws-1]; + wl_list_insert(&output->workspaces[nws - 1]->views, + &view->link); + view->workspace = output->workspaces[nws - 1]; } - wl_list_for_each_safe(view,tmp,&output->workspaces[i]->unmanaged_views,link) { + wl_list_for_each_safe( + view, tmp, &output->workspaces[i]->unmanaged_views, link) { wl_list_remove(&view->link); - wl_list_insert(&output->workspaces[nws-1]->unmanaged_views,&view->link); - view->workspace = output->workspaces[nws-1]; + wl_list_insert(&output->workspaces[nws - 1]->unmanaged_views, + &view->link); + view->workspace = output->workspaces[nws - 1]; } workspace_free(output->workspaces[i]); } @@ -746,7 +750,10 @@ keybinding_set_nws(struct cg_server *server, int nws) { } } server->nws = nws; - seat_set_focus(server->seat,server->curr_output->workspaces[server->curr_output->curr_workspace]->focused_tile->view); + seat_set_focus( + server->seat, + server->curr_output->workspaces[server->curr_output->curr_workspace] + ->focused_tile->view); } void diff --git a/keybinding.h b/keybinding.h index 42ad114..24f8af2 100644 --- a/keybinding.h +++ b/keybinding.h @@ -44,10 +44,10 @@ enum keybinding_action { KEYBINDING_FOCUS_TOP, KEYBINDING_FOCUS_BOTTOM, - KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition - KEYBINDING_BACKGROUND, //data.color is the background color - KEYBINDING_DEFINEMODE, //data.c is the mode name - KEYBINDING_WORKSPACES, //data.i is the number of workspaces + KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition + KEYBINDING_BACKGROUND, // data.color is the background color + KEYBINDING_DEFINEMODE, // data.c is the mode name + KEYBINDING_WORKSPACES, // data.i is the number of workspaces }; union keybinding_params { @@ -56,7 +56,7 @@ union keybinding_params { int32_t i; bool b; float color[3]; - struct keybinding* kb; + struct keybinding *kb; }; struct keybinding { diff --git a/parse.c b/parse.c index 5b0ac6e..cb6abe3 100644 --- a/parse.c +++ b/parse.c @@ -262,7 +262,10 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - wlr_log(WLR_ERROR, "Workspace number must be a integer number larger or equal to 1. Got %ld", ws); + wlr_log(WLR_ERROR, + "Workspace number must be a integer number larger or equal " + "to 1. Got %ld", + ws); return -1; } keybinding->data.u = ws - 1; @@ -277,8 +280,10 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, long ws = strtol(nws_str, NULL, 10); if(ws < 1) { - wlr_log( - WLR_ERROR, "Workspace number must be an integer larger or equal to 1. Got %ld", ws); + wlr_log(WLR_ERROR, + "Workspace number must be an integer larger or equal to 1. " + "Got %ld", + ws); return -1; } keybinding->data.u = ws - 1; From 4bdc2640a74ff66413ba3814fb3281f88f19017a Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 29 Mar 2020 11:47:44 +0000 Subject: [PATCH 12/13] Merge 1.0.6 for compatibility testing --- Bugs.md | 29 +++++ README.md | 48 ++++++-- meson.build | 74 +++++++----- meson_options.txt | 1 + seat.c | 243 ++++++++++----------------------------- seat.h | 23 ++-- signatures/cagebreak.sig | Bin 0 -> 566 bytes view.c | 12 +- 8 files changed, 194 insertions(+), 236 deletions(-) create mode 100644 signatures/cagebreak.sig diff --git a/Bugs.md b/Bugs.md index 90758b8..491d2c6 100644 --- a/Bugs.md +++ b/Bugs.md @@ -26,3 +26,32 @@ Steps to reproduce: * enter text into the "Tags" field * if autocompletion of tags pops up, the keyboard will not enter further keystrokes into the text field + +### Issue 2 + + * Github issue number: N/A + * Fixed: 1.0.4 + +This issue fixes wrong consumption of modifier key on some keyboards. + +### Issue 3 + + * github issue number: N/A + * Fixed: 1.0.5 + +This issue is a bug causing crashes in cagebreak under specific circumstances. + +Steps to reproduce: + + * start cagebreak + * vertical split + * open a terminal on the left pane + * open firefox on the right pane + * focus the left pane + * close the terminal + * close firefox using the mouse while keeping focus on the left pane + * this causes a crash with the following error message: + +``` +(EE) failed to read Wayland events: Broken pipe +``` diff --git a/README.md b/README.md index 8117d1f..c793ac0 100644 --- a/README.md +++ b/README.md @@ -74,13 +74,19 @@ it is merged into `master`, creating a new release, which is tagged and signed. Merging into master is always done by ``` -git merge --no-ff development -git tag -u keyid version -git push origin master +git checkout development +git pull origin development +git checkout master +git merge --squash development +git tag -u keyid version HEAD +git tag -v version +git push --tags origin master ``` and a log message roughly describing the features is added in the commit. +In the past, our git history did not always reflect this scheme. + ### Releases Release checklist @@ -99,6 +105,8 @@ Release checklist * [ ] wiki * [ ] Changelog in README * [ ] Document fixed bugs in Bugs.md + * [ ] Update hashes of the binary + * [ ] Update signature of the binary * [ ] Signature * [ ] Branching Strategy @@ -120,10 +128,36 @@ The full public keys can be found in `keys/` along with any revocation certifica ### Reproducible Builds -Currently our project seems to build the same way on any given system, when compiled -multiple times. However, at the moment we are unable to supply instructions -for building our software reproducibly. Reproducible builds are planned for the -near future. +Cagebreak offers reproducible builds given the exact library versions specified +in `meson.build`. Should a version mismatch occur, a warning will be emitted. We have +decided on this compromise to allow flexibility and security. In general we will +adapt the versions to the packages available under archlinux at the time of +release. + +#### Reproducible Build Instructions + +All hashes and signatures are provided for the following build instructions. + +``` +meson build -Dxwayland=true --buildtype=release +ninja -C build +``` + +#### Hashes for Builds + +For every release after 1.0.5, hashes will be provided. + +1.0.6 + + * sha 256: 712ae9a8f17a9e589e108f0d503da203cc5eaf1c4a6ca6efb5b4c83b432ce0b8 + * sha 512: d574003023a00cfd6623aac986a5a7f397cfd0bc9114017629a8c72731b0df3977c4a31768502dfa8a6607be06930089b2ccf6ffca9b5bcd1096b7ca0aede226 + +#### GPG Signatures + +For every release after 1.0.5, a GPG signature will be provided in `signatures`. + +The current signature is called `cagebreak.sig`, whereas all older signatures +will be named after their release version. ### Fuzzing diff --git a/meson.build b/meson.build index 9904430..a65d0b6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.2', + version: '1.0.6', license: 'MIT', default_options: [ 'c_std=c11', @@ -101,18 +101,10 @@ else have_xwayland = false endif -version = '@0@'.format(meson.project_version()) -git = find_program('git', native: true, required: false) -if git.found() - git_commit = run_command([git, 'rev-parse', '--short', 'HEAD']) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD']) - if git_commit.returncode() == 0 and git_branch.returncode() == 0 - version = '@0@-@1@ (branch \'@2@\')'.format( - meson.project_version(), - git_commit.stdout().strip(), - git_branch.stdout().strip(), - ) - endif +if get_option('version_override') != '' + version = '@0@'.format(get_option('version_override')) +else + version = '@0@'.format(meson.project_version()) endif conf_data = configuration_data() @@ -173,21 +165,49 @@ endforeach foreach header : cagebreak_header_strings cagebreak_headers += files(header) endforeach +cagebreak_dependencies_dict = { + 'server_protos': server_protos, + 'wayland_server': wayland_server, + 'wayland_client': wayland_client, + 'wayland_cursor': wayland_cursor, + 'wlroots': wlroots, + 'xkbcommon': xkbcommon, + 'fontconfig': fontconfig, + 'pixman': pixman, + 'pango': pango, + 'cairo': cairo, + 'pangocairo': pangocairo, + 'math': math +} -cagebreak_dependencies = [ - server_protos, - wayland_server, - wayland_client, - wayland_cursor, - wlroots, - xkbcommon, - fontconfig, - pixman, - math, - pango, - cairo, - pangocairo, -] +reproducible_build_versions = { + 'server_protos': '1.0.6', + 'wayland_server': '1.18.0', + 'wayland_client': '1.18.0', + 'wayland_cursor': '1.18.0', + 'wlroots': '0.10.1', + 'xkbcommon': '0.10.0', + 'fontconfig': '2.13.91', + 'pixman': '0.38.4', + 'pango': '1.44.7', + 'cairo': '1.17.3', + 'pangocairo': '1.44.7', + 'math': '-1' +} + +cagebreak_dependencies = [] + +foreach name, dep : cagebreak_dependencies_dict + cagebreak_dependencies += dep +endforeach + +foreach name, dep : cagebreak_dependencies_dict + if reproducible_build_versions[name] != '-1' and reproducible_build_versions[name] != dep.version() + warning('The installed version of "' + name + '" on your machine (' + dep.version() + ') differs from the one used to generate the binary specified in the README section "Reproducible Builds" (' + reproducible_build_versions[name] + '). Cagebreak does not guarantee a reproducible build for this configuration.' + ) + break + endif +endforeach executable( meson.project_name(), diff --git a/meson_options.txt b/meson_options.txt index 5982c3d..bb96c4f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,3 @@ option('xwayland', type: 'boolean', value: 'false', description: 'Enable support for X11 applications') option('fuzz', type: 'boolean', value: 'false', description: 'Enable building fuzzer targets') +option('version_override', type: 'string', description: 'Set the project version to the string specified. Used for creating hashes for reproducible builds.') diff --git a/seat.c b/seat.c index 57c2b04..7567586 100644 --- a/seat.c +++ b/seat.c @@ -112,7 +112,7 @@ static void update_capabilities(const struct cg_seat *seat) { uint32_t caps = 0; - if(!wl_list_empty(&seat->keyboards)) { + if(!wl_list_empty(&seat->keyboard_groups)) { caps |= WL_SEAT_CAPABILITY_KEYBOARD; } if(!wl_list_empty(&seat->pointers)) { @@ -216,41 +216,41 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) { static int handle_keyboard_repeat(void *data) { - struct cg_keyboard *keyboard = (struct cg_keyboard *)data; - struct wlr_keyboard *wlr_device = keyboard->device->keyboard; - if(keyboard->repeat_keybinding != NULL) { + struct cg_keyboard_group *cg_group = data; + struct wlr_keyboard *wlr_device = + cg_group->wlr_group->input_device->keyboard; + if(cg_group->repeat_keybinding != NULL) { if(wlr_device->repeat_info.rate > 0) { if(wl_event_source_timer_update( - keyboard->key_repeat_timer, + cg_group->key_repeat_timer, 1000 / wlr_device->repeat_info.rate) < 0) { wlr_log(WLR_DEBUG, "failed to update key repeat timer"); } } - run_action((*keyboard->repeat_keybinding)->action, - keyboard->seat->server, - (*keyboard->repeat_keybinding)->data); + run_action((*cg_group->repeat_keybinding)->action, + cg_group->seat->server, + (*cg_group->repeat_keybinding)->data); } return 0; } static void -handle_modifier_event(struct cg_keyboard *keyboard) { - wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); - wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat, - &keyboard->device->keyboard->modifiers); +handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) { + wlr_seat_set_keyboard(seat->seat, device); + wlr_seat_keyboard_notify_modifiers(seat->seat, + &device->keyboard->modifiers); - wlr_idle_notify_activity(keyboard->seat->server->idle, - keyboard->seat->seat); + wlr_idle_notify_activity(seat->server->idle, seat->seat); } void -keyboard_disarm_key_repeat(struct cg_keyboard *keyboard) { - if(!keyboard) { +keyboard_disarm_key_repeat(struct cg_keyboard_group *group) { + if(!group) { return; } - keyboard->repeat_keybinding = NULL; - if(wl_event_source_timer_update(keyboard->key_repeat_timer, 0) < 0) { + group->repeat_keybinding = NULL; + if(wl_event_source_timer_update(group->key_repeat_timer, 0) < 0) { wlr_log(WLR_DEBUG, "failed to disarm key repeat timer"); } } @@ -258,7 +258,7 @@ keyboard_disarm_key_repeat(struct cg_keyboard *keyboard) { static bool handle_command_key_bindings(struct cg_server *server, xkb_keysym_t sym, uint32_t modifiers, uint32_t mode, - struct cg_keyboard *keyboard) { + struct cg_keyboard_group *group) { struct keybinding **keybinding = find_keybinding( server->keybindings, &(struct keybinding){.key = sym, .mode = mode, .modifiers = modifiers}); @@ -271,15 +271,16 @@ handle_command_key_bindings(struct cg_server *server, xkb_keysym_t sym, "Recognized keybinding pressed (key: %d, mode: %d, modifiers: %d)", sym, mode, modifiers); - if(keyboard->device->keyboard->repeat_info.delay > 0) { - keyboard->repeat_keybinding = keybinding; - if(wl_event_source_timer_update( - keyboard->key_repeat_timer, - keyboard->device->keyboard->repeat_info.delay) < 0) { + if(group->wlr_group->input_device->keyboard->repeat_info.delay > 0) { + group->repeat_keybinding = keybinding; + if(wl_event_source_timer_update(group->key_repeat_timer, + group->wlr_group->input_device + ->keyboard->repeat_info.delay) < + 0) { wlr_log(WLR_DEBUG, "failed to set key repeat timer"); } } - message_clear(keyboard->seat->server->curr_output); + message_clear(group->seat->server->curr_output); run_action((*keybinding)->action, server, (*keybinding)->data); wlr_idle_notify_activity(server->idle, server->seat->seat); return true; @@ -315,42 +316,42 @@ key_is_modifier(const xkb_keysym_t key) { } static void -handle_key_event(struct cg_keyboard *keyboard, void *data) { - struct cg_seat *seat = keyboard->seat; +handle_key_event(struct cg_keyboard_group *group, struct cg_seat *seat, + void *data) { struct wlr_event_keyboard_key *event = data; + struct wlr_input_device *device = group->wlr_group->input_device; /* Translate from libinput keycode to an xkbcommon keycode. */ xkb_keycode_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, - keycode, &syms); + int nsyms = + xkb_state_key_get_syms(device->keyboard->xkb_state, keycode, &syms); bool handled = false; for(int i = 0; i < nsyms; ++i) { if(event->state == WLR_KEY_PRESSED && !key_is_modifier(syms[i])) { - uint32_t modifiers = - wlr_keyboard_get_modifiers(keyboard->device->keyboard); + uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); /* Get the consumed_modifiers and remove them from the modifier list */ xkb_mod_mask_t consumed_modifiers = - xkb_state_key_get_consumed_mods2( - keyboard->device->keyboard->xkb_state, keycode, - XKB_CONSUMED_MODE_XKB); + xkb_state_key_get_consumed_mods2(device->keyboard->xkb_state, + keycode, + XKB_CONSUMED_MODE_GTK); if(handle_command_key_bindings(seat->server, syms[i], modifiers & ~consumed_modifiers, - seat->mode, keyboard)) { + seat->mode, group)) { handled = true; } - } else if(keyboard->repeat_keybinding != NULL && handled == false) { - keyboard_disarm_key_repeat(keyboard); + } else if(group->repeat_keybinding != NULL && handled == false) { + keyboard_disarm_key_repeat(group); } } if(!handled) { /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat->seat, keyboard->device); + wlr_seat_set_keyboard(seat->seat, device); wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); } @@ -358,130 +359,28 @@ handle_key_event(struct cg_keyboard *keyboard, void *data) { wlr_idle_notify_activity(seat->server->idle, seat->seat); } -static void -cg_keyboard_group_remove(struct cg_keyboard *keyboard); - -static void -cg_keyboard_destroy(struct cg_keyboard *keyboard) { - struct cg_seat *seat = keyboard->seat; - - if(keyboard->device->keyboard->group != NULL) { - cg_keyboard_group_remove(keyboard); - } - - if(wlr_seat_get_keyboard(seat->seat) == keyboard->device->keyboard) { - wlr_seat_set_keyboard(seat->seat, NULL); - } - - keyboard_disarm_key_repeat(keyboard); - wl_event_source_remove(keyboard->key_repeat_timer); - - free(keyboard); -} - -static void -destroy_empty_wlr_keyboard_group(void *data) { - wlr_keyboard_group_destroy(data); -} - -static void -cg_keyboard_group_remove(struct cg_keyboard *keyboard) { - struct wlr_keyboard_group *wlr_group = keyboard->device->keyboard->group; - - wlr_keyboard_group_remove_keyboard(keyboard->device->keyboard->group, - keyboard->device->keyboard); - - if(wl_list_empty(&wlr_group->devices)) { - wlr_log(WLR_DEBUG, "Destroying empty keyboard group %p", - (void *)wlr_group); - struct cg_keyboard_group *cg_group = wlr_group->data; - wlr_group->data = NULL; - wl_list_remove(&cg_group->link); - wl_list_remove(&cg_group->key.link); - wl_list_remove(&cg_group->modifiers.link); - cg_keyboard_destroy(cg_group->keyboard); - free(cg_group); - - // To prevent use-after-free conditions when handling key events, defer - // freeing the wlr_keyboard_group until idle - if(keyboard->seat->server->running) { - wl_event_loop_add_idle(keyboard->seat->server->event_loop, - destroy_empty_wlr_keyboard_group, wlr_group); - } else { - destroy_empty_wlr_keyboard_group(wlr_group); - } - } -} - -static void -handle_keyboard_destroy(struct wl_listener *listener, void *_data) { - struct cg_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); - struct cg_seat *seat = keyboard->seat; - wl_list_remove(&keyboard->link); - wl_list_remove(&keyboard->destroy.link); - cg_keyboard_destroy(keyboard); - update_capabilities(seat); -} - static void handle_keyboard_group_key(struct wl_listener *listener, void *data) { struct cg_keyboard_group *cg_group = wl_container_of(listener, cg_group, key); - handle_key_event(cg_group->keyboard, data); + handle_key_event(cg_group, cg_group->seat, data); } static void handle_keyboard_group_modifiers(struct wl_listener *listener, void *_data) { struct cg_keyboard_group *group = wl_container_of(listener, group, modifiers); - handle_modifier_event(group->keyboard); -} - -static bool -keymaps_match(struct xkb_keymap *km1, struct xkb_keymap *km2) { - char *km1_str = xkb_keymap_get_as_string(km1, XKB_KEYMAP_FORMAT_TEXT_V1); - char *km2_str = xkb_keymap_get_as_string(km2, XKB_KEYMAP_FORMAT_TEXT_V1); - bool result = strcmp(km1_str, km2_str) == 0; - free(km1_str); - free(km2_str); - return result; -} - -static bool -repeat_info_match(const struct cg_keyboard *a, const struct wlr_keyboard *b) { - return a->device->keyboard->repeat_info.rate == b->repeat_info.rate && - a->device->keyboard->repeat_info.delay == b->repeat_info.delay; -} - -struct cg_keyboard * -cg_keyboard_from_seat(struct cg_seat *seat, struct wlr_input_device *device) { - struct cg_keyboard *keyboard = calloc(1, sizeof(struct cg_keyboard)); - if(keyboard == NULL) { - wlr_log(WLR_ERROR, "Could not allocate new cg_keyboard."); - return NULL; - } - - keyboard->seat = seat; - keyboard->device = device; - - keyboard->key_repeat_timer = wl_event_loop_add_timer( - seat->server->event_loop, handle_keyboard_repeat, keyboard); - - return keyboard; + handle_modifier_event(group->wlr_group->input_device, group->seat); } static void -keyboard_group_add(const struct cg_keyboard *keyboard) { - struct cg_seat *seat = keyboard->seat; - struct wlr_keyboard *wlr_keyboard = keyboard->device->keyboard; +cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) { + struct wlr_keyboard *wlr_keyboard = device->keyboard; struct cg_keyboard_group *group; wl_list_for_each(group, &seat->keyboard_groups, link) { struct wlr_keyboard_group *wlr_group = group->wlr_group; - if(keymaps_match(wlr_keyboard->keymap, wlr_group->keyboard.keymap) && - repeat_info_match(keyboard, &wlr_group->keyboard)) { - wlr_log(WLR_DEBUG, "Adding keyboard %p to group %p.", - (void *)keyboard, (void *)wlr_group); - wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard); + if(wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard)) { + wlr_log(WLR_DEBUG, "Adding keyboard to existing group."); return; } } @@ -493,6 +392,7 @@ keyboard_group_add(const struct cg_keyboard *keyboard) { wlr_log(WLR_ERROR, "Failed to allocate keyboard group."); return; } + cg_group->seat = seat; cg_group->wlr_group = wlr_keyboard_group_create(); if(cg_group->wlr_group == NULL) { wlr_log(WLR_ERROR, "Failed to create wlr keyboard group."); @@ -501,22 +401,12 @@ keyboard_group_add(const struct cg_keyboard *keyboard) { cg_group->wlr_group->data = cg_group; wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, - keyboard->device->keyboard->keymap); + device->keyboard->keymap); wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, - keyboard->device->keyboard->repeat_info.rate, - keyboard->device->keyboard->repeat_info.delay); - wlr_log(WLR_DEBUG, "Created keyboard group %p", - (void *)cg_group->wlr_group); + device->keyboard->repeat_info.rate, + device->keyboard->repeat_info.delay); + wlr_log(WLR_DEBUG, "Created keyboard group."); - cg_group->keyboard = - cg_keyboard_from_seat(seat, cg_group->wlr_group->input_device); - if(cg_group->keyboard == NULL) { - wlr_log(WLR_ERROR, "Failed to create keyboard from seat."); - goto cleanup; - } - - wlr_log(WLR_DEBUG, "Adding keyboard %p to group %p.", (void *)keyboard, - (void *)cg_group->wlr_group); wlr_keyboard_group_add_keyboard(cg_group->wlr_group, wlr_keyboard); wl_list_insert(&seat->keyboard_groups, &cg_group->link); @@ -525,6 +415,10 @@ keyboard_group_add(const struct cg_keyboard *keyboard) { wl_signal_add(&cg_group->wlr_group->keyboard.events.modifiers, &cg_group->modifiers); + + cg_group->key_repeat_timer = wl_event_loop_add_timer( + seat->server->event_loop, handle_keyboard_repeat, cg_group); + cg_group->modifiers.notify = handle_keyboard_group_modifiers; return; @@ -537,16 +431,9 @@ cleanup: static void handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) { - struct cg_keyboard *keyboard = calloc(1, sizeof(struct cg_keyboard)); - if(!keyboard) { - wlr_log(WLR_ERROR, "Cannot allocate keyboard"); - return; - } - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if(!context) { wlr_log(WLR_ERROR, "Unable to create XBK context"); - free(keyboard); return; } @@ -561,28 +448,19 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) { if(!keymap) { wlr_log(WLR_ERROR, "Unable to configure keyboard: keymap does not exist"); - free(keyboard); xkb_context_unref(context); return; } - keyboard->seat = seat; - keyboard->device = device; wlr_keyboard_set_keymap(device->keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); - keyboard_group_add(keyboard); + cg_keyboard_group_add(device, seat); - wlr_seat_set_keyboard(seat->seat, device->keyboard->group->input_device); - - wl_list_insert(&seat->keyboards, &keyboard->link); - keyboard->destroy.notify = handle_keyboard_destroy; - wl_signal_add(&device->events.destroy, &keyboard->destroy); - keyboard->key_repeat_timer = wl_event_loop_add_timer( - seat->server->event_loop, handle_keyboard_repeat, keyboard); + wlr_seat_set_keyboard(seat->seat, device); } static void @@ -914,9 +792,11 @@ handle_destroy(struct wl_listener *listener, void *_data) { struct cg_seat *seat = wl_container_of(listener, seat, destroy); wl_list_remove(&seat->destroy.link); - struct cg_keyboard *keyboard, *keyboard_tmp; - wl_list_for_each_safe(keyboard, keyboard_tmp, &seat->keyboards, link) { - handle_keyboard_destroy(&keyboard->destroy, NULL); + struct cg_keyboard_group *group, *group_tmp; + wl_list_for_each_safe(group, group_tmp, &seat->keyboard_groups, link) { + wlr_keyboard_group_destroy(group->wlr_group); + wl_event_source_remove(group->key_repeat_timer); + free(group); } struct cg_pointer *pointer, *pointer_tmp; wl_list_for_each_safe(pointer, pointer_tmp, &seat->pointers, link) { @@ -1014,7 +894,6 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) { wl_signal_add(&seat->seat->events.request_set_primary_selection, &seat->request_set_primary_selection); - wl_list_init(&seat->keyboards); wl_list_init(&seat->keyboard_groups); wl_list_init(&seat->pointers); wl_list_init(&seat->touch); diff --git a/seat.h b/seat.h index 7d1d7c7..a7632d7 100644 --- a/seat.h +++ b/seat.h @@ -14,22 +14,11 @@ struct wlr_backend; #define DEFAULT_XCURSOR "left_ptr" #define XCURSOR_SIZE 24 -struct cg_keyboard_group { - struct cg_keyboard *keyboard; - - struct wlr_keyboard_group *wlr_group; - struct cg_seat *seat; - struct wl_listener key; - struct wl_listener modifiers; - struct wl_list link; -}; - struct cg_seat { struct wlr_seat *seat; struct cg_server *server; struct wl_listener destroy; - struct wl_list keyboards; struct wl_list keyboard_groups; struct wl_list pointers; struct wl_list touch; @@ -66,14 +55,16 @@ struct cg_seat { struct cg_view *focused_view; }; -struct cg_keyboard { - struct wl_list link; // seat::keyboards +struct cg_keyboard_group { + struct wlr_keyboard_group *wlr_group; struct cg_seat *seat; - struct wlr_input_device *device; - struct wl_listener destroy; - struct keybinding **repeat_keybinding; + struct wl_listener key; + struct wl_listener modifiers; + struct wl_list link; + struct wl_event_source *key_repeat_timer; + struct keybinding **repeat_keybinding; }; struct cg_pointer { diff --git a/signatures/cagebreak.sig b/signatures/cagebreak.sig new file mode 100644 index 0000000000000000000000000000000000000000..3a641bee171da79f5d93fc627d5230d0786eb715 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-ZpKYEIH7WG5|K!!g`E=I|>?~Ua0$zY^*8mC$5XAX( z*9`0|Tc$z}|64$gG`MHKZ=AWaCuyalWsk4kO22O@Vk;D@>@jJuMc1+zpA&G+@{_qV zY9~dDUAwMOK2VHMa&iLO!uOvyglM zhBjpy;1P1#FHLT#7v>lpVVi6Z)1C)>q}@RqNpe^BE8D&&DY2=Mik-G~dS%Sl z0UXfHXw_6n^tAebKouvI4 z_=BR(cP)Ly>xoA^o*f2+Q=qp@z(YPty4N-AOu~Yv{8k&L$Lf7F?L)YbTwZlvADEF0 E$r~dTVE_OC literal 0 HcmV?d00001 diff --git a/view.c b/view.c index acd7603..6b0ed87 100644 --- a/view.c +++ b/view.c @@ -234,10 +234,14 @@ view_unmap(struct cg_view *view) { struct cg_tile *view_tile = view_get_tile(view); wlr_output_damage_add_box(view_tile->workspace->output->damage, &view_tile->tile); - if(view->workspace->server->seat->seat->keyboard_state - .focused_surface == NULL || - view->workspace->server->seat->seat->keyboard_state - .focused_surface == view->wlr_surface) { + if((view->workspace->server->seat->seat->keyboard_state + .focused_surface == NULL || + view->workspace->server->seat->seat->keyboard_state + .focused_surface == view->wlr_surface) && + view->workspace->server->curr_output + ->workspaces[view->workspace->server->curr_output + ->curr_workspace] + ->focused_tile == view_tile) { seat_set_focus(view->workspace->server->seat, prev); } else { view_tile->view = prev; From 9c93e3d4e84bea2eb75591eb90dfe4c5d6bf63cf Mon Sep 17 00:00:00 2001 From: Cagebreak Signing Key 1 Date: Sun, 29 Mar 2020 12:51:26 +0000 Subject: [PATCH 13/13] Prepare for merge --- Bugs.md | 24 ++++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Bugs.md b/Bugs.md index 491d2c6..835fc94 100644 --- a/Bugs.md +++ b/Bugs.md @@ -55,3 +55,27 @@ Steps to reproduce: ``` (EE) failed to read Wayland events: Broken pipe ``` + +### Issue 4 + + github issue number: #1 + Fixed: 1.0.7 + +This issue is code duplication in `parse.c`. + +Github issue text: + +``` +As of right now, the actions which can be run in the config file and the +actions which can be run as a keybinding are parsed separately in `parse.c`. +This leads to a lot of code duplication. Furthermore, unifying these +functionalities would enable a more versatile configuration. For instance, it +would enable the user to write `hsplit` into the configuration file to split +the output on startup and workspace 2 to set the default workspace to +workspace 2. Therefore, this change would simplify the code base, while at +the same time increasing the feature set. + +PS: As a side effect, this would allow quirky statements such as +`bind dbind r hsplit` which would bind the d key to binding the r key to +split the output... +``` diff --git a/meson.build b/meson.build index a65d0b6..e42700b 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cagebreak', 'c', - version: '1.0.6', + version: '1.0.7', license: 'MIT', default_options: [ 'c_std=c11',