X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcfgparse.y;h=2a22aae4ef6bef8197ceb65121bff3dd43bb569b;hb=7be5ece6636f7a4c800ab0c5dd6289b38db7b435;hp=71727c978ae2b722be81fda0170953a62b677fff;hpb=622b94f176c3a6959c13ca2162be673c7b8028c4;p=i3%2Fi3 diff --git a/src/cfgparse.y b/src/cfgparse.y index 71727c97..2a22aae4 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -3,6 +3,8 @@ * vim:ts=4:sw=4:expandtab * */ +#undef I3__FILE__ +#define I3__FILE__ "cfgparse.y" #include #include #include @@ -11,6 +13,8 @@ #include "all.h" +bool force_old_config_parser = false; + static pid_t configerror_pid = -1; static Match current_match; @@ -19,6 +23,9 @@ static Barconfig current_bar; * store this in a separate variable because in the i3 config struct we just * store the i3Font. */ static char *font_pattern; +/* The path to the temporary script files used by i3-nagbar. We need to keep + * them around to delete the files in the i3-nagbar SIGCHLD handler. */ +static char *edit_script_path, *pager_script_path; typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yylex(struct context *context); @@ -51,7 +58,7 @@ void yyerror(const char *error_message) { ELOG("\n"); } -int yywrap() { +int yywrap(void) { return 1; } @@ -103,6 +110,7 @@ static int detect_version(char *buf) { strncasecmp(bind, "focus down", strlen("focus down")) == 0 || strncasecmp(bind, "border normal", strlen("border normal")) == 0 || strncasecmp(bind, "border 1pixel", strlen("border 1pixel")) == 0 || + strncasecmp(bind, "border pixel", strlen("border pixel")) == 0 || strncasecmp(bind, "border borderless", strlen("border borderless")) == 0 || strncasecmp(bind, "--no-startup-id", strlen("--no-startup-id")) == 0 || strncasecmp(bind, "bar", strlen("bar")) == 0) { @@ -233,6 +241,12 @@ static char *migrate_config(char *input, off_t size) { */ static void nagbar_exited(EV_P_ ev_child *watcher, int revents) { ev_child_stop(EV_A_ watcher); + + if (unlink(edit_script_path) != 0) + warn("Could not delete temporary i3-nagbar script %s", edit_script_path); + if (unlink(pager_script_path) != 0) + warn("Could not delete temporary i3-nagbar script %s", pager_script_path); + if (!WIFEXITED(watcher->rstatus)) { fprintf(stderr, "ERROR: i3-nagbar did not exit normally.\n"); return; @@ -264,6 +278,23 @@ static void nagbar_cleanup(EV_P_ ev_cleanup *watcher, int revent) { } #endif +/* + * Writes the given command as a shell script to path. + * Returns true unless something went wrong. + * + */ +static bool write_nagbar_script(const char *path, const char *command) { + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR); + if (fd == -1) { + warn("Could not create temporary script to store the nagbar command"); + return false; + } + write(fd, "#!/bin/sh\n", strlen("#!/bin/sh\n")); + write(fd, command, strlen(command)); + close(fd); + return true; +} + /* * 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 @@ -276,6 +307,18 @@ static void start_configerror_nagbar(const char *config_path) { return; fprintf(stderr, "Starting i3-nagbar due to configuration errors\n"); + + /* We need to create a custom script containing our actual command + * since not every terminal emulator which is contained in + * i3-sensible-terminal supports -e with multiple arguments (and not + * all of them support -e with one quoted argument either). + * + * NB: The paths need to be unique, that is, don’t assume users close + * their nagbars at any point in time (and they still need to work). + * */ + edit_script_path = get_process_filename("nagbar-cfgerror-edit"); + pager_script_path = get_process_filename("nagbar-cfgerror-pager"); + configerror_pid = fork(); if (configerror_pid == -1) { warn("Could not fork()"); @@ -284,10 +327,17 @@ static void start_configerror_nagbar(const char *config_path) { /* child */ if (configerror_pid == 0) { + char *edit_command, *pager_command; + sasprintf(&edit_command, "i3-sensible-editor \"%s\" && i3-msg reload\n", config_path); + sasprintf(&pager_command, "i3-sensible-pager \"%s\"\n", errorfilename); + if (!write_nagbar_script(edit_script_path, edit_command) || + !write_nagbar_script(pager_script_path, pager_command)) + return; + char *editaction, *pageraction; - sasprintf(&editaction, "i3-sensible-terminal -e sh -c \"i3-sensible-editor \\\"%s\\\" && i3-msg reload\"", config_path); - sasprintf(&pageraction, "i3-sensible-terminal -e i3-sensible-pager \"%s\"", errorfilename); + sasprintf(&editaction, "i3-sensible-terminal -e \"%s\"", edit_script_path); + sasprintf(&pageraction, "i3-sensible-terminal -e \"%s\"", pager_script_path); char *argv[] = { NULL, /* will be replaced by the executable path */ "-t", @@ -384,8 +434,10 @@ static void check_for_duplicate_bindings(struct context *context) { /* Check if the keycodes or modifiers are different. If so, they * can't be duplicate */ if (bind->keycode != current->keycode || - bind->mods != current->mods) + bind->mods != current->mods || + bind->release != current->release) continue; + context->has_errors = true; if (current->keycode != 0) { ELOG("Duplicate keybinding in config file:\n modmask %d with keycode %d, command \"%s\"\n", @@ -575,15 +627,20 @@ void parse_file(const char *f) { } } - /* now lex/parse it */ - yy_scan_string(new); context = scalloc(sizeof(struct context)); context->filename = f; - if (yyparse() != 0) { - fprintf(stderr, "Could not parse configfile\n"); - exit(1); + if (force_old_config_parser) { + /* now lex/parse it */ + yy_scan_string(new); + if (yyparse() != 0) { + fprintf(stderr, "Could not parse configfile\n"); + exit(1); + } + } else { + struct ConfigResult *config_output = parse_config(new, context); + yajl_gen_free(config_output->json_gen); } check_for_duplicate_bindings(context); @@ -619,7 +676,8 @@ void parse_file(const char *f) { start_configerror_nagbar(f); } - yylex_destroy(); + if (force_old_config_parser) + yylex_destroy(); FREE(context->line_copy); free(context); FREE(font_pattern); @@ -664,6 +722,8 @@ void parse_file(const char *f) { %token TOKCONTROL "control" %token TOKSHIFT "shift" %token TOKFLOATING_MODIFIER "floating_modifier" +%token TOKFLOATING_MAXIMUM_SIZE "floating_maximum_size" +%token TOKFLOATING_MINIMUM_SIZE "floating_minimum_size" %token QUOTEDSTRING "" %token TOKWORKSPACE "workspace" %token TOKOUTPUT "output" @@ -677,6 +737,7 @@ void parse_file(const char *f) { %token TOKCOLOR %token TOKARROW "→" %token TOKMODE "mode" +%token TOK_TIME_MS "ms" %token TOK_BAR "bar" %token TOK_ORIENTATION "default_orientation" %token TOK_HORIZ "horizontal" @@ -687,11 +748,16 @@ void parse_file(const char *f) { %token TOKNEWFLOAT "new_float" %token TOK_NORMAL "normal" %token TOK_NONE "none" +%token TOK_PIXEL "pixel" %token TOK_1PIXEL "1pixel" +%token TOK_HIDE_EDGE_BORDERS "hide_edge_borders" +%token TOK_BOTH "both" %token TOKFOCUSFOLLOWSMOUSE "focus_follows_mouse" %token TOK_FORCE_FOCUS_WRAPPING "force_focus_wrapping" %token TOK_FORCE_XINERAMA "force_xinerama" +%token TOK_FAKE_OUTPUTS "fake_outputs" %token TOK_WORKSPACE_AUTO_BAF "workspace_auto_back_and_forth" +%token TOK_WORKSPACE_URGENCY_TIMER "force_display_urgency_hint" %token TOKWORKSPACEBAR "workspace_bar" %token TOK_DEFAULT "default" %token TOK_STACKING "stacking" @@ -708,6 +774,14 @@ void parse_file(const char *f) { %token TOK_BAR_MODE "mode (bar)" %token TOK_BAR_HIDE "hide" %token TOK_BAR_DOCK "dock" +%token TOK_BAR_MODIFIER "modifier (bar)" +%token TOK_BAR_CONTROL "shift (bar)" +%token TOK_BAR_SHIFT "control (bar)" +%token TOK_BAR_MOD1 "Mod1" +%token TOK_BAR_MOD2 "Mod2" +%token TOK_BAR_MOD3 "Mod3" +%token TOK_BAR_MOD4 "Mod4" +%token TOK_BAR_MOD5 "Mod5" %token TOK_BAR_POSITION "position" %token TOK_BAR_BOTTOM "bottom" %token TOK_BAR_TOP "top" @@ -724,6 +798,7 @@ void parse_file(const char *f) { %token TOK_BAR_COLOR_INACTIVE_WORKSPACE "inactive_workspace" %token TOK_BAR_COLOR_URGENT_WORKSPACE "urgent_workspace" %token TOK_NO_STARTUP_ID "--no-startup-id" +%token TOK_RELEASE "--release" %token TOK_MARK "mark" %token TOK_CLASS "class" @@ -732,6 +807,7 @@ void parse_file(const char *f) { %token TOK_ID "id" %token TOK_CON_ID "con_id" %token TOK_TITLE "title" +%token TOK_URGENT "urgent" %type binding %type bindcode @@ -742,15 +818,21 @@ void parse_file(const char *f) { %type layout_mode %type border_style %type new_window +%type hide_edge_borders +%type edge_hiding_mode %type new_float %type colorpixel %type bool %type popup_setting %type bar_position_position %type bar_mode_mode +%type bar_modifier_modifier %type optional_no_startup_id +%type optional_border_width +%type optional_release %type command %type word_or_number +%type duration %type qstring_or_number %type optional_workspace_name %type workspace_name @@ -768,14 +850,19 @@ line: | for_window | mode | bar + | floating_maximum_size + | floating_minimum_size | floating_modifier | orientation | workspace_layout | new_window | new_float + | hide_edge_borders | focus_follows_mouse | force_focus_wrapping | force_xinerama + | fake_outputs + | force_display_urgency_hint | workspace_back_and_forth | workspace_bar | workspace @@ -813,33 +900,40 @@ binding: ; bindcode: - binding_modifiers NUMBER command + optional_release binding_modifiers NUMBER command { - printf("\tFound keycode binding mod%d with key %d and command %s\n", $1, $2, $3); + DLOG("bindcode: release = %d, mod = %d, key = %d, command = %s\n", $1, $2, $3, $4); Binding *new = scalloc(sizeof(Binding)); - new->keycode = $2; - new->mods = $1; - new->command = $3; + new->release = $1; + new->keycode = $3; + new->mods = $2; + new->command = $4; $$ = new; } ; bindsym: - binding_modifiers word_or_number command + optional_release binding_modifiers word_or_number command { - printf("\tFound keysym binding mod%d with key %s and command %s\n", $1, $2, $3); + DLOG("bindsym: release = %d, mod = %d, key = %s, command = %s\n", $1, $2, $3, $4); Binding *new = scalloc(sizeof(Binding)); - new->symbol = $2; - new->mods = $1; - new->command = $3; + new->release = $1; + new->symbol = $3; + new->mods = $2; + new->command = $4; $$ = new; } ; +optional_release: + /* empty */ { $$ = B_UPON_KEYPRESS; } + | TOK_RELEASE { $$ = B_UPON_KEYRELEASE; } + ; + for_window: TOK_FOR_WINDOW match command { @@ -944,6 +1038,20 @@ criterion: current_match.title = regex_new($3); free($3); } + | TOK_URGENT '=' STR + { + printf("criteria: urgent = %s\n", $3); + if (strcasecmp($3, "latest") == 0 || + strcasecmp($3, "newest") == 0 || + strcasecmp($3, "recent") == 0 || + strcasecmp($3, "last") == 0) { + current_match.urgent = U_LATEST; + } else if (strcasecmp($3, "oldest") == 0 || + strcasecmp($3, "first") == 0) { + current_match.urgent = U_OLDEST; + } + free($3); + } ; qstring_or_number: @@ -959,6 +1067,11 @@ word_or_number: } ; +duration: + NUMBER { sasprintf(&$$, "%d", $1); } + | NUMBER TOK_TIME_MS { sasprintf(&$$, "%d", $1); } + ; + mode: TOKMODE QUOTEDSTRING '{' modelines '}' { @@ -1042,6 +1155,7 @@ barline: | bar_tray_output | bar_position | bar_mode + | bar_modifier | bar_font | bar_workspace_buttons | bar_verbose @@ -1119,6 +1233,23 @@ bar_mode_mode: | TOK_BAR_DOCK { $$ = M_DOCK; } ; +bar_modifier: + TOK_BAR_MODIFIER bar_modifier_modifier + { + DLOG("modifier %d\n", $2); + current_bar.modifier = $2; + }; + +bar_modifier_modifier: + TOK_BAR_CONTROL { $$ = M_CONTROL; } + | TOK_BAR_SHIFT { $$ = M_SHIFT; } + | TOK_BAR_MOD1 { $$ = M_MOD1; } + | TOK_BAR_MOD2 { $$ = M_MOD2; } + | TOK_BAR_MOD3 { $$ = M_MOD3; } + | TOK_BAR_MOD4 { $$ = M_MOD4; } + | TOK_BAR_MOD5 { $$ = M_MOD5; } + ; + bar_font: TOK_BAR_FONT STR { @@ -1183,36 +1314,90 @@ bar_color_statusline: bar_color_focused_workspace: TOK_BAR_COLOR_FOCUSED_WORKSPACE HEXCOLOR HEXCOLOR { - DLOG("focused_ws = %s and %s\n", $2, $3); + /* Old syntax: text / background */ + DLOG("focused_ws = %s, %s (old)\n", $2, $3); + current_bar.colors.focused_workspace_bg = $3; current_bar.colors.focused_workspace_text = $2; + } + | TOK_BAR_COLOR_FOCUSED_WORKSPACE HEXCOLOR HEXCOLOR HEXCOLOR + { + /* New syntax: border / background / text */ + DLOG("focused_ws = %s, %s and %s\n", $2, $3, $4); + current_bar.colors.focused_workspace_border = $2; current_bar.colors.focused_workspace_bg = $3; + current_bar.colors.focused_workspace_text = $4; } ; bar_color_active_workspace: TOK_BAR_COLOR_ACTIVE_WORKSPACE HEXCOLOR HEXCOLOR { - DLOG("active_ws = %s and %s\n", $2, $3); + /* Old syntax: text / background */ + DLOG("active_ws = %s, %s (old)\n", $2, $3); + current_bar.colors.active_workspace_bg = $3; current_bar.colors.active_workspace_text = $2; + } + | TOK_BAR_COLOR_ACTIVE_WORKSPACE HEXCOLOR HEXCOLOR HEXCOLOR + { + /* New syntax: border / background / text */ + DLOG("active_ws = %s, %s and %s\n", $2, $3, $4); + current_bar.colors.active_workspace_border = $2; current_bar.colors.active_workspace_bg = $3; + current_bar.colors.active_workspace_text = $4; } ; bar_color_inactive_workspace: TOK_BAR_COLOR_INACTIVE_WORKSPACE HEXCOLOR HEXCOLOR { - DLOG("inactive_ws = %s and %s\n", $2, $3); + /* Old syntax: text / background */ + DLOG("inactive_ws = %s, %s (old)\n", $2, $3); + current_bar.colors.inactive_workspace_bg = $3; current_bar.colors.inactive_workspace_text = $2; + } + | TOK_BAR_COLOR_INACTIVE_WORKSPACE HEXCOLOR HEXCOLOR HEXCOLOR + { + DLOG("inactive_ws = %s, %s and %s\n", $2, $3, $4); + current_bar.colors.inactive_workspace_border = $2; current_bar.colors.inactive_workspace_bg = $3; + current_bar.colors.inactive_workspace_text = $4; } ; bar_color_urgent_workspace: TOK_BAR_COLOR_URGENT_WORKSPACE HEXCOLOR HEXCOLOR { - DLOG("urgent_ws = %s and %s\n", $2, $3); + /* Old syntax: text / background */ + DLOG("urgent_ws = %s, %s (old)\n", $2, $3); + current_bar.colors.urgent_workspace_bg = $3; current_bar.colors.urgent_workspace_text = $2; + } + | TOK_BAR_COLOR_URGENT_WORKSPACE HEXCOLOR HEXCOLOR HEXCOLOR + { + DLOG("urgent_ws = %s, %s and %s\n", $2, $3, $4); + current_bar.colors.urgent_workspace_border = $2; current_bar.colors.urgent_workspace_bg = $3; + current_bar.colors.urgent_workspace_text = $4; + } + ; + +floating_maximum_size: + TOKFLOATING_MAXIMUM_SIZE NUMBER WORD NUMBER + { + printf("floating_maximum_width = %d\n", $2); + printf("floating_maximum_height = %d\n", $4); + config.floating_maximum_width = $2; + config.floating_maximum_height = $4; + } + ; + +floating_minimum_size: + TOKFLOATING_MINIMUM_SIZE NUMBER WORD NUMBER + { + printf("floating_minimum_width = %d\n", $2); + printf("floating_minimum_height = %d\n", $4); + config.floating_minimum_width = $2; + config.floating_minimum_height = $4; } ; @@ -1306,9 +1491,27 @@ new_float: ; border_style: - TOK_NORMAL { $$ = BS_NORMAL; } - | TOK_NONE { $$ = BS_NONE; } - | TOK_1PIXEL { $$ = BS_1PIXEL; } + TOK_NORMAL optional_border_width + { + /* FIXME: the whole border_style thing actually screws up when new_float is used because it overwrites earlier values :-/ */ + config.default_border_width = $2; + $$ = BS_NORMAL; + } + | TOK_1PIXEL + { + config.default_border_width = 1; + $$ = BS_PIXEL; + } + | TOK_NONE + { + config.default_border_width = 0; + $$ = BS_NONE; + } + | TOK_PIXEL optional_border_width + { + config.default_border_width = $2; + $$ = BS_PIXEL; + } ; bool: @@ -1327,6 +1530,22 @@ bool: } ; +hide_edge_borders: + TOK_HIDE_EDGE_BORDERS edge_hiding_mode + { + DLOG("hide edge borders = %d\n", $2); + config.hide_edge_borders = $2; + } + ; + +edge_hiding_mode: + TOK_NONE { $$ = ADJ_NONE; } + | TOK_VERT { $$ = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE; } + | TOK_HORIZ { $$ = ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE; } + | TOK_BOTH { $$ = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE | ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE; } + | bool { $$ = ($1 ? ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE : ADJ_NONE); } + ; + focus_follows_mouse: TOKFOCUSFOLLOWSMOUSE bool { @@ -1351,6 +1570,14 @@ force_xinerama: } ; +fake_outputs: + TOK_FAKE_OUTPUTS STR + { + DLOG("fake outputs = %s\n", $2); + config.fake_outputs = $2; + } + ; + workspace_back_and_forth: TOK_WORKSPACE_AUTO_BAF bool { @@ -1359,6 +1586,14 @@ workspace_back_and_forth: } ; +force_display_urgency_hint: + TOK_WORKSPACE_URGENCY_TIMER duration + { + DLOG("workspace urgency_timer = %f\n", atoi($2) / 1000.0); + config.workspace_urgency_timer = atoi($2) / 1000.0; + } + ; + workspace_bar: TOKWORKSPACEBAR bool { @@ -1547,6 +1782,11 @@ exec_always: } ; +optional_border_width: + /* empty */ { $$ = 2; } // 2 pixels is the default value for any type of border + | NUMBER { $$ = $1; } + ; + optional_no_startup_id: /* empty */ { $$ = false; } | TOK_NO_STARTUP_ID { $$ = true; } @@ -1588,6 +1828,15 @@ color: dest->background = $3; dest->text = $4; } + | TOKCOLOR colorpixel colorpixel colorpixel colorpixel + { + struct Colortriple *dest = $1; + + dest->border = $2; + dest->background = $3; + dest->text = $4; + dest->indicator = $5; + } ; colorpixel: