From: Michael Stapelberg Date: Thu, 5 Jan 2012 21:39:34 +0000 (+0000) Subject: tests: add scratchpad test X-Git-Tag: 4.2~158 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ed37a63942a8f462e155593bd4a3b378336e577d;p=i3%2Fi3 tests: add scratchpad test --- diff --git a/testcases/t/185-scratchpad.t b/testcases/t/185-scratchpad.t new file mode 100644 index 00000000..072e02d5 --- /dev/null +++ b/testcases/t/185-scratchpad.t @@ -0,0 +1,302 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Tests for the scratchpad functionality. +# +use i3test; +use List::Util qw(first); + +my $i3 = i3(get_socket_path()); +my $tmp = fresh_workspace; + +################################################################################ +# 1: Verify that the __i3 output contains the __i3_scratch workspace and that +# it’s empty initially. Also, __i3 should not show up in GET_OUTPUTS so that +# tools like i3bar will not handle it. Similarly, __i3_scratch should not show +# up in GET_WORKSPACES. After all, you should not be able to switch to it. +################################################################################ + +my $tree = $i3->get_tree->recv; +is($tree->{name}, 'root', 'root node is the first thing we get'); + +my @__i3 = grep { $_->{name} eq '__i3' } @{$tree->{nodes}}; +is(scalar @__i3, 1, 'output __i3 found'); + +my $content = first { $_->{type} == 2 } @{$__i3[0]->{nodes}}; +my @workspaces = @{$content->{nodes}}; +my @workspace_names = map { $_->{name} } @workspaces; +ok('__i3_scratch' ~~ @workspace_names, '__i3_scratch workspace found'); + +my $get_outputs = $i3->get_outputs->recv; +my $get_ws = $i3->get_workspaces->recv; +my @output_names = map { $_->{name} } @$get_outputs; +my @ws_names = map { $_->{name} } @$get_ws; + +ok(!('__i3' ~~ @output_names), '__i3 not in GET_OUTPUTS'); +ok(!('__i3_scratch' ~~ @ws_names), '__i3_scratch ws not in GET_WORKSPACES'); + +################################################################################ +# 2: Verify that you cannot switch to the __i3_scratch workspace and moving +# windows to __i3_scratch does not work (users should be aware of the different +# behavior and acknowledge that by using the scratchpad commands). +################################################################################ + +# Try focusing the workspace. +my $__i3_scratch = get_ws('__i3_scratch'); +is($__i3_scratch->{focused}, 0, '__i3_scratch ws not focused'); + +cmd 'workspace __i3_scratch'; + +$__i3_scratch = get_ws('__i3_scratch'); +is($__i3_scratch->{focused}, 0, '__i3_scratch ws still not focused'); + + +# Try moving a window to it. +is(scalar @{$__i3_scratch->{floating_nodes}}, 0, '__i3_scratch ws empty'); + +my $window = open_window; +cmd 'move workspace __i3_scratch'; + +$__i3_scratch = get_ws('__i3_scratch'); +is(scalar @{$__i3_scratch->{floating_nodes}}, 0, '__i3_scratch ws empty'); + + +# Try moving the window with the 'output ' command. +# We hardcode output left since the pseudo-output will be initialized before +# every other output, so it will always be the first one. +cmd 'move output left'; + +$__i3_scratch = get_ws('__i3_scratch'); +is(scalar @{$__i3_scratch->{floating_nodes}}, 0, '__i3_scratch ws empty'); + + +# Try moving the window with the 'output ' command. +cmd 'move output __i3'; + +$__i3_scratch = get_ws('__i3_scratch'); +is(scalar @{$__i3_scratch->{floating_nodes}}, 0, '__i3_scratch ws empty'); + + +################################################################################ +# 3: Verify that 'scratchpad toggle' sends a window to the __i3_scratch +# workspace and sets the scratchpad flag to SCRATCHPAD_FRESH. The window’s size +# and position will be changed (once!) on the next 'scratchpad show' and the +# flag will be changed to SCRATCHPAD_CHANGED. +################################################################################ + +my ($nodes, $focus) = get_ws_content($tmp); +is(scalar @$nodes, 1, 'precisely one window on current ws'); +is($nodes->[0]->{scratchpad_state}, 'none', 'scratchpad_state none'); + +cmd 'move scratchpad'; + +$__i3_scratch = get_ws('__i3_scratch'); +my @scratch_nodes = @{$__i3_scratch->{floating_nodes}}; +is(scalar @scratch_nodes, 1, '__i3_scratch contains our window'); +($nodes, $focus) = get_ws_content($tmp); +is(scalar @$nodes, 0, 'no window on current ws anymore'); + +is($scratch_nodes[0]->{scratchpad_state}, 'fresh', 'scratchpad_state fresh'); + +$tree = $i3->get_tree->recv; +my $__i3 = first { $_->{name} eq '__i3' } @{$tree->{nodes}}; +isnt($tree->{focus}->[0], $__i3->{id}, '__i3 output not focused'); + +$get_outputs = $i3->get_outputs->recv; +$get_ws = $i3->get_workspaces->recv; +@output_names = map { $_->{name} } @$get_outputs; +@ws_names = map { $_->{name} } @$get_ws; + +ok(!('__i3' ~~ @output_names), '__i3 not in GET_OUTPUTS'); +ok(!('__i3_scratch' ~~ @ws_names), '__i3_scratch ws not in GET_WORKSPACES'); + +################################################################################ +# 4: Verify that 'scratchpad show' makes the window visible. +################################################################################ + +# Open another window so that we can check if focus is on the scratchpad window +# after showing it. +my $second_window = open_window; +my $old_focus = get_focused($tmp); + +cmd 'scratchpad show'; + +isnt(get_focused($tmp), $old_focus, 'focus changed'); + +$__i3_scratch = get_ws('__i3_scratch'); +@scratch_nodes = @{$__i3_scratch->{floating_nodes}}; +is(scalar @scratch_nodes, 0, '__i3_scratch is now empty'); + +my $ws = get_ws($tmp); +my $output = $tree->{nodes}->[1]; +my $scratchrect = $ws->{floating_nodes}->[0]->{rect}; +my $outputrect = $output->{rect}; + +is($scratchrect->{width}, $outputrect->{width} * 0.5, 'scratch width is 50%'); +is($scratchrect->{height}, $outputrect->{height} * 0.75, 'scratch height is 75%'); +is($scratchrect->{x}, + ($outputrect->{width} / 2) - ($scratchrect->{width} / 2), + 'scratch window centered horizontally'); +is($scratchrect->{y}, + ($outputrect->{height} / 2 ) - ($scratchrect->{height} / 2), + 'scratch window centered vertically'); + +################################################################################ +# 5: Another 'scratchpad show' should make that window go to the scratchpad +# again. +################################################################################ + +cmd 'scratchpad show'; + +$__i3_scratch = get_ws('__i3_scratch'); +@scratch_nodes = @{$__i3_scratch->{floating_nodes}}; +is(scalar @scratch_nodes, 1, '__i3_scratch contains our window'); + +is($scratch_nodes[0]->{scratchpad_state}, 'changed', 'scratchpad_state changed'); + +################################################################################ +# 6: Verify that repeated 'scratchpad show' cycle through the stack, that is, +# toggling a visible window should insert it at the bottom of the stack of the +# __i3_scratch workspace. +################################################################################ + +my $third_window = open_window(name => 'scratch-match'); +cmd 'move scratchpad'; + +$__i3_scratch = get_ws('__i3_scratch'); +@scratch_nodes = @{$__i3_scratch->{floating_nodes}}; +is(scalar @scratch_nodes, 2, '__i3_scratch contains both windows'); + +is($scratch_nodes[0]->{scratchpad_state}, 'changed', 'changed window first'); +is($scratch_nodes[1]->{scratchpad_state}, 'fresh', 'fresh window is second'); + +my $changed_id = $scratch_nodes[0]->{nodes}->[0]->{id}; +my $fresh_id = $scratch_nodes[1]->{nodes}->[0]->{id}; +is($scratch_nodes[0]->{id}, $__i3_scratch->{focus}->[0], 'changed window first'); +is($scratch_nodes[1]->{id}, $__i3_scratch->{focus}->[1], 'fresh window second'); + +# Repeatedly use 'scratchpad show' and check that the windows are different. +cmd 'scratchpad show'; + +is(get_focused($tmp), $changed_id, 'focus changed'); + +$ws = get_ws($tmp); +$scratchrect = $ws->{floating_nodes}->[0]->{rect}; +is($scratchrect->{width}, $outputrect->{width} * 0.5, 'scratch width is 50%'); +is($scratchrect->{height}, $outputrect->{height} * 0.75, 'scratch height is 75%'); +is($scratchrect->{x}, + ($outputrect->{width} / 2) - ($scratchrect->{width} / 2), + 'scratch window centered horizontally'); +is($scratchrect->{y}, + ($outputrect->{height} / 2 ) - ($scratchrect->{height} / 2), + 'scratch window centered vertically'); + +cmd 'scratchpad show'; + +isnt(get_focused($tmp), $changed_id, 'focus changed'); + +cmd 'scratchpad show'; + +is(get_focused($tmp), $fresh_id, 'focus changed'); + +cmd 'scratchpad show'; + +isnt(get_focused($tmp), $fresh_id, 'focus changed'); + +################################################################################ +# 7: Verify that using scratchpad show with criteria works as expected: +# When matching a scratchpad window which is visible, it should hide it. +# When matching a scratchpad window which is on __i3_scratch, it should show it. +# When matching a non-scratchpad window, it should be a no-op. +################################################################################ + +# Verify that using 'scratchpad show' without any matching windows is a no-op. +$old_focus = get_focused($tmp); + +cmd '[title="nomatch"] scratchpad show'; + +is(get_focused($tmp), $old_focus, 'non-matching criteria have no effect'); + +# Verify that we can use criteria to show a scratchpad window. +cmd '[title="scratch-match"] scratchpad show'; + +my $scratch_focus = get_focused($tmp); +isnt($scratch_focus, $old_focus, 'matching criteria works'); + +cmd '[title="scratch-match"] scratchpad show'; + +isnt(get_focused($tmp), $scratch_focus, 'matching criteria works'); +is(get_focused($tmp), $old_focus, 'focus restored'); + +# Verify that we cannot use criteria to show a non-scratchpad window. +my $tmp2 = fresh_workspace; +my $non_scratch_window = open_window(name => 'non-scratch'); +cmd "workspace $tmp"; +is(get_focused($tmp), $old_focus, 'focus still ok'); +cmd '[title="non-match"] scratchpad show'; +is(get_focused($tmp), $old_focus, 'focus unchanged'); + +################################################################################ +# 8: Show it, move it around, hide it. Verify that the position is retained +# when showing it again. +################################################################################ + +cmd '[title="scratch-match"] scratchpad show'; + +isnt(get_focused($tmp), $old_focus, 'scratchpad window shown'); + +my $oldrect = get_ws($tmp)->{floating_nodes}->[0]->{rect}; + +cmd 'move left'; + +$scratchrect = get_ws($tmp)->{floating_nodes}->[0]->{rect}; +isnt($scratchrect->{x}, $oldrect->{x}, 'x position changed'); +$oldrect = $scratchrect; + +# hide it, then show it again +cmd '[title="scratch-match"] scratchpad show'; +cmd '[title="scratch-match"] scratchpad show'; + +# verify the position is still the same +$scratchrect = get_ws($tmp)->{floating_nodes}->[0]->{rect}; + +is_deeply($scratchrect, $oldrect, 'position/size the same'); + +# hide it again for the next test +cmd '[title="scratch-match"] scratchpad show'; + +is(get_focused($tmp), $old_focus, 'scratchpad window hidden'); + +is(scalar @{get_ws($tmp)->{nodes}}, 1, 'precisely one window on current ws'); + +################################################################################ +# 9: restart i3 and verify that the scratchpad show still works +################################################################################ + +$__i3_scratch = get_ws('__i3_scratch'); +my $old_nodes = scalar @{$__i3_scratch->{nodes}}; +my $old_floating_nodes = scalar @{$__i3_scratch->{floating_nodes}}; + +cmd 'restart'; +sleep 1; + +does_i3_live; + +$__i3_scratch = get_ws('__i3_scratch'); +is(scalar @{$__i3_scratch->{nodes}}, $old_nodes, "number of nodes matches ($old_nodes)"); +is(scalar @{$__i3_scratch->{floating_nodes}}, $old_floating_nodes, "number of floating nodes matches ($old_floating_nodes)"); + +is(scalar @{get_ws($tmp)->{nodes}}, 1, 'still precisely one window on current ws'); +is(scalar @{get_ws($tmp)->{floating_nodes}}, 0, 'still no floating windows on current ws'); + +# verify that we can display the scratchpad window +cmd '[title="scratch-match"] scratchpad show'; + +$ws = get_ws($tmp); +is(scalar @{$ws->{nodes}}, 1, 'still precisely one window on current ws'); +is(scalar @{$ws->{floating_nodes}}, 1, 'precisely one floating windows on current ws'); +is($ws->{floating_nodes}->[0]->{scratchpad_state}, 'changed', 'scratchpad_state is "changed"'); + +# TODO: make i3bar display *something* when a window on the scratchpad has the urgency hint + +done_testing;