Change workspace assignments to use the RandR output name instead of <screen>
This commit is contained in:
parent
c9c068c36c
commit
aae824b1f3
|
@ -1,7 +1,7 @@
|
||||||
i3 User’s Guide
|
i3 User’s Guide
|
||||||
===============
|
===============
|
||||||
Michael Stapelberg <michael+i3@stapelberg.de>
|
Michael Stapelberg <michael+i3@stapelberg.de>
|
||||||
August 2009
|
March 2010
|
||||||
|
|
||||||
This document contains all information you need to configuring and using the i3
|
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
|
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*:
|
*Syntax*:
|
||||||
----------------------------------
|
----------------------------------
|
||||||
workspace <number> screen <screen>
|
workspace <number> output <output>
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
Screen can be either a number (starting at 0 for the first screen) or a
|
The output is the name of the RandR output you attach your screen to. On a
|
||||||
position. When using numbers, it is not guaranteed that your screens always
|
laptop, you might have VGA1 and LVDS1 as output names. You can see the
|
||||||
get the same number. Though, unless you upgrade your X server or drivers, the
|
available outputs by running +xrandr --current+.
|
||||||
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.
|
|
||||||
|
|
||||||
*Examples*:
|
*Examples*:
|
||||||
---------------------------
|
---------------------------
|
||||||
workspace 1 screen 0
|
workspace 1 output LVDS1
|
||||||
workspace 5 screen 1
|
workspace 5 output VGA1
|
||||||
|
|
||||||
workspace 1 screen 1280
|
|
||||||
workspace 2 screen x800
|
|
||||||
workspace 3 screen 1280x800
|
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
=== Named workspaces
|
=== Named workspaces
|
||||||
|
@ -396,10 +388,10 @@ them names (of course UTF-8 is supported):
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
workspace <number> <name>
|
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*:
|
*Examples*:
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -206,9 +206,8 @@ struct Workspace {
|
||||||
/** Are the floating clients on this workspace currently hidden? */
|
/** Are the floating clients on this workspace currently hidden? */
|
||||||
bool floating_hidden;
|
bool floating_hidden;
|
||||||
|
|
||||||
/** A <screen> specifier on which this workspace would like to be (if
|
/** The name of the RandR output this screen should be on */
|
||||||
* the screen is available). screen := <number> | <position> */
|
char *preferred_output;
|
||||||
char *preferred_screen;
|
|
||||||
|
|
||||||
/** Temporary flag needed for re-querying xinerama screens */
|
/** Temporary flag needed for re-querying xinerama screens */
|
||||||
bool reassigned;
|
bool reassigned;
|
||||||
|
|
|
@ -17,13 +17,6 @@
|
||||||
TAILQ_HEAD(outputs_head, xoutput);
|
TAILQ_HEAD(outputs_head, xoutput);
|
||||||
extern struct outputs_head outputs;
|
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
|
* We have just established a connection to the X server and need the initial
|
||||||
* XRandR information to setup workspaces for each screen.
|
* XRandR information to setup workspaces for each screen.
|
||||||
|
@ -43,6 +36,12 @@ void randr_query_screens(xcb_connection_t *conn);
|
||||||
*/
|
*/
|
||||||
Output *get_first_output();
|
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
|
* Looks in virtual_screens for the i3Screen which contains coordinates x, y
|
||||||
*
|
*
|
||||||
|
|
|
@ -39,8 +39,8 @@ EOL (\r?\n)
|
||||||
%s BIND_A2WS_COND
|
%s BIND_A2WS_COND
|
||||||
%s ASSIGN_COND
|
%s ASSIGN_COND
|
||||||
%s COLOR_COND
|
%s COLOR_COND
|
||||||
%s SCREEN_COND
|
%s OUTPUT_COND
|
||||||
%s SCREEN_AWS_COND
|
%s OUTPUT_AWS_COND
|
||||||
%x BUFFER_LINE
|
%x BUFFER_LINE
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -67,6 +67,7 @@ EOL (\r?\n)
|
||||||
|
|
||||||
|
|
||||||
<BIND_A2WS_COND>[^\n]+ { BEGIN(INITIAL); yylval.string = strdup(yytext); return STR; }
|
<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; }
|
^[ \t]*#[^\n]* { return TOKCOMMENT; }
|
||||||
<COLOR_COND>[0-9a-fA-F]+ { yylval.string = strdup(yytext); return HEX; }
|
<COLOR_COND>[0-9a-fA-F]+ { yylval.string = strdup(yytext); return HEX; }
|
||||||
[0-9]+ { yylval.number = atoi(yytext); return NUMBER; }
|
[0-9]+ { yylval.number = atoi(yytext); return NUMBER; }
|
||||||
|
@ -75,7 +76,14 @@ bind { BEGIN(BIND_COND); return TOKBIND; }
|
||||||
bindsym { BEGIN(BINDSYM_COND); return TOKBINDSYM; }
|
bindsym { BEGIN(BINDSYM_COND); return TOKBINDSYM; }
|
||||||
floating_modifier { BEGIN(INITIAL); return TOKFLOATING_MODIFIER; }
|
floating_modifier { BEGIN(INITIAL); return TOKFLOATING_MODIFIER; }
|
||||||
workspace { BEGIN(INITIAL); return TOKWORKSPACE; }
|
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; }
|
terminal { BEGIN(BIND_AWS_COND); return TOKTERMINAL; }
|
||||||
font { BEGIN(BIND_AWS_COND); return TOKFONT; }
|
font { BEGIN(BIND_AWS_COND); return TOKFONT; }
|
||||||
assign { BEGIN(ASSIGN_COND); return TOKASSIGN; }
|
assign { BEGIN(ASSIGN_COND); return TOKASSIGN; }
|
||||||
|
@ -112,15 +120,15 @@ shift { return TOKSHIFT; }
|
||||||
{EOL} {
|
{EOL} {
|
||||||
FREE(context->line_copy);
|
FREE(context->line_copy);
|
||||||
context->line_number++;
|
context->line_number++;
|
||||||
|
BEGIN(INITIAL);
|
||||||
yy_push_state(BUFFER_LINE);
|
yy_push_state(BUFFER_LINE);
|
||||||
}
|
}
|
||||||
<SCREEN_AWS_COND>x { return (int)yytext[0]; }
|
|
||||||
<BIND_COND>[ \t]+ { BEGIN(BIND_AWS_COND); return WHITESPACE; }
|
<BIND_COND>[ \t]+ { BEGIN(BIND_AWS_COND); return WHITESPACE; }
|
||||||
<BINDSYM_COND>[ \t]+ { BEGIN(BINDSYM_AWS_COND); return WHITESPACE; }
|
<BINDSYM_COND>[ \t]+ { BEGIN(BINDSYM_AWS_COND); return WHITESPACE; }
|
||||||
<BIND_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
|
<BIND_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
|
||||||
<BINDSYM_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; }
|
<OUTPUT_COND>[ \t]+ { BEGIN(OUTPUT_AWS_COND); return WHITESPACE; }
|
||||||
<SCREEN_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
|
<OUTPUT_AWS_COND>[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; }
|
||||||
[ \t]+ { return WHITESPACE; }
|
[ \t]+ { return WHITESPACE; }
|
||||||
\"[^\"]+\" {
|
\"[^\"]+\" {
|
||||||
/* if ASSIGN_COND then */
|
/* if ASSIGN_COND then */
|
||||||
|
|
|
@ -197,6 +197,7 @@ void parse_file(const char *f) {
|
||||||
%token <string>STR "<string>"
|
%token <string>STR "<string>"
|
||||||
%token <string>STR_NG "<string (non-greedy)>"
|
%token <string>STR_NG "<string (non-greedy)>"
|
||||||
%token <string>HEX "<hex>"
|
%token <string>HEX "<hex>"
|
||||||
|
%token <string>OUTPUT "<RandR output>"
|
||||||
%token TOKBIND
|
%token TOKBIND
|
||||||
%token TOKTERMINAL
|
%token TOKTERMINAL
|
||||||
%token TOKCOMMENT "<comment>"
|
%token TOKCOMMENT "<comment>"
|
||||||
|
@ -209,7 +210,7 @@ void parse_file(const char *f) {
|
||||||
%token TOKFLOATING_MODIFIER "floating_modifier"
|
%token TOKFLOATING_MODIFIER "floating_modifier"
|
||||||
%token QUOTEDSTRING "<quoted string>"
|
%token QUOTEDSTRING "<quoted string>"
|
||||||
%token TOKWORKSPACE "workspace"
|
%token TOKWORKSPACE "workspace"
|
||||||
%token TOKSCREEN "screen"
|
%token TOKOUTPUT "output"
|
||||||
%token TOKASSIGN "assign"
|
%token TOKASSIGN "assign"
|
||||||
%token TOKSET
|
%token TOKSET
|
||||||
%token TOKIPCSOCKET "ipc_socket"
|
%token TOKIPCSOCKET "ipc_socket"
|
||||||
|
@ -429,14 +430,14 @@ focus_follows_mouse:
|
||||||
;
|
;
|
||||||
|
|
||||||
workspace:
|
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;
|
int ws_num = $<number>3;
|
||||||
if (ws_num < 1) {
|
if (ws_num < 1) {
|
||||||
DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
|
DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
|
||||||
} else {
|
} else {
|
||||||
Workspace *ws = workspace_get(ws_num - 1);
|
Workspace *ws = workspace_get(ws_num - 1);
|
||||||
ws->preferred_screen = sstrdup($<string>7);
|
ws->preferred_output = sstrdup($<string>7);
|
||||||
if ($<string>8 != NULL)
|
if ($<string>8 != NULL)
|
||||||
workspace_set_name(ws, $<string>8);
|
workspace_set_name(ws, $<string>8);
|
||||||
}
|
}
|
||||||
|
@ -447,6 +448,7 @@ workspace:
|
||||||
if (ws_num < 1) {
|
if (ws_num < 1) {
|
||||||
DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
|
DLOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
|
||||||
} else {
|
} else {
|
||||||
|
DLOG("workspace name to: %s\n", $<string>5);
|
||||||
if ($<string>5 != NULL)
|
if ($<string>5 != NULL)
|
||||||
workspace_set_name(workspace_get(ws_num - 1), $<string>5);
|
workspace_set_name(workspace_get(ws_num - 1), $<string>5);
|
||||||
}
|
}
|
||||||
|
@ -464,13 +466,6 @@ workspace_name:
|
||||||
| WORD { $<string>$ = $<string>1; }
|
| 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:
|
assign:
|
||||||
TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow assign_target
|
TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow assign_target
|
||||||
{
|
{
|
||||||
|
|
41
src/randr.c
41
src/randr.c
|
@ -44,25 +44,6 @@ typedef xcb_randr_get_screen_resources_current_reply_t resources_reply;
|
||||||
/* Stores all outputs available in your current session. */
|
/* Stores all outputs available in your current session. */
|
||||||
struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs);
|
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
|
* 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
|
* 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) {
|
static Output *get_output_by_id(xcb_randr_output_t id) {
|
||||||
Output *screen;
|
Output *output;
|
||||||
TAILQ_FOREACH(screen, &outputs, outputs)
|
TAILQ_FOREACH(output, &outputs, outputs)
|
||||||
if (screen->id == id)
|
if (output->id == id)
|
||||||
return screen;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
* Assigns the given workspace to the given output by correctly updating its
|
||||||
* state and reconfiguring all the clients on this workspace.
|
* 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
|
/* 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
|
* to be on is not available at the moment, we initialize it with
|
||||||
* the output which was given */
|
* the output which was given */
|
||||||
if (ws->preferred_screen == NULL ||
|
if (ws->preferred_output == NULL ||
|
||||||
(ws->output = get_screen_from_preference(ws->preferred_screen)) == NULL)
|
(ws->output = get_output_by_name(ws->preferred_output)) == NULL)
|
||||||
ws->output = output;
|
ws->output = output;
|
||||||
|
|
||||||
DLOG("old_output = %p, ws->output = %p\n", old_output, ws->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
|
* 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 *get_first_workspace_for_screen(Output *output) {
|
||||||
|
@ -333,8 +281,8 @@ Workspace *get_first_workspace_for_screen(Output *output) {
|
||||||
|
|
||||||
Workspace *ws;
|
Workspace *ws;
|
||||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||||
if (ws->preferred_screen == NULL ||
|
if (ws->preferred_output == NULL ||
|
||||||
!screens_are_equal(get_screen_from_preference(ws->preferred_screen), output))
|
get_output_by_name(ws->preferred_output) != output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result = ws;
|
result = ws;
|
||||||
|
|
Loading…
Reference in New Issue