From 60ae26c19d31f3e20a939bcd01b750d1112dab6c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 10 Jun 2011 16:03:59 +0200 Subject: [PATCH] Implement 'workspace next/prev' (+test) --- docs/userguide | 11 ++--- include/workspace.h | 12 ++++++ src/cmdparse.l | 6 ++- src/cmdparse.y | 13 +++++- src/workspace.c | 26 ++++++++++++ testcases/t/17-workspace.t | 86 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 145 insertions(+), 9 deletions(-) diff --git a/docs/userguide b/docs/userguide index 205b5a99..0046028a 100644 --- a/docs/userguide +++ b/docs/userguide @@ -653,13 +653,10 @@ bindsym Mod1+semicolon move right To change to a specific workspace, use the +workspace+ command, followed by the number or name of the workspace. To move containers, use +move workspace+. -////////////////////////////////////////////////////////////////////////////// -TODO: not yet implemented - -You can also switch to the next and previous workspace with the commands +nw+ -and +pw+, 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 combination. -////////////////////////////////////////////////////////////////////////////// +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 1, 3, 4 and 9 and you want to cycle through them with a single key +combination. *Examples*: ------------------------- diff --git a/include/workspace.h b/include/workspace.h index 367c150e..aebf1365 100644 --- a/include/workspace.h +++ b/include/workspace.h @@ -49,6 +49,18 @@ bool workspace_is_visible(Con *ws); /** Switches to the given workspace */ void workspace_show(const char *num); +/** + * Focuses the next workspace. + * + */ +void workspace_next(); + +/** + * Focuses the previous workspace. + * + */ +void workspace_prev(); + #if 0 /** * Assigns the given workspace to the given screen by correctly updating its diff --git a/src/cmdparse.l b/src/cmdparse.l index 641265e6..9a0bc903 100644 --- a/src/cmdparse.l +++ b/src/cmdparse.l @@ -71,6 +71,11 @@ EOL (\r?\n) cmdyycolumn = 1; } + /* the next/prev tokens are here to recognize them *before* handling + * strings ('workspace' command) */ +next { return TOK_NEXT; } +prev { return TOK_PREV; } + \"[^\"]+\" { BEGIN(INITIAL); /* strip quotes */ @@ -120,7 +125,6 @@ workspace { WS_STRING; return TOK_WORKSPACE; } focus { return TOK_FOCUS; } move { return TOK_MOVE; } open { return TOK_OPEN; } -prev { return TOK_PREV; } split { return TOK_SPLIT; } horizontal { return TOK_HORIZONTAL; } vertical { return TOK_VERTICAL; } diff --git a/src/cmdparse.y b/src/cmdparse.y index f86bead9..32683112 100644 --- a/src/cmdparse.y +++ b/src/cmdparse.y @@ -142,6 +142,7 @@ char *parse_cmd(const char *new) { %token TOK_FOCUS "focus" %token TOK_MOVE "move" %token TOK_OPEN "open" +%token TOK_NEXT "next" %token TOK_PREV "prev" %token TOK_SPLIT "split" %token TOK_HORIZONTAL "horizontal" @@ -487,7 +488,17 @@ optional_kill_mode: ; workspace: - TOK_WORKSPACE STR + TOK_WORKSPACE TOK_NEXT + { + workspace_next(); + tree_render(); + } + | TOK_WORKSPACE TOK_PREV + { + workspace_prev(); + tree_render(); + } + | TOK_WORKSPACE STR { printf("should switch to workspace %s\n", $2); workspace_show($2); diff --git a/src/workspace.c b/src/workspace.c index 3a637b2f..ec57df8d 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -231,6 +231,32 @@ void workspace_show(const char *num) { ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"focus\"}"); } +/* + * Focuses the next workspace. + * + */ +void workspace_next() { + Con *ws = con_get_workspace(focused); + Con *next = TAILQ_NEXT(ws, nodes); + if (!next) + next = TAILQ_FIRST(&(ws->parent->nodes_head)); + + workspace_show(next->name); +} + +/* + * Focuses the previous workspace. + * + */ +void workspace_prev() { + Con *ws = con_get_workspace(focused); + Con *prev = TAILQ_PREV(ws, nodes_head, nodes); + if (!prev) + prev = TAILQ_LAST(&(ws->parent->nodes_head), nodes_head); + + workspace_show(prev->name); +} + static bool get_urgency_flag(Con *con) { Con *child; TAILQ_FOREACH(child, &(con->nodes_head), nodes) diff --git a/testcases/t/17-workspace.t b/testcases/t/17-workspace.t index e7892b2b..32f82969 100644 --- a/testcases/t/17-workspace.t +++ b/testcases/t/17-workspace.t @@ -4,6 +4,7 @@ # Tests whether we can switch to a non-existant workspace # (necessary for further tests) # +use List::Util qw(first); use i3test; sub workspace_exists { @@ -32,4 +33,89 @@ cmd "workspace $otmp"; cmd "workspace $otmp"; ok(workspace_exists($otmp), 'other workspace still exists'); + +##################################################################### +# check if the workspace next / prev commands work +##################################################################### + +cmd 'workspace next'; + +ok(!workspace_exists('next'), 'workspace "next" does not exist'); + +cmd "workspace $tmp"; +cmd 'open'; + +ok(workspace_exists($tmp), 'workspace created'); + +cmd "workspace $otmp"; +cmd 'open'; + +ok(workspace_exists($tmp), 'workspace tmp still exists'); +ok(workspace_exists($otmp), 'workspace otmp created'); + +sub focused_ws_con { + my $i3 = i3("/tmp/nestedcons"); + my $tree = $i3->get_tree->recv; + my @outputs = @{$tree->{nodes}}; + my @cons; + for my $output (@outputs) { + # get the first CT_CON of each output + my $content = first { $_->{type} == 2 } @{$output->{nodes}}; + my @focused = @{$content->{focus}}; + return first { $_->{id} == $focused[0] } @{$content->{nodes}}; + } +} + +sub focused_ws { + my $con = focused_ws_con; + return $con->{name}; +} + +is(focused_ws(), $otmp, 'focused workspace is otmp'); + +cmd 'workspace prev'; +is(focused_ws(), $tmp, 'focused workspace is tmp after workspace prev'); + +cmd 'workspace next'; +is(focused_ws(), $otmp, 'focused workspace is otmp after workspace next'); + + +##################################################################### +# check that wrapping works +##################################################################### + +cmd 'workspace next'; +is(focused_ws(), '1', 'focused workspace is 1 after workspace next'); + +cmd 'workspace next'; +is(focused_ws(), $tmp, 'focused workspace is tmp after workspace next'); + +cmd 'workspace next'; +is(focused_ws(), $otmp, 'focused workspace is otmp after workspace next'); + + +cmd 'workspace prev'; +is(focused_ws(), $tmp, 'focused workspace is tmp after workspace prev'); + +cmd 'workspace prev'; +is(focused_ws(), '1', 'focused workspace is tmp after workspace prev'); + +cmd 'workspace prev'; +is(focused_ws(), $otmp, 'focused workspace is otmp after workspace prev'); + + +##################################################################### +# check if we can change to "next" / "prev" +##################################################################### + +cmd 'workspace "next"'; + +ok(workspace_exists('next'), 'workspace "next" exists'); +is(focused_ws(), 'next', 'now on workspace next'); + +cmd 'workspace "prev"'; + +ok(workspace_exists('prev'), 'workspace "prev" exists'); +is(focused_ws(), 'prev', 'now on workspace prev'); + done_testing;