i3 User’s Guide
===============
Michael Stapelberg <michael+i3@stapelberg.de>
-August 2009
+March 2010
This document contains all information you need to configuring and using the i3
window manager. If it does not, please contact me on IRC, Jabber or E-Mail and
*Syntax*:
----------------------------------
-workspace <number> screen <screen>
+workspace <number> output <output>
----------------------------------
-Screen can be either a number (starting at 0 for the first screen) or a
-position. When using numbers, it is not guaranteed that your screens always
-get the same number. Though, unless you upgrade your X server or drivers, the
-order usually stays the same. When using positions, you have to specify the
-exact pixel where the screen *starts*, not a pixel which is contained by the
-screen. Thus, if your first screen has the dimensions 1280x800, you can match
-the second screen right of it by specifying 1280. You cannot use 1281.
+The output is the name of the RandR output you attach your screen to. On a
+laptop, you might have VGA1 and LVDS1 as output names. You can see the
+available outputs by running +xrandr --current+.
*Examples*:
---------------------------
-workspace 1 screen 0
-workspace 5 screen 1
-
-workspace 1 screen 1280
-workspace 2 screen x800
-workspace 3 screen 1280x800
+workspace 1 output LVDS1
+workspace 5 output VGA1
---------------------------
=== Named workspaces
*Syntax*:
---------------------------------------
workspace <number> <name>
-workspace <number> screen <screen> name
+workspace <number> output <output> name
---------------------------------------
-For more details about the screen-part of this command, see above.
+For more details about the output-part of this command, see above.
*Examples*:
--------------------------
/** Are the floating clients on this workspace currently hidden? */
bool floating_hidden;
- /** A <screen> specifier on which this workspace would like to be (if
- * the screen is available). screen := <number> | <position> */
- char *preferred_screen;
+ /** The name of the RandR output this screen should be on */
+ char *preferred_output;
/** Temporary flag needed for re-querying xinerama screens */
bool reassigned;
TAILQ_HEAD(outputs_head, xoutput);
extern struct outputs_head outputs;
-/**
- * Returns true if both screen objects describe the same screen (checks their
- * size and position).
- *
- */
-bool screens_are_equal(Output *screen1, Output *screen2);
-
/**
* We have just established a connection to the X server and need the initial
* XRandR information to setup workspaces for each screen.
*/
Output *get_first_output();
+/**
+ * Returns the output with the given name if it is active (!) or NULL.
+ *
+ */
+Output *get_output_by_name(const char *name);
+
/**
* Looks in virtual_screens for the i3Screen which contains coordinates x, y
*
%s BIND_A2WS_COND
%s ASSIGN_COND
%s COLOR_COND
-%s SCREEN_COND
-%s SCREEN_AWS_COND
+%s OUTPUT_COND
+%s OUTPUT_AWS_COND
%x BUFFER_LINE
%%
<BIND_A2WS_COND>[^\n]+ { BEGIN(INITIAL); yylval.string = strdup(yytext); return STR; }
+<OUTPUT_AWS_COND>[a-zA-Z0-9_-]+ { BEGIN(BIND_A2WS_COND); yylval.string = strdup(yytext); return OUTPUT; }
^[ \t]*#[^\n]* { return TOKCOMMENT; }
<COLOR_COND>[0-9a-fA-F]+ { yylval.string = strdup(yytext); return HEX; }
[0-9]+ { yylval.number = atoi(yytext); return NUMBER; }
bindsym { BEGIN(BINDSYM_COND); return TOKBINDSYM; }
floating_modifier { BEGIN(INITIAL); return TOKFLOATING_MODIFIER; }
workspace { BEGIN(INITIAL); return TOKWORKSPACE; }
-screen { BEGIN(SCREEN_COND); return TOKSCREEN; }
+output { BEGIN(OUTPUT_COND); return TOKOUTPUT; }
+screen {
+ /* for compatibility until v3.φ */
+ ELOG("Assignments to screens are DEPRECATED and will not work. " \
+ "Please replace them with assignments to outputs.\n");
+ BEGIN(OUTPUT_COND);
+ return TOKOUTPUT;
+ }
terminal { BEGIN(BIND_AWS_COND); return TOKTERMINAL; }
font { BEGIN(BIND_AWS_COND); return TOKFONT; }
assign { BEGIN(ASSIGN_COND); return TOKASSIGN; }
{EOL} {
FREE(context->line_copy);
context->line_number++;
+ BEGIN(INITIAL);
yy_push_state(BUFFER_LINE);
}
-<SCREEN_AWS_COND>x { return (int)yytext[0]; }
<BIND_COND>[ \t]+ { BEGIN(BIND_AWS_COND); return WHITESPACE; }
<BINDSYM_COND>[ \t]+ { BEGIN(BINDSYM_AWS_COND); return WHITESPACE; }
<BIND_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
<BINDSYM_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
-<SCREEN_COND>[ \t]+ { BEGIN(SCREEN_AWS_COND); return WHITESPACE; }
-<SCREEN_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
+<OUTPUT_COND>[ \t]+ { BEGIN(OUTPUT_AWS_COND); return WHITESPACE; }
+<OUTPUT_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
[ \t]+ { return WHITESPACE; }
\"[^\"]+\" {
/* if ASSIGN_COND then */
%token <string>STR "<string>"
%token <string>STR_NG "<string (non-greedy)>"
%token <string>HEX "<hex>"
+%token <string>OUTPUT "<RandR output>"
%token TOKBIND
%token TOKTERMINAL
%token TOKCOMMENT "<comment>"
%token TOKFLOATING_MODIFIER "floating_modifier"
%token QUOTEDSTRING "<quoted string>"
%token TOKWORKSPACE "workspace"
-%token TOKSCREEN "screen"
+%token TOKOUTPUT "output"
%token TOKASSIGN "assign"
%token TOKSET
%token TOKIPCSOCKET "ipc_socket"
;
workspace:
- TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen optional_workspace_name
+ TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKOUTPUT WHITESPACE OUTPUT optional_workspace_name
{
int ws_num = $<number>3;
if (ws_num < 1) {
DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
} else {
Workspace *ws = workspace_get(ws_num - 1);
- ws->preferred_screen = sstrdup($<string>7);
+ ws->preferred_output = sstrdup($<string>7);
if ($<string>8 != NULL)
workspace_set_name(ws, $<string>8);
}
if (ws_num < 1) {
DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
} else {
+ DLOG("workspace name to: %s\n", $<string>5);
if ($<string>5 != NULL)
workspace_set_name(workspace_get(ws_num - 1), $<string>5);
}
| WORD { $<string>$ = $<string>1; }
;
-screen:
- NUMBER { asprintf(&$<string>$, "%d", $<number>1); }
- | NUMBER 'x' { asprintf(&$<string>$, "%d", $<number>1); }
- | NUMBER 'x' NUMBER { asprintf(&$<string>$, "%dx%d", $<number>1, $<number>3); }
- | 'x' NUMBER { asprintf(&$<string>$, "x%d", $<number>2); }
- ;
-
assign:
TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow assign_target
{
struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs);
/*
- * Returns true if both screen objects describe the same screen (checks their
- * size and position).
+ * Get a specific output by its internal X11 id. Used by randr_query_screens
+ * to check if the output is new (only in the first scan) or if we are
+ * re-scanning.
*
*/
-bool screens_are_equal(Output *screen1, Output *screen2) {
- /* If one of both objects (or both) are NULL, we cannot compare them */
- if (screen1 == NULL || screen2 == NULL)
- return false;
-
- /* If the pointers are equal, take the short-circuit */
- if (screen1 == screen2)
- return true;
-
- /* Compare their size and position - other properties are not relevant
- * to determine if a screen is equal to another one */
- return (memcmp(&(screen1->rect), &(screen2->rect), sizeof(Rect)) == 0);
+static Output *get_output_by_id(xcb_randr_output_t id) {
+ Output *output;
+ TAILQ_FOREACH(output, &outputs, outputs)
+ if (output->id == id)
+ return output;
+
+ return NULL;
}
/*
- * Get a specific output by its internal X11 id. Used by randr_query_screens
- * to check if the output is new (only in the first scan) or if we are
- * re-scanning.
+ * Returns the output with the given name if it is active (!) or NULL.
*
*/
-static Output *get_output_by_id(xcb_randr_output_t id) {
- Output *screen;
- TAILQ_FOREACH(screen, &outputs, outputs)
- if (screen->id == id)
- return screen;
+Output *get_output_by_name(const char *name) {
+ Output *output;
+ TAILQ_FOREACH(output, &outputs, outputs)
+ if (output->active &&
+ strcasecmp(output->name, name) == 0)
+ return output;
return NULL;
}
}
}
-
-/*
- * Parses the preferred_screen property of a workspace. You can either specify
- * the screen number (it is not given that the screen numbering always stays
- * the same) or the screen coordinates (exact coordinates, e.g. 1280 will match
- * the screen starting at x=1280, but 1281 will not). For coordinates, you can
- * either specify an x coordinate ("1280") or an y coordinate ("x800") or both
- * ("1280x800").
- *
- */
-static Output *get_screen_from_preference(char *preference) {
- Output *screen;
- char *rest;
- int preferred_screen = strtol(preference, &rest, 10);
-
- DLOG("Getting screen for preference \"%s\" (%d)\n", preference, preferred_screen);
-
- if ((rest == preference) || (preferred_screen >= num_screens)) {
- int x = INT_MAX, y = INT_MAX;
- if (strchr(preference, 'x') != NULL) {
- /* Check if only the y coordinate was specified */
- if (*preference == 'x')
- y = atoi(preference+1);
- else {
- x = atoi(preference);
- y = atoi(strchr(preference, 'x') + 1);
- }
- } else {
- x = atoi(preference);
- }
-
- DLOG("Looking for screen at %d x %d\n", x, y);
-
- TAILQ_FOREACH(screen, &outputs, outputs)
- if ((x == INT_MAX || screen->rect.x == x) &&
- (y == INT_MAX || screen->rect.y == y)) {
- DLOG("found %p\n", screen);
- return screen;
- }
-
- DLOG("none found\n");
- return NULL;
- } else {
- int c = 0;
- TAILQ_FOREACH(screen, &outputs, outputs)
- if (c++ == preferred_screen)
- return screen;
- }
-
- return NULL;
-}
-
/*
* Assigns the given workspace to the given output by correctly updating its
* state and reconfiguring all the clients on this workspace.
/* If this workspace has no preferred output or if the output it wants
* to be on is not available at the moment, we initialize it with
* the output which was given */
- if (ws->preferred_screen == NULL ||
- (ws->output = get_screen_from_preference(ws->preferred_screen)) == NULL)
+ if (ws->preferred_output == NULL ||
+ (ws->output = get_output_by_name(ws->preferred_output)) == NULL)
ws->output = output;
DLOG("old_output = %p, ws->output = %p\n", old_output, ws->output);
/*
* Gets the first unused workspace for the given screen, taking into account
- * the preferred_screen setting of every workspace (workspace assignments).
+ * the preferred_output setting of every workspace (workspace assignments).
*
*/
Workspace *get_first_workspace_for_screen(Output *output) {
Workspace *ws;
TAILQ_FOREACH(ws, workspaces, workspaces) {
- if (ws->preferred_screen == NULL ||
- !screens_are_equal(get_screen_from_preference(ws->preferred_screen), output))
+ if (ws->preferred_output == NULL ||
+ get_output_by_name(ws->preferred_output) != output)
continue;
result = ws;