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;
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;
}
if (configerror_pid == 0) {
char *editaction,
*pageraction;
- if (asprintf(&editaction, "i3-sensible-terminal -e sh -c \"i3-sensible-editor \\\"%s\\\" && i3-msg reload\"", config_path) == -1)
- exit(1);
- if (asprintf(&pageraction, "i3-sensible-terminal -e i3-sensible-pager \"%s\"", errorfilename) == -1)
- exit(1);
+ 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);
char *argv[] = {
NULL, /* will be replaced by the executable path */
+ "-t",
+ (context->has_errors ? "error" : "warning"),
"-m",
- "You have an error in your i3 config file!",
+ (context->has_errors ?
+ "You have an error in your i3 config file!" :
+ "Your config is outdated. Please fix the warnings to make sure everything works."),
"-b",
"edit config",
editaction,
(errorfilename ? "-b" : NULL),
- "show errors",
+ (context->has_errors ? "show errors" : "show warnings"),
pageraction,
NULL
};
}
}
+static void migrate_i3bar_exec(struct Autostart *exec) {
+ ELOG("**********************************************************************\n");
+ ELOG("IGNORING exec command: %s\n", exec->command);
+ ELOG("It contains \"i3bar\". Since i3 v4.1, i3bar will be automatically started\n");
+ ELOG("for each 'bar' configuration block in your i3 config. Please remove the exec\n");
+ ELOG("line and add the following to your i3 config:\n");
+ ELOG("\n");
+ ELOG(" bar {\n");
+ ELOG(" status_command i3status\n");
+ ELOG(" }\n");
+ ELOG("**********************************************************************\n");
+
+ /* Generate a dummy bar configuration */
+ Barconfig *bar_config = scalloc(sizeof(Barconfig));
+ /* The hard-coded ID is not a problem. It does not conflict with the
+ * auto-generated bar IDs and having multiple hard-coded IDs is irrelevant
+ * – they all just contain status_command = i3status */
+ bar_config->id = sstrdup("migrate-bar");
+ bar_config->status_command = sstrdup("i3status");
+ TAILQ_INSERT_TAIL(&barconfigs, bar_config, configs);
+
+ /* Trigger an i3-nagbar */
+ context->has_warnings = true;
+}
+
void parse_file(const char *f) {
SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables);
int fd, ret, read_bytes = 0;
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 {
check_for_duplicate_bindings(context);
- if (context->has_errors) {
+ /* XXX: The following code will be removed in i3 v4.3 (three releases from
+ * now, as of 2011-10-22) */
+ /* Check for any exec or exec_always lines starting i3bar. We remove these
+ * and add a bar block instead. Additionally, a i3-nagbar warning (not an
+ * error) will be displayed so that users update their config file. */
+ struct Autostart *exec, *next;
+ for (exec = TAILQ_FIRST(&autostarts); exec; ) {
+ next = TAILQ_NEXT(exec, autostarts);
+ if (strstr(exec->command, "i3bar") != NULL) {
+ migrate_i3bar_exec(exec);
+ TAILQ_REMOVE(&autostarts, exec, autostarts);
+ }
+ exec = next;
+ }
+
+ for (exec = TAILQ_FIRST(&autostarts_always); exec; ) {
+ next = TAILQ_NEXT(exec, autostarts_always);
+ if (strstr(exec->command, "i3bar") != NULL) {
+ migrate_i3bar_exec(exec);
+ TAILQ_REMOVE(&autostarts_always, exec, autostarts_always);
+ }
+ exec = next;
+ }
+
+ 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_BAR_OUTPUT "output (bar)"
%token TOK_BAR_TRAY_OUTPUT "tray_output"
%token TOK_BAR_SOCKET_PATH "socket_path"
-%token TOK_BAR_MODE "mode"
+%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_FONT "font"
+%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_COLORS "colors"
%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_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> popup_setting
%type <number> bar_position_position
%type <number> bar_mode_mode
+%type <number> bar_modifier_modifier
+%type <number> optional_no_startup_id
%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
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
| NUMBER
{
- asprintf(&$$, "%d", $1);
+ sasprintf(&$$, "%d", $1);
}
;
*(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;
}
;
;
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) {
- asprintf(&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
{
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;
+ context->has_warnings = true;
printf("assignment of %s to *%s*\n", $2, $3);
char *workspace = $3;
char *criteria = $2;
if ((separator = strchr(criteria, '/')) != NULL) {
*(separator++) = '\0';
char *pattern;
- if (asprintf(&pattern, "(?i)%s", separator) == -1) {
- ELOG("asprintf failed\n");
- break;
- }
+ sasprintf(&pattern, "(?i)%s", separator);
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;
- }
+ sasprintf(&pattern, "(?i)%s", criteria);
match->class = regex_new(pattern);
free(pattern);
printf(" class = %s\n", criteria);
;
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: