From 38a9eabff134b23bb0883561034dd2578e1231b1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 23 Sep 2011 20:37:45 +0100 Subject: [PATCH] tests: implement sync_with_i3 and use it instead of sleep() Also use open_standard_window() in a few more places where appropriate --- testcases/t/02-fullscreen.t | 10 +- testcases/t/05-ipc.t | 11 +-- testcases/t/06-focus.t | 2 +- testcases/t/08-focus-stack.t | 24 +---- testcases/t/09-stacking.t | 2 - testcases/t/11-goto.t | 4 +- testcases/t/12-floating-resize.t | 24 ++--- testcases/t/13-urgent.t | 6 +- testcases/t/19-match.t | 17 +--- testcases/t/33-size-hints.t | 2 +- testcases/t/35-floating-focus.t | 59 +++++++---- testcases/t/36-floating-ws-empty.t | 15 +-- testcases/t/37-floating-unmap.t | 17 +--- testcases/t/38-floating-attach.t | 43 +------- testcases/t/40-focus-lost.t | 6 +- testcases/t/41-resize.t | 7 +- testcases/t/45-flattening.t | 3 - testcases/t/46-floating-reinsert.t | 19 +--- testcases/t/47-regress-floatingmove.t | 3 - testcases/t/48-regress-floatingmovews.t | 8 +- testcases/t/53-floating-originalsize.t | 2 +- testcases/t/56-fullscreen-focus.t | 2 +- testcases/t/62-regress-dock-urgent.t | 2 +- testcases/t/63-wm-state.t | 15 +-- testcases/t/67-workspace_layout.t | 4 + testcases/t/70-force_focus_wrapping.t | 3 + testcases/t/lib/i3test.pm | 126 +++++++++++++++++++----- 27 files changed, 198 insertions(+), 238 deletions(-) diff --git a/testcases/t/02-fullscreen.t b/testcases/t/02-fullscreen.t index 34e5364e..e83e45ac 100644 --- a/testcases/t/02-fullscreen.t +++ b/testcases/t/02-fullscreen.t @@ -59,11 +59,9 @@ my $new_rect = $window->rect; ok(!eq_deeply($new_rect, $original_rect), "Window got repositioned"); $original_rect = $new_rect; -sleep 0.25; - $window->fullscreen(1); -sleep 0.25; +sync_with_i3($x); $new_rect = $window->rect; ok(!eq_deeply($new_rect, $original_rect), "Window got repositioned after fullscreen"); @@ -135,12 +133,12 @@ $new_rect = $swindow->rect; ok(!eq_deeply($new_rect, $original_rect), "Window got repositioned"); $swindow->fullscreen(1); -sleep 0.25; +sync_with_i3($x); is(fullscreen_windows(), 1, 'amount of fullscreen windows'); $window->fullscreen(0); -sleep 0.25; +sync_with_i3($x); is(fullscreen_windows(), 0, 'amount of fullscreen windows'); ok($swindow->mapped, 'window mapped after other fullscreen ended'); @@ -152,7 +150,7 @@ ok($swindow->mapped, 'window mapped after other fullscreen ended'); ########################################################################### $swindow->fullscreen(0); -sleep 0.25; +sync_with_i3($x); is(fullscreen_windows(), 0, 'amount of fullscreen windows after disabling'); diff --git a/testcases/t/05-ipc.t b/testcases/t/05-ipc.t index a910c930..0d18040e 100644 --- a/testcases/t/05-ipc.t +++ b/testcases/t/05-ipc.t @@ -2,11 +2,6 @@ # vim:ts=4:sw=4:expandtab use i3test; -use X11::XCB qw(:all); - -BEGIN { - use_ok('X11::XCB::Connection') or BAIL_OUT('Cannot load X11::XCB::Connection'); -} my $x = X11::XCB::Connection->new; @@ -18,16 +13,14 @@ fresh_workspace; # Create a window so we can get a focus different from NULL my $window = open_standard_window($x); -diag("window->id = " . $window->id); - -sleep 0.25; +sync_with_i3($x); my $focus = $x->input_focus; -diag("old focus = $focus"); # Switch to another workspace fresh_workspace; +sync_with_i3($x); my $new_focus = $x->input_focus; isnt($focus, $new_focus, "Focus changed"); diff --git a/testcases/t/06-focus.t b/testcases/t/06-focus.t index d357c8a9..b3add322 100644 --- a/testcases/t/06-focus.t +++ b/testcases/t/06-focus.t @@ -24,7 +24,7 @@ cmd 'split v'; my $top = open_standard_window($x); my $mid = open_standard_window($x); my $bottom = open_standard_window($x); -sleep 0.25; +##sleep 0.25; diag("top id = " . $top->id); diag("mid id = " . $mid->id); diff --git a/testcases/t/08-focus-stack.t b/testcases/t/08-focus-stack.t index f8143979..33a5884a 100644 --- a/testcases/t/08-focus-stack.t +++ b/testcases/t/08-focus-stack.t @@ -4,11 +4,6 @@ # over an unfocused tiling client and destroying the floating one again. use i3test; -use X11::XCB qw(:all); - -BEGIN { - use_ok('X11::XCB::Window') or BAIL_OUT('Could not load X11::XCB::Window'); -} my $x = X11::XCB::Connection->new; @@ -19,30 +14,21 @@ cmd 'split h'; my $tiled_left = open_standard_window($x); my $tiled_right = open_standard_window($x); -sleep 0.25; +sync_with_i3($x); # Get input focus before creating the floating window my $focus = $x->input_focus; # Create a floating window which is smaller than the minimum enforced size of i3 -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 1, 1, 30, 30], - background_color => '#C0C0C0', - type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); +my $window = open_standard_window($x, undef, 1); +sync_with_i3($x); -isa_ok($window, 'X11::XCB::Window'); - -$window->map; - -sleep 1; -sleep 0.25; is($x->input_focus, $window->id, 'floating window focused'); $window->unmap; -sleep 0.25; +# TODO: wait for unmap +sync_with_i3($x); is($x->input_focus, $focus, 'Focus correctly restored'); diff --git a/testcases/t/09-stacking.t b/testcases/t/09-stacking.t index 1cb205ed..cc285f32 100644 --- a/testcases/t/09-stacking.t +++ b/testcases/t/09-stacking.t @@ -27,9 +27,7 @@ $i3->command('9')->recv; ##################################################################### my $top = i3test::open_standard_window($x); -sleep(0.25); my $mid = i3test::open_standard_window($x); -sleep(0.25); my $bottom = i3test::open_standard_window($x); sleep(0.25); diff --git a/testcases/t/11-goto.t b/testcases/t/11-goto.t index 542dc828..44cf55ab 100644 --- a/testcases/t/11-goto.t +++ b/testcases/t/11-goto.t @@ -21,11 +21,8 @@ cmd 'split h'; ##################################################################### my $top = open_standard_window($x); -sleep 0.25; my $mid = open_standard_window($x); -sleep 0.25; my $bottom = open_standard_window($x); -sleep 0.25; diag("top id = " . $top->id); diag("mid id = " . $mid->id); @@ -39,6 +36,7 @@ sub focus_after { my $msg = shift; cmd $msg; + sync_with_i3($x); return $x->input_focus; } diff --git a/testcases/t/12-floating-resize.t b/testcases/t/12-floating-resize.t index 09297df0..1aec9573 100644 --- a/testcases/t/12-floating-resize.t +++ b/testcases/t/12-floating-resize.t @@ -1,8 +1,5 @@ #!perl # vim:ts=4:sw=4:expandtab -# Beware that this test uses workspace 9 to perform some tests (it expects -# the workspace to be empty). -# TODO: skip it by default? use i3test; use X11::XCB qw(:all); @@ -20,30 +17,22 @@ fresh_workspace; ##################################################################### # Create a floating window -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', - # replace the type with 'utility' as soon as the coercion works again in X11::XCB - window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); - -isa_ok($window, 'X11::XCB::Window'); - -$window->map; -sleep 0.25; +my $window = open_standard_window($x, undef, 1); # See if configurerequests cause window movements (they should not) my ($a, $t) = $window->rect; $window->rect(X11::XCB::Rect->new(x => $a->x, y => $a->y, width => $a->width, height => $a->height)); -sleep 0.25; +sync_with_i3($x); + my ($na, $nt) = $window->rect; is_deeply($na, $a, 'Rects are equal after configurerequest'); sub test_resize { $window->rect(X11::XCB::Rect->new(x => 0, y => 0, width => 100, height => 100)); + sync_with_i3($x); + my ($absolute, $top) = $window->rect; # Make sure the width/height are different from what we’re gonna test, so @@ -52,7 +41,8 @@ sub test_resize { isnt($absolute->height, 500, 'height != 500'); $window->rect(X11::XCB::Rect->new(x => 0, y => 0, width => 300, height => 500)); - sleep 0.25; + + sync_with_i3($x); ($absolute, $top) = $window->rect; diff --git a/testcases/t/13-urgent.t b/testcases/t/13-urgent.t index f40b72fb..83c36a98 100644 --- a/testcases/t/13-urgent.t +++ b/testcases/t/13-urgent.t @@ -31,7 +31,7 @@ is(@urgent, 0, 'no window got the urgent flag'); # Add the urgency hint, switch to a different workspace and back again ##################################################################### $top->add_hint('urgency'); -sleep 0.5; +sync_with_i3($x); @content = @{get_ws_content($tmp)}; @urgent = grep { $_->{urgent} } @content; @@ -48,7 +48,7 @@ cmd '[id="' . $top->id . '"] focus'; is(@urgent, 0, 'no window got the urgent flag after focusing'); $top->add_hint('urgency'); -sleep 0.5; +sync_with_i3($x); @urgent = grep { $_->{urgent} } @{get_ws_content($tmp)}; is(@urgent, 0, 'no window got the urgent flag after re-setting urgency hint'); @@ -62,7 +62,7 @@ ok(!$ws->{urgent}, 'urgent flag not set on workspace'); my $otmp = fresh_workspace; $top->add_hint('urgency'); -sleep 0.5; +sync_with_i3($x); $ws = get_ws($tmp); ok($ws->{urgent}, 'urgent flag set on workspace'); diff --git a/testcases/t/19-match.t b/testcases/t/19-match.t index e4fc6ec0..93822f1f 100644 --- a/testcases/t/19-match.t +++ b/testcases/t/19-match.t @@ -12,20 +12,7 @@ ok(@{get_ws_content($tmp)} == 0, 'no containers yet'); # Open a new window my $x = X11::XCB::Connection->new; -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30 ], - background_color => '#C0C0C0', -); - -$window->map; -# give it some time to be picked up by the window manager -# TODO: better check for $window->mapped or something like that? -# maybe we can even wait for getting mapped? -my $c = 0; -while (@{get_ws_content($tmp)} == 0 and $c++ < 5) { - sleep 0.25; -} +my $window = open_standard_window($x); my $content = get_ws_content($tmp); ok(@{$content} == 1, 'window mapped'); my $win = $content->[0]; @@ -114,7 +101,7 @@ ok(@{$content} == 2, 'two windows opened'); cmd '[class="special" title="left"] kill'; -sleep 0.25; +sync_with_i3($x); $content = get_ws_content($tmp); is(@{$content}, 1, 'one window still there'); diff --git a/testcases/t/33-size-hints.t b/testcases/t/33-size-hints.t index 05897c88..e212dc72 100644 --- a/testcases/t/33-size-hints.t +++ b/testcases/t/33-size-hints.t @@ -32,7 +32,7 @@ sleep 0.25; $win->hints->aspect($aspect); $x->flush; -sleep 0.25; +sync_with_i3($x); my $rect = $win->rect; my $ar = $rect->width / $rect->height; diff --git a/testcases/t/35-floating-focus.t b/testcases/t/35-floating-focus.t index 6adad246..fc94c440 100644 --- a/testcases/t/35-floating-focus.t +++ b/testcases/t/35-floating-focus.t @@ -16,6 +16,8 @@ my $tmp = fresh_workspace; my $first = open_standard_window($x); my $second = open_standard_window($x); +sync_with_i3($x); + is($x->input_focus, $second->id, 'second window focused'); cmd 'floating enable'; @@ -34,12 +36,16 @@ $first = open_standard_window($x); # window 2 $second = open_standard_window($x); # window 3 my $third = open_standard_window($x); # window 4 +sync_with_i3($x); + is($x->input_focus, $third->id, 'last container focused'); cmd 'floating enable'; cmd '[id="' . $second->id . '"] focus'; +sync_with_i3($x); + is($x->input_focus, $second->id, 'second con focused'); cmd 'floating enable'; @@ -47,7 +53,8 @@ cmd 'floating enable'; # now kill the third one (it's floating). focus should stay unchanged cmd '[id="' . $third->id . '"] kill'; -sleep 0.25; +# TODO: wait for unmapnotify +sync_with_i3($x); is($x->input_focus, $second->id, 'second con still focused after killing third'); @@ -63,12 +70,16 @@ $first = open_standard_window($x, '#ff0000'); # window 5 $second = open_standard_window($x, '#00ff00'); # window 6 my $third = open_standard_window($x, '#0000ff'); # window 7 +sync_with_i3($x); + is($x->input_focus, $third->id, 'last container focused'); cmd 'floating enable'; cmd '[id="' . $second->id . '"] focus'; +sync_with_i3($x); + is($x->input_focus, $second->id, 'second con focused'); cmd 'floating enable'; @@ -77,13 +88,14 @@ cmd 'floating enable'; # also floating cmd 'kill'; -sleep 0.25; +# TODO: wait for unmapnotify +sync_with_i3($x); is($x->input_focus, $third->id, 'third con focused'); cmd 'kill'; - -sleep 0.25; +# TODO: wait for unmapnotify +sync_with_i3($x); is($x->input_focus, $first->id, 'first con focused after killing all floating cons'); @@ -99,29 +111,34 @@ cmd 'layout stacked'; $second = open_standard_window($x, '#00ff00'); # window 6 $third = open_standard_window($x, '#0000ff'); # window 7 +sync_with_i3($x); + is($x->input_focus, $third->id, 'last container focused'); cmd 'floating enable'; cmd '[id="' . $second->id . '"] focus'; +sync_with_i3($x); + is($x->input_focus, $second->id, 'second con focused'); cmd 'floating enable'; -sleep 0.5; +sync_with_i3($x); # now kill the second one. focus should fall back to the third one, which is # also floating cmd 'kill'; -sleep 0.25; +# TODO: wait for unmapnotify +sync_with_i3($x); -is($x->input_focus, $third->id, 'second con focused'); +is($x->input_focus, $third->id, 'third con focused'); cmd 'kill'; - -sleep 0.25; +# TODO: wait for unmapnotify +sync_with_i3($x); is($x->input_focus, $first->id, 'first con focused after killing all floating cons'); @@ -134,6 +151,8 @@ $tmp = fresh_workspace; $first = open_standard_window($x, '#ff0000'); # window 8 $second = open_standard_window($x, '#00ff00'); # window 9 +sync_with_i3($x); + is($x->input_focus, $second->id, 'second container focused'); cmd 'floating enable'; @@ -142,31 +161,31 @@ is($x->input_focus, $second->id, 'second container focused'); cmd 'focus tiling'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $first->id, 'first (tiling) container focused'); cmd 'focus floating'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $second->id, 'second (floating) container focused'); cmd 'focus floating'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $second->id, 'second (floating) container still focused'); cmd 'focus mode_toggle'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $first->id, 'first (tiling) container focused'); cmd 'focus mode_toggle'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $second->id, 'second (floating) container focused'); @@ -180,35 +199,37 @@ $first = open_standard_window($x, '#ff0000', 1); # window 10 $second = open_standard_window($x, '#00ff00', 1); # window 11 $third = open_standard_window($x, '#0000ff', 1); # window 12 +sync_with_i3($x); + is($x->input_focus, $third->id, 'third container focused'); cmd 'focus left'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $second->id, 'second container focused'); cmd 'focus left'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $first->id, 'first container focused'); cmd 'focus left'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $third->id, 'focus wrapped to third container'); cmd 'focus right'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $first->id, 'focus wrapped to first container'); cmd 'focus right'; -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $second->id, 'focus on second container'); diff --git a/testcases/t/36-floating-ws-empty.t b/testcases/t/36-floating-ws-empty.t index f33d04db..91467ed3 100644 --- a/testcases/t/36-floating-ws-empty.t +++ b/testcases/t/36-floating-ws-empty.t @@ -22,20 +22,7 @@ ok(workspace_exists($tmp), "workspace $tmp exists"); my $x = X11::XCB::Connection->new; # Create a floating window which is smaller than the minimum enforced size of i3 -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', - # replace the type with 'utility' as soon as the coercion works again in X11::XCB - window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); - -isa_ok($window, 'X11::XCB::Window'); - -$window->map; - -sleep 0.25; - +my $window = open_standard_window($x, undef, 1); ok($window->mapped, 'Window is mapped'); # switch to a different workspace, see if the window is still mapped? diff --git a/testcases/t/37-floating-unmap.t b/testcases/t/37-floating-unmap.t index 3ae4b12d..b3be1348 100644 --- a/testcases/t/37-floating-unmap.t +++ b/testcases/t/37-floating-unmap.t @@ -21,27 +21,14 @@ my $tmp = fresh_workspace; my $x = X11::XCB::Connection->new; # Create a floating window which is smaller than the minimum enforced size of i3 -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', - # replace the type with 'utility' as soon as the coercion works again in X11::XCB - window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); - -isa_ok($window, 'X11::XCB::Window'); - -$window->map; - -sleep 0.25; - +my $window = open_standard_window($x, undef, 1); ok($window->mapped, 'Window is mapped'); # switch to a different workspace, see if the window is still mapped? my $otmp = fresh_workspace; -sleep 0.25; +sync_with_i3($x); ok(!$window->mapped, 'Window is not mapped after switching ws'); diff --git a/testcases/t/38-floating-attach.t b/testcases/t/38-floating-attach.t index 31bddafd..411ffa8e 100644 --- a/testcases/t/38-floating-attach.t +++ b/testcases/t/38-floating-attach.t @@ -5,7 +5,6 @@ use i3test; use X11::XCB qw(:all); -use Time::HiRes qw(sleep); BEGIN { use_ok('X11::XCB::Window'); @@ -22,20 +21,7 @@ my $tmp = fresh_workspace; my $x = X11::XCB::Connection->new; # Create a floating window -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', - # replace the type with 'utility' as soon as the coercion works again in X11::XCB - window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); - -isa_ok($window, 'X11::XCB::Window'); - -$window->map; - -sleep 0.25; - +my $window = open_standard_window($x, undef, 1); ok($window->mapped, 'Window is mapped'); my $ws = get_ws($tmp); @@ -45,17 +31,7 @@ is(@{$ws->{floating_nodes}}, 1, 'one floating node'); is(@{$nodes}, 0, 'no tiling nodes'); # Create a tiling window -my $twindow = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', -); - -isa_ok($twindow, 'X11::XCB::Window'); - -$twindow->map; - -sleep 0.25; +my $twindow = open_standard_window($x); ($nodes, $focus) = get_ws_content($tmp); @@ -78,20 +54,7 @@ is(@{$ws->{floating_nodes}}, 0, 'no floating nodes so far'); is(@{$ws->{nodes}}, 1, 'one tiling node (stacked con)'); # Create a floating window -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', - # replace the type with 'utility' as soon as the coercion works again in X11::XCB - window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); - -isa_ok($window, 'X11::XCB::Window'); - -$window->map; - -sleep 0.25; - +my $window = open_standard_window($x, undef, 1); ok($window->mapped, 'Window is mapped'); $ws = get_ws($tmp); diff --git a/testcases/t/40-focus-lost.t b/testcases/t/40-focus-lost.t index 9df220d1..1121f124 100644 --- a/testcases/t/40-focus-lost.t +++ b/testcases/t/40-focus-lost.t @@ -4,7 +4,6 @@ # bug introduced by 77d0d42ed2d7ac8cafe267c92b35a81c1b9491eb use i3test; use X11::XCB qw(:all); -use Time::HiRes qw(sleep); BEGIN { use_ok('X11::XCB::Window'); @@ -26,11 +25,10 @@ sub check_order { my $tmp = fresh_workspace; my $left = open_standard_window($x); -sleep 0.25; my $mid = open_standard_window($x); -sleep 0.25; my $right = open_standard_window($x); -sleep 0.25; + +sync_with_i3($x); diag("left = " . $left->id . ", mid = " . $mid->id . ", right = " . $right->id); diff --git a/testcases/t/41-resize.t b/testcases/t/41-resize.t index 1d1b1206..2a3846d8 100644 --- a/testcases/t/41-resize.t +++ b/testcases/t/41-resize.t @@ -15,9 +15,9 @@ my $tmp = fresh_workspace; cmd 'split v'; my $top = open_standard_window($x); -sleep 0.25; my $bottom = open_standard_window($x); -sleep 0.25; + +sync_with_i3($x); diag("top = " . $top->id . ", bottom = " . $bottom->id); @@ -55,9 +55,7 @@ $tmp = fresh_workspace; cmd 'split v'; $top = open_standard_window($x); -sleep 0.25; $bottom = open_standard_window($x); -sleep 0.25; cmd 'split h'; cmd 'layout stacked'; @@ -79,7 +77,6 @@ is($nodes->[1]->{percent}, 0.75, 'bottom window got 75%'); $tmp = fresh_workspace; $top = open_standard_window($x); -sleep 0.25; cmd 'floating enable'; diff --git a/testcases/t/45-flattening.t b/testcases/t/45-flattening.t index 98b93ef1..4a57f211 100644 --- a/testcases/t/45-flattening.t +++ b/testcases/t/45-flattening.t @@ -18,11 +18,8 @@ my $x = X11::XCB::Connection->new; my $tmp = fresh_workspace; my $left = open_standard_window($x); -sleep 0.25; my $mid = open_standard_window($x); -sleep 0.25; my $right = open_standard_window($x); -sleep 0.25; cmd 'move before v'; cmd 'move after h'; diff --git a/testcases/t/46-floating-reinsert.t b/testcases/t/46-floating-reinsert.t index a4e90d4d..07f78956 100644 --- a/testcases/t/46-floating-reinsert.t +++ b/testcases/t/46-floating-reinsert.t @@ -2,7 +2,6 @@ # vim:ts=4:sw=4:expandtab # use X11::XCB qw(:all); -use Time::HiRes qw(sleep); use i3test; BEGIN { @@ -14,13 +13,10 @@ my $x = X11::XCB::Connection->new; my $tmp = fresh_workspace; my $left = open_standard_window($x); -sleep 0.25; my $mid = open_standard_window($x); -sleep 0.25; cmd 'split v'; my $bottom = open_standard_window($x); -sleep 0.25; my ($nodes, $focus) = get_ws_content($tmp); @@ -31,20 +27,7 @@ my ($nodes, $focus) = get_ws_content($tmp); my $x = X11::XCB::Connection->new; # Create a floating window -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30], - background_color => '#C0C0C0', - # replace the type with 'utility' as soon as the coercion works again in X11::XCB - window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_UTILITY'), -); - -isa_ok($window, 'X11::XCB::Window'); - -$window->map; - -sleep 0.25; - +my $window = open_standard_window($x, undef, 1); ok($window->mapped, 'Window is mapped'); ($nodes, $focus) = get_ws_content($tmp); diff --git a/testcases/t/47-regress-floatingmove.t b/testcases/t/47-regress-floatingmove.t index 6e04916d..8425f6d9 100644 --- a/testcases/t/47-regress-floatingmove.t +++ b/testcases/t/47-regress-floatingmove.t @@ -17,11 +17,8 @@ my $x = X11::XCB::Connection->new; my $tmp = fresh_workspace; my $left = open_standard_window($x); -sleep 0.25; my $mid = open_standard_window($x); -sleep 0.25; my $right = open_standard_window($x); -sleep 0.25; # go to workspace level cmd 'level up'; diff --git a/testcases/t/48-regress-floatingmovews.t b/testcases/t/48-regress-floatingmovews.t index 0bec5418..355e697a 100644 --- a/testcases/t/48-regress-floatingmovews.t +++ b/testcases/t/48-regress-floatingmovews.t @@ -17,20 +17,20 @@ my $tmp = fresh_workspace; # open a tiling window on the first workspace open_standard_window($x); -sleep 0.25; +#sleep 0.25; my $first = get_focused($tmp); # on a different ws, open a floating window my $otmp = fresh_workspace; open_standard_window($x); -sleep 0.25; +#sleep 0.25; my $float = get_focused($otmp); cmd 'mode toggle'; -sleep 0.25; +#sleep 0.25; # move the floating con to first workspace cmd "move workspace $tmp"; -sleep 0.25; +#sleep 0.25; # switch to the first ws and check focus is(get_focused($tmp), $float, 'floating client correctly focused'); diff --git a/testcases/t/53-floating-originalsize.t b/testcases/t/53-floating-originalsize.t index 16e62c20..1daa2709 100644 --- a/testcases/t/53-floating-originalsize.t +++ b/testcases/t/53-floating-originalsize.t @@ -30,7 +30,7 @@ cmp_ok($absolute->{width}, '>', 400, 'i3 raised the width'); cmp_ok($absolute->{height}, '>', 150, 'i3 raised the height'); cmd 'floating toggle'; -sleep 0.25; +sync_with_i3($x); ($absolute, $top) = $window->rect; diff --git a/testcases/t/56-fullscreen-focus.t b/testcases/t/56-fullscreen-focus.t index ee60dc7a..89af6219 100644 --- a/testcases/t/56-fullscreen-focus.t +++ b/testcases/t/56-fullscreen-focus.t @@ -56,7 +56,7 @@ cmd "move workspace $tmp2"; # verify that the third window has the focus -sleep 0.25; +sync_with_i3($x); is($x->input_focus, $third->id, 'third window focused'); diff --git a/testcases/t/62-regress-dock-urgent.t b/testcases/t/62-regress-dock-urgent.t index 8d188738..5fb88129 100644 --- a/testcases/t/62-regress-dock-urgent.t +++ b/testcases/t/62-regress-dock-urgent.t @@ -52,7 +52,7 @@ is($docknode->{rect}->{height}, 30, 'dock node has unchanged height'); $window->add_hint('urgency'); -sleep 0.25; +sync_with_i3($x); does_i3_live; diff --git a/testcases/t/63-wm-state.t b/testcases/t/63-wm-state.t index 7e983289..b9161400 100644 --- a/testcases/t/63-wm-state.t +++ b/testcases/t/63-wm-state.t @@ -16,25 +16,18 @@ BEGIN { my $x = X11::XCB::Connection->new; -my $window = $x->root->create_child( - class => WINDOW_CLASS_INPUT_OUTPUT, - rect => [ 0, 0, 30, 30 ], - background_color => '#00ff00', - event_mask => [ 'structure_notify' ], -); +my $window = open_standard_window($x); -$window->name('Window 1'); -$window->map; +sync_with_i3($x); diag('window mapped'); -sleep 0.5; - is($window->state, ICCCM_WM_STATE_NORMAL, 'WM_STATE normal'); $window->unmap; -sleep 0.5; +# TODO: wait for unmapnotify +sync_with_i3($x); is($window->state, ICCCM_WM_STATE_WITHDRAWN, 'WM_STATE withdrawn'); diff --git a/testcases/t/67-workspace_layout.t b/testcases/t/67-workspace_layout.t index 2b9f6e56..0e07ebf7 100644 --- a/testcases/t/67-workspace_layout.t +++ b/testcases/t/67-workspace_layout.t @@ -30,6 +30,8 @@ ok(@{get_ws_content($tmp)} == 0, 'no containers yet'); my $first = open_standard_window($x); my $second = open_standard_window($x); +sync_with_i3($x); + is($x->input_focus, $second->id, 'second window focused'); ok(@{get_ws_content($tmp)} == 2, 'two containers opened'); isnt($content[0]->{layout}, 'stacked', 'layout not stacked'); @@ -57,6 +59,8 @@ ok(@{get_ws_content($tmp)} == 0, 'no containers yet'); $first = open_standard_window($x); $second = open_standard_window($x); +sync_with_i3($x); + is($x->input_focus, $second->id, 'second window focused'); my @content = @{get_ws_content($tmp)}; ok(@content == 1, 'one con at workspace level'); diff --git a/testcases/t/70-force_focus_wrapping.t b/testcases/t/70-force_focus_wrapping.t index f2dfc18e..cf1c3216 100644 --- a/testcases/t/70-force_focus_wrapping.t +++ b/testcases/t/70-force_focus_wrapping.t @@ -73,6 +73,9 @@ cmd 'layout tabbed'; cmd 'focus parent'; $third = open_standard_window($x); + +sync_with_i3($x); + is($x->input_focus, $third->id, 'third window focused'); cmd 'focus left'; diff --git a/testcases/t/lib/i3test.pm b/testcases/t/lib/i3test.pm index 9ded4942..2a51dad6 100644 --- a/testcases/t/lib/i3test.pm +++ b/testcases/t/lib/i3test.pm @@ -40,6 +40,7 @@ our @EXPORT = qw( my $tester = Test::Builder->new(); my $_cached_socket_path = undef; +my $_sync_window = undef; my $tmp_socket_path = undef; BEGIN { @@ -66,6 +67,44 @@ use warnings; goto \&Exporter::import; } +# +# Waits for the next event and calls the given callback for every event to +# determine if this is the event we are waiting for. +# +# Can be used to wait until a window is mapped, until a ClientMessage is +# received, etc. +# +# wait_for_event $x, 0.25, sub { $_[0]->{response_type} == MAP_NOTIFY }; +# +sub wait_for_event { + my ($x, $timeout, $cb) = @_; + + my $cv = AE::cv; + + my $prep = EV::prepare sub { + $x->flush; + }; + + my $check = EV::check sub { + while (defined(my $event = $x->poll_for_event)) { + if ($cb->($event)) { + $cv->send(1); + last; + } + } + }; + + my $watcher = EV::io $x->get_file_descriptor, EV::READ, sub { + # do nothing, we only need this watcher so that EV picks up the events + }; + + # Trigger timeout after $timeout seconds (can be fractional) + my $timeout = AE::timer $timeout, 0, sub { say STDERR "timeout"; $cv->send(0) }; + + my $result = $cv->recv; + return $result; +} + sub open_standard_window { my ($x, $color, $floating) = @_; @@ -88,29 +127,7 @@ sub open_standard_window { $window->name('Window ' . counter_window()); $window->map; - # wait for the mapped event with a timeout of 0.25s - my $cv = AE::cv; - - my $prep = EV::prepare sub { - $x->flush; - }; - - my $check = EV::check sub { - while (defined(my $event = $x->poll_for_event)) { - if ($event->{response_type} == MAP_NOTIFY) { - $cv->send(0) - } - } - }; - - my $watcher = EV::io $x->get_file_descriptor, EV::READ, sub { - # do nothing, we only need this watcher so that EV picks up the events - }; - - # Trigger timeout after 0.25s - my $timeout = AE::timer 0.5, 0, sub { say STDERR "timeout"; $cv->send(1) }; - - my $result = $cv->recv; + wait_for_event $x, 0.5, sub { $_[0]->{response_type} == MAP_NOTIFY }; return $window; } @@ -239,6 +256,69 @@ sub focused_ws { } } +# +# Sends an I3_SYNC ClientMessage with a random value to the root window. +# i3 will reply with the same value, but, due to the order of events it +# processes, only after all other events are done. +# +# This can be used to ensure the results of a cmd 'focus left' are pushed to +# X11 and that $x->input_focus returns the correct value afterwards. +# +# See also docs/testsuite for a long explanation +# +sub sync_with_i3 { + my ($x) = @_; + + # Since we need a (mapped) window for receiving a ClientMessage, we create + # one on the first call of sync_with_i3. It will be re-used in all + # subsequent calls. + if (!defined($_sync_window)) { + $_sync_window = $x->root->create_child( + class => WINDOW_CLASS_INPUT_OUTPUT, + rect => X11::XCB::Rect->new(x => -15, y => -15, width => 10, height => 10 ), + override_redirect => 1, + background_color => '#ff0000', + event_mask => [ 'structure_notify' ], + ); + + $_sync_window->map; + + wait_for_event $x, 0.5, sub { $_[0]->{response_type} == MAP_NOTIFY }; + } + + my $root = $x->root->id; + # Generate a random number to identify this particular ClientMessage. + my $myrnd = int(rand(255)) + 1; + + # Generate a ClientMessage, see xcb_client_message_t + my $msg = pack "CCSLLLLLLL", + CLIENT_MESSAGE, # response_type + 32, # format + 0, # sequence + $root, # destination window + $x->atom(name => 'I3_SYNC')->id, + + $_sync_window->id, # data[0]: our own window id + $myrnd, # data[1]: a random value to identify the request + 0, + 0, + 0; + + # Send it to the root window -- since i3 uses the SubstructureRedirect + # event mask, it will get the ClientMessage. + $x->send_event(0, $root, EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg); + + # now wait until the reply is here + return wait_for_event $x, 1, sub { + my ($event) = @_; + # TODO: const + return 0 unless $event->{response_type} == 161; + + my ($win, $rnd) = unpack "LL", $event->{data}; + return ($rnd == $myrnd); + }; +} + sub does_i3_live { my $tree = i3(get_socket_path())->get_tree->recv; my @nodes = @{$tree->{nodes}};