Merge branch 'workspace_on_output' into next

This commit is contained in:
Michael Stapelberg 2012-01-08 16:33:48 +00:00
commit 9c11ef4b23
8 changed files with 255 additions and 14 deletions

View File

@ -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

View File

@ -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.
* *

View File

@ -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>\"[^\"]+\" {

View File

@ -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;

View File

@ -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 == '"')

View File

@ -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.
* *

View File

@ -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}
}
} }
# #

View File

@ -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 dont 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;