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
next
Orestis Floros 2017-09-06 04:10:22 +03:00
parent 71e309597c
commit fa5d8a0209
2 changed files with 146 additions and 28 deletions

View File

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

View File

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