]> git.sur5r.net Git - i3/i3/commitdiff
Implement fake-outputs option (cmdline, cfg) for multi-monitor testing
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 9 Apr 2012 12:27:33 +0000 (14:27 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 9 Apr 2012 12:28:36 +0000 (14:28 +0200)
This kills the dependency on xdmx and makes the testsuite simpler
and more flexible (in the output sizes / configurations).

15 files changed:
include/all.h
include/config.h
include/fake_outputs.h [new file with mode: 0644]
src/cfgparse.l
src/cfgparse.y
src/fake_outputs.c [new file with mode: 0644]
src/main.c
testcases/complete-run.pl
testcases/lib/StartXDummy.pm
testcases/lib/i3test.pm
testcases/t/500-multi-monitor.t
testcases/t/501-scratchpad.t
testcases/t/502-focus-output.t
testcases/t/503-workspace.t
testcases/t/504-move-workspace-to-output.t

index 648b0e0ac40727115d0b5f9e238cd9969a1c71fd..e550b08bcfa4a61ebae70ec434fc797a4764926a 100644 (file)
@@ -75,5 +75,6 @@
 #include "scratchpad.h"
 #include "commands.h"
 #include "commands_parser.h"
+#include "fake_outputs.h"
 
 #endif
index e959a2dc6f6f4787dc190b2ca02970bb9ba3ca1f..310f8b02e6b7aa8a9e61d9c0aec3952a3270c69e 100644 (file)
@@ -134,6 +134,9 @@ struct Config {
      * is fetched once and never updated. */
     bool force_xinerama;
 
+    /** Overwrites output detection (for testing), see src/fake_outputs.c */
+    char *fake_outputs;
+
     /** Automatic workspace back and forth switching. If this is set, a
      * switch to the currently active workspace will switch to the
      * previously focused one instead, making it possible to fast toggle
diff --git a/include/fake_outputs.h b/include/fake_outputs.h
new file mode 100644 (file)
index 0000000..adb10a0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * vim:ts=4:sw=4:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
+ *
+ * Faking outputs is useful in pathological situations (like network X servers
+ * which don’t support multi-monitor in a useful way) and for our testsuite.
+ *
+ */
+#ifndef _FAKE_OUTPUTS_H
+#define _FAKE_OUTPUTS_H
+
+/**
+ * Creates outputs according to the given specification.
+ * The specification must be in the format wxh+x+y, for example 1024x768+0+0,
+ * with multiple outputs separated by commas:
+ *   1900x1200+0+0,1280x1024+1900+0
+ *
+ */
+void fake_outputs_init(const char *output_spec);
+
+#endif
index 81847ed7085cba1e9b06ebc924e35be523f9915c..161ddfdc48a492394a3794525ea043c9a00369c4 100644 (file)
@@ -203,6 +203,8 @@ none                            { return TOK_NONE; }
 focus_follows_mouse             { return TOKFOCUSFOLLOWSMOUSE; }
 force_focus_wrapping            { return TOK_FORCE_FOCUS_WRAPPING; }
 force_xinerama                  { return TOK_FORCE_XINERAMA; }
+fake_outputs                    { WS_STRING; return TOK_FAKE_OUTPUTS; }
+fake-outputs                    { WS_STRING; return TOK_FAKE_OUTPUTS; }
 workspace_auto_back_and_forth   { return TOK_WORKSPACE_AUTO_BAF; }
 workspace_bar                   { return TOKWORKSPACEBAR; }
 popup_during_fullscreen         { return TOK_POPUP_DURING_FULLSCREEN; }
index 7aeb0a7eb48eb6a37394680db480603b8081ce64..ab8be57c120d6555d73a4712c452f0cad890bc96 100644 (file)
@@ -693,6 +693,7 @@ void parse_file(const char *f) {
 %token                  TOKFOCUSFOLLOWSMOUSE        "focus_follows_mouse"
 %token                  TOK_FORCE_FOCUS_WRAPPING    "force_focus_wrapping"
 %token                  TOK_FORCE_XINERAMA          "force_xinerama"
+%token                  TOK_FAKE_OUTPUTS            "fake_outputs"
 %token                  TOK_WORKSPACE_AUTO_BAF      "workspace_auto_back_and_forth"
 %token                  TOKWORKSPACEBAR             "workspace_bar"
 %token                  TOK_DEFAULT                 "default"
@@ -790,6 +791,7 @@ line:
     | focus_follows_mouse
     | force_focus_wrapping
     | force_xinerama
+    | fake_outputs
     | workspace_back_and_forth
     | workspace_bar
     | workspace
@@ -1451,6 +1453,14 @@ force_xinerama:
     }
     ;
 
+fake_outputs:
+    TOK_FAKE_OUTPUTS STR
+    {
+        DLOG("fake outputs = %s\n", $2);
+        config.fake_outputs = $2;
+    }
+    ;
+
 workspace_back_and_forth:
     TOK_WORKSPACE_AUTO_BAF bool
     {
diff --git a/src/fake_outputs.c b/src/fake_outputs.c
new file mode 100644 (file)
index 0000000..512a808
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * vim:ts=4:sw=4:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
+ *
+ * Faking outputs is useful in pathological situations (like network X servers
+ * which don’t support multi-monitor in a useful way) and for our testsuite.
+ *
+ */
+#include "all.h"
+
+static int num_screens;
+
+/*
+ * Looks in outputs for the Output whose start coordinates are x, y
+ *
+ */
+static Output *get_screen_at(int x, int y) {
+    Output *output;
+    TAILQ_FOREACH(output, &outputs, outputs)
+        if (output->rect.x == x && output->rect.y == y)
+            return output;
+
+    return NULL;
+}
+
+/*
+ * Creates outputs according to the given specification.
+ * The specification must be in the format wxh+x+y, for example 1024x768+0+0,
+ * with multiple outputs separated by commas:
+ *   1900x1200+0+0,1280x1024+1900+0
+ *
+ */
+void fake_outputs_init(const char *output_spec) {
+    char useless_buffer[1024];
+    const char *walk = output_spec;
+    unsigned int x, y, width, height;
+    while (sscanf(walk, "%ux%u+%u+%u", &width, &height, &x, &y) == 4) {
+        DLOG("Parsed output as width = %u, height = %u at (%u, %u)\n",
+             width, height, x, y);
+        Output *new_output = get_screen_at(x, y);
+        if (new_output != NULL) {
+            DLOG("Re-used old output %p\n", new_output);
+            /* This screen already exists. We use the littlest screen so that the user
+               can always see the complete workspace */
+            new_output->rect.width = min(new_output->rect.width, width);
+            new_output->rect.height = min(new_output->rect.height, height);
+        } else {
+            new_output = scalloc(sizeof(Output));
+            sasprintf(&(new_output->name), "fake-%d", num_screens);
+            DLOG("Created new fake output %s (%p)\n", new_output->name, new_output);
+            new_output->active = true;
+            new_output->rect.x = x;
+            new_output->rect.y = y;
+            new_output->rect.width = width;
+            new_output->rect.height = height;
+            /* We always treat the screen at 0x0 as the primary screen */
+            if (new_output->rect.x == 0 && new_output->rect.y == 0)
+                TAILQ_INSERT_HEAD(&outputs, new_output, outputs);
+            else TAILQ_INSERT_TAIL(&outputs, new_output, outputs);
+            output_init_con(new_output);
+            init_ws_for_output(new_output, output_get_content(new_output->con));
+            num_screens++;
+        }
+
+        /* Figure out how long the input was to skip it */
+        walk += sprintf(useless_buffer, "%ux%u+%u+%u", width, height, x, y) + 1;
+    }
+
+    if (num_screens == 0) {
+        ELOG("No screens found. Please fix your setup. i3 will exit now.\n");
+        exit(0);
+    }
+}
index 0d7246078f06296a1891c8c5f3b1453e584263f9..d75984682118514e9c2a55a3121f41b7e5329ef3 100644 (file)
@@ -252,6 +252,7 @@ int main(int argc, char *argv[]) {
     char *layout_path = NULL;
     bool delete_layout_path = false;
     bool force_xinerama = false;
+    char *fake_outputs = NULL;
     bool disable_signalhandler = false;
     static struct option long_options[] = {
         {"no-autostart", no_argument, 0, 'a'},
@@ -267,6 +268,8 @@ int main(int argc, char *argv[]) {
         {"shmlog_size", required_argument, 0, 0},
         {"get-socketpath", no_argument, 0, 0},
         {"get_socketpath", no_argument, 0, 0},
+        {"fake_outputs", required_argument, 0, 0},
+        {"fake-outputs", required_argument, 0, 0},
         {0, 0, 0, 0}
     };
     int option_index = 0, opt;
@@ -368,6 +371,11 @@ int main(int argc, char *argv[]) {
                     layout_path = sstrdup(optarg);
                     delete_layout_path = true;
                     break;
+                } else if (strcmp(long_options[option_index].name, "fake-outputs") == 0 ||
+                           strcmp(long_options[option_index].name, "fake_outputs") == 0) {
+                    LOG("Initializing fake outputs: %s\n", optarg);
+                    fake_outputs = sstrdup(optarg);
+                    break;
                 }
                 /* fall-through */
             default:
@@ -656,10 +664,18 @@ int main(int argc, char *argv[]) {
 
     free(greply);
 
-    /* Force Xinerama (for drivers which don't support RandR yet, esp. the
-     * nVidia binary graphics driver), when specified either in the config
-     * file or on command-line */
-    if (force_xinerama || config.force_xinerama) {
+    /* Setup fake outputs for testing */
+    if (fake_outputs == NULL && config.fake_outputs != NULL)
+        fake_outputs = config.fake_outputs;
+
+    if (fake_outputs != NULL) {
+        fake_outputs_init(fake_outputs);
+        FREE(fake_outputs);
+        config.fake_outputs = NULL;
+    } else if (force_xinerama || config.force_xinerama) {
+        /* Force Xinerama (for drivers which don't support RandR yet, esp. the
+         * nVidia binary graphics driver), when specified either in the config
+         * file or on command-line */
         xinerama_init();
     } else {
         DLOG("Checking for XRandR...\n");
index 15def35c85516332c5acc3f771969810c573da48..020e2f90b737ab3499be140f58af4c6fb6c95c44 100755 (executable)
@@ -72,16 +72,9 @@ my @testfiles = @ARGV;
 
 my $numtests = scalar @testfiles;
 
-# When the user specifies displays, we don’t run multi-monitor tests at all
-# (because we don’t know which displaynumber is the X-Server with multiple
-# monitors).
-my $multidpy = undef;
-
 # No displays specified, let’s start some Xdummy instances.
 if (@displays == 0) {
-    my $dpyref;
-    ($dpyref, $multidpy) = start_xdummy($parallel, $numtests);
-    @displays = @$dpyref;
+    @displays = start_xdummy($parallel, $numtests);
 }
 
 # 1: create an output directory for this test-run
@@ -111,16 +104,6 @@ for my $display (@displays) {
     }
 }
 
-my @multi_worker;
-if (defined($multidpy)) {
-    my $x = X11::XCB::Connection->new(display => $multidpy);
-    if ($x->has_error) {
-        die "Could not connect to multi-monitor display $multidpy\n";
-    } else {
-        push @multi_worker, worker($multidpy, $x, $outdir, \%options);
-    }
-}
-
 # Read previous timing information, if available. We will be able to roughly
 # predict the test duration and schedule a good order for the tests.
 my $timingsjson = StartXDummy::slurp('.last_run_timings.json');
@@ -149,30 +132,21 @@ my @done;
 my $num = @testfiles;
 my $harness = TAP::Harness->new({ });
 
-my @single_monitor_tests = grep { m,^t/([0-9]+)-, && $1 < 500 } @testfiles;
-my @multi_monitor_tests = grep { m,^t/([0-9]+)-, && $1 >= 500 } @testfiles;
-
 my $aggregator = TAP::Parser::Aggregator->new();
 $aggregator->start();
 
-status_init(displays => [ @displays, $multidpy ], tests => $num);
+status_init(displays => \@displays, tests => $num);
 
 my $single_cv = AE::cv;
-my $multi_cv = AE::cv;
 
 # We start tests concurrently: For each display, one test gets started. Every
 # test starts another test after completing.
 for (@single_worker) {
     $single_cv->begin;
-    take_job($_, $single_cv, \@single_monitor_tests);
-}
-for (@multi_worker) {
-    $multi_cv->begin;
-    take_job($_, $multi_cv, \@multi_monitor_tests);
+    take_job($_, $single_cv, \@testfiles);
 }
 
 $single_cv->recv;
-$multi_cv->recv;
 
 $aggregator->stop();
 
index c854a62e8bbdeb67725cd35678e8d6add7e3551d..5c739fca022ddf4ee678d9b9eeae6fad557567dd 100644 (file)
@@ -75,17 +75,12 @@ sub start_xdummy {
     # If /proc/cpuinfo does not exist, we fall back to 2 cores.
     $num_cores ||= 2;
 
-    # If unset, we use num_cores * 2, plus two extra xdummys to combine to a
-    # multi-monitor setup using Xdmx.
-    $parallel ||= ($num_cores * 2) + 2;
+    # If unset, we use num_cores * 2.
+    $parallel ||= ($num_cores * 2);
 
     # If we are running a small number of tests, don’t over-parallelize.
     $parallel = $numtests if $numtests < $parallel;
 
-    # Ensure we have at least 1 X-Server plus two X-Servers for multi-monitor
-    # tests.
-    $parallel = 3 if $parallel < 3;
-
     # First get the last used display number, then increment it by one.
     # Effectively falls back to 1 if no X server is running.
     my ($displaynum) = map { /(\d+)$/ } reverse sort glob($x_socketpath . '*');
@@ -107,20 +102,7 @@ sub start_xdummy {
 
     wait_for_x(\@sockets_waiting);
 
-    # Now combine the last two displays to a multi-monitor display using Xdmx
-    my $first = pop @displays;
-    my $second = pop @displays;
-
-    # make sure this display isn’t in use yet
-    $displaynum++ while -e ($x_socketpath . $displaynum);
-    say 'starting xdmx on display :' . $displaynum;
-
-    my $multidpy = ":$displaynum";
-    my $socket = fork_xserver($displaynum, 'Xdmx', '+xinerama', '-xinput',
-            'local', '-display', $first, '-display', $second, '-ac', $multidpy);
-    wait_for_x([ $socket ]);
-
-    return \@displays, $multidpy;
+    return @displays;
 }
 
 1
index f7be1b665d8a9f3eb8697e1d27a7bbf155ce97a2..4c41a7f2f27d4ccbc210f913417262dcabdd7992 100644 (file)
@@ -288,7 +288,7 @@ sub fresh_workspace {
     if (exists($args{output})) {
         my $i3 = i3(get_socket_path());
         my $tree = $i3->get_tree->recv;
-        my $output = first { $_->{name} eq "xinerama-$args{output}" }
+        my $output = first { $_->{name} eq "fake-$args{output}" }
                         @{$tree->{nodes}};
         die "BUG: Could not find output $args{output}" unless defined($output);
         # Get the focused workspace on that output and switch to it.
index 1f42f0bbba820fedf7eccda7c8707c896e6274d8..5c341d63be5af6dfb4c157ff4d067f4ff3cdc35b 100644 (file)
@@ -4,7 +4,15 @@
 # Tests that the provided X-Server to the t/5??-*.t tests is actually providing
 # multiple monitors.
 #
-use i3test;
+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
+
+fake-outputs 1024x768+0+0,1024x768+1024+0
+EOT
+my $pid = launch_with_config($config);
 
 my $i3 = i3(get_socket_path());
 
@@ -15,7 +23,9 @@ my $i3 = i3(get_socket_path());
 my $tree = $i3->get_tree->recv;
 
 my @outputs = map { $_->{name} } @{$tree->{nodes}};
-is_deeply(\@outputs, [ '__i3', 'xinerama-0', 'xinerama-1' ],
+is_deeply(\@outputs, [ '__i3', 'fake-0', 'fake-1' ],
           'multi-monitor outputs ok');
 
+exit_gracefully($pid);
+
 done_testing;
index ef57ffad7f394d78e4912dcbbcc56aa2df399874..97a64a4a3c4014a52954abaea72b5f0e34b1b311 100644 (file)
@@ -5,7 +5,15 @@
 # ticket #596, bug present until up to commit
 # 89dded044b4fffe78f9d70778748fabb7ac533e9.
 #
-use i3test;
+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
+
+fake-outputs 1024x768+0+0,1024x768+1024+0
+EOT
+my $pid = launch_with_config($config);
 
 my $i3 = i3(get_socket_path());
 
@@ -92,4 +100,6 @@ $second = fresh_workspace(output => 0);
 
 verify_scratchpad_switch($first, $second);
 
+exit_gracefully($pid);
+
 done_testing;
index 139b670ab948cebfffd0cdaedaffb46b739b3d0e..01e987231689622980b56b2ca3ed62c7f6491cde 100644 (file)
@@ -3,9 +3,17 @@
 #
 # Verifies the 'focus output' command works properly.
 
-use i3test;
+use i3test i3_autostart => 0;
 use List::Util qw(first);
 
+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);
+
 my $tmp = fresh_workspace;
 my $i3 = i3(get_socket_path());
 
@@ -20,31 +28,33 @@ sub focused_output {
     return $output->{name};
 }
 
-is(focused_output, 'xinerama-0', 'focus on first output');
+is(focused_output, 'fake-0', 'focus on first output');
 
 cmd 'focus output right';
-is(focused_output, 'xinerama-1', 'focus on second output');
+is(focused_output, 'fake-1', 'focus on second output');
 
 # focus should wrap when we focus to the right again.
 cmd 'focus output right';
-is(focused_output, 'xinerama-0', 'focus on first output again');
+is(focused_output, 'fake-0', 'focus on first output again');
 
 cmd 'focus output left';
-is(focused_output, 'xinerama-1', 'focus back on second output');
+is(focused_output, 'fake-1', 'focus back on second output');
 
 cmd 'focus output left';
-is(focused_output, 'xinerama-0', 'focus on first output again');
+is(focused_output, 'fake-0', 'focus on first output again');
 
 cmd 'focus output up';
-is(focused_output, 'xinerama-0', 'focus still on first output');
+is(focused_output, 'fake-0', 'focus still on first output');
 
 cmd 'focus output down';
-is(focused_output, 'xinerama-0', 'focus still on first output');
+is(focused_output, 'fake-0', 'focus still on first output');
+
+cmd 'focus output fake-1';
+is(focused_output, 'fake-1', 'focus on second output');
 
-cmd 'focus output xinerama-1';
-is(focused_output, 'xinerama-1', 'focus on second output');
+cmd 'focus output fake-0';
+is(focused_output, 'fake-0', 'focus on first output');
 
-cmd 'focus output xinerama-0';
-is(focused_output, 'xinerama-0', 'focus on first output');
+exit_gracefully($pid);
 
 done_testing;
index 7122cb34f503761e34af70d94e760e14b2be6533..19d9f95ae32469db50f754887ea504b96aaade3c 100644 (file)
@@ -4,7 +4,15 @@
 # Tests whether 'workspace next_on_output' and the like work correctly.
 #
 use List::Util qw(first);
-use i3test;
+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
+
+fake-outputs 1024x768+0+0,1024x768+1024+0
+EOT
+my $pid = launch_with_config($config);
 
 ################################################################################
 # Setup workspaces so that they stay open (with an empty container).
@@ -61,4 +69,6 @@ cmd 'workspace 2';
 cmd 'workspace prev_on_output';
 is(focused_ws, '2', 'workspace 2 focused');
 
+exit_gracefully($pid);
+
 done_testing;
index 7f6f990c0e8a745fa10e52e5c4f63ae020057c36..57e5694333a30b7013b981f042b174939c15820f 100644 (file)
@@ -4,11 +4,19 @@
 # Tests whether the 'move workspace <ws> to [output] <output>' command works
 #
 use List::Util qw(first);
-use i3test;
+use i3test i3_autostart => 0;
 
 # TODO:
 # introduce 'move workspace 3 to output <output>' with synonym 'move workspace 3 to <output>'
 
+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);
+
 ################################################################################
 # Setup workspaces so that they stay open (with an empty container).
 ################################################################################
@@ -42,42 +50,42 @@ cmd 'workspace 5';
 is(focused_ws, '5', 'workspace 5 focused');
 
 my ($x0, $x1) = workspaces_per_screen();
-ok('5' ~~ @$x0, 'workspace 5 on xinerama-0');
+ok('5' ~~ @$x0, 'workspace 5 on fake-0');
 
-cmd 'move workspace to output xinerama-1';
+cmd 'move workspace to output fake-1';
 
 sub workspaces_per_screen {
     my $i3 = i3(get_socket_path());
     my $tree = $i3->get_tree->recv;
     my @outputs = @{$tree->{nodes}};
 
-    my $xinerama0 = first { $_->{name} eq 'xinerama-0' } @outputs;
-    my $xinerama0_content = first { $_->{type} == 2 } @{$xinerama0->{nodes}};
+    my $fake0 = first { $_->{name} eq 'fake-0' } @outputs;
+    my $fake0_content = first { $_->{type} == 2 } @{$fake0->{nodes}};
 
-    my $xinerama1 = first { $_->{name} eq 'xinerama-1' } @outputs;
-    my $xinerama1_content = first { $_->{type} == 2 } @{$xinerama1->{nodes}};
+    my $fake1 = first { $_->{name} eq 'fake-1' } @outputs;
+    my $fake1_content = first { $_->{type} == 2 } @{$fake1->{nodes}};
 
-    my @xinerama0_workspaces = map { $_->{name} } @{$xinerama0_content->{nodes}};
-    my @xinerama1_workspaces = map { $_->{name} } @{$xinerama1_content->{nodes}};
+    my @fake0_workspaces = map { $_->{name} } @{$fake0_content->{nodes}};
+    my @fake1_workspaces = map { $_->{name} } @{$fake1_content->{nodes}};
 
-    return \@xinerama0_workspaces, \@xinerama1_workspaces;
+    return \@fake0_workspaces, \@fake1_workspaces;
 }
 
 ($x0, $x1) = workspaces_per_screen();
-ok('5' ~~ @$x1, 'workspace 5 now on xinerama-1');
+ok('5' ~~ @$x1, 'workspace 5 now on fake-1');
 
 ################################################################################
 # Verify that a new workspace will be created when moving the last workspace.
 ################################################################################
 
-is_deeply($x0, [ '1' ], 'only workspace 1 remaining on xinerama-0');
+is_deeply($x0, [ '1' ], 'only workspace 1 remaining on fake-0');
 
 cmd 'workspace 1';
-cmd 'move workspace to output xinerama-1';
+cmd 'move workspace to output fake-1';
 
 ($x0, $x1) = workspaces_per_screen();
-ok('1' ~~ @$x1, 'workspace 1 now on xinerama-1');
-is_deeply($x0, [ '3' ], 'workspace 2 created on xinerama-0');
+ok('1' ~~ @$x1, 'workspace 1 now on fake-1');
+is_deeply($x0, [ '3' ], 'workspace 2 created on fake-0');
 
 ################################################################################
 # Verify that 'move workspace to output <direction>' works
@@ -87,7 +95,7 @@ cmd 'workspace 5';
 cmd 'move workspace to output left';
 
 ($x0, $x1) = workspaces_per_screen();
-ok('5' ~~ @$x0, 'workspace 5 back on xinerama-0');
+ok('5' ~~ @$x0, 'workspace 5 back on fake-0');
 
 ################################################################################
 # Verify that coordinates of floating windows are fixed correctly when moving a
@@ -108,4 +116,6 @@ is($old_rect->{y}, $new_rect->{y}, 'y coordinate unchanged');
 is($old_rect->{width}, $new_rect->{width}, 'width unchanged');
 is($old_rect->{height}, $new_rect->{height}, 'height unchanged');
 
+exit_gracefully($pid);
+
 done_testing;