From 099df7f438e3ad4ce3887aeb5b9f5c031813b06d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 17 Jul 2010 13:27:34 +0200 Subject: [PATCH] Bugfix: Keep focus on the current workspace when moving containers, add testcase --- include/con.h | 8 ++++++ src/con.c | 45 ++++++++++++++++++++++++++++++--- src/tree.c | 15 +---------- testcases/t/32-move-workspace.t | 45 +++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 testcases/t/32-move-workspace.t diff --git a/include/con.h b/include/con.h index 716ebfd3..fb862150 100644 --- a/include/con.h +++ b/include/con.h @@ -121,4 +121,12 @@ void con_move_to_workspace(Con *con, Con *workspace); */ int con_orientation(Con *con); +/** + * Returns the container which will be focused next when the given container + * is not available anymore. Called in tree_close and con_move_to_workspace + * to properly restore focus. + * + */ +Con *con_next_focused(Con *con); + #endif diff --git a/src/con.c b/src/con.c index a28d6633..4eeaf13c 100644 --- a/src/con.c +++ b/src/con.c @@ -360,21 +360,28 @@ void con_toggle_fullscreen(Con *con) { * */ void con_move_to_workspace(Con *con, Con *workspace) { - /* 1: get the focused container of this workspace by going down as far as + /* 1: save the container which is going to be focused after the current + * container is moved away */ + Con *focus_next = con_next_focused(con); + + /* 2: get the focused container of this workspace by going down as far as * possible */ Con *next = workspace; while (!TAILQ_EMPTY(&(next->focus_head))) next = TAILQ_FIRST(&(next->focus_head)); - /* 2: we go up one level, but only when next is a normal container */ + /* 3: we go up one level, but only when next is a normal container */ if (next->type != CT_WORKSPACE) next = next->parent; DLOG("Re-attaching container to %p / %s\n", next, next->name); - /* 3: re-attach the con to the parent of this focused container */ + /* 4: re-attach the con to the parent of this focused container */ con_detach(con); con_attach(con, next); + + /* 5: keep focus on the current workspace */ + con_focus(focus_next); } /* @@ -390,3 +397,35 @@ int con_orientation(Con *con) { return con->orientation; } + +/* + * Returns the container which will be focused next when the given container + * is not available anymore. Called in tree_close and con_move_to_workspace + * to properly restore focus. + * + */ +Con *con_next_focused(Con *con) { + Con *next; + /* floating containers are attached to a workspace, so we focus either the + * next floating container (if any) or the workspace itself. */ + if (con->type == CT_FLOATING_CON) { + next = TAILQ_NEXT(con, floating_windows); + if (next == TAILQ_END(&(parent->floating_head))) + next = con_get_workspace(con); + return next; + } + + /* try to focus the next container on the same level as this one */ + next = TAILQ_NEXT(con, focused); + + /* if none, go up to its parent and go down the focus stack as far as + * possible, excluding the current container */ + if (next == TAILQ_END(&(parent->nodes_head))) { + next = con->parent; + while (!TAILQ_EMPTY(&(next->focus_head)) && + TAILQ_FIRST(&(next->focus_head)) != con) + next = TAILQ_FIRST(&(next->focus_head)); + } + + return next; +} diff --git a/src/tree.c b/src/tree.c index 491548da..f695f944 100644 --- a/src/tree.c +++ b/src/tree.c @@ -138,20 +138,7 @@ void tree_close(Con *con, bool kill_window) { fix_floating_parent(croot, con); /* Get the container which is next focused */ - Con *next; - if (con->type == CT_FLOATING_CON) { - next = TAILQ_NEXT(con, floating_windows); - if (next == TAILQ_END(&(parent->floating_head))) - next = con_get_workspace(con); - } else { - next = TAILQ_NEXT(con, focused); - if (next == TAILQ_END(&(parent->nodes_head))) { - next = parent; - while (!TAILQ_EMPTY(&(next->focus_head)) && - TAILQ_FIRST(&(next->focus_head)) != con) - next = TAILQ_FIRST(&(next->focus_head)); - } - } + Con *next = con_next_focused(con); DLOG("closing %p, kill_window = %d\n", con, kill_window); Con *child; diff --git a/testcases/t/32-move-workspace.t b/testcases/t/32-move-workspace.t new file mode 100644 index 00000000..7889d5a7 --- /dev/null +++ b/testcases/t/32-move-workspace.t @@ -0,0 +1,45 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Checks if the 'move workspace' command works correctly +# +use i3test tests => 7; +use Time::HiRes qw(sleep); + +my $i3 = i3("/tmp/nestedcons"); + +# We move the pointer out of our way to avoid a bug where the focus will +# be set to the window under the cursor +my $x = X11::XCB::Connection->new; +$x->root->warp_pointer(0, 0); + +my $tmp = get_unused_workspace(); +my $tmp2 = get_unused_workspace(); +$i3->command("workspace $tmp")->recv; + +ok(@{get_ws_content($tmp)} == 0, 'no containers yet'); + +$i3->command('open')->recv; +my ($nodes, $focus) = get_ws_content($tmp); +my $first = $focus->[0]; +$i3->command('open')->recv; +($nodes, $focus) = get_ws_content($tmp); +my $second = $focus->[0]; +ok(@{get_ws_content($tmp)} == 2, 'two containers on first ws'); + +$i3->command("workspace $tmp2")->recv; +ok(@{get_ws_content($tmp2)} == 0, 'no containers on second ws yet'); + +$i3->command("workspace $tmp")->recv; + +$i3->command("move workspace $tmp2")->recv; +ok(@{get_ws_content($tmp)} == 1, 'one container on first ws anymore'); +ok(@{get_ws_content($tmp2)} == 1, 'one container on second ws'); +($nodes, $focus) = get_ws_content($tmp2); + +is($focus->[0], $second, 'same container on different ws'); + +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[0]->{focused}, 1, 'first container focused on first ws'); + +diag( "Testing i3, Perl $], $^X" ); -- 2.39.5