X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcfgparse.y;h=9a417f2aba0b54aeb65cd059f9947d756e617c6d;hb=6420b2b102bab214ad0bf1fa0f5e190f02984e82;hp=dc29860cda021f1f23552ed0bfce8cfaf25aa2d6;hpb=67aab7c8bd7bdb2bff5064b14efb1149d7995f55;p=i3%2Fi3 diff --git a/src/cfgparse.y b/src/cfgparse.y index dc29860c..9a417f2a 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -240,6 +240,23 @@ static void nagbar_exited(EV_P_ ev_child *watcher, int revents) { configerror_pid = -1; } +/* We need ev >= 4 for the following code. Since it is not *that* important (it + * only makes sure that there are no i3-nagbar instances left behind) we still + * support old systems with libev 3. */ +#if EV_VERSION_MAJOR >= 4 +/* + * Cleanup handler. Will be called when i3 exits. Kills i3-nagbar with signal + * SIGKILL (9) to make sure there are no left-over i3-nagbar processes. + * + */ +static void nagbar_cleanup(EV_P_ ev_cleanup *watcher, int revent) { + if (configerror_pid != -1) { + LOG("Sending SIGKILL (9) to i3-nagbar with PID %d\n", configerror_pid); + kill(configerror_pid, SIGKILL); + } +} +#endif + /* * Starts an i3-nagbar process which alerts the user that his configuration * file contains one or more errors. Also offers two buttons: One to launch an @@ -259,9 +276,9 @@ static void start_configerror_nagbar(const char *config_path) { if (configerror_pid == 0) { char *editaction, *pageraction; - if (asprintf(&editaction, TERM_EMU " -e sh -c \"${EDITOR:-vi} \"%s\" && i3-msg reload\"", config_path) == -1) + if (asprintf(&editaction, "i3-sensible-terminal -e sh -c \"i3-sensible-editor \\\"%s\\\" && i3-msg reload\"", config_path) == -1) exit(1); - if (asprintf(&pageraction, TERM_EMU " -e sh -c \"${PAGER:-less} \"%s\"\"", errorfilename) == -1) + if (asprintf(&pageraction, "i3-sensible-terminal -e i3-sensible-pager \"%s\"", errorfilename) == -1) exit(1); char *argv[] = { NULL, /* will be replaced by the executable path */ @@ -283,6 +300,17 @@ static void start_configerror_nagbar(const char *config_path) { ev_child *child = smalloc(sizeof(ev_child)); ev_child_init(child, &nagbar_exited, configerror_pid, 0); ev_child_start(main_loop, child); + +/* We need ev >= 4 for the following code. Since it is not *that* important (it + * only makes sure that there are no i3-nagbar instances left behind) we still + * support old systems with libev 3. */ +#if EV_VERSION_MAJOR >= 4 + /* install a cleanup watcher (will be called when i3 exits and i3-nagbar is + * still running) */ + ev_cleanup *cleanup = smalloc(sizeof(ev_cleanup)); + ev_cleanup_init(cleanup, nagbar_cleanup); + ev_cleanup_start(main_loop, cleanup); +#endif } /* @@ -311,6 +339,53 @@ void kill_configerror_nagbar(bool wait_for_it) { waitpid(configerror_pid, NULL, 0); } +/* + * Checks for duplicate key bindings (the same keycode or keysym is configured + * more than once). If a duplicate binding is found, a message is printed to + * stderr and the has_errors variable is set to true, which will start + * i3-nagbar. + * + */ +static void check_for_duplicate_bindings(struct context *context) { + Binding *bind, *current; + TAILQ_FOREACH(current, bindings, bindings) { + TAILQ_FOREACH(bind, bindings, bindings) { + /* Abort when we reach the current keybinding, only check the + * bindings before */ + if (bind == current) + break; + + /* Check if one is using keysym while the other is using bindsym. + * If so, skip. */ + /* XXX: It should be checked at a later place (when translating the + * keysym to keycodes) if there are any duplicates */ + if ((bind->symbol == NULL && current->symbol != NULL) || + (bind->symbol != NULL && current->symbol == NULL)) + continue; + + /* If bind is NULL, current has to be NULL, too (see above). + * If the keycodes differ, it can't be a duplicate. */ + if (bind->symbol != NULL && + strcasecmp(bind->symbol, current->symbol) != 0) + continue; + + /* Check if the keycodes or modifiers are different. If so, they + * can't be duplicate */ + if (bind->keycode != current->keycode || + bind->mods != current->mods) + continue; + context->has_errors = true; + if (current->keycode != 0) { + ELOG("Duplicate keybinding in config file:\n modmask %d with keycode %d, command \"%s\"\n", + current->mods, current->keycode, current->command); + } else { + ELOG("Duplicate keybinding in config file:\n modmask %d with keysym %s, command \"%s\"\n", + current->mods, current->symbol, current->command); + } + } + } +} + void parse_file(const char *f) { SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables); int fd, ret, read_bytes = 0; @@ -472,6 +547,8 @@ void parse_file(const char *f) { exit(1); } + check_for_duplicate_bindings(context); + if (context->has_errors) { start_configerror_nagbar(f); } @@ -539,11 +616,13 @@ void parse_file(const char *f) { %token TOK_AUTO "auto" %token TOK_WORKSPACE_LAYOUT "workspace_layout" %token TOKNEWWINDOW "new_window" +%token TOKNEWFLOAT "new_float" %token TOK_NORMAL "normal" %token TOK_NONE "none" %token TOK_1PIXEL "1pixel" %token TOKFOCUSFOLLOWSMOUSE "focus_follows_mouse" %token TOK_FORCE_FOCUS_WRAPPING "force_focus_wrapping" +%token TOK_FORCE_XINERAMA "force_xinerama" %token TOKWORKSPACEBAR "workspace_bar" %token TOK_DEFAULT "default" %token TOK_STACKING "stacking" @@ -557,6 +636,7 @@ void parse_file(const char *f) { %token TOK_MARK "mark" %token TOK_CLASS "class" %token TOK_INSTANCE "instance" +%token TOK_WINDOW_ROLE "window_role" %token TOK_ID "id" %token TOK_CON_ID "con_id" %token TOK_TITLE "title" @@ -570,6 +650,7 @@ void parse_file(const char *f) { %type layout_mode %type border_style %type new_window +%type new_float %type colorpixel %type bool %type popup_setting @@ -594,8 +675,10 @@ line: | orientation | workspace_layout | new_window + | new_float | focus_follows_mouse | force_focus_wrapping + | force_xinerama | workspace_bar | workspace | assign @@ -706,12 +789,20 @@ criterion: TOK_CLASS '=' STR { printf("criteria: class = %s\n", $3); - current_match.class = $3; + current_match.class = regex_new($3); + free($3); } | TOK_INSTANCE '=' STR { printf("criteria: instance = %s\n", $3); - current_match.instance = $3; + current_match.instance = regex_new($3); + free($3); + } + | TOK_WINDOW_ROLE '=' STR + { + printf("criteria: window_role = %s\n", $3); + current_match.role = regex_new($3); + free($3); } | TOK_CON_ID '=' STR { @@ -746,12 +837,14 @@ criterion: | TOK_MARK '=' STR { printf("criteria: mark = %s\n", $3); - current_match.mark = $3; + current_match.mark = regex_new($3); + free($3); } | TOK_TITLE '=' STR { printf("criteria: title = %s\n", $3); - current_match.title = $3; + current_match.title = regex_new($3); + free($3); } ; @@ -888,6 +981,14 @@ new_window: } ; +new_float: + TOKNEWFLOAT border_style + { + DLOG("new floating windows should start with border style %d\n", $2); + config.default_floating_border = $2; + } + ; + border_style: TOK_NORMAL { $$ = BS_NORMAL; } | TOK_NONE { $$ = BS_NONE; } @@ -926,6 +1027,14 @@ force_focus_wrapping: } ; +force_xinerama: + TOK_FORCE_XINERAMA bool + { + DLOG("force xinerama = %d\n", $2); + config.force_xinerama = $2; + } + ; + workspace_bar: TOKWORKSPACEBAR bool { @@ -1001,6 +1110,13 @@ workspace_name: assign: TOKASSIGN window_class STR { + /* This is the old, deprecated form of assignments. It’s provided for + * compatibility in version (4.1, 4.2, 4.3) and will be removed + * afterwards. It triggers an i3-nagbar warning starting from 4.1. */ + ELOG("You are using the old assign syntax (without criteria). " + "Please see the User's Guide for the new syntax and fix " + "your config file.\n"); + context->has_errors = true; printf("assignment of %s to *%s*\n", $2, $3); char *workspace = $3; char *criteria = $2; @@ -1012,15 +1128,27 @@ assign: char *separator = NULL; if ((separator = strchr(criteria, '/')) != NULL) { *(separator++) = '\0'; - match->title = sstrdup(separator); + char *pattern; + if (asprintf(&pattern, "(?i)%s", separator) == -1) { + ELOG("asprintf failed\n"); + break; + } + match->title = regex_new(pattern); + free(pattern); + printf(" title = %s\n", separator); + } + if (*criteria != '\0') { + char *pattern; + if (asprintf(&pattern, "(?i)%s", criteria) == -1) { + ELOG("asprintf failed\n"); + break; + } + match->class = regex_new(pattern); + free(pattern); + printf(" class = %s\n", criteria); } - if (*criteria != '\0') - match->class = sstrdup(criteria); free(criteria); - printf(" class = %s\n", match->class); - printf(" title = %s\n", match->title); - /* Compatibility with older versions: If the assignment target starts * with ~, we create the equivalent of: * @@ -1048,6 +1176,19 @@ assign: assignment->dest.workspace = workspace; TAILQ_INSERT_TAIL(&assignments, assignment, assignments); } + | TOKASSIGN match STR + { + if (match_is_empty(¤t_match)) { + ELOG("Match is empty, ignoring this assignment\n"); + break; + } + printf("new assignment, using above criteria, to workspace %s\n", $3); + Assignment *assignment = scalloc(sizeof(Assignment)); + assignment->match = current_match; + assignment->type = A_TO_WORKSPACE; + assignment->dest.workspace = $3; + TAILQ_INSERT_TAIL(&assignments, assignment, assignments); + } ; window_class: