* 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>
static Match current_match;
static Barconfig current_bar;
+/* The pattern which was specified by the user, for example -misc-fixed-*. We
+ * 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 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",
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 {
}
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();
FREE(context->line_copy);
free(context);
+ FREE(font_pattern);
free(new);
free(buf);
%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 TOK_NORMAL "normal"
%token TOK_NONE "none"
%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 TOKWORKSPACEBAR "workspace_bar"
%token TOK_DEFAULT "default"
%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_ACTIVE_WORKSPACE "active_workspace"
%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_release
%type <string> command
%type <string> word_or_number
+%type <string> qstring_or_number
%type <string> optional_workspace_name
%type <string> workspace_name
%type <string> window_class
| 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
| 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 */ { $$ = false; }
+ | TOK_RELEASE { $$ = true; }
+ ;
+
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:
+ QUOTEDSTRING
+ | NUMBER { sasprintf(&$$, "%d", $1); }
+ ;
word_or_number:
WORD
*(x++) = (rand() % 26) + 'a';
}
+ /* If no font was explicitly set, we use the i3 font as default */
+ if (!current_bar.font && font_pattern)
+ current_bar.font = sstrdup(font_pattern);
+
/* Copy the current (static) structure into a dynamically allocated
* one, then cleanup our static one. */
Barconfig *bar_config = scalloc(sizeof(Barconfig));
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;
}
;
}
;
+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
{
;
workspace:
- TOKWORKSPACE NUMBER TOKOUTPUT OUTPUT optional_workspace_name
+ TOKWORKSPACE qstring_or_number TOKOUTPUT OUTPUT optional_workspace_name
{
- int ws_num = $2;
- if (ws_num < 1) {
- DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
- } else {
- char *ws_name = NULL;
- if ($5 == NULL) {
- sasprintf(&ws_name, "%d", ws_num);
- } else {
- ws_name = $5;
- }
+ char *ws_name = $2;
+
+ if ($5 != NULL) {
+ ELOG("The old (v3) syntax workspace <number> output <output> <name> is deprecated.\n");
+ ELOG("Please use the new syntax: workspace \"<workspace>\" output <output>\n");
+ ELOG("In your case, the following should work:\n");
+ ELOG(" workspace \"%s\" output %s\n", $5, $4);
+ ws_name = $5;
+ context->has_warnings = true;
+ }
- DLOG("Should assign workspace %s to output %s\n", ws_name, $4);
- /* Check for earlier assignments of the same workspace so that we
- * don’t have assignments of a single workspace to different
- * outputs */
- struct Workspace_Assignment *assignment;
- bool duplicate = false;
- TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
- if (strcasecmp(assignment->name, ws_name) == 0) {
- ELOG("You have a duplicate workspace assignment for workspace \"%s\"\n",
- ws_name);
- assignment->output = $4;
- duplicate = true;
- }
- }
- if (!duplicate) {
- assignment = scalloc(sizeof(struct Workspace_Assignment));
- assignment->name = ws_name;
+ DLOG("Assigning workspace \"%s\" to output \"%s\"\n", ws_name, $4);
+ /* Check for earlier assignments of the same workspace so that we
+ * don’t have assignments of a single workspace to different
+ * outputs */
+ struct Workspace_Assignment *assignment;
+ bool duplicate = false;
+ TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
+ if (strcasecmp(assignment->name, ws_name) == 0) {
+ ELOG("You have a duplicate workspace assignment for workspace \"%s\"\n",
+ ws_name);
assignment->output = $4;
- TAILQ_INSERT_TAIL(&ws_assignments, assignment, ws_assignments);
+ duplicate = true;
}
}
+ if (!duplicate) {
+ assignment = scalloc(sizeof(struct Workspace_Assignment));
+ assignment->name = ws_name;
+ assignment->output = $4;
+ TAILQ_INSERT_TAIL(&ws_assignments, assignment, ws_assignments);
+ }
}
| TOKWORKSPACE NUMBER workspace_name
{
;
exec:
- TOKEXEC STR
+ TOKEXEC optional_no_startup_id STR
{
struct Autostart *new = smalloc(sizeof(struct Autostart));
- new->command = $2;
+ new->command = $3;
+ new->no_startup_id = $2;
TAILQ_INSERT_TAIL(&autostarts, new, autostarts);
}
;
exec_always:
- TOKEXEC_ALWAYS STR
+ TOKEXEC_ALWAYS optional_no_startup_id STR
{
struct Autostart *new = smalloc(sizeof(struct Autostart));
- new->command = $2;
+ new->command = $3;
+ new->no_startup_id = $2;
TAILQ_INSERT_TAIL(&autostarts_always, new, autostarts_always);
}
;
+optional_no_startup_id:
+ /* empty */ { $$ = false; }
+ | TOK_NO_STARTUP_ID { $$ = true; }
+ ;
+
terminal:
TOKTERMINAL STR
{
TOKFONT STR
{
config.font = load_font($2, true);
+ set_font(&config.font);
printf("font %s\n", $2);
- free($2);
+ FREE(font_pattern);
+ font_pattern = $2;
}
;
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: