Change workspace assignments to use the RandR output name instead of <screen>

This commit is contained in:
Michael Stapelberg 2010-03-02 13:35:43 +01:00
parent c9c068c36c
commit aae824b1f3
7 changed files with 59 additions and 123 deletions

View File

@ -1,7 +1,7 @@
i3 Users 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
@ -367,25 +367,17 @@ default it will use 1 for the first screen, 2 for the second screen and so on).
*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
@ -396,10 +388,10 @@ them names (of course UTF-8 is supported):
*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*:
--------------------------

View File

@ -206,9 +206,8 @@ struct Workspace {
/** 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;

View File

@ -17,13 +17,6 @@
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.
@ -43,6 +36,12 @@ void randr_query_screens(xcb_connection_t *conn);
*/
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
*

View File

@ -39,8 +39,8 @@ EOL (\r?\n)
%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
%%
@ -67,6 +67,7 @@ EOL (\r?\n)
<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; }
@ -75,7 +76,14 @@ bind { BEGIN(BIND_COND); return TOKBIND; }
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; }
@ -112,15 +120,15 @@ shift { return TOKSHIFT; }
{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 */

View File

@ -197,6 +197,7 @@ void parse_file(const char *f) {
%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>"
@ -209,7 +210,7 @@ void parse_file(const char *f) {
%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"
@ -429,14 +430,14 @@ focus_follows_mouse:
;
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);
}
@ -447,6 +448,7 @@ workspace:
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);
}
@ -464,13 +466,6 @@ workspace_name:
| 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
{

View File

@ -44,25 +44,6 @@ typedef xcb_randr_get_screen_resources_current_reply_t resources_reply;
/* Stores all outputs available in your current session. */
struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs);
/*
* Returns true if both screen objects describe the same screen (checks their
* size and position).
*
*/
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);
}
/*
* 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
@ -70,10 +51,24 @@ bool screens_are_equal(Output *screen1, Output *screen2) {
*
*/
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 *output;
TAILQ_FOREACH(output, &outputs, outputs)
if (output->id == id)
return output;
return NULL;
}
/*
* Returns the output with the given name if it is active (!) or NULL.
*
*/
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;
}

View File

@ -195,58 +195,6 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
}
}
/*
* 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.
@ -311,8 +259,8 @@ void workspace_initialize(Workspace *ws, Output *output, bool recheck) {
/* 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);
@ -325,7 +273,7 @@ void workspace_initialize(Workspace *ws, Output *output, bool recheck) {
/*
* 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) {
@ -333,8 +281,8 @@ 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;