From fa5d8a0209bdd7d0f47414dbc21f4bf4ea41821e Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Wed, 6 Sep 2017 04:10:22 +0300 Subject: [PATCH] Make swap work with fullscreen windows Swap works like normal with fullscreen windows but swaps the fullscreen mode of the 2 containers after it's done. Fixes #2811 --- src/con.c | 23 +++++-- testcases/t/291-swap.t | 151 +++++++++++++++++++++++++++++++++++------ 2 files changed, 146 insertions(+), 28 deletions(-) diff --git a/src/con.c b/src/con.c index 04aacd32..a663db31 100644 --- a/src/con.c +++ b/src/con.c @@ -2276,15 +2276,14 @@ bool con_swap(Con *first, Con *second) { Con *current_ws = con_get_workspace(old_focus); const bool focused_within_first = (first == old_focus || con_has_parent(old_focus, first)); const bool focused_within_second = (second == old_focus || con_has_parent(old_focus, second)); + fullscreen_mode_t first_fullscreen_mode = first->fullscreen_mode; + fullscreen_mode_t second_fullscreen_mode = second->fullscreen_mode; - if (!con_fullscreen_permits_focusing(first_ws)) { - DLOG("Cannot swap because target workspace \"%s\" is obscured.\n", first_ws->name); - return false; + if (first_fullscreen_mode != CF_NONE) { + con_disable_fullscreen(first); } - - if (!con_fullscreen_permits_focusing(second_ws)) { - DLOG("Cannot swap because target workspace \"%s\" is obscured.\n", second_ws->name); - return false; + if (second_fullscreen_mode != CF_NONE) { + con_disable_fullscreen(second); } double first_percent = first->percent; @@ -2385,7 +2384,17 @@ bool con_swap(Con *first, Con *second) { second->percent = first_percent; fake->percent = 0.0; + SWAP(first_fullscreen_mode, second_fullscreen_mode, fullscreen_mode_t); + swap_end: + /* The two windows exchange their original fullscreen status */ + if (first_fullscreen_mode != CF_NONE) { + con_enable_fullscreen(first, first_fullscreen_mode); + } + if (second_fullscreen_mode != CF_NONE) { + con_enable_fullscreen(second, second_fullscreen_mode); + } + /* We don't actually need this since percentages-wise we haven't changed * anything, but we'll better be safe than sorry and just make sure as we'd * otherwise crash i3. */ diff --git a/testcases/t/291-swap.t b/testcases/t/291-swap.t index 53932597..f9ac3b6a 100644 --- a/testcases/t/291-swap.t +++ b/testcases/t/291-swap.t @@ -25,10 +25,17 @@ for_window[class="mark_B"] mark B EOT my ($ws, $ws1, $ws2, $ws3); -my ($nodes, $expected_focus, $A, $B, $F); +my ($node, $nodes, $expected_focus, $A, $B, $F); my ($result); +my @fullscreen_permutations = ([], ["A"], ["B"], ["A", "B"]); my @urgent; +sub fullscreen_windows { + my $ws = shift if @_; + + scalar grep { $_->{fullscreen_mode} != 0 } @{get_ws_content($ws)} +} + ############################################################################### # Invalid con_id should not crash i3 # See issue #2895. @@ -162,26 +169,114 @@ kill_all_windows; # | Y | B | Focus Stacks: # +---+---+ H2: B, Y ############################################################################### +for my $fullscreen (@fullscreen_permutations){ + $ws1 = fresh_workspace; + $A = open_window(wm_class => 'mark_A'); + $expected_focus = get_focused($ws1); + open_window; + cmd 'focus left'; + + $ws2 = fresh_workspace; + open_window; + $B = open_window(wm_class => 'mark_B'); + + my $A_fullscreen = "A" ~~ @$fullscreen || 0; + my $B_fullscreen = "B" ~~ @$fullscreen || 0; + $A->fullscreen($A_fullscreen); + $B->fullscreen($B_fullscreen); + sync_with_i3; + + cmd '[con_mark=B] swap container with mark A'; + + $nodes = get_ws_content($ws1); + $node = $nodes->[0]; + is($node->{window}, $B->{id}, 'B is on ws1:left'); + is(fullscreen_windows($ws1), $A_fullscreen, 'amount of fullscreen windows in ws1'); + is($node->{fullscreen_mode}, $A_fullscreen, 'B got A\'s fullscreen mode'); + + $nodes = get_ws_content($ws2); + $node = $nodes->[1]; + is($node->{window}, $A->{id}, 'A is on ws2:right'); + is(get_focused($ws2), $expected_focus, 'A is focused'); + is(fullscreen_windows($ws2), $B_fullscreen, 'amount of fullscreen windows in ws2'); + is($node->{fullscreen_mode}, $B_fullscreen, 'A got B\'s fullscreen mode'); + + kill_all_windows; +} + +############################################################################### +# Swap a non-fullscreen window with a fullscreen one in different workspaces. +# Layout: O1[ W1[ H1 ] W2[ B ] ] +# +# +---+---+ Layout: H1[ A F ] +# | A | F | Focus Stacks: +# +---+---+ H1: F, A +# +# +---+---+ +# | B | +# +---+---+ +############################################################################### $ws1 = fresh_workspace; + $A = open_window(wm_class => 'mark_A'); +$F = open_window(); +$F->fullscreen(1); $expected_focus = get_focused($ws1); -open_window; -cmd 'focus left'; $ws2 = fresh_workspace; -open_window; $B = open_window(wm_class => 'mark_B'); +$B->fullscreen(1); cmd '[con_mark=B] swap container with mark A'; $nodes = get_ws_content($ws1); is($nodes->[0]->{window}, $B->{id}, 'B is on ws1:left'); +is(fullscreen_windows($ws1), 1, 'F still fullscreen in ws1'); +is(get_focused($ws1), $expected_focus, 'F is still focused'); $nodes = get_ws_content($ws2); -is($nodes->[1]->{window}, $A->{id}, 'A is on ws2:right'); -is(get_focused($ws2), $expected_focus, 'A is focused'); +is($nodes->[0]->{window}, $A->{id}, 'A is on ws1'); -kill_all_windows; +############################################################################### +# Try a more exotic layout with fullscreen containers. +# A and F are fullscreened as a stack of two vertical containers before the +# swap is performed. +# A is swapped with fullscreened window B which is in another workspace. +# +# +---+---+ Layout: H1[ X V1[ A F ] ] +# | | A | Focus Stacks: +# | X +---+ H1: V1, X +# | | F | V1: F, A +# +---+---+ +############################################################################### +$ws1 = fresh_workspace; + +open_window; +$A = open_window(wm_class => 'mark_A'); +cmd "split v"; +open_window; +cmd "focus parent"; +cmd "fullscreen enable"; +$F = fullscreen_windows($ws1); +$expected_focus = get_focused($ws1); + +$ws2 = fresh_workspace; +$B = open_window(wm_class => 'mark_B'); +$B->fullscreen(1); + +cmd '[con_mark=B] swap container with mark A'; + +sync_with_i3; +does_i3_live; + +$nodes = get_ws_content($ws1); +is($nodes->[1]->{nodes}->[0]->{window}, $B->{id}, 'B is on top right in ws1'); +is(get_focused($ws1), $expected_focus, 'The container of the stacked windows remains focused in ws1'); +is(fullscreen_windows($ws1), $F, 'Same amount of fullscreen windows in ws1'); + +$nodes = get_ws_content($ws2); +is($nodes->[0]->{window}, $A->{id}, 'A is on ws2'); +is(fullscreen_windows($ws2), 1, 'A is in fullscreen mode'); ############################################################################### # Swap two non-focused containers within the same workspace. @@ -232,27 +327,41 @@ kill_all_windows; # | F | # +---+ ############################################################################### -$ws1 = fresh_workspace; -$A = open_window(wm_class => 'mark_A'); +for my $fullscreen (@fullscreen_permutations){ + $ws1 = fresh_workspace; + $A = open_window(wm_class => 'mark_A'); -$ws2 = fresh_workspace; -$B = open_window(wm_class => 'mark_B'); + $ws2 = fresh_workspace; + $B = open_window(wm_class => 'mark_B'); -$ws3 = fresh_workspace; -open_window; -$expected_focus = get_focused($ws3); + $ws3 = fresh_workspace; + open_window; + $expected_focus = get_focused($ws3); -cmd '[con_mark=B] swap container with mark A'; + my $A_fullscreen = "A" ~~ @$fullscreen || 0; + my $B_fullscreen = "B" ~~ @$fullscreen || 0; + $A->fullscreen($A_fullscreen); + $B->fullscreen($B_fullscreen); + sync_with_i3; -$nodes = get_ws_content($ws1); -is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace'); + cmd '[con_mark=B] swap container with mark A'; -$nodes = get_ws_content($ws2); -is($nodes->[0]->{window}, $A->{id}, 'A is on the second workspace'); + $nodes = get_ws_content($ws1); + $node = $nodes->[0]; + is($node->{window}, $B->{id}, 'B is on the first workspace'); + is(fullscreen_windows($ws1), $A_fullscreen, 'amount of fullscreen windows in ws1'); + is($node->{fullscreen_mode}, $A_fullscreen, 'B got A\'s fullscreen mode'); -is(get_focused($ws3), $expected_focus, 'F is still focused'); + $nodes = get_ws_content($ws2); + $node = $nodes->[0]; + is($node->{window}, $A->{id}, 'A is on the second workspace'); + is(fullscreen_windows($ws2), $B_fullscreen, 'amount of fullscreen windows in ws2'); + is($node->{fullscreen_mode}, $B_fullscreen, 'A got B\'s fullscreen mode'); -kill_all_windows; + is(get_focused($ws3), $expected_focus, 'F is still focused'); + + kill_all_windows; +} ############################################################################### # Swap two non-focused containers with one being on a different workspace.