* vim:ts=4:sw=4:expandtab
*
*/
+#undef I3__FILE__
+#define I3__FILE__ "cfgparse.y"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "all.h"
+bool force_old_config_parser = false;
+
static pid_t configerror_pid = -1;
static Match current_match;
* 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);
ELOG("\n");
}
-int yywrap() {
+int yywrap(void) {
return 1;
}
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 borderless", strlen("border borderless")) == 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) {
printf("deciding for version 4 due to this line: %.*s\n", (int)(walk-line), line);
return 4;
}
*/
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;
}
#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
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()");
/* 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",
/* 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",
v_value = strstr(value, "\t");
*(v_value++) = '\0';
+ while (*v_value == '\t' || *v_value == ' ')
+ v_value++;
struct Variable *new = scalloc(sizeof(struct Variable));
new->key = sstrdup(v_key);
/* We need to convert this v3 configuration */
char *converted = migrate_config(new, stbuf.st_size);
if (converted != NULL) {
- printf("\n");
- printf("****************************************************************\n");
- printf("NOTE: Automatically converted configuration file from v3 to v4.\n");
- printf("\n");
- printf("Please convert your config file to v4. You can use this command:\n");
- printf(" mv %s %s.O\n", f, f);
- printf(" i3-migrate-config-to-v4 %s.O > %s\n", f, f);
- printf("****************************************************************\n");
- printf("\n");
+ ELOG("\n");
+ ELOG("****************************************************************\n");
+ ELOG("NOTE: Automatically converted configuration file from v3 to v4.\n");
+ ELOG("\n");
+ ELOG("Please convert your config file to v4. You can use this command:\n");
+ ELOG(" mv %s %s.O\n", f, f);
+ ELOG(" i3-migrate-config-to-v4 %s.O > %s\n", f, f);
+ ELOG("****************************************************************\n");
+ ELOG("\n");
free(new);
new = converted;
} else {
}
}
- /* 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);
}
if (context->has_errors || context->has_warnings) {
+ ELOG("FYI: You are using i3 version " I3_VERSION "\n");
+ if (version == 3)
+ ELOG("Please convert your configfile first, then fix any remaining errors (see above).\n");
start_configerror_nagbar(f);
}
- yylex_destroy();
+ if (force_old_config_parser)
+ yylex_destroy();
FREE(context->line_copy);
free(context);
FREE(font_pattern);
%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 <string> QUOTEDSTRING "<quoted string>"
%token TOKWORKSPACE "workspace"
%token TOKOUTPUT "output"
%token <color> TOKCOLOR
%token TOKARROW "→"
%token TOKMODE "mode"
+%token TOK_TIME_MS "ms"
%token TOK_BAR "bar"
%token TOK_ORIENTATION "default_orientation"
%token TOK_HORIZ "horizontal"
%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"
%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"
%token TOK_BAR_STATUS_COMMAND "status_command"
+%token TOK_BAR_I3BAR_COMMAND "i3bar_command"
%token TOK_BAR_FONT "font (bar)"
%token TOK_BAR_WORKSPACE_BUTTONS "workspace_buttons"
%token TOK_BAR_VERBOSE "verbose"
%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"
%token TOK_ID "id"
%token TOK_CON_ID "con_id"
%token TOK_TITLE "title"
+%token TOK_URGENT "urgent"
%type <binding> binding
%type <binding> bindcode
%type <number> layout_mode
%type <number> border_style
%type <number> new_window
+%type <number> hide_edge_borders
+%type <number> edge_hiding_mode
%type <number> new_float
%type <number> colorpixel
%type <number> bool
%type <number> popup_setting
%type <number> bar_position_position
%type <number> bar_mode_mode
+%type <number> bar_modifier_modifier
%type <number> optional_no_startup_id
+%type <number> optional_border_width
+%type <number> optional_release
%type <string> command
%type <string> word_or_number
+%type <string> duration
%type <string> qstring_or_number
%type <string> optional_workspace_name
%type <string> workspace_name
| 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
;
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
{
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:
}
;
+duration:
+ NUMBER { sasprintf(&$$, "%d", $1); }
+ | NUMBER TOK_TIME_MS { sasprintf(&$$, "%d", $1); }
+ ;
+
mode:
TOKMODE QUOTEDSTRING '{' modelines '}'
{
barline:
comment
| bar_status_command
+ | bar_i3bar_command
| bar_output
| bar_tray_output
| bar_position
| bar_mode
+ | bar_modifier
| bar_font
| bar_workspace_buttons
| bar_verbose
}
;
+bar_i3bar_command:
+ TOK_BAR_I3BAR_COMMAND STR
+ {
+ DLOG("should add i3bar_command %s\n", $2);
+ FREE(current_bar.i3bar_command);
+ current_bar.i3bar_command = $2;
+ }
+ ;
+
bar_output:
TOK_BAR_OUTPUT STR
{
| 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
{
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;
}
;
;
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:
}
;
+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
{
}
;
+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
{
}
;
+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
{
}
;
+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; }
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: