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);
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;
/* 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 <string> WORD "<word>"
%token <string> STR "<string>"
%token <string> STR_NG "<string (non-greedy)>"
-%token <string> HEX "<hex>"
%token <string> HEXCOLOR "#<hex>"
%token <string> OUTPUT "<RandR output>"
%token TOKBINDCODE
%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_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"
%type <number> popup_setting
%type <number> bar_position_position
%type <number> bar_mode_mode
+%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
}
;
-
+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_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
{
;
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;
}
;
;
colorpixel:
- '#' HEX
+ HEXCOLOR
{
- char *hex;
- if (asprintf(&hex, "#%s", $2) == -1)
- die("asprintf()");
- free($2);
- $$ = get_colorpixel(hex);
- free(hex);
+ $$ = get_colorpixel($1);
+ free($1);
}
;