diff --git a/src/scratchpad.c b/src/scratchpad.c index a4d29505..9997f17d 100644 --- a/src/scratchpad.c +++ b/src/scratchpad.c @@ -88,12 +88,23 @@ void scratchpad_show(Con *con) { con_toggle_fullscreen(focused, CF_OUTPUT); } + /* If this was 'scratchpad show' without criteria, we check if the + * currently focused window is a scratchpad window and should be hidden + * again. */ + if (!con && + (floating = con_inside_floating(focused)) && + floating->scratchpad_state != SCRATCHPAD_NONE) { + DLOG("Focused window is a scratchpad window, hiding it.\n"); + scratchpad_move(focused); + return; + } + /* If this was 'scratchpad show' without criteria, we check if there is a * unfocused scratchpad on the current workspace and focus it */ Con *walk_con; Con *focused_ws = con_get_workspace(focused); TAILQ_FOREACH(walk_con, &(focused_ws->floating_head), floating_windows) { - if ((floating = con_inside_floating(walk_con)) && + if (!con && (floating = con_inside_floating(walk_con)) && floating->scratchpad_state != SCRATCHPAD_NONE && floating != con_inside_floating(focused)) { DLOG("Found an unfocused scratchpad window on this workspace\n"); @@ -112,7 +123,7 @@ void scratchpad_show(Con *con) { focused_ws = con_get_workspace(focused); TAILQ_FOREACH(walk_con, &all_cons, all_cons) { Con *walk_ws = con_get_workspace(walk_con); - if (walk_ws && + if (!con && walk_ws && !con_is_internal(walk_ws) && focused_ws != walk_ws && (floating = con_inside_floating(walk_con)) && floating->scratchpad_state != SCRATCHPAD_NONE) { @@ -123,14 +134,10 @@ void scratchpad_show(Con *con) { } } - /* If this was 'scratchpad show' without criteria, we check if the - * currently focused window is a scratchpad window and should be hidden - * again. */ - if (!con && - (floating = con_inside_floating(focused)) && - floating->scratchpad_state != SCRATCHPAD_NONE) { - DLOG("Focused window is a scratchpad window, hiding it.\n"); - scratchpad_move(focused); + /* If this was 'scratchpad show' with criteria, we check if the window + * is actually in the scratchpad */ + if (con && con->parent->scratchpad_state == SCRATCHPAD_NONE) { + DLOG("Window is not in the scratchpad, doing nothing.\n"); return; } diff --git a/testcases/t/202-scratchpad-criteria.t b/testcases/t/202-scratchpad-criteria.t index 2603f65a..5ba8bfdd 100644 --- a/testcases/t/202-scratchpad-criteria.t +++ b/testcases/t/202-scratchpad-criteria.t @@ -17,26 +17,35 @@ # Verifies that using criteria to address scratchpad windows works. use i3test; -################################################################################ +##################################################################### # 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. -################################################################################ +# - 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. +# - When matching a scratchpad window, +# non-matching windows shouldn't appear +###################################################################### my $tmp = fresh_workspace; my $third_window = open_window(name => 'scratch-match'); cmd 'move scratchpad'; -# Verify that using 'scratchpad show' without any matching windows is a no-op. +##################################################################### +# Verify that using 'scratchpad show' without any matching windows is +# a no-op. +##################################################################### my $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); @@ -47,12 +56,102 @@ 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'; +cmd '[title="non-scratch"] scratchpad show'; is(get_focused($tmp), $old_focus, 'focus unchanged'); +##################################################################### +# Verify that non-matching windows doesn't appear +##################################################################### +# Subroutine to clear scratchpad +sub clear_scratchpad { + while (scalar @{get_ws('__i3_scratch')->{floating_nodes}}) { + cmd 'scratchpad show'; + cmd 'kill'; + } +} + +#Start from an empty fresh workspace +my $empty_ws = fresh_workspace; +cmd "workspace $empty_ws"; + +my $no_focused = get_focused($empty_ws); +cmd '[title="nothingmatchthistitle"] scratchpad show'; +#Check nothing match +is(get_focused($empty_ws), $no_focused, "no window to focus on"); + +clear_scratchpad; + +open_window(name => "my-scratch-window"); +my $w1_focus = get_focused($empty_ws); +cmd 'move scratchpad'; +cmd '[title="my-scratch-window"] scratchpad show'; +#Check we created and shown a scratchpad window +is(get_focused($empty_ws), $w1_focus, "focus on scratchpad window"); + +#Switching workspace +my $empty_ws2 = fresh_workspace; +cmd "workspace $empty_ws2"; +open_window(name => "my-second-scratch-window"); + +my $w2_focus = get_focused($empty_ws2); +cmd 'move scratchpad'; +cmd '[title="my-second-scratch-window"] scratchpad show'; + +#Check we got the correct window +is(get_focused($empty_ws2), $w2_focus, "focus is on second window"); + +##################################################################### +# Verify that 'scratchpad show' correctly hide multiple scratchpad +# windows +##################################################################### +clear_scratchpad; + +sub check_floating { + my($rws, $n) = @_; + my $ws = get_ws($rws); + is(scalar @{$ws->{nodes}}, 0, 'no windows on ws'); + is(scalar @{$ws->{floating_nodes}}, $n, "$n floating windows on ws"); +} + +my $empty_ws3 = fresh_workspace; +cmd "workspace $empty_ws3"; + +check_floating($empty_ws3, 0); + +#Creating two scratchpad windows +open_window(name => "toggle-1"); +cmd 'move scratchpad'; +open_window(name => "toggle-2"); +cmd 'move scratchpad'; +check_floating($empty_ws3, 0); +#Showing both +cmd '[title="toggle-"] scratchpad show'; + +check_floating($empty_ws3, 2); + +#Hiding both +cmd '[title="toggle-"] scratchpad show'; +check_floating($empty_ws3, 0); + +#Showing both again +cmd '[title="toggle-"] scratchpad show'; +check_floating($empty_ws3, 2); + + +#Hiding one +cmd 'scratchpad show'; +check_floating($empty_ws3, 1); + +#Hiding the last +cmd 'scratchpad show'; +check_floating($empty_ws3, 0); + done_testing;