]> git.sur5r.net Git - i3/i3/commitdiff
Reorder tests to not use the same number (#2947)
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Thu, 14 Sep 2017 15:49:02 +0000 (17:49 +0200)
committerGitHub <noreply@github.com>
Thu, 14 Sep 2017 15:49:02 +0000 (17:49 +0200)
Distinct numbers make re-running individual tests easier by helping with
tab-completion.

Completeness verified using:
% for i in $(seq 0 600)
do
  files=$(ls testcases/t/$(printf "%03d" $i)-*.t 2>&- | wc -l)
  [ "$files" != "0" ] && [ "$files" != "1" ] && echo "clash: $i"
done

46 files changed:
testcases/t/165-for_window_tilingfloating.t [deleted file]
testcases/t/173-regress-focus-assign.t [deleted file]
testcases/t/174-regress-focus-toggle.t [deleted file]
testcases/t/213-move-branch-position.t [deleted file]
testcases/t/231-ipc-window-close.t [deleted file]
testcases/t/231-ipc-window-move.t [deleted file]
testcases/t/232-ipc-window-urgent.t [deleted file]
testcases/t/234-layout-restore-output.t [deleted file]
testcases/t/234-regress-default-floating-border.t [deleted file]
testcases/t/235-wm-class-change-handler.t [deleted file]
testcases/t/238-regress-reload-bindsym.t [deleted file]
testcases/t/240-tabbed-floating-disable-crash.t [deleted file]
testcases/t/243-net-wm-state-hidden.t [deleted file]
testcases/t/251-ewmh-visible-name.t [deleted file]
testcases/t/251-sticky.t [deleted file]
testcases/t/262-root-window-mouse-binding.t [deleted file]
testcases/t/263-edge-borders.t [deleted file]
testcases/t/263-i3-floating-window-atom.t [deleted file]
testcases/t/264-ipc-shutdown-event.t [deleted file]
testcases/t/264-keypress-numlock.t [deleted file]
testcases/t/265-swap.t [deleted file]
testcases/t/271-for_window_tilingfloating.t [new file with mode: 0644]
testcases/t/272-regress-focus-assign.t [new file with mode: 0644]
testcases/t/273-regress-focus-toggle.t [new file with mode: 0644]
testcases/t/274-move-branch-position.t [new file with mode: 0644]
testcases/t/275-ipc-window-close.t [new file with mode: 0644]
testcases/t/276-ipc-window-move.t [new file with mode: 0644]
testcases/t/277-ipc-window-urgent.t [new file with mode: 0644]
testcases/t/278-layout-restore-output.t [new file with mode: 0644]
testcases/t/279-regress-default-floating-border.t [new file with mode: 0644]
testcases/t/280-wm-class-change-handler.t [new file with mode: 0644]
testcases/t/281-regress-reload-bindsym.t [new file with mode: 0644]
testcases/t/282-tabbed-floating-disable-crash.t [new file with mode: 0644]
testcases/t/283-net-wm-state-hidden.t [new file with mode: 0644]
testcases/t/284-ewmh-visible-name.t [new file with mode: 0644]
testcases/t/285-sticky.t [new file with mode: 0644]
testcases/t/286-root-window-mouse-binding.t [new file with mode: 0644]
testcases/t/287-edge-borders.t [new file with mode: 0644]
testcases/t/288-i3-floating-window-atom.t [new file with mode: 0644]
testcases/t/289-ipc-shutdown-event.t [new file with mode: 0644]
testcases/t/290-keypress-numlock.t [new file with mode: 0644]
testcases/t/291-swap.t [new file with mode: 0644]
testcases/t/528-workspace-next-prev.t [deleted file]
testcases/t/529-net-wm-desktop_mm.t [deleted file]
testcases/t/535-workspace-next-prev.t [new file with mode: 0644]
testcases/t/536-net-wm-desktop_mm.t [new file with mode: 0644]

diff --git a/testcases/t/165-for_window_tilingfloating.t b/testcases/t/165-for_window_tilingfloating.t
deleted file mode 100644 (file)
index 760ac53..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-use i3test i3_autostart => 0;
-use X11::XCB qw(PROP_MODE_REPLACE);
-
-##############################################################
-# 13: check that the tiling / floating criteria work.
-##############################################################
-
-my $config = <<"EOT";
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-for_window [tiling] mark tiled
-for_window [floating] mark floated
-EOT
-
-my $pid = launch_with_config($config);
-my $tmp = fresh_workspace;
-
-open_window;
-open_floating_window;
-
-my @nodes = @{get_ws($tmp)->{nodes}};
-cmp_ok(@nodes, '==', 1, 'one tiling container on this workspace');
-is_deeply($nodes[0]->{marks}, [ 'tiled' ], "mark set for 'tiling' criterion");
-
-@nodes = @{get_ws($tmp)->{floating_nodes}};
-cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
-is_deeply($nodes[0]->{nodes}[0]->{marks}, [ 'floated' ], "mark set for 'floating' criterion");
-
-exit_gracefully($pid);
-
-##############################################################
-
-done_testing;
diff --git a/testcases/t/173-regress-focus-assign.t b/testcases/t/173-regress-focus-assign.t
deleted file mode 100644 (file)
index b010963..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Regression: Checks if focus is stolen when a window is managed which is
-# assigned to an invisible workspace
-#
-use i3test i3_autostart => 0;
-
-sub open_special {
-    my %args = @_;
-    $args{name} //= 'special window';
-
-    # We use dont_map because i3 will not map the window on the current
-    # workspace. Thus, open_window would time out in wait_for_map (2 seconds).
-    my $window = open_window(
-        %args,
-        wm_class => 'special',
-        dont_map => 1,
-    );
-    $window->map;
-    return $window;
-}
-
-#####################################################################
-# start a window and see that it does not get assigned with an empty config
-#####################################################################
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-assign [class="special"] targetws
-EOT
-
-my $pid = launch_with_config($config);
-
-my $tmp = fresh_workspace;
-
-ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
-ok(get_ws($tmp)->{focused}, 'current workspace focused');
-
-my $window = open_special;
-sync_with_i3;
-
-ok(@{get_ws_content($tmp)} == 0, 'special window not on current workspace');
-ok(@{get_ws_content('targetws')} == 1, 'special window on targetws');
-ok(get_ws($tmp)->{focused}, 'current workspace still focused');
-
-#####################################################################
-# the same test, but with a floating window
-#####################################################################
-
-$window = open_special(
-    window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'),
-);
-
-ok(@{get_ws_content($tmp)} == 0, 'special window not on current workspace');
-ok(@{get_ws_content('targetws')} == 1, 'special window on targetws');
-ok(get_ws($tmp)->{focused}, 'current workspace still focused');
-
-exit_gracefully($pid);
-
-$window->destroy;
-
-done_testing;
diff --git a/testcases/t/174-regress-focus-toggle.t b/testcases/t/174-regress-focus-toggle.t
deleted file mode 100644 (file)
index 192e975..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Regression: Checks if i3 still lives after using 'focus mode_toggle' on an
-# empty workspace. This regression was fixed in
-# 0848844f2d41055f6ffc69af1149d7a873460976.
-#
-use i3test;
-use v5.10;
-
-my $tmp = fresh_workspace;
-
-cmd 'focus mode_toggle';
-
-does_i3_live;
-
-done_testing;
diff --git a/testcases/t/213-move-branch-position.t b/testcases/t/213-move-branch-position.t
deleted file mode 100644 (file)
index c2928c9..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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 that movement of a con into a branch will place the moving con at the
-# correct position within the branch.
-#
-# If the direction of movement is the same as the orientation of the branch
-# container, append or prepend the container to the branch in the obvious way.
-# If the movement is to the right or downward, insert the moving container in
-# the first position (i.e., the leftmost or top position resp.) If the movement
-# is to the left or upward, insert the moving container in the last position
-# (i.e., the rightmost or bottom position resp.)
-#
-# If the direction of movement is different from the orientation of the branch
-# container, insert the container into the branch after the focused-inactive
-# container.
-#
-# For testing purposes, we will demonstrate the behavior for tabbed containers
-# to represent the case of split-horizontal branches and stacked containers to
-# represent the case of split-vertical branches.
-#
-# Ticket: #1060
-# Bug still in: 4.6-109-g18cfc36
-
-use i3test;
-
-# Opens tabs on the presently focused branch and adds several additional
-# windows. Shifts focus to somewhere in the middle of the tabs so the most
-# general case can be assumed.
-sub open_tabs {
-    cmd 'layout tabbed';
-    open_window;
-    open_window;
-    open_window;
-    open_window;
-    cmd 'focus left; focus left'
-}
-
-# Likewise for a stack
-sub open_stack {
-    cmd 'layout stacking';
-    open_window;
-    open_window;
-    open_window;
-    open_window;
-    cmd 'focus up; focus up'
-}
-
-# Gets the position of the given leaf within the given branch. The first
-# position is one (1). Returns negative one (-1) if the leaf cannot be found
-# within the branch.
-sub get_leaf_position {
-    my ($branch, $leaf) = @_;
-    my $position = -1;
-    for my $i (0 .. @{$branch->{nodes}}) {
-        if ($branch->{nodes}[$i]->{id} == $leaf) {
-            $position = $i + 1;
-            last;
-        };
-    }
-    return $position;
-}
-
-# convenience function to focus a con by id to avoid having to type an ugly
-# command each time
-sub focus_con {
-    my $con_id = shift @_;
-    cmd "[con_id=\"$con_id\"] focus";
-}
-
-# Places a leaf into a branch and focuses the leaf. The newly created branch
-# will have orientation specified by the second parameter.
-sub branchify {
-    my ($con_id, $orientation) = @_;
-    focus_con($con_id);
-    $orientation eq 'horizontal' ? cmd 'splith' : cmd 'splitv';
-    open_window;
-    focus_con($con_id);
-}
-
-##############################################################################
-# When moving a con right into tabs, the moving con should be placed as the
-# first tab in the branch
-##############################################################################
-my $ws = fresh_workspace;
-
-# create the target leaf
-open_window;
-my $target_leaf = get_focused($ws);
-
-# create the tabbed branch container
-open_window;
-cmd 'splith';
-open_tabs;
-
-# move the target leaf into the tabbed branch
-focus_con($target_leaf);
-cmd 'move right';
-
-# the target leaf should be the first in the branch
-my $branch = shift @{get_ws_content($ws)};
-is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con right into tabs placed it as the first tab in the branch');
-
-# repeat the test when the target is in a branch
-cmd 'move up; move left';
-branchify($target_leaf, 'vertical');
-cmd 'move right';
-
-$branch = pop @{get_ws_content($ws)};
-is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con right into tabs from a branch placed it as the first tab in the branch');
-
-##############################################################################
-# When moving a con right into a stack, the moving con should be placed
-# below the focused-inactive leaf
-##############################################################################
-$ws = fresh_workspace;
-
-# create the target leaf
-open_window;
-$target_leaf = get_focused($ws);
-
-# create the stacked branch container and find the focused leaf
-open_window;
-cmd 'splith';
-open_stack;
-my $secondary_leaf = get_focused($ws);
-
-# move the target leaf into the stacked branch
-focus_con($target_leaf);
-cmd 'move right';
-
-# the secondary focus leaf should be below the target
-$branch = shift @{get_ws_content($ws)};
-my $target_leaf_position = get_leaf_position($branch, $target_leaf);
-my $secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con right into a stack placed it below the focused-inactive leaf');
-
-# repeat the test when the target is in a branch
-cmd 'move up; move left';
-branchify($target_leaf, 'vertical');
-cmd 'move right';
-
-$branch = pop @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con right into a stack from a branch placed it below the focused-inactive leaf');
-
-##############################################################################
-# When moving a con down into a stack, the moving con should be placed at the
-# top of the stack
-##############################################################################
-$ws = fresh_workspace;
-cmd 'layout splitv';
-
-# create the target leaf
-open_window;
-$target_leaf = get_focused($ws);
-
-# create the stacked branch container
-open_window;
-cmd 'splitv';
-open_stack;
-
-# move the target leaf into the stacked branch
-focus_con($target_leaf);
-cmd 'move down';
-
-# the target leaf should be on the top of the stack
-$branch = shift @{get_ws_content($ws)};
-is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con down into a stack placed it on the top of the stack');
-
-# repeat the test when the target is in a branch
-cmd 'move right; move up';
-branchify($target_leaf, 'horizontal');
-cmd 'move down';
-
-$branch = pop @{get_ws_content($ws)};
-is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con down into a stack from a branch placed it on the top of the stack');
-
-##############################################################################
-# When moving a con down into tabs, the moving con should be placed after the
-# focused-inactive tab
-##############################################################################
-$ws = fresh_workspace;
-cmd 'layout splitv';
-
-# create the target leaf
-open_window;
-$target_leaf = get_focused($ws);
-
-# create the tabbed branch container and find the focused tab
-open_window;
-cmd 'splitv';
-open_tabs;
-$secondary_leaf = get_focused($ws);
-
-# move the target leaf into the tabbed branch
-focus_con($target_leaf);
-cmd 'move down';
-
-# the secondary focus tab should be to the right
-$branch = shift @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con down into tabs placed it after the focused-inactive tab');
-
-# repeat the test when the target is in a branch
-cmd 'move right; move up';
-branchify($target_leaf, 'horizontal');
-cmd 'move down';
-
-$branch = pop @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con down into tabs from a branch placed it after the focused-inactive tab');
-
-##############################################################################
-# When moving a con left into tabs, the moving con should be placed as the last
-# tab in the branch
-##############################################################################
-$ws = fresh_workspace;
-
-# create the tabbed branch container
-open_window;
-cmd 'splith';
-open_tabs;
-
-# create the target leaf
-cmd 'focus parent';
-open_window;
-$target_leaf = get_focused($ws);
-
-# move the target leaf into the tabbed branch
-cmd 'move left';
-
-# the target leaf should be last in the branch
-$branch = shift @{get_ws_content($ws)};
-
-is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con left into tabs placed it as the last tab in the branch');
-
-# repeat the test when the target leaf is in a branch
-cmd 'move up; move right';
-branchify($target_leaf, 'vertical');
-cmd 'move left';
-
-$branch = shift @{get_ws_content($ws)};
-is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con left into tabs from a branch placed it as the last tab in the branch');
-
-##############################################################################
-# When moving a con left into a stack, the moving con should be placed below
-# the focused-inactive leaf
-##############################################################################
-$ws = fresh_workspace;
-
-# create the stacked branch container and find the focused leaf
-open_window;
-open_stack;
-$secondary_leaf = get_focused($ws);
-
-# create the target leaf to the right
-cmd 'focus parent';
-open_window;
-$target_leaf = get_focused($ws);
-
-# move the target leaf into the stacked branch
-cmd 'move left';
-
-# the secondary focus leaf should be below
-$branch = shift @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con left into a stack placed it below the focused-inactive leaf');
-
-# repeat the test when the target leaf is in a branch
-cmd 'move up; move right';
-branchify($target_leaf, 'vertical');
-cmd 'move left';
-
-$branch = shift @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con left into a stack from a branch placed it below the focused-inactive leaf');
-
-##############################################################################
-# When moving a con up into a stack, the moving con should be placed last in
-# the stack
-##############################################################################
-$ws = fresh_workspace;
-cmd 'layout splitv';
-
-# create the stacked branch container
-open_window;
-cmd 'splitv';
-open_stack;
-
-# create the target leaf
-cmd 'focus parent';
-open_window;
-$target_leaf = get_focused($ws);
-
-# move the target leaf into the stacked branch
-cmd 'move up';
-
-# the target leaf should be on the bottom of the stack
-$branch = shift @{get_ws_content($ws)};
-
-is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con up into stack placed it on the bottom of the stack');
-
-# repeat the test when the target leaf is in a branch
-cmd 'move right; move down';
-branchify($target_leaf, 'horizontal');
-cmd 'move up';
-
-$branch = shift @{get_ws_content($ws)};
-
-is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con up into stack from a branch placed it on the bottom of the stack');
-
-##############################################################################
-# When moving a con up into tabs, the moving con should be placed after the
-# focused-inactive tab
-##############################################################################
-$ws = fresh_workspace;
-cmd 'layout splitv';
-
-# create the tabbed branch container and find the focused leaf
-open_window;
-cmd 'splitv';
-open_tabs;
-$secondary_leaf = get_focused($ws);
-
-# create the target leaf below
-cmd 'focus parent';
-open_window;
-$target_leaf = get_focused($ws);
-
-# move the target leaf into the tabbed branch
-cmd 'move up';
-
-# the secondary focus tab should be to the right
-$branch = shift @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con up into tabs placed it after the focused-inactive tab');
-
-# repeat the test when the target leaf is in a branch
-cmd 'move right; move down';
-branchify($target_leaf, 'horizontal');
-cmd 'move up';
-
-$branch = shift @{get_ws_content($ws)};
-$target_leaf_position = get_leaf_position($branch, $target_leaf);
-$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
-
-is($target_leaf_position, $secondary_leaf_position + 1, 'moving con up into tabs from a branch placed it after the focused-inactive tab');
-
-done_testing;
diff --git a/testcases/t/231-ipc-window-close.t b/testcases/t/231-ipc-window-close.t
deleted file mode 100644 (file)
index 3483cf4..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests that the ipc close event works properly
-#
-# Bug still in: 4.8-7-gf4a8253
-use i3test;
-
-my $i3 = i3(get_socket_path());
-$i3->connect()->recv;
-
-my $cv;
-my $t;
-
-sub reset_test {
-    $cv = AE::cv;
-    $t = AE::timer(0.5, 0, sub { $cv->send(0); });
-}
-
-reset_test;
-
-$i3->subscribe({
-        window => sub {
-            my ($e) = @_;
-            if ($e->{change} eq 'close') {
-                $cv->send($e->{container});
-            }
-        },
-    })->recv;
-
-my $window = open_window;
-
-cmd 'kill';
-my $con = $cv->recv;
-
-ok($con, 'closing a window should send the window::close event');
-is($con->{window}, $window->{id}, 'the event should contain information about the window');
-
-done_testing;
diff --git a/testcases/t/231-ipc-window-move.t b/testcases/t/231-ipc-window-move.t
deleted file mode 100644 (file)
index 117d27f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests that the ipc window::move event works properly
-#
-# Bug still in: 4.8-7-gf4a8253
-use i3test;
-
-my $i3 = i3(get_socket_path());
-$i3->connect()->recv;
-
-my $cv;
-my $t;
-
-sub reset_test {
-    $cv = AE::cv;
-    $t = AE::timer(0.5, 0, sub { $cv->send(0); });
-}
-
-reset_test;
-
-$i3->subscribe({
-        window => sub {
-            my ($e) = @_;
-            if ($e->{change} eq 'move') {
-                $cv->send($e->{container});
-            }
-        },
-    })->recv;
-
-my $dummy_window = open_window;
-my $window = open_window;
-
-cmd 'move right';
-my $con = $cv->recv;
-
-ok($con, 'moving a window should emit the window::move event');
-is($con->{window}, $window->{id}, 'the event should contain info about the window');
-
-reset_test;
-
-cmd 'move to workspace ws_new';
-$con = $cv->recv;
-
-ok($con, 'moving a window to a different workspace should emit the window::move event');
-is($con->{window}, $window->{id}, 'the event should contain info about the window');
-
-done_testing;
diff --git a/testcases/t/232-ipc-window-urgent.t b/testcases/t/232-ipc-window-urgent.t
deleted file mode 100644 (file)
index 09226ff..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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 that the window::urgent event works correctly. The window::urgent event
-# should be emitted when a window becomes urgent or loses its urgent status.
-#
-use i3test;
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-force_display_urgency_hint 0ms
-EOT
-
-my $i3 = i3(get_socket_path());
-$i3->connect()->recv;
-
-my $cv;
-$i3->subscribe({
-    window => sub {
-        my ($event) = @_;
-        $cv->send($event) if $event->{change} eq 'urgent';
-    }
-})->recv;
-
-my $t;
-$t = AnyEvent->timer(
-    after => 0.5,
-    cb => sub {
-        $cv->send(0);
-    }
-);
-
-$cv = AnyEvent->condvar;
-fresh_workspace;
-my $win = open_window;
-my $dummy_win = open_window;
-
-$win->add_hint('urgency');
-my $event = $cv->recv;
-
-isnt($event, 0, 'an urgent con should emit the window::urgent event');
-is($event->{container}->{window}, $win->{id}, 'the event should contain information about the window');
-is($event->{container}->{urgent}, 1, 'the container should be urgent');
-
-$cv = AnyEvent->condvar;
-$win->delete_hint('urgency');
-$event = $cv->recv;
-
-isnt($event, 0, 'an urgent con should emit the window::urgent event');
-is($event->{container}->{window}, $win->{id}, 'the event should contain information about the window');
-is($event->{container}->{urgent}, 0, 'the container should not be urgent');
-
-done_testing;
diff --git a/testcases/t/234-layout-restore-output.t b/testcases/t/234-layout-restore-output.t
deleted file mode 100644 (file)
index 5a1f376..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Verifies that entire outputs can be saved and restored properly by i3.
-# Ticket: #1306
-# Bug still in: 4.8-26-gf96ec19
-use i3test;
-use File::Temp qw(tempfile);
-use IO::Handle;
-
-my $ws = fresh_workspace;
-
-################################################################################
-# Append a new workspace with a name.
-################################################################################
-
-ok(!workspace_exists('ws_new'), 'workspace "ws_new" does not exist yet');
-
-my ($fh, $filename) = tempfile(UNLINK => 1);
-print $fh <<'EOT';
-// vim:ts=4:sw=4:et
-{
-    // workspace with 1 children
-    "border": "pixel",
-    "floating": "auto_off",
-    "layout": "splith",
-    "percent": null,
-    "type": "workspace",
-    "name": "ws_new",
-    "nodes": [
-        {
-            "border": "pixel",
-            "floating": "auto_off",
-            "geometry": {
-               "height": 268,
-               "width": 484,
-               "x": 0,
-               "y": 0
-            },
-            "name": "vals@w00t: ~",
-            "percent": 1,
-            "swallows": [
-               {
-                  "class": "^URxvt$"
-               // "instance": "^urxvt$",
-               // "title": "^vals\\@w00t\\:\\ \\~$"
-               }
-            ],
-            "type": "con"
-        }
-    ]
-}
-EOT
-$fh->flush;
-cmd "append_layout $filename";
-
-ok(workspace_exists('ws_new'), 'workspace "ws_new" exists now');
-
-does_i3_live;
-
-close($fh);
-
-################################################################################
-# Append a new workspace with a name that clashes with an existing workspace.
-################################################################################
-
-my @old_workspaces = @{get_workspace_names()};
-
-cmd "append_layout $filename";
-
-my @new_workspaces = @{get_workspace_names()};
-cmp_ok(scalar @new_workspaces, '>', scalar @old_workspaces, 'more workspaces than before');
-
-my %created_workspaces = map { ($_, 1) } @new_workspaces;
-delete $created_workspaces{$_} for @old_workspaces;
-diag('created workspaces = ' . Dumper(keys %created_workspaces));
-cmp_ok(scalar keys %created_workspaces, '>', 0, 'new workspaces appeared');
-
-################################################################################
-# Append a new workspace without a name.
-################################################################################
-
-ok(!workspace_exists('unnamed'), 'workspace "unnamed" does not exist yet');
-
-($fh, $filename) = tempfile(UNLINK => 1);
-print $fh <<'EOT';
-// vim:ts=4:sw=4:et
-{
-    // workspace with 1 children
-    "border": "pixel",
-    "floating": "auto_off",
-    "layout": "splith",
-    "percent": null,
-    "type": "workspace",
-    "nodes": [
-        {
-            "border": "pixel",
-            "floating": "auto_off",
-            "geometry": {
-               "height": 268,
-               "width": 484,
-               "x": 0,
-               "y": 0
-            },
-            "name": "vals@w00t: ~",
-            "percent": 1,
-            "swallows": [
-               {
-                  "class": "^URxvt$"
-               // "instance": "^urxvt$",
-               // "title": "^vals\\@w00t\\:\\ \\~$"
-               }
-            ],
-            "type": "con"
-        }
-    ]
-}
-EOT
-$fh->flush;
-cmd "append_layout $filename";
-
-ok(workspace_exists('unnamed'), 'workspace "unnamed" exists now');
-
-################################################################################
-# Append a workspace with a numeric name, ensure it has ->num set.
-################################################################################
-
-ok(!workspace_exists('4'), 'workspace "4" does not exist yet');
-
-($fh, $filename) = tempfile(UNLINK => 1);
-print $fh <<'EOT';
-// vim:ts=4:sw=4:et
-{
-    // workspace with 1 children
-    "border": "pixel",
-    "floating": "auto_off",
-    "layout": "splith",
-    "percent": null,
-    "type": "workspace",
-    "name": "4",
-    "nodes": [
-        {
-            "border": "pixel",
-            "floating": "auto_off",
-            "geometry": {
-               "height": 268,
-               "width": 484,
-               "x": 0,
-               "y": 0
-            },
-            "name": "vals@w00t: ~",
-            "percent": 1,
-            "swallows": [
-               {
-                  "class": "^URxvt$"
-               // "instance": "^urxvt$",
-               // "title": "^vals\\@w00t\\:\\ \\~$"
-               }
-            ],
-            "type": "con"
-        }
-    ]
-}
-EOT
-$fh->flush;
-cmd "append_layout $filename";
-
-ok(workspace_exists('4'), 'workspace "4" exists now');
-$ws = get_ws("4");
-is($ws->{num}, 4, 'workspace number is 4');
-
-################################################################################
-# Append a workspace with a numeric name, with the “type” property at the end
-# of the JSON blurb (which is valid and sometimes happens).
-################################################################################
-
-ok(!workspace_exists('5'), 'workspace "5" does not exist yet');
-
-($fh, $filename) = tempfile(UNLINK => 1);
-print $fh <<'EOT';
-// vim:ts=4:sw=4:et
-{
-    // workspace with 1 children
-    "border": "pixel",
-    "floating": "auto_off",
-    "layout": "splith",
-    "percent": null,
-    "name": "5",
-    "nodes": [
-        {
-            "border": "pixel",
-            "floating": "auto_off",
-            "geometry": {
-               "height": 268,
-               "width": 484,
-               "x": 0,
-               "y": 0
-            },
-            "name": "vals@w00t: ~",
-            "percent": 1,
-            "swallows": [
-               {
-                  "class": "^URxvt$"
-               // "instance": "^urxvt$",
-               // "title": "^vals\\@w00t\\:\\ \\~$"
-               }
-            ],
-            "type": "con"
-        }
-    ],
-    "type": "workspace"
-}
-EOT
-$fh->flush;
-cmd "append_layout $filename";
-
-ok(workspace_exists('5'), 'workspace "5" exists now');
-$ws = get_ws("5");
-is($ws->{num}, 5, 'workspace number is 5');
-
-done_testing;
diff --git a/testcases/t/234-regress-default-floating-border.t b/testcases/t/234-regress-default-floating-border.t
deleted file mode 100644 (file)
index d5994f5..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# This is a regression test for a bug where a normal floating default border is
-# not applied when the default tiling border is set to a pixel value.
-# Ticket: #1305
-# Bug still in: 4.8-62-g7381b50
-use i3test i3_autostart => 0;
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-new_window pixel 5
-new_float normal
-EOT
-
-my $pid = launch_with_config($config);
-
-my $ws = fresh_workspace;
-
-my $float_window = open_floating_window;
-
-my @floating = @{get_ws($ws)->{floating_nodes}};
-
-is($floating[0]->{nodes}[0]->{border}, 'normal', 'default floating border is `normal`');
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/235-wm-class-change-handler.t b/testcases/t/235-wm-class-change-handler.t
deleted file mode 100644 (file)
index ce237b5..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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 that changes to WM_CLASS are internally processed by i3 by updating the
-# cached property and running assignments. This allows the property to be used
-# in criteria selection
-# Ticket: #1052
-# Bug still in: 4.8-73-g6bf7f8e
-use i3test i3_autostart => 0;
-use X11::XCB qw(PROP_MODE_REPLACE);
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-for_window [class="Special"] mark special_class_mark
-EOT
-
-my $pid = launch_with_config($config);
-
-sub change_window_class {
-    my ($window, $class, $length) = @_;
-    my $atomname = $x->atom(name => 'WM_CLASS');
-    my $atomtype = $x->atom(name => 'STRING');
-    $length ||= length($class) + 1;
-    $x->change_property(
-        PROP_MODE_REPLACE,
-        $window->id,
-        $atomname->id,
-        $atomtype->id,
-        8,
-        $length,
-        $class
-    );
-    sync_with_i3;
-}
-
-my $ws = fresh_workspace;
-
-my $win = open_window;
-
-change_window_class($win, "special\0Special");
-
-my $con = @{get_ws_content($ws)}[0];
-
-is($con->{window_properties}->{class}, 'Special',
-    'The container class should be updated when a window changes class');
-
-is($con->{window_properties}->{instance}, 'special',
-    'The container instance should be updated when a window changes instance');
-
-# The mark `special_class_mark` is added in a `for_window` assignment in the
-# config for testing purposes
-is_deeply($con->{marks}, [ 'special_class_mark' ],
-    'A `for_window` assignment should run for a match when the window changes class');
-
-change_window_class($win, "abcdefghijklmnopqrstuv\0abcd", 24);
-
-$con = @{get_ws_content($ws)}[0];
-
-is($con->{window_properties}->{class}, 'a',
-    'Non-null-terminated strings should be handled correctly');
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/238-regress-reload-bindsym.t b/testcases/t/238-regress-reload-bindsym.t
deleted file mode 100644 (file)
index 6d5d12c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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 that the binding event works properly
-# Ticket: #1210
-use i3test i3_autostart => 0;
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-bindsym r reload
-EOT
-
-SKIP: {
-    qx(which xdotool 2> /dev/null);
-
-    skip 'xdotool is required to test the binding event. `[apt-get install|pacman -S] xdotool`', 1 if $?;
-
-    my $pid = launch_with_config($config);
-
-    my $i3 = i3(get_socket_path());
-    $i3->connect->recv;
-
-    qx(xdotool key r);
-
-    does_i3_live;
-
-    exit_gracefully($pid);
-
-}
-done_testing;
diff --git a/testcases/t/240-tabbed-floating-disable-crash.t b/testcases/t/240-tabbed-floating-disable-crash.t
deleted file mode 100644 (file)
index 7947158..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Verifies that i3 does not crash when floating and then unfloating an
-# unfocused window within a tabbed container.
-# Ticket: #1484
-# Bug still in: 4.9.1-124-g856e1f9
-use i3test i3_autostart => 0;
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-workspace_layout tabbed
-EOT
-
-my $pid = launch_with_config($config);
-
-open_window;
-open_window;
-
-# Mark the second window, then focus the workspace.
-cmd 'mark foo, focus parent, focus parent';
-
-# Float and unfloat the marked window (without it being focused).
-cmd '[con_mark=foo] floating enable, floating disable';
-
-does_i3_live;
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/243-net-wm-state-hidden.t b/testcases/t/243-net-wm-state-hidden.t
deleted file mode 100644 (file)
index 3f2301c..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests for setting and removing the _NET_WM_STATE_HIDDEN atom properly.
-# Ticket: #1648
-use i3test;
-use X11::XCB qw(:all);
-
-sub is_hidden {
-    sync_with_i3;
-    my $atom = $x->atom(name => '_NET_WM_STATE_HIDDEN');
-
-    my ($con) = @_;
-    my $cookie = $x->get_property(
-        0,
-        $con->{id},
-        $x->atom(name => '_NET_WM_STATE')->id,
-        GET_PROPERTY_TYPE_ANY,
-        0,
-        4096
-    );
-
-    my $reply = $x->get_property_reply($cookie->{sequence});
-    my $len = $reply->{length};
-    return 0 if $len == 0;
-
-    my @atoms = unpack("L$len", $reply->{value});
-    for (my $i = 0; $i < $len; $i++) {
-        return 1 if $atoms[$i] == $atom->id;
-    }
-
-    return 0;
-}
-
-my ($tabA, $tabB, $tabC, $subtabA, $subtabB, $windowA, $windowB);
-
-###############################################################################
-# Given two containers next to each other, when focusing one, then the other
-# one does not have _NET_WM_STATE_HIDDEN set.
-###############################################################################
-
-fresh_workspace;
-$windowA = open_window;
-$windowB = open_window;
-
-ok(!is_hidden($windowA), 'left window does not have _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($windowB), 'right window does not have _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given two containers on different workspaces, when one is focused, then
-# the other one does not have _NET_WM_STATE_HIDDEN set.
-###############################################################################
-
-fresh_workspace;
-$windowA = open_window;
-fresh_workspace;
-$windowB = open_window;
-
-ok(!is_hidden($windowA), 'left window does not have _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($windowB), 'right window does not have _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given two containers in the same tabbed container, when one is focused, then
-# (only) the other one has _NET_WM_STATE_HIDDEN set.
-# Given the other tab is focused, then the atom is transferred.
-###############################################################################
-
-fresh_workspace;
-$tabA = open_window;
-cmd 'layout tabbed';
-$tabB = open_window;
-
-ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabB), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
-
-cmd 'focus left';
-
-ok(!is_hidden($tabA), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
-ok(is_hidden($tabB), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given three containers in the same stacked container, when the focused tab
-# is moved to another workspace, then the now focused tab does not have
-# _NET_WM_STATE_HIDDEN set anymore.
-###############################################################################
-
-fresh_workspace;
-$tabA = open_window;
-cmd 'layout stacked';
-$tabB = open_window;
-$tabC = open_window;
-cmd 'move window to workspace unused';
-
-ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabB), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabC), 'moved window does not have _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given three containers in the same stacked container, when a not focused
-# tab is moved to another workspace, then it does not have _NET_WM_STATE_HIDDEN
-# set anymore.
-###############################################################################
-
-fresh_workspace;
-$tabA = open_window;
-cmd 'layout stacked';
-$tabB = open_window;
-cmd 'mark moveme';
-$tabC = open_window;
-cmd '[con_mark="moveme"] move window to workspace unused';
-
-ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabB), 'moved window does not have _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabC), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given a tabbed container and some other container, when the latter is moved
-# into the tabbed container, then all other tabs have _NET_WM_STATE_HIDDEN
-# set.
-###############################################################################
-
-fresh_workspace;
-$tabA = open_window;
-cmd 'layout tabbed';
-$tabB = open_window;
-cmd 'focus parent';
-cmd 'split h';
-$tabC = open_window;
-cmd 'move left';
-
-ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
-ok(is_hidden($tabB), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabC), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given a stacked container nested inside another tabbed container with the
-# inner one being in the currently focused tab, then the focused tab of the
-# inner container does not have _NET_WM_STATE_HIDDEN set.
-###############################################################################
-
-fresh_workspace;
-$tabA = open_window;
-cmd 'layout tabbed';
-$tabB = open_window;
-cmd 'split h';
-open_window;
-cmd 'split v';
-cmd 'layout stacked';
-$subtabA = open_window;
-$subtabB = open_window;
-
-ok(is_hidden($tabA), 'unfocused outer tab has _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($tabB), 'focused outer tab does not have _NET_WM_STATE_HIDDEN set');
-ok(is_hidden($subtabA), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set');
-ok(!is_hidden($subtabB), 'focused inner tab does not have _NET_WM_STATE_HIDDEN set');
-
-cmd 'focus left';
-
-ok(!is_hidden($subtabB), 'focused inner tab does not have _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-# Given a stacked container nested inside another tabbed container with the
-# inner one being in a currently not focused tab, then all tabs of the inner
-# container have _NET_WM_STATE_HIDDEN set.
-###############################################################################
-
-fresh_workspace;
-$tabA = open_window;
-cmd 'layout tabbed';
-$tabB = open_window;
-cmd 'split h';
-open_window;
-cmd 'split v';
-cmd 'layout stacked';
-$subtabA = open_window;
-$subtabB = open_window;
-cmd 'focus parent';
-cmd 'focus parent';
-cmd 'focus left';
-
-ok(!is_hidden($tabA), 'focused outer tab does not have _NET_WM_STATE_HIDDEN set');
-ok(is_hidden($tabB), 'unfocused outer tab has _NET_WM_STATE_HIDDEN set');
-ok(is_hidden($subtabA), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set');
-ok(is_hidden($subtabB), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set');
-
-###############################################################################
-
-done_testing;
diff --git a/testcases/t/251-ewmh-visible-name.t b/testcases/t/251-ewmh-visible-name.t
deleted file mode 100644 (file)
index c201b39..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests that _NET_WM_VISIBLE_NAME is set correctly.
-# Ticket: #1872
-use i3test;
-use X11::XCB qw(:all);
-
-my ($con);
-
-sub get_visible_name {
-    sync_with_i3;
-    my ($con) = @_;
-
-    my $cookie = $x->get_property(
-        0,
-        $con->{id},
-        $x->atom(name => '_NET_WM_VISIBLE_NAME')->id,
-        $x->atom(name => 'UTF8_STRING')->id,
-        0,
-        4096
-    );
-
-    my $reply = $x->get_property_reply($cookie->{sequence});
-    return undef if $reply->{value_len} == 0;
-    return $reply->{value};
-}
-
-###############################################################################
-# 1: _NET_WM_VISIBLE_NAME is set when the title format of a window is changed.
-###############################################################################
-
-fresh_workspace;
-$con = open_window(name => 'boring title');
-is(get_visible_name($con), undef, 'sanity check: initially no visible name is set');
-
-cmd 'title_format custom';
-is(get_visible_name($con), 'custom', 'the visible name is updated');
-
-cmd 'title_format "<s>%title</s>"';
-is(get_visible_name($con), '<s>boring title</s>', 'markup is returned as is');
-
-###############################################################################
-# 2: _NET_WM_VISIBLE_NAME is removed if not needed.
-###############################################################################
-
-fresh_workspace;
-$con = open_window(name => 'boring title');
-cmd 'title_format custom';
-is(get_visible_name($con), 'custom', 'sanity check: a visible name is set');
-
-cmd 'title_format %title';
-is(get_visible_name($con), undef, 'the visible name is removed again');
-
-###############################################################################
-
-done_testing;
diff --git a/testcases/t/251-sticky.t b/testcases/t/251-sticky.t
deleted file mode 100644 (file)
index 85fc11f..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests sticky windows.
-# Ticket: #1455
-use i3test;
-
-my ($ws, $tmp, $focused);
-
-###############################################################################
-# 1: Given a sticky tiling container, when the workspace is switched, then
-#    nothing happens.
-###############################################################################
-fresh_workspace;
-open_window(wm_class => 'findme');
-cmd 'sticky enable';
-$ws = fresh_workspace;
-
-is(@{get_ws($ws)->{nodes}}, 0, 'tiling sticky container did not move');
-is(@{get_ws($ws)->{floating_nodes}}, 0, 'tiling sticky container did not move');
-cmd '[class="findme"] kill';
-
-###############################################################################
-# 2: Given a sticky floating container, when the workspace is switched, then
-#    the container moves to the new workspace.
-###############################################################################
-$ws = fresh_workspace;
-open_floating_window(wm_class => 'findme');
-$focused = get_focused($ws);
-cmd 'sticky enable';
-$ws = fresh_workspace;
-
-is(@{get_ws($ws)->{floating_nodes}}, 1, 'floating sticky container moved to new workspace');
-is(get_focused($ws), $focused, 'sticky container has focus');
-cmd '[class="findme"] kill';
-
-###############################################################################
-# 3: Given two sticky floating containers, when the workspace is switched,
-#    then both containers move to the new workspace.
-###############################################################################
-fresh_workspace;
-open_floating_window(wm_class => 'findme');
-cmd 'sticky enable';
-open_floating_window(wm_class => 'findme');
-cmd 'sticky enable';
-$ws = fresh_workspace;
-
-is(@{get_ws($ws)->{floating_nodes}}, 2, 'multiple sticky windows can be used at the same time');
-cmd '[class="findme"] kill';
-
-###############################################################################
-# 4: Given an unfocused sticky floating container and a tiling container on the
-#    target workspace, when the workspace is switched, then the tiling container
-#    is focused.
-###############################################################################
-$ws = fresh_workspace;
-open_window;
-$focused = get_focused($ws);
-fresh_workspace;
-open_floating_window(wm_class => 'findme');
-cmd 'sticky enable';
-open_window;
-cmd 'workspace ' . $ws;
-
-is(get_focused($ws), $focused, 'the tiling container has focus');
-cmd '[class="findme"] kill';
-
-###############################################################################
-# 5: Given a focused sticky floating container and a tiling container on the
-#    target workspace, when the workspace is switched, then the tiling container
-#    is focused.
-###############################################################################
-$ws = fresh_workspace;
-open_window;
-$tmp = fresh_workspace;
-open_floating_window(wm_class => 'findme');
-$focused = get_focused($tmp);
-cmd 'sticky enable';
-cmd 'workspace ' . $ws;
-
-is(get_focused($ws), $focused, 'the sticky container has focus');
-cmd '[class="findme"] kill';
-
-###############################################################################
-# 6: Given a floating container on a non-visible workspace, when the window
-#    is made sticky, then the window immediately jumps to the currently
-#    visible workspace.
-###############################################################################
-fresh_workspace;
-open_floating_window(wm_class => 'findme');
-cmd 'mark sticky';
-$ws = fresh_workspace;
-cmd '[con_mark=sticky] sticky enable';
-
-is(@{get_ws($ws)->{floating_nodes}}, 1, 'the sticky window jumps to the front');
-cmd '[class="findme"] kill';
-
-###############################################################################
-
-done_testing;
diff --git a/testcases/t/262-root-window-mouse-binding.t b/testcases/t/262-root-window-mouse-binding.t
deleted file mode 100644 (file)
index c8fd89e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Verifies that mouse bindings work on the root window if
-# --whole-window is set.
-# Ticket: #2115
-use i3test i3_autostart => 0;
-use i3test::XTEST;
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-workspace_auto_back_and_forth no
-bindsym --whole-window button4 workspace special
-EOT
-
-my $pid = launch_with_config($config);
-fresh_workspace;
-
-xtest_button_press(4, 50, 50);
-xtest_button_release(4, 50, 50);
-sync_with_i3;
-
-is(focused_ws(), 'special', 'the binding was triggered');
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/263-edge-borders.t b/testcases/t/263-edge-borders.t
deleted file mode 100644 (file)
index 6da1dac..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests that the hide_edge_borders smart option works
-# Ticket: #2188
-
-use i3test i3_autostart => 0;
-
-####################################################################
-# 1: check that the borders are present on a floating windows
-#####################################################################
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-new_window pixel 2
-new_float pixel 2
-hide_edge_borders smart
-EOT
-
-my $pid = launch_with_config($config);
-
-my $tmp = fresh_workspace;
-
-ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
-
-my $floatwindow = open_floating_window;
-
-my $wscontent = get_ws($tmp);
-
-my @floating = @{$wscontent->{floating_nodes}};
-ok(@floating == 1, 'one floating container opened');
-is($floating[0]->{nodes}[0]->{current_border_width}, 2, 'floating current border width set to 2');
-is($floatwindow->rect->width, $floating[0]->{rect}->{width} - 2*2, 'floating border width 2');
-
-exit_gracefully($pid);
-
-#####################################################################
-# 2: check that the borders are present on a workspace with two tiled
-# windows visible
-#####################################################################
-
-$config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-new_window pixel 2
-new_float pixel 2
-hide_edge_borders smart
-EOT
-
-$pid = launch_with_config($config);
-
-$tmp = fresh_workspace;
-
-ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
-
-my $tilewindow = open_window;
-my $tilewindow2 = open_window;
-
-$wscontent = get_ws($tmp);
-
-my @tiled = @{$wscontent->{nodes}};
-ok(@tiled == 2, 'two tiled container opened');
-is($tiled[0]->{current_border_width}, 2, 'first tiled current border width set to 2');
-is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*2, 'first tiled border width 2');
-is($tiled[1]->{current_border_width}, 2, 'second tiled current border width set to 2');
-is($tilewindow2->rect->width, $tiled[1]->{rect}->{width} - 2*2, 'second tiled border width 2');
-
-exit_gracefully($pid);
-
-#####################################################################
-# 3: check that the borders are hidden on a workspace with one tiled
-# window visible
-#####################################################################
-
-$config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-new_window pixel 2
-new_float pixel 2
-hide_edge_borders smart
-EOT
-
-$pid = launch_with_config($config);
-
-$tmp = fresh_workspace;
-
-ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
-
-$tilewindow = open_window;
-
-$wscontent = get_ws($tmp);
-
-@tiled = @{$wscontent->{nodes}};
-ok(@tiled == 1, 'one tiled container opened');
-is($tiled[0]->{current_border_width}, 2, 'tiled current border width set to 2');
-is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*0, 'single tiled border width 0');
-
-exit_gracefully($pid);
-
-#####################################################################
-# 4: check that the borders are present on a workspace with two tiled
-# windows visible, recursively
-#####################################################################
-
-$config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-new_window pixel 2
-new_float pixel 2
-hide_edge_borders smart
-EOT
-
-$pid = launch_with_config($config);
-
-$tmp = fresh_workspace;
-
-ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
-
-$tilewindow = open_window;
-$tilewindow2 = open_window;
-ok(@{get_ws_content($tmp)} == 2, 'two containers opened');
-
-cmd 'layout tabbed';
-ok(@{get_ws_content($tmp)} == 1, 'layout tabbed -> back to one container');
-
-cmd 'focus parent';
-my $tilewindow3 = open_window;
-ok(@{get_ws_content($tmp)} == 2, 'after split & new window, two containers');
-
-$wscontent = get_ws($tmp);
-
-# Ensure i3’s X11 requests are processed before our inquiry via
-# $tilewindow->rect:
-sync_with_i3;
-
-@tiled = @{$wscontent->{nodes}};
-ok(@tiled == 2, 'two tiled container opened in another container');
-is($tiled[0]->{current_border_width}, -1, 'first tiled current border width set to -1');
-is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*2, 'first tiled border width 2');
-is($tiled[1]->{current_border_width}, 2, 'second tiled current border width set to 2');
-is($tilewindow2->rect->width, $tiled[1]->{rect}->{width} - 2*2, 'second tiled border width 2');
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/263-i3-floating-window-atom.t b/testcases/t/263-i3-floating-window-atom.t
deleted file mode 100644 (file)
index 43b69cc..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests for our proprietary atom I3_FLOATING_WINDOW to allow
-# identifying floating windows.
-# Ticket: #2223
-use i3test;
-use X11::XCB qw(:all);
-
-my ($con);
-
-sub has_i3_floating_window {
-    sync_with_i3;
-
-    my ($con) = @_;
-    my $cookie = $x->get_property(
-        0,
-        $con->{id},
-        $x->atom(name => 'I3_FLOATING_WINDOW')->id,
-        $x->atom(name => 'CARDINAL')->id,
-        0,
-        1
-    );
-
-    my $reply = $x->get_property_reply($cookie->{sequence});
-    return 0 if $reply->{length} != 1;
-
-    return unpack("L", $reply->{value});
-}
-
-###############################################################################
-# Toggling floating on a container adds / removes I3_FLOATING_WINDOW.
-###############################################################################
-
-fresh_workspace;
-
-$con = open_window;
-is(has_i3_floating_window($con), 0, 'I3_FLOATING_WINDOW is not set');
-
-cmd 'floating enable';
-is(has_i3_floating_window($con), 1, 'I3_FLOATING_WINDOW is set');
-
-cmd 'floating disable';
-is(has_i3_floating_window($con), 0, 'I3_FLOATING_WINDOW is not set');
-
-###############################################################################
-# A window that is floated when managed has I3_FLOATING_WINDOW set.
-###############################################################################
-#
-fresh_workspace;
-
-$con = open_floating_window;
-is(has_i3_floating_window($con), 1, 'I3_FLOATING_WINDOW is set');
-
-###############################################################################
-
-done_testing;
diff --git a/testcases/t/264-ipc-shutdown-event.t b/testcases/t/264-ipc-shutdown-event.t
deleted file mode 100644 (file)
index 379b9bf..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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 the ipc shutdown event. This event is triggered when the connection to
-# the ipc is about to shutdown because of a user action such as with a
-# `restart` or `exit` command. The `change` field indicates why the ipc is
-# shutting down. It can be either "restart" or "exit".
-#
-# Ticket: #2318
-# Bug still in: 4.12-46-g2123888
-use i3test;
-
-SKIP: {
-    skip "AnyEvent::I3 too old (need >= 0.17)", 1 if $AnyEvent::I3::VERSION < 0.17;
-
-my $i3 = i3(get_socket_path());
-$i3->connect->recv;
-
-my $cv = AE::cv;
-my $timer = AE::timer 0.5, 0, sub { $cv->send(0); };
-
-$i3->subscribe({
-        shutdown => sub {
-            $cv->send(shift);
-        }
-    })->recv;
-
-cmd 'restart';
-
-my $e = $cv->recv;
-
-diag "Event:\n", Dumper($e);
-ok($e, 'the shutdown event should emit when the ipc is restarted by command');
-is($e->{change}, 'restart', 'the `change` field should tell the reason for the shutdown');
-
-# restarting kills the ipc client so we have to make a new one
-$i3 = i3(get_socket_path());
-$i3->connect->recv;
-
-$cv = AE::cv;
-$timer = AE::timer 0.5, 0, sub { $cv->send(0); };
-
-$i3->subscribe({
-        shutdown => sub {
-            $cv->send(shift);
-        }
-    })->recv;
-
-cmd 'exit';
-
-$e = $cv->recv;
-
-diag "Event:\n", Dumper($e);
-ok($e, 'the shutdown event should emit when the ipc is exited by command');
-is($e->{change}, 'exit', 'the `change` field should tell the reason for the shutdown');
-}
-
-done_testing;
diff --git a/testcases/t/264-keypress-numlock.t b/testcases/t/264-keypress-numlock.t
deleted file mode 100644 (file)
index fcc39ea..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Verifies that one can bind on numpad keys in different numlock states.
-# Ticket: #2346
-# Bug still in: 4.12-78-g85bb324
-use i3test i3_autostart => 0;
-use i3test::XTEST;
-use ExtUtils::PkgConfig;
-
-SKIP: {
-    skip "libxcb-xkb too old (need >= 1.11)", 1 unless
-        ExtUtils::PkgConfig->atleast_version('xcb-xkb', '1.11');
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-# Same key, different numlock states.
-bindsym Mod2+KP_1 nop KP_1
-bindsym KP_End nop KP_End
-
-# Binding which should work with numlock and without.
-bindsym Mod4+a nop a
-
-# Binding which should work with numlock and without, see issue #2418.
-bindsym Escape nop Escape
-
-# Binding which should work with numlock and without, see issue #2418.
-bindsym Shift+Escape nop Shift+Escape
-
-# Binding which should work with numlock and without, see issue #2418.
-bindsym Mod1+Shift+q nop Mod1+Shift+q
-
-# Binding which should work with numlock and without, see issue #2559.
-bindcode 39 nop s
-EOT
-
-my $pid = launch_with_config($config);
-
-start_binding_capture;
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(87); # KP_End
-        xtest_key_release(87); # KP_End
-    },
-    ),
-   'KP_End',
-   'triggered the "KP_End" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(87); # KP_1
-        xtest_key_release(87); # KP_1
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'KP_1',
-   'triggered the "KP_1" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(133); # Super_L
-        xtest_key_press(38); # a
-        xtest_key_release(38); # a
-        xtest_key_release(133); # Super_L
-    },
-    ),
-   'a',
-   'triggered the "a" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(133); # Super_L
-        xtest_key_press(38); # a
-        xtest_key_release(38); # a
-        xtest_key_release(133); # Super_L
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'a',
-   'triggered the "a" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(9); # Escape
-        xtest_key_release(9); # Escape
-    },
-    ),
-   'Escape',
-   'triggered the "Escape" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(9); # Escape
-        xtest_key_release(9); # Escape
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'Escape',
-   'triggered the "Escape" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(50); # Shift_L
-        xtest_key_press(9); # Escape
-        xtest_key_release(9); # Escape
-        xtest_key_release(50); # Shift_L
-    },
-    ),
-   'Shift+Escape',
-   'triggered the "Escape" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(50); # Shift_L
-        xtest_key_press(9); # Escape
-        xtest_key_release(9); # Escape
-        xtest_key_release(50); # Shift_L
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'Shift+Escape',
-   'triggered the "Escape" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(50); # Shift_L
-        xtest_key_press(64); # Alt_L
-        xtest_key_press(24); # q
-        xtest_key_release(24); # q
-        xtest_key_release(64); # Alt_L
-        xtest_key_release(50); # Shift_L
-    },
-    ),
-   'Mod1+Shift+q',
-   'triggered the "Mod1+Shift+q" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(50); # Shift_L
-        xtest_key_press(64); # Alt_L
-        xtest_key_press(24); # q
-        xtest_key_release(24); # q
-        xtest_key_release(64); # Alt_L
-        xtest_key_release(50); # Shift_L
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'Mod1+Shift+q',
-   'triggered the "Mod1+Shift+q" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(39); # s
-        xtest_key_release(39); # s
-    },
-    ),
-   's',
-   'triggered the "s" keybinding without Num_Lock');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(39); # s
-        xtest_key_release(39); # s
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   's',
-   'triggered the "s" keybinding with Num_Lock');
-
-sync_with_i3;
-is(scalar @i3test::XTEST::binding_events, 12, 'Received exactly 12 binding events');
-
-exit_gracefully($pid);
-
-################################################################################
-# Verify bindings for modifiers work
-################################################################################
-
-$config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-bindsym Mod4+Return nop Return
-
-# Binding which should work with numlock and without, see issue #2559.
-bindcode --release 133 nop Super_L
-EOT
-
-$pid = launch_with_config($config);
-
-start_binding_capture;
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(133); # Super_L
-        xtest_key_release(133); # Super_L
-    },
-    ),
-   'Super_L',
-   'triggered the "Super_L" keybinding without Num_Lock');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(133); # Super_L
-        xtest_key_release(133); # Super_L
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'Super_L',
-   'triggered the "Super_L" keybinding with Num_Lock');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(133); # Super_L
-        xtest_key_press(36); # Return
-        xtest_key_release(36); # Return
-        xtest_key_release(133); # Super_L
-    },
-    ),
-   'Return',
-   'triggered the "Return" keybinding without Num_Lock');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(133); # Super_L
-        xtest_key_press(36); # Return
-        xtest_key_release(36); # Return
-        xtest_key_release(133); # Super_L
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'Return',
-   'triggered the "Return" keybinding with Num_Lock');
-
-sync_with_i3;
-is(scalar @i3test::XTEST::binding_events, 16, 'Received exactly 16 binding events');
-
-exit_gracefully($pid);
-
-################################################################################
-# Verify the binding is only triggered for KP_End, not KP_1
-################################################################################
-
-$config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-bindsym KP_End nop KP_End
-bindcode 88 nop KP_Down
-EOT
-
-$pid = launch_with_config($config);
-
-start_binding_capture;
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(87); # KP_End
-        xtest_key_release(87); # KP_End
-    },
-    ),
-   'KP_End',
-   'triggered the "KP_End" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(88); # KP_Down
-        xtest_key_release(88); # KP_Down
-    },
-    ),
-   'KP_Down',
-   'triggered the "KP_Down" keybinding');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(87); # KP_1
-        xtest_key_release(87); # KP_1
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'timeout',
-   'Did not trigger the KP_End keybinding with KP_1');
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_key_press(88); # KP_2
-        xtest_key_release(88); # KP_2
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'timeout',
-   'Did not trigger the KP_Down keybinding with KP_2');
-
-# TODO: This test does not verify that i3 does _NOT_ grab keycode 87 with Mod2.
-
-sync_with_i3;
-is(scalar @i3test::XTEST::binding_events, 18, 'Received exactly 18 binding events');
-
-exit_gracefully($pid);
-
-################################################################################
-# Verify mouse bindings are unaffected by NumLock
-################################################################################
-
-$config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-bindsym --whole-window button4 nop button4
-EOT
-
-$pid = launch_with_config($config);
-
-my $win = open_window;
-
-start_binding_capture;
-
-is(listen_for_binding(
-    sub {
-        xtest_key_press(77); # enable Num_Lock
-        xtest_key_release(77); # enable Num_Lock
-        xtest_button_press(4, 50, 50);
-        xtest_button_release(4, 50, 50);
-        xtest_key_press(77); # disable Num_Lock
-        xtest_key_release(77); # disable Num_Lock
-    },
-    ),
-   'button4',
-   'triggered the button4 keybinding with NumLock');
-
-is(listen_for_binding(
-    sub {
-       xtest_button_press(4, 50, 50);
-       xtest_button_release(4, 50, 50);
-    },
-    ),
-   'button4',
-   'triggered the button4 keybinding without NumLock');
-
-exit_gracefully($pid);
-
-}
-
-done_testing;
diff --git a/testcases/t/265-swap.t b/testcases/t/265-swap.t
deleted file mode 100644 (file)
index 810c39a..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests the swap command.
-# Ticket: #917
-use i3test i3_autostart => 0;
-
-my $config = <<EOT;
-# i3 config file (v4)
-font font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-for_window[class="mark_A"] mark A
-for_window[class="mark_B"] mark B
-EOT
-
-my ($pid);
-my ($ws, $ws1, $ws2, $ws3);
-my ($nodes, $expected_focus, $A, $B, $F);
-my ($result);
-my @urgent;
-
-$pid = launch_with_config($config);
-
-###############################################################################
-# Invalid con_id should not crash i3
-# See issue #2895.
-###############################################################################
-
-$ws = fresh_workspace;
-
-open_window;
-cmd "swap container with con_id 1";
-
-does_i3_live;
-kill_all_windows;
-
-###############################################################################
-# Swap 2 windows in different workspaces using con_id
-###############################################################################
-
-$ws = fresh_workspace;
-open_window;
-$A = get_focused($ws);
-
-$ws = fresh_workspace;
-open_window;
-
-cmd "swap container with con_id $A";
-is(get_focused($ws), $A, 'A is now focused');
-
-kill_all_windows;
-
-###############################################################################
-# Swap two containers next to each other.
-# Focus should stay on B because both windows are on the focused workspace.
-# The focused container is B.
-#
-# +---+---+    Layout: H1[ A B ]
-# | A | B |    Focus Stacks:
-# +---+---+        H1: B, A
-###############################################################################
-$ws = fresh_workspace;
-
-$A = open_window(wm_class => 'mark_A');
-$B = open_window(wm_class => 'mark_B');
-$expected_focus = get_focused($ws);
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws);
-is($nodes->[0]->{window}, $B->{id}, 'B is on the left');
-is($nodes->[1]->{window}, $A->{id}, 'A is on the right');
-is(get_focused($ws), $expected_focus, 'B is still focused');
-
-kill_all_windows;
-
-###############################################################################
-# Swap two containers with different parents.
-# In this test, the focus head of the left v-split container is A.
-# The focused container is B.
-#
-# +---+---+    Layout: H1[ V1[ A Y ] V2[ X B ] ]
-# | A | X |    Focus Stacks:
-# +---+---+        H1: V2, V1
-# | Y | B |        V1: A, Y
-# +---+---+        V2: B, X
-###############################################################################
-$ws = fresh_workspace;
-
-$A = open_window(wm_class => 'mark_A');
-$B = open_window(wm_class => 'mark_B');
-cmd 'split v';
-open_window;
-cmd 'move up, focus left';
-cmd 'split v';
-open_window;
-cmd 'focus up, focus right, focus down';
-$expected_focus = get_focused($ws);
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws);
-is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
-is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
-is(get_focused($ws), $expected_focus, 'B is still focused');
-
-kill_all_windows;
-
-###############################################################################
-# Swap two containers with different parents.
-# In this test, the focus head of the left v-split container is _not_ A.
-# The focused container is B.
-#
-# +---+---+    Layout: H1[ V1[ A Y ] V2[ X B ] ]
-# | A | X |    Focus Stacks:
-# +---+---+        H1: V2, V1
-# | Y | B |        V1: Y, A
-# +---+---+        V2: B, X
-###############################################################################
-$ws = fresh_workspace;
-
-$A = open_window(wm_class => 'mark_A');
-$B = open_window(wm_class => 'mark_B');
-cmd 'split v';
-open_window;
-cmd 'move up, focus left';
-cmd 'split v';
-open_window;
-cmd 'focus right, focus down';
-$expected_focus = get_focused($ws);
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws);
-is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
-is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
-is(get_focused($ws), $expected_focus, 'B is still focused');
-
-kill_all_windows;
-
-###############################################################################
-# Swap two containers with one being on a different workspace.
-# The focused container is B.
-#
-# Layout: O1[ W1[ H1 ] W2[ H2 ] ]
-# Focus Stacks:
-#     O1: W2, W1
-#
-# +---+---+    Layout: H1[ A X ]
-# | A | X |    Focus Stacks:
-# +---+---+        H1: A, X
-#
-# +---+---+    Layout: H2[ Y, B ]
-# | Y | B |    Focus Stacks:
-# +---+---+        H2: B, Y
-###############################################################################
-$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');
-
-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');
-
-$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');
-
-kill_all_windows;
-
-###############################################################################
-# Swap two non-focused containers within the same workspace.
-#
-# +---+---+    Layout: H1[ V1[ A X ] V2[ F B ] ]
-# | A | F |    Focus Stacks:
-# +---+---+        H1: V2, V1
-# | X | B |        V1: A, X
-# +---+---+        V2: F, B
-###############################################################################
-$ws = fresh_workspace;
-
-$A = open_window(wm_class => 'mark_A');
-$B = open_window(wm_class => 'mark_B');
-cmd 'split v';
-open_window;
-cmd 'move up, focus left';
-cmd 'split v';
-open_window;
-cmd 'focus up, focus right';
-$expected_focus = get_focused($ws);
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws);
-is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
-is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
-is(get_focused($ws), $expected_focus, 'F is still focused');
-
-kill_all_windows;
-
-###############################################################################
-# Swap two non-focused containers which are both on different workspaces.
-#
-# Layout: O1[ W1[ A ] W2[ B ] W3[ F ] ]
-# Focus Stacks:
-#     O1: W3, W2, W1
-#
-# +---+
-# | A |
-# +---+
-#
-# +---+
-# | B |
-# +---+
-#
-# +---+
-# | F |
-# +---+
-###############################################################################
-$ws1 = fresh_workspace;
-$A = open_window(wm_class => 'mark_A');
-
-$ws2 = fresh_workspace;
-$B = open_window(wm_class => 'mark_B');
-
-$ws3 = fresh_workspace;
-open_window;
-$expected_focus = get_focused($ws3);
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws1);
-is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace');
-
-$nodes = get_ws_content($ws2);
-is($nodes->[0]->{window}, $A->{id}, 'A is on the second workspace');
-
-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.
-#
-# Layout: O1[ W1[ A ] W2[ H2 ] ]
-# Focus Stacks:
-#     O1: W2, W1
-#
-# +---+
-# | A |
-# +---+
-#
-# +---+---+    Layout: H2[ B, F ]
-# | B | F |    Focus Stacks:
-# +---+---+        H2: F, B
-###############################################################################
-
-$ws1 = fresh_workspace;
-$A = open_window(wm_class => 'mark_A');
-
-$ws2 = fresh_workspace;
-$B = open_window(wm_class => 'mark_B');
-open_window;
-$expected_focus = get_focused($ws2);
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws1);
-is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace');
-
-$nodes = get_ws_content($ws2);
-is($nodes->[0]->{window}, $A->{id}, 'A is on the left of the second workspace');
-is(get_focused($ws2), $expected_focus, 'F is still focused');
-
-kill_all_windows;
-
-###############################################################################
-# 1. A container cannot be swapped with its parent.
-# 2. A container cannot be swapped with one of its children.
-#
-#      ↓A↓
-# +---+---+    Layout: H1[ X V1[ Y B ] ]
-# |   | Y |        (with A := V1)
-# | X +---+
-# |   | B |
-# +---+---+
-###############################################################################
-$ws = fresh_workspace;
-open_window;
-open_window;
-cmd 'split v';
-$B = open_window(wm_class => 'mark_B');
-cmd 'focus parent, mark A, focus child';
-
-$result = cmd '[con_mark=B] swap container with mark A';
-is($result->[0]->{success}, 0, 'B cannot be swappd with its parent');
-
-$result = cmd '[con_mark=A] swap container with mark B';
-is($result->[0]->{success}, 0, 'A cannot be swappd with one of its children');
-
-kill_all_windows;
-
-###############################################################################
-# Swapping two containers preserves the geometry of the container they are
-# being swapped with.
-#
-# Before:
-# +---+-------+
-# | A |   B   |
-# +---+-------+
-#
-# After:
-# +---+-------+
-# | B |   A   |
-# +---+-------+
-###############################################################################
-$ws = fresh_workspace;
-$A = open_window(wm_class => 'mark_A');
-$B = open_window(wm_class => 'mark_B');
-cmd 'resize grow width 0 or 25 ppt';
-
-# sanity checks
-$nodes = get_ws_content($ws);
-cmp_float($nodes->[0]->{percent}, 0.25, 'A has 25% width');
-cmp_float($nodes->[1]->{percent}, 0.75, 'B has 75% width');
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws);
-cmp_float($nodes->[0]->{percent}, 0.25, 'B has 25% width');
-cmp_float($nodes->[1]->{percent}, 0.75, 'A has 75% width');
-
-kill_all_windows;
-
-###############################################################################
-# Swapping containers not sharing the same parent preserves the geometry of
-# the container they are swapped with.
-#
-# Before:
-# +---+-----+
-# | A |     |
-# +---+  B  |
-# |   |     |
-# | Y +-----+
-# |   |  X  |
-# +---+-----+
-#
-# After:
-# +---+-----+
-# | B |     |
-# +---+  A  |
-# |   |     |
-# | Y +-----+
-# |   |  X  |
-# +---+-----+
-###############################################################################
-$ws = fresh_workspace;
-
-$A = open_window(wm_class => 'mark_A');
-$B = open_window(wm_class => 'mark_B');
-cmd 'split v';
-open_window;
-cmd 'focus up, resize grow height 0 or 25 ppt';
-cmd 'focus left, split v';
-open_window;
-cmd 'resize grow height 0 or 25 ppt';
-
-# sanity checks
-$nodes = get_ws_content($ws);
-cmp_float($nodes->[0]->{nodes}->[0]->{percent}, 0.25, 'A has 25% height');
-cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.75, 'B has 75% height');
-
-cmd '[con_mark=B] swap container with mark A';
-
-$nodes = get_ws_content($ws);
-cmp_float($nodes->[0]->{nodes}->[0]->{percent}, 0.25, 'B has 25% height');
-cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.75, 'A has 75% height');
-
-kill_all_windows;
-
-###############################################################################
-# Swapping containers moves the urgency hint correctly.
-###############################################################################
-
-$ws1 = fresh_workspace;
-$A = open_window(wm_class => 'mark_A');
-$ws2 = fresh_workspace;
-$B = open_window(wm_class => 'mark_B');
-open_window;
-
-$B->add_hint('urgency');
-sync_with_i3;
-
-cmd '[con_mark=B] swap container with mark A';
-
-@urgent = grep { $_->{urgent} } @{get_ws_content($ws1)};
-is(@urgent, 1, 'B is marked urgent');
-is(get_ws($ws1)->{urgent}, 1, 'the first workspace is marked urgent');
-
-@urgent = grep { $_->{urgent} } @{get_ws_content($ws2)};
-is(@urgent, 0, 'A is not marked urgent');
-is(get_ws($ws2)->{urgent}, 0, 'the second workspace is not marked urgent');
-
-kill_all_windows;
-
-###############################################################################
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/271-for_window_tilingfloating.t b/testcases/t/271-for_window_tilingfloating.t
new file mode 100644 (file)
index 0000000..760ac53
--- /dev/null
@@ -0,0 +1,49 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+use i3test i3_autostart => 0;
+use X11::XCB qw(PROP_MODE_REPLACE);
+
+##############################################################
+# 13: check that the tiling / floating criteria work.
+##############################################################
+
+my $config = <<"EOT";
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+for_window [tiling] mark tiled
+for_window [floating] mark floated
+EOT
+
+my $pid = launch_with_config($config);
+my $tmp = fresh_workspace;
+
+open_window;
+open_floating_window;
+
+my @nodes = @{get_ws($tmp)->{nodes}};
+cmp_ok(@nodes, '==', 1, 'one tiling container on this workspace');
+is_deeply($nodes[0]->{marks}, [ 'tiled' ], "mark set for 'tiling' criterion");
+
+@nodes = @{get_ws($tmp)->{floating_nodes}};
+cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
+is_deeply($nodes[0]->{nodes}[0]->{marks}, [ 'floated' ], "mark set for 'floating' criterion");
+
+exit_gracefully($pid);
+
+##############################################################
+
+done_testing;
diff --git a/testcases/t/272-regress-focus-assign.t b/testcases/t/272-regress-focus-assign.t
new file mode 100644 (file)
index 0000000..b010963
--- /dev/null
@@ -0,0 +1,77 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Regression: Checks if focus is stolen when a window is managed which is
+# assigned to an invisible workspace
+#
+use i3test i3_autostart => 0;
+
+sub open_special {
+    my %args = @_;
+    $args{name} //= 'special window';
+
+    # We use dont_map because i3 will not map the window on the current
+    # workspace. Thus, open_window would time out in wait_for_map (2 seconds).
+    my $window = open_window(
+        %args,
+        wm_class => 'special',
+        dont_map => 1,
+    );
+    $window->map;
+    return $window;
+}
+
+#####################################################################
+# start a window and see that it does not get assigned with an empty config
+#####################################################################
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+assign [class="special"] targetws
+EOT
+
+my $pid = launch_with_config($config);
+
+my $tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+ok(get_ws($tmp)->{focused}, 'current workspace focused');
+
+my $window = open_special;
+sync_with_i3;
+
+ok(@{get_ws_content($tmp)} == 0, 'special window not on current workspace');
+ok(@{get_ws_content('targetws')} == 1, 'special window on targetws');
+ok(get_ws($tmp)->{focused}, 'current workspace still focused');
+
+#####################################################################
+# the same test, but with a floating window
+#####################################################################
+
+$window = open_special(
+    window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'),
+);
+
+ok(@{get_ws_content($tmp)} == 0, 'special window not on current workspace');
+ok(@{get_ws_content('targetws')} == 1, 'special window on targetws');
+ok(get_ws($tmp)->{focused}, 'current workspace still focused');
+
+exit_gracefully($pid);
+
+$window->destroy;
+
+done_testing;
diff --git a/testcases/t/273-regress-focus-toggle.t b/testcases/t/273-regress-focus-toggle.t
new file mode 100644 (file)
index 0000000..192e975
--- /dev/null
@@ -0,0 +1,30 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Regression: Checks if i3 still lives after using 'focus mode_toggle' on an
+# empty workspace. This regression was fixed in
+# 0848844f2d41055f6ffc69af1149d7a873460976.
+#
+use i3test;
+use v5.10;
+
+my $tmp = fresh_workspace;
+
+cmd 'focus mode_toggle';
+
+does_i3_live;
+
+done_testing;
diff --git a/testcases/t/274-move-branch-position.t b/testcases/t/274-move-branch-position.t
new file mode 100644 (file)
index 0000000..c2928c9
--- /dev/null
@@ -0,0 +1,376 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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 that movement of a con into a branch will place the moving con at the
+# correct position within the branch.
+#
+# If the direction of movement is the same as the orientation of the branch
+# container, append or prepend the container to the branch in the obvious way.
+# If the movement is to the right or downward, insert the moving container in
+# the first position (i.e., the leftmost or top position resp.) If the movement
+# is to the left or upward, insert the moving container in the last position
+# (i.e., the rightmost or bottom position resp.)
+#
+# If the direction of movement is different from the orientation of the branch
+# container, insert the container into the branch after the focused-inactive
+# container.
+#
+# For testing purposes, we will demonstrate the behavior for tabbed containers
+# to represent the case of split-horizontal branches and stacked containers to
+# represent the case of split-vertical branches.
+#
+# Ticket: #1060
+# Bug still in: 4.6-109-g18cfc36
+
+use i3test;
+
+# Opens tabs on the presently focused branch and adds several additional
+# windows. Shifts focus to somewhere in the middle of the tabs so the most
+# general case can be assumed.
+sub open_tabs {
+    cmd 'layout tabbed';
+    open_window;
+    open_window;
+    open_window;
+    open_window;
+    cmd 'focus left; focus left'
+}
+
+# Likewise for a stack
+sub open_stack {
+    cmd 'layout stacking';
+    open_window;
+    open_window;
+    open_window;
+    open_window;
+    cmd 'focus up; focus up'
+}
+
+# Gets the position of the given leaf within the given branch. The first
+# position is one (1). Returns negative one (-1) if the leaf cannot be found
+# within the branch.
+sub get_leaf_position {
+    my ($branch, $leaf) = @_;
+    my $position = -1;
+    for my $i (0 .. @{$branch->{nodes}}) {
+        if ($branch->{nodes}[$i]->{id} == $leaf) {
+            $position = $i + 1;
+            last;
+        };
+    }
+    return $position;
+}
+
+# convenience function to focus a con by id to avoid having to type an ugly
+# command each time
+sub focus_con {
+    my $con_id = shift @_;
+    cmd "[con_id=\"$con_id\"] focus";
+}
+
+# Places a leaf into a branch and focuses the leaf. The newly created branch
+# will have orientation specified by the second parameter.
+sub branchify {
+    my ($con_id, $orientation) = @_;
+    focus_con($con_id);
+    $orientation eq 'horizontal' ? cmd 'splith' : cmd 'splitv';
+    open_window;
+    focus_con($con_id);
+}
+
+##############################################################################
+# When moving a con right into tabs, the moving con should be placed as the
+# first tab in the branch
+##############################################################################
+my $ws = fresh_workspace;
+
+# create the target leaf
+open_window;
+my $target_leaf = get_focused($ws);
+
+# create the tabbed branch container
+open_window;
+cmd 'splith';
+open_tabs;
+
+# move the target leaf into the tabbed branch
+focus_con($target_leaf);
+cmd 'move right';
+
+# the target leaf should be the first in the branch
+my $branch = shift @{get_ws_content($ws)};
+is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con right into tabs placed it as the first tab in the branch');
+
+# repeat the test when the target is in a branch
+cmd 'move up; move left';
+branchify($target_leaf, 'vertical');
+cmd 'move right';
+
+$branch = pop @{get_ws_content($ws)};
+is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con right into tabs from a branch placed it as the first tab in the branch');
+
+##############################################################################
+# When moving a con right into a stack, the moving con should be placed
+# below the focused-inactive leaf
+##############################################################################
+$ws = fresh_workspace;
+
+# create the target leaf
+open_window;
+$target_leaf = get_focused($ws);
+
+# create the stacked branch container and find the focused leaf
+open_window;
+cmd 'splith';
+open_stack;
+my $secondary_leaf = get_focused($ws);
+
+# move the target leaf into the stacked branch
+focus_con($target_leaf);
+cmd 'move right';
+
+# the secondary focus leaf should be below the target
+$branch = shift @{get_ws_content($ws)};
+my $target_leaf_position = get_leaf_position($branch, $target_leaf);
+my $secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con right into a stack placed it below the focused-inactive leaf');
+
+# repeat the test when the target is in a branch
+cmd 'move up; move left';
+branchify($target_leaf, 'vertical');
+cmd 'move right';
+
+$branch = pop @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con right into a stack from a branch placed it below the focused-inactive leaf');
+
+##############################################################################
+# When moving a con down into a stack, the moving con should be placed at the
+# top of the stack
+##############################################################################
+$ws = fresh_workspace;
+cmd 'layout splitv';
+
+# create the target leaf
+open_window;
+$target_leaf = get_focused($ws);
+
+# create the stacked branch container
+open_window;
+cmd 'splitv';
+open_stack;
+
+# move the target leaf into the stacked branch
+focus_con($target_leaf);
+cmd 'move down';
+
+# the target leaf should be on the top of the stack
+$branch = shift @{get_ws_content($ws)};
+is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con down into a stack placed it on the top of the stack');
+
+# repeat the test when the target is in a branch
+cmd 'move right; move up';
+branchify($target_leaf, 'horizontal');
+cmd 'move down';
+
+$branch = pop @{get_ws_content($ws)};
+is($branch->{nodes}[0]->{id}, $target_leaf, 'moving con down into a stack from a branch placed it on the top of the stack');
+
+##############################################################################
+# When moving a con down into tabs, the moving con should be placed after the
+# focused-inactive tab
+##############################################################################
+$ws = fresh_workspace;
+cmd 'layout splitv';
+
+# create the target leaf
+open_window;
+$target_leaf = get_focused($ws);
+
+# create the tabbed branch container and find the focused tab
+open_window;
+cmd 'splitv';
+open_tabs;
+$secondary_leaf = get_focused($ws);
+
+# move the target leaf into the tabbed branch
+focus_con($target_leaf);
+cmd 'move down';
+
+# the secondary focus tab should be to the right
+$branch = shift @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con down into tabs placed it after the focused-inactive tab');
+
+# repeat the test when the target is in a branch
+cmd 'move right; move up';
+branchify($target_leaf, 'horizontal');
+cmd 'move down';
+
+$branch = pop @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con down into tabs from a branch placed it after the focused-inactive tab');
+
+##############################################################################
+# When moving a con left into tabs, the moving con should be placed as the last
+# tab in the branch
+##############################################################################
+$ws = fresh_workspace;
+
+# create the tabbed branch container
+open_window;
+cmd 'splith';
+open_tabs;
+
+# create the target leaf
+cmd 'focus parent';
+open_window;
+$target_leaf = get_focused($ws);
+
+# move the target leaf into the tabbed branch
+cmd 'move left';
+
+# the target leaf should be last in the branch
+$branch = shift @{get_ws_content($ws)};
+
+is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con left into tabs placed it as the last tab in the branch');
+
+# repeat the test when the target leaf is in a branch
+cmd 'move up; move right';
+branchify($target_leaf, 'vertical');
+cmd 'move left';
+
+$branch = shift @{get_ws_content($ws)};
+is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con left into tabs from a branch placed it as the last tab in the branch');
+
+##############################################################################
+# When moving a con left into a stack, the moving con should be placed below
+# the focused-inactive leaf
+##############################################################################
+$ws = fresh_workspace;
+
+# create the stacked branch container and find the focused leaf
+open_window;
+open_stack;
+$secondary_leaf = get_focused($ws);
+
+# create the target leaf to the right
+cmd 'focus parent';
+open_window;
+$target_leaf = get_focused($ws);
+
+# move the target leaf into the stacked branch
+cmd 'move left';
+
+# the secondary focus leaf should be below
+$branch = shift @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con left into a stack placed it below the focused-inactive leaf');
+
+# repeat the test when the target leaf is in a branch
+cmd 'move up; move right';
+branchify($target_leaf, 'vertical');
+cmd 'move left';
+
+$branch = shift @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con left into a stack from a branch placed it below the focused-inactive leaf');
+
+##############################################################################
+# When moving a con up into a stack, the moving con should be placed last in
+# the stack
+##############################################################################
+$ws = fresh_workspace;
+cmd 'layout splitv';
+
+# create the stacked branch container
+open_window;
+cmd 'splitv';
+open_stack;
+
+# create the target leaf
+cmd 'focus parent';
+open_window;
+$target_leaf = get_focused($ws);
+
+# move the target leaf into the stacked branch
+cmd 'move up';
+
+# the target leaf should be on the bottom of the stack
+$branch = shift @{get_ws_content($ws)};
+
+is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con up into stack placed it on the bottom of the stack');
+
+# repeat the test when the target leaf is in a branch
+cmd 'move right; move down';
+branchify($target_leaf, 'horizontal');
+cmd 'move up';
+
+$branch = shift @{get_ws_content($ws)};
+
+is($branch->{nodes}->[-1]->{id}, $target_leaf, 'moving con up into stack from a branch placed it on the bottom of the stack');
+
+##############################################################################
+# When moving a con up into tabs, the moving con should be placed after the
+# focused-inactive tab
+##############################################################################
+$ws = fresh_workspace;
+cmd 'layout splitv';
+
+# create the tabbed branch container and find the focused leaf
+open_window;
+cmd 'splitv';
+open_tabs;
+$secondary_leaf = get_focused($ws);
+
+# create the target leaf below
+cmd 'focus parent';
+open_window;
+$target_leaf = get_focused($ws);
+
+# move the target leaf into the tabbed branch
+cmd 'move up';
+
+# the secondary focus tab should be to the right
+$branch = shift @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con up into tabs placed it after the focused-inactive tab');
+
+# repeat the test when the target leaf is in a branch
+cmd 'move right; move down';
+branchify($target_leaf, 'horizontal');
+cmd 'move up';
+
+$branch = shift @{get_ws_content($ws)};
+$target_leaf_position = get_leaf_position($branch, $target_leaf);
+$secondary_leaf_position = get_leaf_position($branch, $secondary_leaf);
+
+is($target_leaf_position, $secondary_leaf_position + 1, 'moving con up into tabs from a branch placed it after the focused-inactive tab');
+
+done_testing;
diff --git a/testcases/t/275-ipc-window-close.t b/testcases/t/275-ipc-window-close.t
new file mode 100644 (file)
index 0000000..3483cf4
--- /dev/null
@@ -0,0 +1,52 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests that the ipc close event works properly
+#
+# Bug still in: 4.8-7-gf4a8253
+use i3test;
+
+my $i3 = i3(get_socket_path());
+$i3->connect()->recv;
+
+my $cv;
+my $t;
+
+sub reset_test {
+    $cv = AE::cv;
+    $t = AE::timer(0.5, 0, sub { $cv->send(0); });
+}
+
+reset_test;
+
+$i3->subscribe({
+        window => sub {
+            my ($e) = @_;
+            if ($e->{change} eq 'close') {
+                $cv->send($e->{container});
+            }
+        },
+    })->recv;
+
+my $window = open_window;
+
+cmd 'kill';
+my $con = $cv->recv;
+
+ok($con, 'closing a window should send the window::close event');
+is($con->{window}, $window->{id}, 'the event should contain information about the window');
+
+done_testing;
diff --git a/testcases/t/276-ipc-window-move.t b/testcases/t/276-ipc-window-move.t
new file mode 100644 (file)
index 0000000..117d27f
--- /dev/null
@@ -0,0 +1,61 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests that the ipc window::move event works properly
+#
+# Bug still in: 4.8-7-gf4a8253
+use i3test;
+
+my $i3 = i3(get_socket_path());
+$i3->connect()->recv;
+
+my $cv;
+my $t;
+
+sub reset_test {
+    $cv = AE::cv;
+    $t = AE::timer(0.5, 0, sub { $cv->send(0); });
+}
+
+reset_test;
+
+$i3->subscribe({
+        window => sub {
+            my ($e) = @_;
+            if ($e->{change} eq 'move') {
+                $cv->send($e->{container});
+            }
+        },
+    })->recv;
+
+my $dummy_window = open_window;
+my $window = open_window;
+
+cmd 'move right';
+my $con = $cv->recv;
+
+ok($con, 'moving a window should emit the window::move event');
+is($con->{window}, $window->{id}, 'the event should contain info about the window');
+
+reset_test;
+
+cmd 'move to workspace ws_new';
+$con = $cv->recv;
+
+ok($con, 'moving a window to a different workspace should emit the window::move event');
+is($con->{window}, $window->{id}, 'the event should contain info about the window');
+
+done_testing;
diff --git a/testcases/t/277-ipc-window-urgent.t b/testcases/t/277-ipc-window-urgent.t
new file mode 100644 (file)
index 0000000..09226ff
--- /dev/null
@@ -0,0 +1,68 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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 that the window::urgent event works correctly. The window::urgent event
+# should be emitted when a window becomes urgent or loses its urgent status.
+#
+use i3test;
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+force_display_urgency_hint 0ms
+EOT
+
+my $i3 = i3(get_socket_path());
+$i3->connect()->recv;
+
+my $cv;
+$i3->subscribe({
+    window => sub {
+        my ($event) = @_;
+        $cv->send($event) if $event->{change} eq 'urgent';
+    }
+})->recv;
+
+my $t;
+$t = AnyEvent->timer(
+    after => 0.5,
+    cb => sub {
+        $cv->send(0);
+    }
+);
+
+$cv = AnyEvent->condvar;
+fresh_workspace;
+my $win = open_window;
+my $dummy_win = open_window;
+
+$win->add_hint('urgency');
+my $event = $cv->recv;
+
+isnt($event, 0, 'an urgent con should emit the window::urgent event');
+is($event->{container}->{window}, $win->{id}, 'the event should contain information about the window');
+is($event->{container}->{urgent}, 1, 'the container should be urgent');
+
+$cv = AnyEvent->condvar;
+$win->delete_hint('urgency');
+$event = $cv->recv;
+
+isnt($event, 0, 'an urgent con should emit the window::urgent event');
+is($event->{container}->{window}, $win->{id}, 'the event should contain information about the window');
+is($event->{container}->{urgent}, 0, 'the container should not be urgent');
+
+done_testing;
diff --git a/testcases/t/278-layout-restore-output.t b/testcases/t/278-layout-restore-output.t
new file mode 100644 (file)
index 0000000..5a1f376
--- /dev/null
@@ -0,0 +1,234 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Verifies that entire outputs can be saved and restored properly by i3.
+# Ticket: #1306
+# Bug still in: 4.8-26-gf96ec19
+use i3test;
+use File::Temp qw(tempfile);
+use IO::Handle;
+
+my $ws = fresh_workspace;
+
+################################################################################
+# Append a new workspace with a name.
+################################################################################
+
+ok(!workspace_exists('ws_new'), 'workspace "ws_new" does not exist yet');
+
+my ($fh, $filename) = tempfile(UNLINK => 1);
+print $fh <<'EOT';
+// vim:ts=4:sw=4:et
+{
+    // workspace with 1 children
+    "border": "pixel",
+    "floating": "auto_off",
+    "layout": "splith",
+    "percent": null,
+    "type": "workspace",
+    "name": "ws_new",
+    "nodes": [
+        {
+            "border": "pixel",
+            "floating": "auto_off",
+            "geometry": {
+               "height": 268,
+               "width": 484,
+               "x": 0,
+               "y": 0
+            },
+            "name": "vals@w00t: ~",
+            "percent": 1,
+            "swallows": [
+               {
+                  "class": "^URxvt$"
+               // "instance": "^urxvt$",
+               // "title": "^vals\\@w00t\\:\\ \\~$"
+               }
+            ],
+            "type": "con"
+        }
+    ]
+}
+EOT
+$fh->flush;
+cmd "append_layout $filename";
+
+ok(workspace_exists('ws_new'), 'workspace "ws_new" exists now');
+
+does_i3_live;
+
+close($fh);
+
+################################################################################
+# Append a new workspace with a name that clashes with an existing workspace.
+################################################################################
+
+my @old_workspaces = @{get_workspace_names()};
+
+cmd "append_layout $filename";
+
+my @new_workspaces = @{get_workspace_names()};
+cmp_ok(scalar @new_workspaces, '>', scalar @old_workspaces, 'more workspaces than before');
+
+my %created_workspaces = map { ($_, 1) } @new_workspaces;
+delete $created_workspaces{$_} for @old_workspaces;
+diag('created workspaces = ' . Dumper(keys %created_workspaces));
+cmp_ok(scalar keys %created_workspaces, '>', 0, 'new workspaces appeared');
+
+################################################################################
+# Append a new workspace without a name.
+################################################################################
+
+ok(!workspace_exists('unnamed'), 'workspace "unnamed" does not exist yet');
+
+($fh, $filename) = tempfile(UNLINK => 1);
+print $fh <<'EOT';
+// vim:ts=4:sw=4:et
+{
+    // workspace with 1 children
+    "border": "pixel",
+    "floating": "auto_off",
+    "layout": "splith",
+    "percent": null,
+    "type": "workspace",
+    "nodes": [
+        {
+            "border": "pixel",
+            "floating": "auto_off",
+            "geometry": {
+               "height": 268,
+               "width": 484,
+               "x": 0,
+               "y": 0
+            },
+            "name": "vals@w00t: ~",
+            "percent": 1,
+            "swallows": [
+               {
+                  "class": "^URxvt$"
+               // "instance": "^urxvt$",
+               // "title": "^vals\\@w00t\\:\\ \\~$"
+               }
+            ],
+            "type": "con"
+        }
+    ]
+}
+EOT
+$fh->flush;
+cmd "append_layout $filename";
+
+ok(workspace_exists('unnamed'), 'workspace "unnamed" exists now');
+
+################################################################################
+# Append a workspace with a numeric name, ensure it has ->num set.
+################################################################################
+
+ok(!workspace_exists('4'), 'workspace "4" does not exist yet');
+
+($fh, $filename) = tempfile(UNLINK => 1);
+print $fh <<'EOT';
+// vim:ts=4:sw=4:et
+{
+    // workspace with 1 children
+    "border": "pixel",
+    "floating": "auto_off",
+    "layout": "splith",
+    "percent": null,
+    "type": "workspace",
+    "name": "4",
+    "nodes": [
+        {
+            "border": "pixel",
+            "floating": "auto_off",
+            "geometry": {
+               "height": 268,
+               "width": 484,
+               "x": 0,
+               "y": 0
+            },
+            "name": "vals@w00t: ~",
+            "percent": 1,
+            "swallows": [
+               {
+                  "class": "^URxvt$"
+               // "instance": "^urxvt$",
+               // "title": "^vals\\@w00t\\:\\ \\~$"
+               }
+            ],
+            "type": "con"
+        }
+    ]
+}
+EOT
+$fh->flush;
+cmd "append_layout $filename";
+
+ok(workspace_exists('4'), 'workspace "4" exists now');
+$ws = get_ws("4");
+is($ws->{num}, 4, 'workspace number is 4');
+
+################################################################################
+# Append a workspace with a numeric name, with the “type” property at the end
+# of the JSON blurb (which is valid and sometimes happens).
+################################################################################
+
+ok(!workspace_exists('5'), 'workspace "5" does not exist yet');
+
+($fh, $filename) = tempfile(UNLINK => 1);
+print $fh <<'EOT';
+// vim:ts=4:sw=4:et
+{
+    // workspace with 1 children
+    "border": "pixel",
+    "floating": "auto_off",
+    "layout": "splith",
+    "percent": null,
+    "name": "5",
+    "nodes": [
+        {
+            "border": "pixel",
+            "floating": "auto_off",
+            "geometry": {
+               "height": 268,
+               "width": 484,
+               "x": 0,
+               "y": 0
+            },
+            "name": "vals@w00t: ~",
+            "percent": 1,
+            "swallows": [
+               {
+                  "class": "^URxvt$"
+               // "instance": "^urxvt$",
+               // "title": "^vals\\@w00t\\:\\ \\~$"
+               }
+            ],
+            "type": "con"
+        }
+    ],
+    "type": "workspace"
+}
+EOT
+$fh->flush;
+cmd "append_layout $filename";
+
+ok(workspace_exists('5'), 'workspace "5" exists now');
+$ws = get_ws("5");
+is($ws->{num}, 5, 'workspace number is 5');
+
+done_testing;
diff --git a/testcases/t/279-regress-default-floating-border.t b/testcases/t/279-regress-default-floating-border.t
new file mode 100644 (file)
index 0000000..d5994f5
--- /dev/null
@@ -0,0 +1,43 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# This is a regression test for a bug where a normal floating default border is
+# not applied when the default tiling border is set to a pixel value.
+# Ticket: #1305
+# Bug still in: 4.8-62-g7381b50
+use i3test i3_autostart => 0;
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 5
+new_float normal
+EOT
+
+my $pid = launch_with_config($config);
+
+my $ws = fresh_workspace;
+
+my $float_window = open_floating_window;
+
+my @floating = @{get_ws($ws)->{floating_nodes}};
+
+is($floating[0]->{nodes}[0]->{border}, 'normal', 'default floating border is `normal`');
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/280-wm-class-change-handler.t b/testcases/t/280-wm-class-change-handler.t
new file mode 100644 (file)
index 0000000..ce237b5
--- /dev/null
@@ -0,0 +1,78 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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 that changes to WM_CLASS are internally processed by i3 by updating the
+# cached property and running assignments. This allows the property to be used
+# in criteria selection
+# Ticket: #1052
+# Bug still in: 4.8-73-g6bf7f8e
+use i3test i3_autostart => 0;
+use X11::XCB qw(PROP_MODE_REPLACE);
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+for_window [class="Special"] mark special_class_mark
+EOT
+
+my $pid = launch_with_config($config);
+
+sub change_window_class {
+    my ($window, $class, $length) = @_;
+    my $atomname = $x->atom(name => 'WM_CLASS');
+    my $atomtype = $x->atom(name => 'STRING');
+    $length ||= length($class) + 1;
+    $x->change_property(
+        PROP_MODE_REPLACE,
+        $window->id,
+        $atomname->id,
+        $atomtype->id,
+        8,
+        $length,
+        $class
+    );
+    sync_with_i3;
+}
+
+my $ws = fresh_workspace;
+
+my $win = open_window;
+
+change_window_class($win, "special\0Special");
+
+my $con = @{get_ws_content($ws)}[0];
+
+is($con->{window_properties}->{class}, 'Special',
+    'The container class should be updated when a window changes class');
+
+is($con->{window_properties}->{instance}, 'special',
+    'The container instance should be updated when a window changes instance');
+
+# The mark `special_class_mark` is added in a `for_window` assignment in the
+# config for testing purposes
+is_deeply($con->{marks}, [ 'special_class_mark' ],
+    'A `for_window` assignment should run for a match when the window changes class');
+
+change_window_class($win, "abcdefghijklmnopqrstuv\0abcd", 24);
+
+$con = @{get_ws_content($ws)}[0];
+
+is($con->{window_properties}->{class}, 'a',
+    'Non-null-terminated strings should be handled correctly');
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/281-regress-reload-bindsym.t b/testcases/t/281-regress-reload-bindsym.t
new file mode 100644 (file)
index 0000000..6d5d12c
--- /dev/null
@@ -0,0 +1,45 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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 that the binding event works properly
+# Ticket: #1210
+use i3test i3_autostart => 0;
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+bindsym r reload
+EOT
+
+SKIP: {
+    qx(which xdotool 2> /dev/null);
+
+    skip 'xdotool is required to test the binding event. `[apt-get install|pacman -S] xdotool`', 1 if $?;
+
+    my $pid = launch_with_config($config);
+
+    my $i3 = i3(get_socket_path());
+    $i3->connect->recv;
+
+    qx(xdotool key r);
+
+    does_i3_live;
+
+    exit_gracefully($pid);
+
+}
+done_testing;
diff --git a/testcases/t/282-tabbed-floating-disable-crash.t b/testcases/t/282-tabbed-floating-disable-crash.t
new file mode 100644 (file)
index 0000000..7947158
--- /dev/null
@@ -0,0 +1,44 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Verifies that i3 does not crash when floating and then unfloating an
+# unfocused window within a tabbed container.
+# Ticket: #1484
+# Bug still in: 4.9.1-124-g856e1f9
+use i3test i3_autostart => 0;
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+workspace_layout tabbed
+EOT
+
+my $pid = launch_with_config($config);
+
+open_window;
+open_window;
+
+# Mark the second window, then focus the workspace.
+cmd 'mark foo, focus parent, focus parent';
+
+# Float and unfloat the marked window (without it being focused).
+cmd '[con_mark=foo] floating enable, floating disable';
+
+does_i3_live;
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/283-net-wm-state-hidden.t b/testcases/t/283-net-wm-state-hidden.t
new file mode 100644 (file)
index 0000000..3f2301c
--- /dev/null
@@ -0,0 +1,201 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests for setting and removing the _NET_WM_STATE_HIDDEN atom properly.
+# Ticket: #1648
+use i3test;
+use X11::XCB qw(:all);
+
+sub is_hidden {
+    sync_with_i3;
+    my $atom = $x->atom(name => '_NET_WM_STATE_HIDDEN');
+
+    my ($con) = @_;
+    my $cookie = $x->get_property(
+        0,
+        $con->{id},
+        $x->atom(name => '_NET_WM_STATE')->id,
+        GET_PROPERTY_TYPE_ANY,
+        0,
+        4096
+    );
+
+    my $reply = $x->get_property_reply($cookie->{sequence});
+    my $len = $reply->{length};
+    return 0 if $len == 0;
+
+    my @atoms = unpack("L$len", $reply->{value});
+    for (my $i = 0; $i < $len; $i++) {
+        return 1 if $atoms[$i] == $atom->id;
+    }
+
+    return 0;
+}
+
+my ($tabA, $tabB, $tabC, $subtabA, $subtabB, $windowA, $windowB);
+
+###############################################################################
+# Given two containers next to each other, when focusing one, then the other
+# one does not have _NET_WM_STATE_HIDDEN set.
+###############################################################################
+
+fresh_workspace;
+$windowA = open_window;
+$windowB = open_window;
+
+ok(!is_hidden($windowA), 'left window does not have _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($windowB), 'right window does not have _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given two containers on different workspaces, when one is focused, then
+# the other one does not have _NET_WM_STATE_HIDDEN set.
+###############################################################################
+
+fresh_workspace;
+$windowA = open_window;
+fresh_workspace;
+$windowB = open_window;
+
+ok(!is_hidden($windowA), 'left window does not have _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($windowB), 'right window does not have _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given two containers in the same tabbed container, when one is focused, then
+# (only) the other one has _NET_WM_STATE_HIDDEN set.
+# Given the other tab is focused, then the atom is transferred.
+###############################################################################
+
+fresh_workspace;
+$tabA = open_window;
+cmd 'layout tabbed';
+$tabB = open_window;
+
+ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabB), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
+
+cmd 'focus left';
+
+ok(!is_hidden($tabA), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
+ok(is_hidden($tabB), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given three containers in the same stacked container, when the focused tab
+# is moved to another workspace, then the now focused tab does not have
+# _NET_WM_STATE_HIDDEN set anymore.
+###############################################################################
+
+fresh_workspace;
+$tabA = open_window;
+cmd 'layout stacked';
+$tabB = open_window;
+$tabC = open_window;
+cmd 'move window to workspace unused';
+
+ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabB), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabC), 'moved window does not have _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given three containers in the same stacked container, when a not focused
+# tab is moved to another workspace, then it does not have _NET_WM_STATE_HIDDEN
+# set anymore.
+###############################################################################
+
+fresh_workspace;
+$tabA = open_window;
+cmd 'layout stacked';
+$tabB = open_window;
+cmd 'mark moveme';
+$tabC = open_window;
+cmd '[con_mark="moveme"] move window to workspace unused';
+
+ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabB), 'moved window does not have _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabC), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given a tabbed container and some other container, when the latter is moved
+# into the tabbed container, then all other tabs have _NET_WM_STATE_HIDDEN
+# set.
+###############################################################################
+
+fresh_workspace;
+$tabA = open_window;
+cmd 'layout tabbed';
+$tabB = open_window;
+cmd 'focus parent';
+cmd 'split h';
+$tabC = open_window;
+cmd 'move left';
+
+ok(is_hidden($tabA), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
+ok(is_hidden($tabB), 'unfocused tab has _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabC), 'focused tab does not have _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given a stacked container nested inside another tabbed container with the
+# inner one being in the currently focused tab, then the focused tab of the
+# inner container does not have _NET_WM_STATE_HIDDEN set.
+###############################################################################
+
+fresh_workspace;
+$tabA = open_window;
+cmd 'layout tabbed';
+$tabB = open_window;
+cmd 'split h';
+open_window;
+cmd 'split v';
+cmd 'layout stacked';
+$subtabA = open_window;
+$subtabB = open_window;
+
+ok(is_hidden($tabA), 'unfocused outer tab has _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($tabB), 'focused outer tab does not have _NET_WM_STATE_HIDDEN set');
+ok(is_hidden($subtabA), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set');
+ok(!is_hidden($subtabB), 'focused inner tab does not have _NET_WM_STATE_HIDDEN set');
+
+cmd 'focus left';
+
+ok(!is_hidden($subtabB), 'focused inner tab does not have _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+# Given a stacked container nested inside another tabbed container with the
+# inner one being in a currently not focused tab, then all tabs of the inner
+# container have _NET_WM_STATE_HIDDEN set.
+###############################################################################
+
+fresh_workspace;
+$tabA = open_window;
+cmd 'layout tabbed';
+$tabB = open_window;
+cmd 'split h';
+open_window;
+cmd 'split v';
+cmd 'layout stacked';
+$subtabA = open_window;
+$subtabB = open_window;
+cmd 'focus parent';
+cmd 'focus parent';
+cmd 'focus left';
+
+ok(!is_hidden($tabA), 'focused outer tab does not have _NET_WM_STATE_HIDDEN set');
+ok(is_hidden($tabB), 'unfocused outer tab has _NET_WM_STATE_HIDDEN set');
+ok(is_hidden($subtabA), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set');
+ok(is_hidden($subtabB), 'unfocused inner tab has _NET_WM_STATE_HIDDEN set');
+
+###############################################################################
+
+done_testing;
diff --git a/testcases/t/284-ewmh-visible-name.t b/testcases/t/284-ewmh-visible-name.t
new file mode 100644 (file)
index 0000000..c201b39
--- /dev/null
@@ -0,0 +1,70 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests that _NET_WM_VISIBLE_NAME is set correctly.
+# Ticket: #1872
+use i3test;
+use X11::XCB qw(:all);
+
+my ($con);
+
+sub get_visible_name {
+    sync_with_i3;
+    my ($con) = @_;
+
+    my $cookie = $x->get_property(
+        0,
+        $con->{id},
+        $x->atom(name => '_NET_WM_VISIBLE_NAME')->id,
+        $x->atom(name => 'UTF8_STRING')->id,
+        0,
+        4096
+    );
+
+    my $reply = $x->get_property_reply($cookie->{sequence});
+    return undef if $reply->{value_len} == 0;
+    return $reply->{value};
+}
+
+###############################################################################
+# 1: _NET_WM_VISIBLE_NAME is set when the title format of a window is changed.
+###############################################################################
+
+fresh_workspace;
+$con = open_window(name => 'boring title');
+is(get_visible_name($con), undef, 'sanity check: initially no visible name is set');
+
+cmd 'title_format custom';
+is(get_visible_name($con), 'custom', 'the visible name is updated');
+
+cmd 'title_format "<s>%title</s>"';
+is(get_visible_name($con), '<s>boring title</s>', 'markup is returned as is');
+
+###############################################################################
+# 2: _NET_WM_VISIBLE_NAME is removed if not needed.
+###############################################################################
+
+fresh_workspace;
+$con = open_window(name => 'boring title');
+cmd 'title_format custom';
+is(get_visible_name($con), 'custom', 'sanity check: a visible name is set');
+
+cmd 'title_format %title';
+is(get_visible_name($con), undef, 'the visible name is removed again');
+
+###############################################################################
+
+done_testing;
diff --git a/testcases/t/285-sticky.t b/testcases/t/285-sticky.t
new file mode 100644 (file)
index 0000000..85fc11f
--- /dev/null
@@ -0,0 +1,113 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests sticky windows.
+# Ticket: #1455
+use i3test;
+
+my ($ws, $tmp, $focused);
+
+###############################################################################
+# 1: Given a sticky tiling container, when the workspace is switched, then
+#    nothing happens.
+###############################################################################
+fresh_workspace;
+open_window(wm_class => 'findme');
+cmd 'sticky enable';
+$ws = fresh_workspace;
+
+is(@{get_ws($ws)->{nodes}}, 0, 'tiling sticky container did not move');
+is(@{get_ws($ws)->{floating_nodes}}, 0, 'tiling sticky container did not move');
+cmd '[class="findme"] kill';
+
+###############################################################################
+# 2: Given a sticky floating container, when the workspace is switched, then
+#    the container moves to the new workspace.
+###############################################################################
+$ws = fresh_workspace;
+open_floating_window(wm_class => 'findme');
+$focused = get_focused($ws);
+cmd 'sticky enable';
+$ws = fresh_workspace;
+
+is(@{get_ws($ws)->{floating_nodes}}, 1, 'floating sticky container moved to new workspace');
+is(get_focused($ws), $focused, 'sticky container has focus');
+cmd '[class="findme"] kill';
+
+###############################################################################
+# 3: Given two sticky floating containers, when the workspace is switched,
+#    then both containers move to the new workspace.
+###############################################################################
+fresh_workspace;
+open_floating_window(wm_class => 'findme');
+cmd 'sticky enable';
+open_floating_window(wm_class => 'findme');
+cmd 'sticky enable';
+$ws = fresh_workspace;
+
+is(@{get_ws($ws)->{floating_nodes}}, 2, 'multiple sticky windows can be used at the same time');
+cmd '[class="findme"] kill';
+
+###############################################################################
+# 4: Given an unfocused sticky floating container and a tiling container on the
+#    target workspace, when the workspace is switched, then the tiling container
+#    is focused.
+###############################################################################
+$ws = fresh_workspace;
+open_window;
+$focused = get_focused($ws);
+fresh_workspace;
+open_floating_window(wm_class => 'findme');
+cmd 'sticky enable';
+open_window;
+cmd 'workspace ' . $ws;
+
+is(get_focused($ws), $focused, 'the tiling container has focus');
+cmd '[class="findme"] kill';
+
+###############################################################################
+# 5: Given a focused sticky floating container and a tiling container on the
+#    target workspace, when the workspace is switched, then the tiling container
+#    is focused.
+###############################################################################
+$ws = fresh_workspace;
+open_window;
+$tmp = fresh_workspace;
+open_floating_window(wm_class => 'findme');
+$focused = get_focused($tmp);
+cmd 'sticky enable';
+cmd 'workspace ' . $ws;
+
+is(get_focused($ws), $focused, 'the sticky container has focus');
+cmd '[class="findme"] kill';
+
+###############################################################################
+# 6: Given a floating container on a non-visible workspace, when the window
+#    is made sticky, then the window immediately jumps to the currently
+#    visible workspace.
+###############################################################################
+fresh_workspace;
+open_floating_window(wm_class => 'findme');
+cmd 'mark sticky';
+$ws = fresh_workspace;
+cmd '[con_mark=sticky] sticky enable';
+
+is(@{get_ws($ws)->{floating_nodes}}, 1, 'the sticky window jumps to the front');
+cmd '[class="findme"] kill';
+
+###############################################################################
+
+done_testing;
diff --git a/testcases/t/286-root-window-mouse-binding.t b/testcases/t/286-root-window-mouse-binding.t
new file mode 100644 (file)
index 0000000..c8fd89e
--- /dev/null
@@ -0,0 +1,42 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Verifies that mouse bindings work on the root window if
+# --whole-window is set.
+# Ticket: #2115
+use i3test i3_autostart => 0;
+use i3test::XTEST;
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+workspace_auto_back_and_forth no
+bindsym --whole-window button4 workspace special
+EOT
+
+my $pid = launch_with_config($config);
+fresh_workspace;
+
+xtest_button_press(4, 50, 50);
+xtest_button_release(4, 50, 50);
+sync_with_i3;
+
+is(focused_ws(), 'special', 'the binding was triggered');
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/287-edge-borders.t b/testcases/t/287-edge-borders.t
new file mode 100644 (file)
index 0000000..6da1dac
--- /dev/null
@@ -0,0 +1,163 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests that the hide_edge_borders smart option works
+# Ticket: #2188
+
+use i3test i3_autostart => 0;
+
+####################################################################
+# 1: check that the borders are present on a floating windows
+#####################################################################
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+my $pid = launch_with_config($config);
+
+my $tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+my $floatwindow = open_floating_window;
+
+my $wscontent = get_ws($tmp);
+
+my @floating = @{$wscontent->{floating_nodes}};
+ok(@floating == 1, 'one floating container opened');
+is($floating[0]->{nodes}[0]->{current_border_width}, 2, 'floating current border width set to 2');
+is($floatwindow->rect->width, $floating[0]->{rect}->{width} - 2*2, 'floating border width 2');
+
+exit_gracefully($pid);
+
+#####################################################################
+# 2: check that the borders are present on a workspace with two tiled
+# windows visible
+#####################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+$pid = launch_with_config($config);
+
+$tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+my $tilewindow = open_window;
+my $tilewindow2 = open_window;
+
+$wscontent = get_ws($tmp);
+
+my @tiled = @{$wscontent->{nodes}};
+ok(@tiled == 2, 'two tiled container opened');
+is($tiled[0]->{current_border_width}, 2, 'first tiled current border width set to 2');
+is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*2, 'first tiled border width 2');
+is($tiled[1]->{current_border_width}, 2, 'second tiled current border width set to 2');
+is($tilewindow2->rect->width, $tiled[1]->{rect}->{width} - 2*2, 'second tiled border width 2');
+
+exit_gracefully($pid);
+
+#####################################################################
+# 3: check that the borders are hidden on a workspace with one tiled
+# window visible
+#####################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+$pid = launch_with_config($config);
+
+$tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+$tilewindow = open_window;
+
+$wscontent = get_ws($tmp);
+
+@tiled = @{$wscontent->{nodes}};
+ok(@tiled == 1, 'one tiled container opened');
+is($tiled[0]->{current_border_width}, 2, 'tiled current border width set to 2');
+is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*0, 'single tiled border width 0');
+
+exit_gracefully($pid);
+
+#####################################################################
+# 4: check that the borders are present on a workspace with two tiled
+# windows visible, recursively
+#####################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+$pid = launch_with_config($config);
+
+$tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+$tilewindow = open_window;
+$tilewindow2 = open_window;
+ok(@{get_ws_content($tmp)} == 2, 'two containers opened');
+
+cmd 'layout tabbed';
+ok(@{get_ws_content($tmp)} == 1, 'layout tabbed -> back to one container');
+
+cmd 'focus parent';
+my $tilewindow3 = open_window;
+ok(@{get_ws_content($tmp)} == 2, 'after split & new window, two containers');
+
+$wscontent = get_ws($tmp);
+
+# Ensure i3’s X11 requests are processed before our inquiry via
+# $tilewindow->rect:
+sync_with_i3;
+
+@tiled = @{$wscontent->{nodes}};
+ok(@tiled == 2, 'two tiled container opened in another container');
+is($tiled[0]->{current_border_width}, -1, 'first tiled current border width set to -1');
+is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*2, 'first tiled border width 2');
+is($tiled[1]->{current_border_width}, 2, 'second tiled current border width set to 2');
+is($tilewindow2->rect->width, $tiled[1]->{rect}->{width} - 2*2, 'second tiled border width 2');
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/288-i3-floating-window-atom.t b/testcases/t/288-i3-floating-window-atom.t
new file mode 100644 (file)
index 0000000..43b69cc
--- /dev/null
@@ -0,0 +1,70 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests for our proprietary atom I3_FLOATING_WINDOW to allow
+# identifying floating windows.
+# Ticket: #2223
+use i3test;
+use X11::XCB qw(:all);
+
+my ($con);
+
+sub has_i3_floating_window {
+    sync_with_i3;
+
+    my ($con) = @_;
+    my $cookie = $x->get_property(
+        0,
+        $con->{id},
+        $x->atom(name => 'I3_FLOATING_WINDOW')->id,
+        $x->atom(name => 'CARDINAL')->id,
+        0,
+        1
+    );
+
+    my $reply = $x->get_property_reply($cookie->{sequence});
+    return 0 if $reply->{length} != 1;
+
+    return unpack("L", $reply->{value});
+}
+
+###############################################################################
+# Toggling floating on a container adds / removes I3_FLOATING_WINDOW.
+###############################################################################
+
+fresh_workspace;
+
+$con = open_window;
+is(has_i3_floating_window($con), 0, 'I3_FLOATING_WINDOW is not set');
+
+cmd 'floating enable';
+is(has_i3_floating_window($con), 1, 'I3_FLOATING_WINDOW is set');
+
+cmd 'floating disable';
+is(has_i3_floating_window($con), 0, 'I3_FLOATING_WINDOW is not set');
+
+###############################################################################
+# A window that is floated when managed has I3_FLOATING_WINDOW set.
+###############################################################################
+#
+fresh_workspace;
+
+$con = open_floating_window;
+is(has_i3_floating_window($con), 1, 'I3_FLOATING_WINDOW is set');
+
+###############################################################################
+
+done_testing;
diff --git a/testcases/t/289-ipc-shutdown-event.t b/testcases/t/289-ipc-shutdown-event.t
new file mode 100644 (file)
index 0000000..379b9bf
--- /dev/null
@@ -0,0 +1,71 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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 the ipc shutdown event. This event is triggered when the connection to
+# the ipc is about to shutdown because of a user action such as with a
+# `restart` or `exit` command. The `change` field indicates why the ipc is
+# shutting down. It can be either "restart" or "exit".
+#
+# Ticket: #2318
+# Bug still in: 4.12-46-g2123888
+use i3test;
+
+SKIP: {
+    skip "AnyEvent::I3 too old (need >= 0.17)", 1 if $AnyEvent::I3::VERSION < 0.17;
+
+my $i3 = i3(get_socket_path());
+$i3->connect->recv;
+
+my $cv = AE::cv;
+my $timer = AE::timer 0.5, 0, sub { $cv->send(0); };
+
+$i3->subscribe({
+        shutdown => sub {
+            $cv->send(shift);
+        }
+    })->recv;
+
+cmd 'restart';
+
+my $e = $cv->recv;
+
+diag "Event:\n", Dumper($e);
+ok($e, 'the shutdown event should emit when the ipc is restarted by command');
+is($e->{change}, 'restart', 'the `change` field should tell the reason for the shutdown');
+
+# restarting kills the ipc client so we have to make a new one
+$i3 = i3(get_socket_path());
+$i3->connect->recv;
+
+$cv = AE::cv;
+$timer = AE::timer 0.5, 0, sub { $cv->send(0); };
+
+$i3->subscribe({
+        shutdown => sub {
+            $cv->send(shift);
+        }
+    })->recv;
+
+cmd 'exit';
+
+$e = $cv->recv;
+
+diag "Event:\n", Dumper($e);
+ok($e, 'the shutdown event should emit when the ipc is exited by command');
+is($e->{change}, 'exit', 'the `change` field should tell the reason for the shutdown');
+}
+
+done_testing;
diff --git a/testcases/t/290-keypress-numlock.t b/testcases/t/290-keypress-numlock.t
new file mode 100644 (file)
index 0000000..fcc39ea
--- /dev/null
@@ -0,0 +1,390 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Verifies that one can bind on numpad keys in different numlock states.
+# Ticket: #2346
+# Bug still in: 4.12-78-g85bb324
+use i3test i3_autostart => 0;
+use i3test::XTEST;
+use ExtUtils::PkgConfig;
+
+SKIP: {
+    skip "libxcb-xkb too old (need >= 1.11)", 1 unless
+        ExtUtils::PkgConfig->atleast_version('xcb-xkb', '1.11');
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+# Same key, different numlock states.
+bindsym Mod2+KP_1 nop KP_1
+bindsym KP_End nop KP_End
+
+# Binding which should work with numlock and without.
+bindsym Mod4+a nop a
+
+# Binding which should work with numlock and without, see issue #2418.
+bindsym Escape nop Escape
+
+# Binding which should work with numlock and without, see issue #2418.
+bindsym Shift+Escape nop Shift+Escape
+
+# Binding which should work with numlock and without, see issue #2418.
+bindsym Mod1+Shift+q nop Mod1+Shift+q
+
+# Binding which should work with numlock and without, see issue #2559.
+bindcode 39 nop s
+EOT
+
+my $pid = launch_with_config($config);
+
+start_binding_capture;
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(87); # KP_End
+        xtest_key_release(87); # KP_End
+    },
+    ),
+   'KP_End',
+   'triggered the "KP_End" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(87); # KP_1
+        xtest_key_release(87); # KP_1
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'KP_1',
+   'triggered the "KP_1" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(133); # Super_L
+        xtest_key_press(38); # a
+        xtest_key_release(38); # a
+        xtest_key_release(133); # Super_L
+    },
+    ),
+   'a',
+   'triggered the "a" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(133); # Super_L
+        xtest_key_press(38); # a
+        xtest_key_release(38); # a
+        xtest_key_release(133); # Super_L
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'a',
+   'triggered the "a" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(9); # Escape
+        xtest_key_release(9); # Escape
+    },
+    ),
+   'Escape',
+   'triggered the "Escape" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(9); # Escape
+        xtest_key_release(9); # Escape
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'Escape',
+   'triggered the "Escape" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(50); # Shift_L
+        xtest_key_press(9); # Escape
+        xtest_key_release(9); # Escape
+        xtest_key_release(50); # Shift_L
+    },
+    ),
+   'Shift+Escape',
+   'triggered the "Escape" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(50); # Shift_L
+        xtest_key_press(9); # Escape
+        xtest_key_release(9); # Escape
+        xtest_key_release(50); # Shift_L
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'Shift+Escape',
+   'triggered the "Escape" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(50); # Shift_L
+        xtest_key_press(64); # Alt_L
+        xtest_key_press(24); # q
+        xtest_key_release(24); # q
+        xtest_key_release(64); # Alt_L
+        xtest_key_release(50); # Shift_L
+    },
+    ),
+   'Mod1+Shift+q',
+   'triggered the "Mod1+Shift+q" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(50); # Shift_L
+        xtest_key_press(64); # Alt_L
+        xtest_key_press(24); # q
+        xtest_key_release(24); # q
+        xtest_key_release(64); # Alt_L
+        xtest_key_release(50); # Shift_L
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'Mod1+Shift+q',
+   'triggered the "Mod1+Shift+q" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(39); # s
+        xtest_key_release(39); # s
+    },
+    ),
+   's',
+   'triggered the "s" keybinding without Num_Lock');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(39); # s
+        xtest_key_release(39); # s
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   's',
+   'triggered the "s" keybinding with Num_Lock');
+
+sync_with_i3;
+is(scalar @i3test::XTEST::binding_events, 12, 'Received exactly 12 binding events');
+
+exit_gracefully($pid);
+
+################################################################################
+# Verify bindings for modifiers work
+################################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+bindsym Mod4+Return nop Return
+
+# Binding which should work with numlock and without, see issue #2559.
+bindcode --release 133 nop Super_L
+EOT
+
+$pid = launch_with_config($config);
+
+start_binding_capture;
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(133); # Super_L
+        xtest_key_release(133); # Super_L
+    },
+    ),
+   'Super_L',
+   'triggered the "Super_L" keybinding without Num_Lock');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(133); # Super_L
+        xtest_key_release(133); # Super_L
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'Super_L',
+   'triggered the "Super_L" keybinding with Num_Lock');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(133); # Super_L
+        xtest_key_press(36); # Return
+        xtest_key_release(36); # Return
+        xtest_key_release(133); # Super_L
+    },
+    ),
+   'Return',
+   'triggered the "Return" keybinding without Num_Lock');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(133); # Super_L
+        xtest_key_press(36); # Return
+        xtest_key_release(36); # Return
+        xtest_key_release(133); # Super_L
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'Return',
+   'triggered the "Return" keybinding with Num_Lock');
+
+sync_with_i3;
+is(scalar @i3test::XTEST::binding_events, 16, 'Received exactly 16 binding events');
+
+exit_gracefully($pid);
+
+################################################################################
+# Verify the binding is only triggered for KP_End, not KP_1
+################################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+bindsym KP_End nop KP_End
+bindcode 88 nop KP_Down
+EOT
+
+$pid = launch_with_config($config);
+
+start_binding_capture;
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(87); # KP_End
+        xtest_key_release(87); # KP_End
+    },
+    ),
+   'KP_End',
+   'triggered the "KP_End" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(88); # KP_Down
+        xtest_key_release(88); # KP_Down
+    },
+    ),
+   'KP_Down',
+   'triggered the "KP_Down" keybinding');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(87); # KP_1
+        xtest_key_release(87); # KP_1
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'timeout',
+   'Did not trigger the KP_End keybinding with KP_1');
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_key_press(88); # KP_2
+        xtest_key_release(88); # KP_2
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'timeout',
+   'Did not trigger the KP_Down keybinding with KP_2');
+
+# TODO: This test does not verify that i3 does _NOT_ grab keycode 87 with Mod2.
+
+sync_with_i3;
+is(scalar @i3test::XTEST::binding_events, 18, 'Received exactly 18 binding events');
+
+exit_gracefully($pid);
+
+################################################################################
+# Verify mouse bindings are unaffected by NumLock
+################################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+bindsym --whole-window button4 nop button4
+EOT
+
+$pid = launch_with_config($config);
+
+my $win = open_window;
+
+start_binding_capture;
+
+is(listen_for_binding(
+    sub {
+        xtest_key_press(77); # enable Num_Lock
+        xtest_key_release(77); # enable Num_Lock
+        xtest_button_press(4, 50, 50);
+        xtest_button_release(4, 50, 50);
+        xtest_key_press(77); # disable Num_Lock
+        xtest_key_release(77); # disable Num_Lock
+    },
+    ),
+   'button4',
+   'triggered the button4 keybinding with NumLock');
+
+is(listen_for_binding(
+    sub {
+       xtest_button_press(4, 50, 50);
+       xtest_button_release(4, 50, 50);
+    },
+    ),
+   'button4',
+   'triggered the button4 keybinding without NumLock');
+
+exit_gracefully($pid);
+
+}
+
+done_testing;
diff --git a/testcases/t/291-swap.t b/testcases/t/291-swap.t
new file mode 100644 (file)
index 0000000..810c39a
--- /dev/null
@@ -0,0 +1,430 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests the swap command.
+# Ticket: #917
+use i3test i3_autostart => 0;
+
+my $config = <<EOT;
+# i3 config file (v4)
+font font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+for_window[class="mark_A"] mark A
+for_window[class="mark_B"] mark B
+EOT
+
+my ($pid);
+my ($ws, $ws1, $ws2, $ws3);
+my ($nodes, $expected_focus, $A, $B, $F);
+my ($result);
+my @urgent;
+
+$pid = launch_with_config($config);
+
+###############################################################################
+# Invalid con_id should not crash i3
+# See issue #2895.
+###############################################################################
+
+$ws = fresh_workspace;
+
+open_window;
+cmd "swap container with con_id 1";
+
+does_i3_live;
+kill_all_windows;
+
+###############################################################################
+# Swap 2 windows in different workspaces using con_id
+###############################################################################
+
+$ws = fresh_workspace;
+open_window;
+$A = get_focused($ws);
+
+$ws = fresh_workspace;
+open_window;
+
+cmd "swap container with con_id $A";
+is(get_focused($ws), $A, 'A is now focused');
+
+kill_all_windows;
+
+###############################################################################
+# Swap two containers next to each other.
+# Focus should stay on B because both windows are on the focused workspace.
+# The focused container is B.
+#
+# +---+---+    Layout: H1[ A B ]
+# | A | B |    Focus Stacks:
+# +---+---+        H1: B, A
+###############################################################################
+$ws = fresh_workspace;
+
+$A = open_window(wm_class => 'mark_A');
+$B = open_window(wm_class => 'mark_B');
+$expected_focus = get_focused($ws);
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws);
+is($nodes->[0]->{window}, $B->{id}, 'B is on the left');
+is($nodes->[1]->{window}, $A->{id}, 'A is on the right');
+is(get_focused($ws), $expected_focus, 'B is still focused');
+
+kill_all_windows;
+
+###############################################################################
+# Swap two containers with different parents.
+# In this test, the focus head of the left v-split container is A.
+# The focused container is B.
+#
+# +---+---+    Layout: H1[ V1[ A Y ] V2[ X B ] ]
+# | A | X |    Focus Stacks:
+# +---+---+        H1: V2, V1
+# | Y | B |        V1: A, Y
+# +---+---+        V2: B, X
+###############################################################################
+$ws = fresh_workspace;
+
+$A = open_window(wm_class => 'mark_A');
+$B = open_window(wm_class => 'mark_B');
+cmd 'split v';
+open_window;
+cmd 'move up, focus left';
+cmd 'split v';
+open_window;
+cmd 'focus up, focus right, focus down';
+$expected_focus = get_focused($ws);
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws);
+is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
+is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
+is(get_focused($ws), $expected_focus, 'B is still focused');
+
+kill_all_windows;
+
+###############################################################################
+# Swap two containers with different parents.
+# In this test, the focus head of the left v-split container is _not_ A.
+# The focused container is B.
+#
+# +---+---+    Layout: H1[ V1[ A Y ] V2[ X B ] ]
+# | A | X |    Focus Stacks:
+# +---+---+        H1: V2, V1
+# | Y | B |        V1: Y, A
+# +---+---+        V2: B, X
+###############################################################################
+$ws = fresh_workspace;
+
+$A = open_window(wm_class => 'mark_A');
+$B = open_window(wm_class => 'mark_B');
+cmd 'split v';
+open_window;
+cmd 'move up, focus left';
+cmd 'split v';
+open_window;
+cmd 'focus right, focus down';
+$expected_focus = get_focused($ws);
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws);
+is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
+is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
+is(get_focused($ws), $expected_focus, 'B is still focused');
+
+kill_all_windows;
+
+###############################################################################
+# Swap two containers with one being on a different workspace.
+# The focused container is B.
+#
+# Layout: O1[ W1[ H1 ] W2[ H2 ] ]
+# Focus Stacks:
+#     O1: W2, W1
+#
+# +---+---+    Layout: H1[ A X ]
+# | A | X |    Focus Stacks:
+# +---+---+        H1: A, X
+#
+# +---+---+    Layout: H2[ Y, B ]
+# | Y | B |    Focus Stacks:
+# +---+---+        H2: B, Y
+###############################################################################
+$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');
+
+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');
+
+$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');
+
+kill_all_windows;
+
+###############################################################################
+# Swap two non-focused containers within the same workspace.
+#
+# +---+---+    Layout: H1[ V1[ A X ] V2[ F B ] ]
+# | A | F |    Focus Stacks:
+# +---+---+        H1: V2, V1
+# | X | B |        V1: A, X
+# +---+---+        V2: F, B
+###############################################################################
+$ws = fresh_workspace;
+
+$A = open_window(wm_class => 'mark_A');
+$B = open_window(wm_class => 'mark_B');
+cmd 'split v';
+open_window;
+cmd 'move up, focus left';
+cmd 'split v';
+open_window;
+cmd 'focus up, focus right';
+$expected_focus = get_focused($ws);
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws);
+is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
+is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
+is(get_focused($ws), $expected_focus, 'F is still focused');
+
+kill_all_windows;
+
+###############################################################################
+# Swap two non-focused containers which are both on different workspaces.
+#
+# Layout: O1[ W1[ A ] W2[ B ] W3[ F ] ]
+# Focus Stacks:
+#     O1: W3, W2, W1
+#
+# +---+
+# | A |
+# +---+
+#
+# +---+
+# | B |
+# +---+
+#
+# +---+
+# | F |
+# +---+
+###############################################################################
+$ws1 = fresh_workspace;
+$A = open_window(wm_class => 'mark_A');
+
+$ws2 = fresh_workspace;
+$B = open_window(wm_class => 'mark_B');
+
+$ws3 = fresh_workspace;
+open_window;
+$expected_focus = get_focused($ws3);
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws1);
+is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace');
+
+$nodes = get_ws_content($ws2);
+is($nodes->[0]->{window}, $A->{id}, 'A is on the second workspace');
+
+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.
+#
+# Layout: O1[ W1[ A ] W2[ H2 ] ]
+# Focus Stacks:
+#     O1: W2, W1
+#
+# +---+
+# | A |
+# +---+
+#
+# +---+---+    Layout: H2[ B, F ]
+# | B | F |    Focus Stacks:
+# +---+---+        H2: F, B
+###############################################################################
+
+$ws1 = fresh_workspace;
+$A = open_window(wm_class => 'mark_A');
+
+$ws2 = fresh_workspace;
+$B = open_window(wm_class => 'mark_B');
+open_window;
+$expected_focus = get_focused($ws2);
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws1);
+is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace');
+
+$nodes = get_ws_content($ws2);
+is($nodes->[0]->{window}, $A->{id}, 'A is on the left of the second workspace');
+is(get_focused($ws2), $expected_focus, 'F is still focused');
+
+kill_all_windows;
+
+###############################################################################
+# 1. A container cannot be swapped with its parent.
+# 2. A container cannot be swapped with one of its children.
+#
+#      ↓A↓
+# +---+---+    Layout: H1[ X V1[ Y B ] ]
+# |   | Y |        (with A := V1)
+# | X +---+
+# |   | B |
+# +---+---+
+###############################################################################
+$ws = fresh_workspace;
+open_window;
+open_window;
+cmd 'split v';
+$B = open_window(wm_class => 'mark_B');
+cmd 'focus parent, mark A, focus child';
+
+$result = cmd '[con_mark=B] swap container with mark A';
+is($result->[0]->{success}, 0, 'B cannot be swappd with its parent');
+
+$result = cmd '[con_mark=A] swap container with mark B';
+is($result->[0]->{success}, 0, 'A cannot be swappd with one of its children');
+
+kill_all_windows;
+
+###############################################################################
+# Swapping two containers preserves the geometry of the container they are
+# being swapped with.
+#
+# Before:
+# +---+-------+
+# | A |   B   |
+# +---+-------+
+#
+# After:
+# +---+-------+
+# | B |   A   |
+# +---+-------+
+###############################################################################
+$ws = fresh_workspace;
+$A = open_window(wm_class => 'mark_A');
+$B = open_window(wm_class => 'mark_B');
+cmd 'resize grow width 0 or 25 ppt';
+
+# sanity checks
+$nodes = get_ws_content($ws);
+cmp_float($nodes->[0]->{percent}, 0.25, 'A has 25% width');
+cmp_float($nodes->[1]->{percent}, 0.75, 'B has 75% width');
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws);
+cmp_float($nodes->[0]->{percent}, 0.25, 'B has 25% width');
+cmp_float($nodes->[1]->{percent}, 0.75, 'A has 75% width');
+
+kill_all_windows;
+
+###############################################################################
+# Swapping containers not sharing the same parent preserves the geometry of
+# the container they are swapped with.
+#
+# Before:
+# +---+-----+
+# | A |     |
+# +---+  B  |
+# |   |     |
+# | Y +-----+
+# |   |  X  |
+# +---+-----+
+#
+# After:
+# +---+-----+
+# | B |     |
+# +---+  A  |
+# |   |     |
+# | Y +-----+
+# |   |  X  |
+# +---+-----+
+###############################################################################
+$ws = fresh_workspace;
+
+$A = open_window(wm_class => 'mark_A');
+$B = open_window(wm_class => 'mark_B');
+cmd 'split v';
+open_window;
+cmd 'focus up, resize grow height 0 or 25 ppt';
+cmd 'focus left, split v';
+open_window;
+cmd 'resize grow height 0 or 25 ppt';
+
+# sanity checks
+$nodes = get_ws_content($ws);
+cmp_float($nodes->[0]->{nodes}->[0]->{percent}, 0.25, 'A has 25% height');
+cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.75, 'B has 75% height');
+
+cmd '[con_mark=B] swap container with mark A';
+
+$nodes = get_ws_content($ws);
+cmp_float($nodes->[0]->{nodes}->[0]->{percent}, 0.25, 'B has 25% height');
+cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.75, 'A has 75% height');
+
+kill_all_windows;
+
+###############################################################################
+# Swapping containers moves the urgency hint correctly.
+###############################################################################
+
+$ws1 = fresh_workspace;
+$A = open_window(wm_class => 'mark_A');
+$ws2 = fresh_workspace;
+$B = open_window(wm_class => 'mark_B');
+open_window;
+
+$B->add_hint('urgency');
+sync_with_i3;
+
+cmd '[con_mark=B] swap container with mark A';
+
+@urgent = grep { $_->{urgent} } @{get_ws_content($ws1)};
+is(@urgent, 1, 'B is marked urgent');
+is(get_ws($ws1)->{urgent}, 1, 'the first workspace is marked urgent');
+
+@urgent = grep { $_->{urgent} } @{get_ws_content($ws2)};
+is(@urgent, 0, 'A is not marked urgent');
+is(get_ws($ws2)->{urgent}, 0, 'the second workspace is not marked urgent');
+
+kill_all_windows;
+
+###############################################################################
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/528-workspace-next-prev.t b/testcases/t/528-workspace-next-prev.t
deleted file mode 100644 (file)
index 1a83de2..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests whether 'workspace next' works correctly.
-#
-use List::Util qw(first);
-use i3test i3_autostart => 0;
-
-sub assert_next {
-    my ($expected) = @_;
-
-    cmd 'workspace next';
-    # We need to sync after changing focus to a different output to wait for the
-    # EnterNotify to be processed, otherwise it will be processed at some point
-    # later in time and mess up our subsequent tests.
-    sync_with_i3;
-
-    is(focused_ws, $expected, "workspace $expected focused");
-}
-
-sub assert_prev {
-    my ($expected) = @_;
-
-    cmd 'workspace prev';
-    # We need to sync after changing focus to a different output to wait for the
-    # EnterNotify to be processed, otherwise it will be processed at some point
-    # later in time and mess up our subsequent tests.
-    sync_with_i3;
-
-    is(focused_ws, $expected, "workspace $expected focused");
-}
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-fake-outputs 1024x768+0+0,1024x768+1024+0
-EOT
-my $pid = launch_with_config($config);
-
-sync_with_i3;
-$x->root->warp_pointer(0, 0);
-sync_with_i3;
-
-################################################################################
-# Setup workspaces so that they stay open (with an empty container).
-# open_window ensures, this
-#
-#                   numbered       named
-# output 1 (left) : 1, 2, 3, 6, 7, B, F, C
-# output 2 (right): 4, 5,          A, D, E
-#
-################################################################################
-
-cmd 'focus output right';
-cmd 'workspace A'; open_window;
-cmd 'workspace D'; open_window;
-cmd 'workspace 4'; open_window;
-cmd 'workspace 5'; open_window;
-cmd 'workspace E'; open_window;
-
-cmd 'focus output left';
-cmd 'workspace 1'; open_window;
-cmd 'workspace 2'; open_window;
-cmd 'workspace B'; open_window;
-cmd 'workspace 3'; open_window;
-cmd 'workspace F'; open_window;
-cmd 'workspace 6'; open_window;
-cmd 'workspace C'; open_window;
-cmd 'workspace 7'; open_window;
-
-################################################################################
-# Use workspace next and verify the correct order.
-# numbered -> numerical sort
-# named -> sort by creation time
-################################################################################
-cmd 'workspace 1';
-is(focused_ws, '1', 'back on workspace 1');
-
-assert_next('2');
-assert_next('3');
-assert_next('4');
-assert_next('5');
-assert_next('6');
-assert_next('7');
-
-assert_next('B');
-assert_next('F');
-assert_next('C');
-assert_next('A');
-assert_next('D');
-assert_next('E');
-assert_next('1');
-
-cmd 'workspace 1';
-is(focused_ws, '1', 'back on workspace 1');
-
-assert_prev('E');
-assert_prev('D');
-assert_prev('A');
-assert_prev('C');
-assert_prev('F');
-assert_prev('B');
-
-assert_prev('7');
-assert_prev('6');
-assert_prev('5');
-assert_prev('4');
-assert_prev('3');
-assert_prev('2');
-assert_prev('1');
-
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/529-net-wm-desktop_mm.t b/testcases/t/529-net-wm-desktop_mm.t
deleted file mode 100644 (file)
index 7723894..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#!perl
-# vim:ts=4:sw=4:expandtab
-#
-# Please read the following documents before working on tests:
-# • http://build.i3wm.org/docs/testsuite.html
-#   (or docs/testsuite)
-#
-# • http://build.i3wm.org/docs/lib-i3test.html
-#   (alternatively: perldoc ./testcases/lib/i3test.pm)
-#
-# • http://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)
-#
-# Tests for _NET_WM_DESKTOP.
-# Ticket: #2153
-use i3test i3_autostart => 0;
-use X11::XCB qw(:all);
-
-sub get_net_wm_desktop {
-    sync_with_i3;
-
-    my ($con) = @_;
-    my $cookie = $x->get_property(
-        0,
-        $con->{id},
-        $x->atom(name => '_NET_WM_DESKTOP')->id,
-        $x->atom(name => 'CARDINAL')->id,
-        0,
-        1
-    );
-
-    my $reply = $x->get_property_reply($cookie->{sequence});
-    return undef if $reply->{length} != 1;
-
-    return unpack("L", $reply->{value});
-}
-
-my $config = <<EOT;
-# i3 config file (v4)
-font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
-
-workspace "0" output "fake-0"
-workspace "1" output "fake-0"
-workspace "2" output "fake-0"
-workspace "10" output "fake-1"
-workspace "11" output "fake-1"
-workspace "12" output "fake-1"
-
-fake-outputs 1024x768+0+0,1024x768+1024+0
-EOT
-
-###############################################################################
-# _NET_WM_DESKTOP is updated when the window is moved to another workspace
-# on another output.
-###############################################################################
-
-my $pid = launch_with_config($config);
-
-cmd 'workspace 0';
-open_window;
-cmd 'workspace 10';
-open_window;
-cmd 'workspace 0';
-my $con = open_window;
-
-cmd 'move window to workspace 10';
-
-is(get_net_wm_desktop($con), 1, '_NET_WM_DESKTOP is updated when moving the window');
-
-exit_gracefully($pid);
-
-done_testing;
diff --git a/testcases/t/535-workspace-next-prev.t b/testcases/t/535-workspace-next-prev.t
new file mode 100644 (file)
index 0000000..1a83de2
--- /dev/null
@@ -0,0 +1,129 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests whether 'workspace next' works correctly.
+#
+use List::Util qw(first);
+use i3test i3_autostart => 0;
+
+sub assert_next {
+    my ($expected) = @_;
+
+    cmd 'workspace next';
+    # We need to sync after changing focus to a different output to wait for the
+    # EnterNotify to be processed, otherwise it will be processed at some point
+    # later in time and mess up our subsequent tests.
+    sync_with_i3;
+
+    is(focused_ws, $expected, "workspace $expected focused");
+}
+
+sub assert_prev {
+    my ($expected) = @_;
+
+    cmd 'workspace prev';
+    # We need to sync after changing focus to a different output to wait for the
+    # EnterNotify to be processed, otherwise it will be processed at some point
+    # later in time and mess up our subsequent tests.
+    sync_with_i3;
+
+    is(focused_ws, $expected, "workspace $expected focused");
+}
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+fake-outputs 1024x768+0+0,1024x768+1024+0
+EOT
+my $pid = launch_with_config($config);
+
+sync_with_i3;
+$x->root->warp_pointer(0, 0);
+sync_with_i3;
+
+################################################################################
+# Setup workspaces so that they stay open (with an empty container).
+# open_window ensures, this
+#
+#                   numbered       named
+# output 1 (left) : 1, 2, 3, 6, 7, B, F, C
+# output 2 (right): 4, 5,          A, D, E
+#
+################################################################################
+
+cmd 'focus output right';
+cmd 'workspace A'; open_window;
+cmd 'workspace D'; open_window;
+cmd 'workspace 4'; open_window;
+cmd 'workspace 5'; open_window;
+cmd 'workspace E'; open_window;
+
+cmd 'focus output left';
+cmd 'workspace 1'; open_window;
+cmd 'workspace 2'; open_window;
+cmd 'workspace B'; open_window;
+cmd 'workspace 3'; open_window;
+cmd 'workspace F'; open_window;
+cmd 'workspace 6'; open_window;
+cmd 'workspace C'; open_window;
+cmd 'workspace 7'; open_window;
+
+################################################################################
+# Use workspace next and verify the correct order.
+# numbered -> numerical sort
+# named -> sort by creation time
+################################################################################
+cmd 'workspace 1';
+is(focused_ws, '1', 'back on workspace 1');
+
+assert_next('2');
+assert_next('3');
+assert_next('4');
+assert_next('5');
+assert_next('6');
+assert_next('7');
+
+assert_next('B');
+assert_next('F');
+assert_next('C');
+assert_next('A');
+assert_next('D');
+assert_next('E');
+assert_next('1');
+
+cmd 'workspace 1';
+is(focused_ws, '1', 'back on workspace 1');
+
+assert_prev('E');
+assert_prev('D');
+assert_prev('A');
+assert_prev('C');
+assert_prev('F');
+assert_prev('B');
+
+assert_prev('7');
+assert_prev('6');
+assert_prev('5');
+assert_prev('4');
+assert_prev('3');
+assert_prev('2');
+assert_prev('1');
+
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/536-net-wm-desktop_mm.t b/testcases/t/536-net-wm-desktop_mm.t
new file mode 100644 (file)
index 0000000..7723894
--- /dev/null
@@ -0,0 +1,75 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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)
+#
+# Tests for _NET_WM_DESKTOP.
+# Ticket: #2153
+use i3test i3_autostart => 0;
+use X11::XCB qw(:all);
+
+sub get_net_wm_desktop {
+    sync_with_i3;
+
+    my ($con) = @_;
+    my $cookie = $x->get_property(
+        0,
+        $con->{id},
+        $x->atom(name => '_NET_WM_DESKTOP')->id,
+        $x->atom(name => 'CARDINAL')->id,
+        0,
+        1
+    );
+
+    my $reply = $x->get_property_reply($cookie->{sequence});
+    return undef if $reply->{length} != 1;
+
+    return unpack("L", $reply->{value});
+}
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+workspace "0" output "fake-0"
+workspace "1" output "fake-0"
+workspace "2" output "fake-0"
+workspace "10" output "fake-1"
+workspace "11" output "fake-1"
+workspace "12" output "fake-1"
+
+fake-outputs 1024x768+0+0,1024x768+1024+0
+EOT
+
+###############################################################################
+# _NET_WM_DESKTOP is updated when the window is moved to another workspace
+# on another output.
+###############################################################################
+
+my $pid = launch_with_config($config);
+
+cmd 'workspace 0';
+open_window;
+cmd 'workspace 10';
+open_window;
+cmd 'workspace 0';
+my $con = open_window;
+
+cmd 'move window to workspace 10';
+
+is(get_net_wm_desktop($con), 1, '_NET_WM_DESKTOP is updated when moving the window');
+
+exit_gracefully($pid);
+
+done_testing;