#!perl
# vim:ts=4:sw=4:expandtab
#
# Please read the following documents before working on tests:
# • https://build.i3wm.org/docs/testsuite.html
# (or docs/testsuite)
#
# • https://build.i3wm.org/docs/lib-i3test.html
# (alternatively: perldoc ./testcases/lib/i3test.pm)
#
# • https://build.i3wm.org/docs/ipc.html
# (or docs/ipc)
#
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
# (unless you are already familiar with Perl)
#
# Test dragging containers.
my ($width, $height) = (1000, 500);
my $config = <<"EOT";
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
focus_follows_mouse no
floating_modifier Mod1
# 2 side by side outputs
fake-outputs ${width}x${height}+0+0P,${width}x${height}+${width}+0
bar {
output primary
}
EOT
use i3test i3_autostart => 0;
use i3test::XTEST;
my $pid = launch_with_config($config);
sub start_drag {
my ($pos_x, $pos_y) = @_;
die "Drag outside of bounds!" unless $pos_x < $width * 2 && $pos_y < $height;
$x->root->warp_pointer($pos_x, $pos_y);
sync_with_i3;
xtest_key_press(64); # Alt_L
xtest_button_press(1, $pos_x, $pos_y);
xtest_sync_with_i3;
}
sub end_drag {
my ($pos_x, $pos_y) = @_;
die "Drag outside of bounds!" unless $pos_x < $width * 2 && $pos_y < $height;
$x->root->warp_pointer($pos_x, $pos_y);
sync_with_i3;
xtest_button_release(1, $pos_x, $pos_y);
xtest_key_release(64); # Alt_L
xtest_sync_with_i3;
}
my ($ws1, $ws2);
my ($A, $B, $tmp);
my ($A_id, $B_id);
sub move_subtest {
my ($cb, $win) = @_;
my @events = events_for($cb, 'window');
my @move = grep { $_->{change} eq 'move' } @events;
is(scalar @move, 1, 'Received 1 window::move event');
is($move[0]->{container}->{window}, $A->{id}, "window id matches");
}
###############################################################################
# Drag floating container onto an empty workspace.
###############################################################################
$ws2 = fresh_workspace(output => 1);
$ws1 = fresh_workspace(output => 0);
$A = open_floating_window(rect => [ 30, 30, 50, 50 ]);
start_drag(40, 40);
end_drag(1050, 50);
is($x->input_focus, $A->id, 'Floating window moved to the right workspace');
is($ws2, focused_ws, 'Empty workspace focused after floating window dragged to it');
###############################################################################
# Drag tiling container onto an empty workspace.
###############################################################################
subtest "Draging tiling container onto an empty workspace produces move event", \&move_subtest,
sub {
$ws2 = fresh_workspace(output => 1);
$ws1 = fresh_workspace(output => 0);
$A = open_window;
start_drag(50, 50);
end_drag(1050, 50);
is($x->input_focus, $A->id, 'Tiling window moved to the right workspace');
is($ws2, focused_ws, 'Empty workspace focused after tiling window dragged to it');
};
###############################################################################
# Drag tiling container onto a container that closes before the drag is
# complete.
###############################################################################
$ws1 = fresh_workspace(output => 0);
$A = open_window;
open_window;
start_drag(600, 300); # Start dragging the second window.
# Try to place it on the first window.
$x->root->warp_pointer(50, 50);
sync_with_i3;
cmd '[id=' . $A->id . '] kill';
sync_with_i3;
end_drag(50, 50);
is(@{get_ws_content($ws1)}, 1, 'One container left in ws1');
###############################################################################
# Drag tiling container onto a tiling container on an other workspace.
###############################################################################
subtest "Draging tiling container onto a tiling container on an other workspace produces move event", \&move_subtest,
sub {
$ws2 = fresh_workspace(output => 1);
open_window;
$B_id = get_focused($ws2);
$ws1 = fresh_workspace(output => 0);
$A = open_window;
$A_id = get_focused($ws1);
start_drag(50, 50);
end_drag(1500, 250); # Center of right output, inner region.
is($ws2, focused_ws, 'Workspace focused after tiling window dragged to it');
$ws2 = get_ws($ws2);
is($ws2->{focus}[0], $A_id, 'A focused first, dragged container kept focus');
is($ws2->{focus}[1], $B_id, 'B focused second');
};
###############################################################################
# Drag tiling container onto a floating container on an other workspace.
###############################################################################
subtest "Draging tiling container onto a floating container on an other workspace produces move event", \&move_subtest,
sub {
$ws2 = fresh_workspace(output => 1);
open_floating_window;
$B_id = get_focused($ws2);
$ws1 = fresh_workspace(output => 0);
$A = open_window;
$A_id = get_focused($ws1);
start_drag(50, 50);
end_drag(1500, 250);
is($ws2, focused_ws, 'Workspace with one floating container focused after tiling window dragged to it');
$ws2 = get_ws($ws2);
is($ws2->{focus}[0], $A_id, 'A focused first, dragged container kept focus');
is($ws2->{floating_nodes}[0]->{nodes}[0]->{id}, $B_id, 'B exists & floating');
};
###############################################################################
# Drag tiling container onto a bar.
###############################################################################
subtest "Draging tiling container onto a bar produces move event", \&move_subtest,
sub {
$ws1 = fresh_workspace(output => 0);
open_window;
$B_id = get_focused($ws1);
$ws2 = fresh_workspace(output => 1);
$A = open_window;
$A_id = get_focused($ws2);
start_drag(1500, 250);
end_drag(1, 498); # Bar on bottom of left output.
is($ws1, focused_ws, 'Workspace focused after tiling window dragged to its bar');
$ws1 = get_ws($ws1);
is($ws1->{focus}[0], $A_id, 'B focused first, dragged container kept focus');
is($ws1->{focus}[1], $B_id, 'A focused second');
};
###############################################################################
# Drag an unfocused tiling container onto it's self.
###############################################################################
$ws1 = fresh_workspace(output => 0);
open_window;
$A_id = get_focused($ws1);
open_window;
$B_id = get_focused($ws1);
start_drag(50, 50);
end_drag(450, 450);
$ws1 = get_ws($ws1);
is($ws1->{focus}[0], $B_id, 'B focused first, kept focus');
is($ws1->{focus}[1], $A_id, 'A focused second, unfocused dragged container didn\'t gain focus');
###############################################################################
# Drag an unfocused tiling container onto an occupied workspace.
###############################################################################
subtest "Draging unfocused tiling container onto an occupied workspace produces move event", \&move_subtest,
sub {
$ws1 = fresh_workspace(output => 0);
$A = open_window;
$A_id = get_focused($ws1);
$ws2 = fresh_workspace(output => 1);
open_window;
$B_id = get_focused($ws2);
start_drag(50, 50);
end_drag(1500, 250); # Center of right output, inner region.
is($ws2, focused_ws, 'Workspace remained focused after dragging unfocused container');
$ws2 = get_ws($ws2);
is($ws2->{focus}[0], $B_id, 'B focused first, kept focus');
is($ws2->{focus}[1], $A_id, 'A focused second, unfocused container didn\'t steal focus');
};
###############################################################################
# Drag fullscreen container onto window in same workspace.
###############################################################################
$ws1 = fresh_workspace(output => 0);
open_window;
$A = open_window;
cmd 'fullscreen enable';
start_drag(900, 100); # Second window
end_drag(50, 50); # To first window
is($ws1, focused_ws, 'Workspace remained focused after dragging fullscreen container');
is_num_fullscreen($ws1, 1, 'Container still fullscreened');
is($x->input_focus, $A->id, 'Fullscreen container still focused');
###############################################################################
# Drag unfocused fullscreen container onto window in other workspace.
###############################################################################
subtest "Draging unfocused fullscreen container onto window in other workspace produces move event", \&move_subtest,
sub {
$ws1 = fresh_workspace(output => 0);
$A = open_window;
cmd 'fullscreen enable';
$ws2 = fresh_workspace(output => 1);
open_window;
open_window;
start_drag(900, 100);
end_drag(1000 + 500 * 0.15 + 10, 200); # left of leftmost window
is($ws2, focused_ws, 'Workspace still focused after dragging fullscreen container to it');
is_num_fullscreen($ws1, 0, 'No fullscreen container in first workspace');
is_num_fullscreen($ws2, 1, 'Moved container still fullscreened');
is($x->input_focus, $A->id, 'Fullscreen container now focused');
$ws2 = get_ws($ws2);
is($ws2->{nodes}->[0]->{window}, $A->id, 'Fullscreen container now leftmost window in second workspace');
};
###############################################################################
# Drag unfocused fullscreen container onto left outter region of window in
# other workspace. The container shouldn't end up in $ws2 because it was
# dragged onto the outter region of the leftmost window. We must also check
# that the focus remains on the other window.
###############################################################################
subtest "Draging unfocused fullscreen container onto left outter region of window in other workspace produces move event", \&move_subtest,
sub {
$ws1 = fresh_workspace(output => 0);
open_window for (1..3);
$A = open_window;
$tmp = get_focused($ws1);
cmd 'fullscreen enable';
$ws2 = fresh_workspace(output => 1);
$B = open_window;
start_drag(990, 100); # rightmost of $ws1
end_drag(1004, 100); # outter region of window of $ws2
is($ws2, focused_ws, 'Workspace still focused after dragging fullscreen container to it');
is_num_fullscreen($ws1, 1, 'Fullscreen container still in first workspace');
is_num_fullscreen($ws2, 0, 'No fullscreen container in second workspace');
is($x->input_focus, $B->id, 'Window of second workspace still has focus');
is(get_focused($ws1), $tmp, 'Fullscreen container still focused in first workspace');
$ws1 = get_ws($ws1);
is($ws1->{nodes}->[3]->{window}, $A->id, 'Fullscreen container still rightmost window in first workspace');
};
exit_gracefully($pid);
###############################################################################
done_testing;