+qx(xvfb-run --help 2>&1);
+if ($? && $options{xvfb}) {
+ say "xvfb-run not found, not running tests under xvfb. Install the xvfb package to speed up tests";
+ $options{xvfb} = 0;
+}
+
+if ($options{xvfb}) {
+ for (my $n = 99; $n < 120; $n++) {
+ my $path = File::Temp::tmpnam($ENV{TMPDIR} // "/tmp", "i3-testsXXXXXX");
+ if (!defined(POSIX::mkfifo($path, 0600))) {
+ die "mkfifo: $!";
+ }
+ my $pid = fork // die "fork: $!";
+ if ($pid == 0) {
+ # Child
+
+ # Xvfb checks whether the parent ignores USR1 and sends USR1 to the
+ # parent when ready, so that the wait call will be interrupted. We
+ # can’t implement this in Perl, as Perl’s waitpid transparently
+ # handles -EINTR.
+ exec('/bin/sh', '-c', qq|trap "exit" INT; trap : USR1; (trap '' USR1; exec Xvfb :$n -screen 0 640x480x8 -nolisten tcp) & PID=\$!; wait; if ! kill -0 \$PID 2>/dev/null; then echo 1:\$PID > $path; else echo 0:\$PID > $path; wait \$PID; fi|);
+ die "exec: $!";
+ }
+ chomp(my $kill = slurp($path));
+ unlink($path);
+ my ($code, $xvfbpid) = ($kill =~ m,^([0-1]):(.*)$,);
+ next unless $code eq '0';
+
+ $ENV{DISPLAY} = ":$n";
+ say "Running tests under Xvfb display $ENV{DISPLAY}";
+
+ push(@CLEANUP, sub {
+ kill(15, $xvfbpid);
+ });
+ last;
+ }
+}
+