use List::Util qw(first);
use Time::HiRes qw(sleep);
use Cwd qw(abs_path);
+use Scalar::Util qw(blessed);
use SocketActivation;
use v5.10;
# thin wrapper around wait_for_event which waits for MAP_NOTIFY
# make sure to include 'structure_notify' in the window’s event_mask attribute
sub wait_for_map {
- wait_for_event 2, sub { $_[0]->{response_type} == MAP_NOTIFY };
+ my ($win) = @_;
+ my $id = (blessed($win) && $win->isa('X11::XCB::Window')) ? $win->id : $win;
+ wait_for_event 2, sub {
+ $_[0]->{response_type} == MAP_NOTIFY and $_[0]->{window} == $id
+ };
}
# Wrapper around wait_for_event which waits for UNMAP_NOTIFY. Also calls
# sync_with_i3 to make sure i3 also picked up and processed the UnmapNotify
# event.
sub wait_for_unmap {
- wait_for_event 2, sub { $_[0]->{response_type} == UNMAP_NOTIFY };
+ my ($win) = @_;
+ # my $id = (blessed($win) && $win->isa('X11::XCB::Window')) ? $win->id : $win;
+ wait_for_event 2, sub {
+ $_[0]->{response_type} == UNMAP_NOTIFY # and $_[0]->{window} == $id
+ };
sync_with_i3($x);
}
return $window if $dont_map;
$window->map;
- wait_for_map($x);
+ wait_for_map($window);
# We sync with i3 here to make sure $x->input_focus is updated.
sync_with_i3($x);
return $window;
$window->map;
-wait_for_map $x;
+wait_for_map $window;
my ($absolute, $top) = $window->rect;
$window->map;
-wait_for_map $x;
+wait_for_map $window;
($absolute, $top) = $window->rect;
$window->map;
-wait_for_map $x;
+wait_for_map $window;
cmd 'floating enable';
+# XXX potentionally racy
($absolute, $top) = $window->rect;
cmp_ok($absolute->{width}, '==', 80, "i3 let the width at 80");
$window->map;
-wait_for_map $x;
+wait_for_map $window;
# open another container to make the window get only half of the screen
cmd 'open';
$window->fullscreen(1);
$window->map;
-wait_for_map $x;
+wait_for_map $window;
$new_rect = $window->rect;
ok(!eq_deeply($new_rect, $original_rect), "Window got repositioned after fullscreen");
$window->destroy;
-wait_for_unmap $x;
+wait_for_unmap $window;
@docked = get_dock_clients();
is(@docked, 0, 'no more dock clients');
$window->destroy;
-wait_for_unmap $x;
+wait_for_unmap $window;
@docked = get_dock_clients();
is(@docked, 0, 'no more dock clients');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@docked = get_dock_clients('top');
is(@docked, 1, 'dock client on top');
$window->destroy;
-wait_for_unmap $x;
+wait_for_unmap $window;
@docked = get_dock_clients();
is(@docked, 0, 'no more dock clients');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@docked = get_dock_clients('bottom');
is(@docked, 1, 'dock client on bottom');
$fwindow->transient_for($window);
$fwindow->map;
-wait_for_map $x;
+wait_for_map $fwindow;
does_i3_live;
$window->unmap;
-wait_for_unmap($x);
+wait_for_unmap $window;
is($x->input_focus, $focus, 'Focus correctly restored');
$child->client_leader($right);
$child->map;
-ok(wait_for_map($x), 'child window mapped');
+ok(wait_for_map($child), 'child window mapped');
my $cgeom;
($abs, $cgeom) = $child->rect;
$child2->client_leader($left);
$child2->map;
-ok(wait_for_map($x), 'second child window mapped');
+ok(wait_for_map($child2), 'second child window mapped');
($abs, $cgeom) = $child2->rect;
cmp_ok(($cgeom->x + $cgeom->width), '<', $rgeom->x, 'child above left window');
$fwindow->transient_for($right);
$fwindow->map;
-ok(wait_for_map($x), 'transient window mapped');
+ok(wait_for_map($fwindow), 'transient window mapped');
my ($absolute, $top) = $fwindow->rect;
ok($absolute->{x} != 0 && $absolute->{y} != 0, 'i3 did not map it to (0x0)');
my $window = open_window($x, { dont_map => 1, name => 'Parent window' });
$window->map;
-ok(wait_for_map($x), 'parent window mapped');
+ok(wait_for_map($window), 'parent window mapped');
#########################################################################
# Switch to a different workspace and open a child window. It should be opened
$child->client_leader($window);
$child->map;
-ok(wait_for_map($x), 'child window mapped');
+ok(wait_for_map($child), 'child window mapped');
isnt($x->input_focus, $child->id, "Child window focused");
is($ws->{num}, 0, 'workspace number is 0');
cmd "workspace aa: $tmp";
-my $ws = get_ws("aa: $tmp");
+$ws = get_ws("aa: $tmp");
ok(defined($ws), "workspace aa: $tmp was created");
is($ws->{num}, -1, 'workspace number is -1');
my $id = $win->{id};
cmd qq|[con_id="$id"] kill|;
-wait_for_unmap $x;
+wait_for_unmap $window;
cmd 'nop checking if its gone';
$content = get_ws_content($tmp);
set_wm_class($left->id, 'special', 'special');
$left->name('left');
$left->map;
-ok(wait_for_map($x), 'left window mapped');
+ok(wait_for_map($left), 'left window mapped');
my $right = $x->root->create_child(
class => WINDOW_CLASS_INPUT_OUTPUT,
set_wm_class($right->id, 'special', 'special');
$right->name('right');
$right->map;
-ok(wait_for_map($x), 'right window mapped');
+ok(wait_for_map($right), 'right window mapped');
# two windows should be here
$content = get_ws_content($tmp);
set_wm_class($left->id, 'special7', 'special7');
$left->name('left');
$left->map;
-ok(wait_for_map($x), 'left window mapped');
+ok(wait_for_map($left), 'left window mapped');
# two windows should be here
$content = get_ws_content($tmp);
cmd '[class="^special[0-9]$"] kill';
-wait_for_unmap $x;
+wait_for_unmap $left;
$content = get_ws_content($tmp);
is(@{$content}, 0, 'window killed');
set_wm_class($left->id, 'special7', 'special7');
$left->name('ä 3');
$left->map;
-ok(wait_for_map($x), 'left window mapped');
+ok(wait_for_map($left), 'left window mapped');
# two windows should be here
$content = get_ws_content($tmp);
cmd '[title="^\w [3]$"] kill';
-wait_for_unmap $x;
+wait_for_unmap $left;
$content = get_ws_content($tmp);
is(@{$content}, 0, 'window killed');
$aspect->max_den(300);
$win->_create;
$win->map;
-wait_for_map $x;
+wait_for_map $win;
$win->hints->aspect($aspect);
$x->flush;
# now kill the third one (it's floating). focus should stay unchanged
cmd '[id="' . $third->id . '"] kill';
-wait_for_unmap($x);
+wait_for_unmap($third);
is($x->input_focus, $second->id, 'second con still focused after killing third');
# now kill the second one. focus should fall back to the third one, which is
# also floating
cmd 'kill';
-wait_for_unmap($x);
+wait_for_unmap($second);
is($x->input_focus, $third->id, 'third con focused');
cmd 'kill';
-wait_for_unmap($x);
+wait_for_unmap($third);
is($x->input_focus, $first->id, 'first con focused after killing all floating cons');
# now kill the second one. focus should fall back to the third one, which is
# also floating
cmd 'kill';
-wait_for_unmap($x);
+wait_for_unmap($second);
is($x->input_focus, $third->id, 'third con focused');
cmd 'kill';
-wait_for_unmap($x);
+wait_for_unmap($third);
is($x->input_focus, $first->id, 'first con focused after killing all floating cons');
$window->destroy;
-wait_for_unmap $x;
+wait_for_unmap $window;
@docked = get_dock_clients;
is(@docked, 0, 'no dock clients found');
$window->unmap;
-wait_for_unmap $x;
+wait_for_unmap $window;
is($window->state, ICCCM_WM_STATE_WITHDRAWN, 'WM_STATE withdrawn');
$window->name('Border window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
my @content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
is($content[0]->{border}, 'normal', 'normal border');
$window->unmap;
-wait_for_unmap $x;
+wait_for_unmap $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 0, 'no more nodes');
set_wm_class($window->id, 'borderless', 'borderless');
$window->name('Borderless window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
is($content[0]->{border}, 'none', 'no border');
$window->unmap;
-wait_for_unmap $x;
+wait_for_unmap $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 0, 'no more nodes');
$window->name('special title');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
is($content[0]->{border}, 'normal', 'still normal border');
$window->unmap;
-wait_for_unmap $x;
+wait_for_unmap $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 0, 'no more nodes');
$window->name('special mark title');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
set_wm_class($window->id, 'borderless', 'borderless');
$window->name('usethis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
is($content[0]->{border}, 'none', 'no border');
cmd 'kill';
-wait_for_unmap $x;
+wait_for_unmap $window;
$window->destroy;
# give i3 a chance to delete the window from its tree
set_wm_class($window->id, 'borderless', 'borderless');
$window->name('notthis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
set_wm_class($window->id, 'bar', 'foo');
$window->name('usethis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
set_wm_class($window->id, 'bar', 'foo');
$window->name('usethis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
set_wm_class($window->id, 'bar', 'foo');
$window->name('usethis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
$window->name('usethis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
$window->name('usethis');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
@content = @{get_ws_content($tmp)};
cmp_ok(@content, '==', 1, 'one node on this workspace now');
set_wm_class($window->id, 'special', 'special');
$window->name('special window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
ok(@{get_ws_content($tmp)} == 1, 'special window got managed to current (random) workspace');
set_wm_class($window->id, 'special', 'special');
$window->name('special window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
ok(@{get_ws_content($tmp)} == 0, 'still no containers');
ok("targetws" ~~ @{get_workspace_names()}, 'targetws exists');
set_wm_class($window->id, 'special', 'special');
$window->name('special window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
my $content = get_ws($tmp);
ok(@{$content->{nodes}} == 0, 'no tiling cons');
set_wm_class($window->id, 'SPEcial', 'SPEcial');
$window->name('special window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
$content = get_ws($tmp);
ok(@{$content->{nodes}} == 0, 'no tiling cons');
set_wm_class($window->id, 'special', 'special');
$window->name('special window');
$window->map;
-wait_for_map $x;
+wait_for_map $window;
$content = get_ws($tmp);
ok(@{$content->{nodes}} == 0, 'no tiling cons');