Merge branch 'workspace_on_output' into next
This commit is contained in:
commit
9c11ef4b23
|
@ -1246,8 +1246,10 @@ number or name of the workspace. To move containers to specific workspaces, use
|
||||||
You can also switch to the next and previous workspace with the commands
|
You can also switch to the next and previous workspace with the commands
|
||||||
+workspace next+ and +workspace prev+, which is handy, for example, if you have
|
+workspace next+ and +workspace prev+, which is handy, for example, if you have
|
||||||
workspace 1, 3, 4 and 9 and you want to cycle through them with a single key
|
workspace 1, 3, 4 and 9 and you want to cycle through them with a single key
|
||||||
combination. Similarly, you can use +move workspace next+ and +move workspace
|
combination. To restrict those to the current output, use +workspace
|
||||||
prev+ to move a container to the next/previous workspace.
|
next_on_output+ and +workspace prev_on_output+. Similarly, you can use +move
|
||||||
|
workspace next+ and +move workspace prev+ to move a container to the
|
||||||
|
next/previous workspace.
|
||||||
|
|
||||||
[[back_and_forth]]
|
[[back_and_forth]]
|
||||||
To switch back to the previously focused workspace, use +workspace
|
To switch back to the previously focused workspace, use +workspace
|
||||||
|
|
|
@ -69,6 +69,18 @@ Con* workspace_next();
|
||||||
*/
|
*/
|
||||||
Con* workspace_prev();
|
Con* workspace_prev();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next workspace on the same output
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con* workspace_next_on_output();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the previous workspace on the same output
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con* workspace_prev_on_output();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focuses the previously focused workspace.
|
* Focuses the previously focused workspace.
|
||||||
*
|
*
|
||||||
|
|
|
@ -78,6 +78,8 @@ EOL (\r?\n)
|
||||||
* handling strings ('workspace' command) */
|
* handling strings ('workspace' command) */
|
||||||
next { BEGIN(INITIAL); return TOK_NEXT; }
|
next { BEGIN(INITIAL); return TOK_NEXT; }
|
||||||
prev { BEGIN(INITIAL); return TOK_PREV; }
|
prev { BEGIN(INITIAL); return TOK_PREV; }
|
||||||
|
next_on_output { BEGIN(INITIAL); return TOK_NEXT_ON_OUTPUT; }
|
||||||
|
prev_on_output { BEGIN(INITIAL); return TOK_PREV_ON_OUTPUT; }
|
||||||
back_and_forth { BEGIN(INITIAL); return TOK_BACK_AND_FORTH; }
|
back_and_forth { BEGIN(INITIAL); return TOK_BACK_AND_FORTH; }
|
||||||
|
|
||||||
<WANT_STRING>\"[^\"]+\" {
|
<WANT_STRING>\"[^\"]+\" {
|
||||||
|
|
|
@ -155,6 +155,8 @@ bool definitelyGreaterThan(float a, float b, float epsilon) {
|
||||||
%token TOK_OPEN "open"
|
%token TOK_OPEN "open"
|
||||||
%token TOK_NEXT "next"
|
%token TOK_NEXT "next"
|
||||||
%token TOK_PREV "prev"
|
%token TOK_PREV "prev"
|
||||||
|
%token TOK_NEXT_ON_OUTPUT "next_on_output"
|
||||||
|
%token TOK_PREV_ON_OUTPUT "prev_on_output"
|
||||||
%token TOK_SCRATCHPAD "scratchpad"
|
%token TOK_SCRATCHPAD "scratchpad"
|
||||||
%token TOK_SHOW "show"
|
%token TOK_SHOW "show"
|
||||||
%token TOK_SPLIT "split"
|
%token TOK_SPLIT "split"
|
||||||
|
@ -680,6 +682,16 @@ workspace:
|
||||||
workspace_show(workspace_prev());
|
workspace_show(workspace_prev());
|
||||||
tree_render();
|
tree_render();
|
||||||
}
|
}
|
||||||
|
| TOK_WORKSPACE TOK_NEXT_ON_OUTPUT
|
||||||
|
{
|
||||||
|
workspace_show(workspace_next_on_output());
|
||||||
|
tree_render();
|
||||||
|
}
|
||||||
|
| TOK_WORKSPACE TOK_PREV_ON_OUTPUT
|
||||||
|
{
|
||||||
|
workspace_show(workspace_prev_on_output());
|
||||||
|
tree_render();
|
||||||
|
}
|
||||||
| TOK_WORKSPACE TOK_BACK_AND_FORTH
|
| TOK_WORKSPACE TOK_BACK_AND_FORTH
|
||||||
{
|
{
|
||||||
workspace_back_and_forth();
|
workspace_back_and_forth();
|
||||||
|
@ -912,6 +924,38 @@ move:
|
||||||
|
|
||||||
tree_render();
|
tree_render();
|
||||||
}
|
}
|
||||||
|
| TOK_MOVE TOK_WORKSPACE TOK_NEXT_ON_OUTPUT
|
||||||
|
{
|
||||||
|
owindow *current;
|
||||||
|
|
||||||
|
/* get the workspace */
|
||||||
|
Con *ws = workspace_next_on_output();
|
||||||
|
|
||||||
|
HANDLE_EMPTY_MATCH;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(current, &owindows, owindows) {
|
||||||
|
printf("matching: %p / %s\n", current->con, current->con->name);
|
||||||
|
con_move_to_workspace(current->con, ws, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_render();
|
||||||
|
}
|
||||||
|
| TOK_MOVE TOK_WORKSPACE TOK_PREV_ON_OUTPUT
|
||||||
|
{
|
||||||
|
owindow *current;
|
||||||
|
|
||||||
|
/* get the workspace */
|
||||||
|
Con *ws = workspace_prev_on_output();
|
||||||
|
|
||||||
|
HANDLE_EMPTY_MATCH;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(current, &owindows, owindows) {
|
||||||
|
printf("matching: %p / %s\n", current->con, current->con->name);
|
||||||
|
con_move_to_workspace(current->con, ws, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_render();
|
||||||
|
}
|
||||||
| TOK_MOVE TOK_OUTPUT STR
|
| TOK_MOVE TOK_OUTPUT STR
|
||||||
{
|
{
|
||||||
owindow *current;
|
owindow *current;
|
||||||
|
|
10
src/randr.c
10
src/randr.c
|
@ -420,11 +420,15 @@ void init_ws_for_output(Output *output, Con *content) {
|
||||||
continue;
|
continue;
|
||||||
DLOG("relevant command = %s\n", bind->command);
|
DLOG("relevant command = %s\n", bind->command);
|
||||||
char *target = bind->command + strlen("workspace ");
|
char *target = bind->command + strlen("workspace ");
|
||||||
/* We check if this is the workspace next/prev/back_and_forth command.
|
/* We check if this is the workspace
|
||||||
* Beware: The workspace names "next", "prev" and "back_and_forth" are
|
* next/prev/next_on_output/prev_on_output/back_and_forth command.
|
||||||
* OK, so we check before stripping the double quotes */
|
* Beware: The workspace names "next", "prev", "next_on_output",
|
||||||
|
* "prev_on_output" and "back_and_forth" are OK, so we check before
|
||||||
|
* stripping the double quotes */
|
||||||
if (strncasecmp(target, "next", strlen("next")) == 0 ||
|
if (strncasecmp(target, "next", strlen("next")) == 0 ||
|
||||||
strncasecmp(target, "prev", strlen("prev")) == 0 ||
|
strncasecmp(target, "prev", strlen("prev")) == 0 ||
|
||||||
|
strncasecmp(target, "next_on_output", strlen("next_on_output")) == 0 ||
|
||||||
|
strncasecmp(target, "prev_on_output", strlen("prev_on_output")) == 0 ||
|
||||||
strncasecmp(target, "back_and_forth", strlen("back_and_forth")) == 0)
|
strncasecmp(target, "back_and_forth", strlen("back_and_forth")) == 0)
|
||||||
continue;
|
continue;
|
||||||
if (*target == '"')
|
if (*target == '"')
|
||||||
|
|
112
src/workspace.c
112
src/workspace.c
|
@ -409,6 +409,118 @@ workspace_prev_end:
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Focuses the next workspace on the same output.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con* workspace_next_on_output() {
|
||||||
|
Con *current = con_get_workspace(focused);
|
||||||
|
Con *next = NULL;
|
||||||
|
Con *output = con_get_output(focused);
|
||||||
|
|
||||||
|
if (current->num == -1) {
|
||||||
|
/* If currently a named workspace, find next named workspace. */
|
||||||
|
next = TAILQ_NEXT(current, nodes);
|
||||||
|
} else {
|
||||||
|
/* If currently a numbered workspace, find next numbered workspace. */
|
||||||
|
NODES_FOREACH(output_get_content(output)) {
|
||||||
|
if (child->type != CT_WORKSPACE)
|
||||||
|
continue;
|
||||||
|
if (child->num == -1)
|
||||||
|
break;
|
||||||
|
/* Need to check child against current and next because we are
|
||||||
|
* traversing multiple lists and thus are not guaranteed the
|
||||||
|
* relative order between the list of workspaces. */
|
||||||
|
if (current->num < child->num && (!next || child->num < next->num))
|
||||||
|
next = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find next named workspace. */
|
||||||
|
if (!next) {
|
||||||
|
bool found_current = false;
|
||||||
|
NODES_FOREACH(output_get_content(output)) {
|
||||||
|
if (child->type != CT_WORKSPACE)
|
||||||
|
continue;
|
||||||
|
if (child == current) {
|
||||||
|
found_current = 1;
|
||||||
|
} else if (child->num == -1 && (current->num != -1 || found_current)) {
|
||||||
|
next = child;
|
||||||
|
goto workspace_next_on_output_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find first workspace. */
|
||||||
|
if (!next) {
|
||||||
|
NODES_FOREACH(output_get_content(output)) {
|
||||||
|
if (child->type != CT_WORKSPACE)
|
||||||
|
continue;
|
||||||
|
if (!next || (child->num != -1 && child->num < next->num))
|
||||||
|
next = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
workspace_next_on_output_end:
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Focuses the previous workspace on same output.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con* workspace_prev_on_output() {
|
||||||
|
Con *current = con_get_workspace(focused);
|
||||||
|
Con *prev = NULL;
|
||||||
|
Con *output = con_get_output(focused);
|
||||||
|
|
||||||
|
if (current->num == -1) {
|
||||||
|
/* If named workspace, find previous named workspace. */
|
||||||
|
prev = TAILQ_PREV(current, nodes_head, nodes);
|
||||||
|
if (prev && prev->num != -1)
|
||||||
|
prev = NULL;
|
||||||
|
} else {
|
||||||
|
/* If numbered workspace, find previous numbered workspace. */
|
||||||
|
NODES_FOREACH_REVERSE(output_get_content(output)) {
|
||||||
|
if (child->type != CT_WORKSPACE || child->num == -1)
|
||||||
|
continue;
|
||||||
|
/* Need to check child against current and previous because we
|
||||||
|
* are traversing multiple lists and thus are not guaranteed
|
||||||
|
* the relative order between the list of workspaces. */
|
||||||
|
if (current->num > child->num && (!prev || child->num > prev->num))
|
||||||
|
prev = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find previous named workspace. */
|
||||||
|
if (!prev) {
|
||||||
|
bool found_current = false;
|
||||||
|
NODES_FOREACH_REVERSE(output_get_content(output)) {
|
||||||
|
if (child->type != CT_WORKSPACE)
|
||||||
|
continue;
|
||||||
|
if (child == current) {
|
||||||
|
found_current = true;
|
||||||
|
} else if (child->num == -1 && (current->num != -1 || found_current)) {
|
||||||
|
prev = child;
|
||||||
|
goto workspace_prev_on_output_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find last workspace. */
|
||||||
|
if (!prev) {
|
||||||
|
NODES_FOREACH_REVERSE(output_get_content(output)) {
|
||||||
|
if (child->type != CT_WORKSPACE)
|
||||||
|
continue;
|
||||||
|
if (!prev || child->num > prev->num)
|
||||||
|
prev = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace_prev_on_output_end:
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Focuses the previously focused workspace.
|
* Focuses the previously focused workspace.
|
||||||
*
|
*
|
||||||
|
|
|
@ -383,18 +383,19 @@ sub workspace_exists {
|
||||||
($name ~~ @{get_workspace_names()})
|
($name ~~ @{get_workspace_names()})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=head2 focused_ws
|
||||||
|
|
||||||
|
Returns the name of the currently focused workspace.
|
||||||
|
|
||||||
|
=cut
|
||||||
sub focused_ws {
|
sub focused_ws {
|
||||||
my $i3 = i3(get_socket_path());
|
my $i3 = i3(get_socket_path());
|
||||||
my $tree = $i3->get_tree->recv;
|
my $tree = $i3->get_tree->recv;
|
||||||
my @outputs = @{$tree->{nodes}};
|
my $focused = $tree->{focus}->[0];
|
||||||
my @cons;
|
my $output = first { $_->{id} == $focused } @{$tree->{nodes}};
|
||||||
for my $output (@outputs) {
|
my $content = first { $_->{type} == 2 } @{$output->{nodes}};
|
||||||
next if $output->{name} eq '__i3';
|
my $first = first { $_->{fullscreen_mode} == 1 } @{$content->{nodes}};
|
||||||
# get the first CT_CON of each output
|
return $first->{name}
|
||||||
my $content = first { $_->{type} == 2 } @{$output->{nodes}};
|
|
||||||
my $first = first { $_->{fullscreen_mode} == 1 } @{$content->{nodes}};
|
|
||||||
return $first->{name}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!perl
|
||||||
|
# vim:ts=4:sw=4:expandtab
|
||||||
|
#
|
||||||
|
# Tests whether 'workspace next_on_output' and the like work correctly.
|
||||||
|
#
|
||||||
|
use List::Util qw(first);
|
||||||
|
use i3test;
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Setup workspaces so that they stay open (with an empty container).
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
is(focused_ws, '1', 'starting on workspace 1');
|
||||||
|
# ensure workspace 1 stays open
|
||||||
|
cmd 'open';
|
||||||
|
|
||||||
|
cmd 'focus output right';
|
||||||
|
is(focused_ws, '2', 'workspace 2 on second output');
|
||||||
|
# ensure workspace 2 stays open
|
||||||
|
cmd 'open';
|
||||||
|
|
||||||
|
cmd 'focus output right';
|
||||||
|
is(focused_ws, '1', 'back on workspace 1');
|
||||||
|
|
||||||
|
# We don’t use fresh_workspace with named workspaces here since they come last
|
||||||
|
# when using 'workspace next'.
|
||||||
|
cmd 'workspace 5';
|
||||||
|
# ensure workspace $tmp stays open
|
||||||
|
cmd 'open';
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Use workspace next and verify the correct order.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# The current order should be:
|
||||||
|
# output 1: 1, 5
|
||||||
|
# output 2: 2
|
||||||
|
cmd 'workspace 1';
|
||||||
|
cmd 'workspace next';
|
||||||
|
is(focused_ws, '2', 'workspace 2 focused');
|
||||||
|
cmd 'workspace next';
|
||||||
|
is(focused_ws, '5', 'workspace 5 focused');
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Now try the same with workspace next_on_output.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
cmd 'workspace 1';
|
||||||
|
cmd 'workspace next_on_output';
|
||||||
|
is(focused_ws, '5', 'workspace 5 focused');
|
||||||
|
cmd 'workspace next_on_output';
|
||||||
|
is(focused_ws, '1', 'workspace 1 focused');
|
||||||
|
|
||||||
|
cmd 'workspace prev_on_output';
|
||||||
|
is(focused_ws, '5', 'workspace 5 focused');
|
||||||
|
cmd 'workspace prev_on_output';
|
||||||
|
is(focused_ws, '1', 'workspace 1 focused');
|
||||||
|
|
||||||
|
cmd 'workspace 2';
|
||||||
|
|
||||||
|
cmd 'workspace prev_on_output';
|
||||||
|
is(focused_ws, '2', 'workspace 2 focused');
|
||||||
|
|
||||||
|
done_testing;
|
Loading…
Reference in New Issue