From 3b1747a1070978b7b0586047e96a7a8f293af3a1 Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Mon, 20 May 2024 21:11:07 +0200 Subject: [PATCH 1/2] Add tests for popup_during_fullscreen --- testcases/t/553-popup_during_fullscreen.t | 127 ++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 testcases/t/553-popup_during_fullscreen.t diff --git a/testcases/t/553-popup_during_fullscreen.t b/testcases/t/553-popup_during_fullscreen.t new file mode 100644 index 00000000..79861d22 --- /dev/null +++ b/testcases/t/553-popup_during_fullscreen.t @@ -0,0 +1,127 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • https://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • https://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • https://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • https://i3wm.org/downloads/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Test popup_during_fullscreen option +use i3test i3_autostart => 0; +use i3test::XTEST; + +sub setup { + kill_all_windows; + + my $ws = fresh_workspace; + my $w1 = open_window; + cmd 'fullscreen'; + is_num_fullscreen($ws, 1, 'sanity check: one fullscreen window'); + return ($ws, $w1); +} + +sub open_transient_for { + my $for = shift; + my $w = open_window({ dont_map => 1, rect => [ 30, 30, 50, 50 ] }); + $w->transient_for($for); + $w->map; + sync_with_i3; + return $w; +} + +sub open_without_map_wait { + my $w = open_window({ dont_map => 1 }); + $w->map; + sync_with_i3; + return $w; +} + +################################################################################ +# Test popup_during_fullscreen ignore +################################################################################ + +my $config = <input_focus, $w1->id, 'fullscreen window still focused'); + +open_without_map_wait; +is_num_fullscreen($ws, 1, 'still one fullscren window'); +is($x->input_focus, $w1->id, 'fullscreen window focused'); + +exit_gracefully($pid); + +################################################################################ +# Test popup_during_fullscreen leave_fullscreen +################################################################################ + +$config = <input_focus, $w1->id, 'fullscreen window focused'); + +# Fullscreen stays when regular windows open +$w1->fullscreen(1); +open_without_map_wait; +is_num_fullscreen($ws, 1, 'still one fullscreen window'); +is($x->input_focus, $w1->id, 'fullscreen window focused'); + + +exit_gracefully($pid); + +################################################################################ +# Test popup_during_fullscreen smart +################################################################################ + +$config = <input_focus, $w2->id, 'popup focused'); + +# Fullscreen stays when regular windows open +open_without_map_wait; +is_num_fullscreen($ws, 1, 'still one fullscreen window'); +is($x->input_focus, $w2->id, 'popup still focused'); + + +exit_gracefully($pid); + +done_testing; From 1993b7e318df066c29804e19c94e3f0b93bed9a1 Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Mon, 20 May 2024 21:10:21 +0200 Subject: [PATCH 2/2] Add `popup_during_fullscreen all` option --- docs/userguide | 22 +++++----- include/configuration.h | 3 ++ parser-specs/config.spec | 2 +- .../changes/6-popup_during_fullscreen-all | 1 + src/config_directives.c | 2 + src/manage.c | 22 +++++----- src/render.c | 40 ++++++++++--------- testcases/t/201-config-parser.t | 2 + testcases/t/553-popup_during_fullscreen.t | 27 +++++++++++++ 9 files changed, 82 insertions(+), 39 deletions(-) create mode 100644 release-notes/changes/6-popup_during_fullscreen-all diff --git a/docs/userguide b/docs/userguide index 152bfd4b..94883dd2 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1229,19 +1229,21 @@ mouse_warping none When you are in fullscreen mode, some applications still open popup windows (take Xpdf for example). This is because these applications might not be aware that they are in fullscreen mode (they do not check the corresponding hint). -There are three things which are possible to do in this situation: +i3 supports four options for this situation: -1. Display the popup if it belongs to the fullscreen application only. This is - the default and should be reasonable behavior for most users. -2. Just ignore the popup (don’t map it). This won’t interrupt you while you are - in fullscreen. However, some apps might react badly to this (deadlock until - you go out of fullscreen). -3. Leave fullscreen mode. +1. +smart+: Display the popup if it belongs to the fullscreen application only. + This is the default and should be reasonable behavior for most users. +2. +ignore+: Just ignore the popup (don’t map it). This won’t interrupt you + while you are in fullscreen. However, some apps might react badly to this + (deadlock until you go out of fullscreen). +3. +leave_fullscreen+: Leave fullscreen mode. +4. +all+: Since i3 4.24: Display all floating windows regardless to which + application they belong to. *Syntax*: ------------------------------------------------------ -popup_during_fullscreen smart|ignore|leave_fullscreen ------------------------------------------------------ +--------------------------------------------------------- +popup_during_fullscreen smart|ignore|leave_fullscreen|all +--------------------------------------------------------- *Example*: ------------------------------ diff --git a/include/configuration.h b/include/configuration.h index 3773e2b5..45f4b294 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -262,6 +262,9 @@ struct Config { /* just ignore the popup, that is, don’t map it */ PDF_IGNORE = 2, + + /* display all floating windows */ + PDF_ALL = 3, } popup_during_fullscreen; /* The number of currently parsed barconfigs */ diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 33708b52..8155d119 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -366,7 +366,7 @@ state RESTART_STATE: # popup_during_fullscreen state POPUP_DURING_FULLSCREEN: - value = 'ignore', 'leave_fullscreen', 'smart' + value = 'ignore', 'leave_fullscreen', 'all', 'smart' -> call cfg_popup_during_fullscreen($value) state TILING_DRAG_MODE: diff --git a/release-notes/changes/6-popup_during_fullscreen-all b/release-notes/changes/6-popup_during_fullscreen-all new file mode 100644 index 00000000..3c82685f --- /dev/null +++ b/release-notes/changes/6-popup_during_fullscreen-all @@ -0,0 +1 @@ +Add popup_during_fullscreen all option diff --git a/src/config_directives.c b/src/config_directives.c index da9da964..cc468fb4 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -579,6 +579,8 @@ CFGFUN(popup_during_fullscreen, const char *value) { config.popup_during_fullscreen = PDF_IGNORE; } else if (strcmp(value, "leave_fullscreen") == 0) { config.popup_during_fullscreen = PDF_LEAVE_FULLSCREEN; + } else if (strcmp(value, "all") == 0) { + config.popup_during_fullscreen = PDF_ALL; } else { config.popup_during_fullscreen = PDF_SMART; } diff --git a/src/manage.c b/src/manage.c index d36335aa..bb215636 100644 --- a/src/manage.c +++ b/src/manage.c @@ -502,7 +502,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki if (config.popup_during_fullscreen == PDF_LEAVE_FULLSCREEN && fs != NULL) { DLOG("There is a fullscreen window, leaving fullscreen mode\n"); - con_toggle_fullscreen(fs, CF_OUTPUT); + con_disable_fullscreen(fs); } else if (config.popup_during_fullscreen == PDF_SMART && fs != NULL && fs->window != NULL) { @@ -524,6 +524,10 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki nc->geometry = (Rect){geom->x, geom->y, geom->width, geom->height}; } + if (config.popup_during_fullscreen == PDF_ALL && want_floating && fs != NULL) { + set_focus = true; + } + if (want_floating) { DLOG("geometry = %d x %d\n", nc->geometry.width, nc->geometry.height); if (floating_enable(nc, true)) { @@ -646,15 +650,13 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki xcb_discard_reply(conn, wm_user_time_cookie.sequence); } - if (set_focus) { - /* Even if the client doesn't want focus, we still need to focus the - * container to not break focus workflows. Our handling towards X will - * take care of not setting the input focus. However, one exception to - * this are clients using the globally active input model which we - * don't want to focus at all. */ - if (nc->window->doesnt_accept_focus && !nc->window->needs_take_focus) { - set_focus = false; - } + /* Even if the client doesn't want focus, we still need to focus the + * container to not break focus workflows. Our handling towards X will take + * care of not setting the input focus. However, one exception to this are + * clients using the globally active input model which we don't want to + * focus at all. */ + if (nc->window->doesnt_accept_focus && !nc->window->needs_take_focus) { + set_focus = false; } /* Defer setting focus after the 'new' event has been sent to ensure the diff --git a/src/render.c b/src/render.c index 2ea58f8b..5c4da8f6 100644 --- a/src/render.c +++ b/src/render.c @@ -250,6 +250,26 @@ static int *precalculate_sizes(Con *con, render_params *p) { return sizes; } +static bool fullscreen_blocks_floating_render(Con *fullscreen, Con *floating) { + if (fullscreen == NULL) { + return false; + } + /* Don’t render floating windows when there is a fullscreen window on that + * workspace. Necessary to make floating fullscreen work correctly (ticket + * #564). Exception to the above rule: popup_during_fullscreen smart|all. */ + switch (config.popup_during_fullscreen) { + case PDF_LEAVE_FULLSCREEN: + case PDF_IGNORE: + return true; + case PDF_SMART: + return fullscreen->window == NULL || + !con_find_transient_for_window(con_descend_focused(floating), fullscreen->window->id); + case PDF_ALL: + return con_has_parent(fullscreen, floating); + } + return false; /* not reachable */ +} + static void render_root(Con *con, Con *fullscreen) { Con *output; if (!fullscreen) { @@ -277,24 +297,8 @@ static void render_root(Con *con, Con *fullscreen) { Con *fullscreen = con_get_fullscreen_covering_ws(workspace); Con *child; TAILQ_FOREACH (child, &(workspace->floating_head), floating_windows) { - if (fullscreen != NULL) { - /* Don’t render floating windows when there is a fullscreen - * window on that workspace. Necessary to make floating - * fullscreen work correctly (ticket #564). Exception to the - * above rule: smart popup_during_fullscreen handling (popups - * belonging to the fullscreen app will be rendered). */ - if (config.popup_during_fullscreen != PDF_SMART || fullscreen->window == NULL) { - continue; - } - - Con *floating_child = con_descend_focused(child); - if (con_find_transient_for_window(floating_child, fullscreen->window->id)) { - DLOG("Rendering floating child even though in fullscreen mode: " - "floating->transient_for (0x%08x) --> fullscreen->id (0x%08x)\n", - floating_child->window->transient_for, fullscreen->window->id); - } else { - continue; - } + if (fullscreen_blocks_floating_render(fullscreen, child)) { + continue; } DLOG("floating child at (%d,%d) with %d x %d\n", child->rect.x, child->rect.y, child->rect.width, child->rect.height); diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index c7f79093..a5e5c77b 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -202,12 +202,14 @@ $config = <<'EOT'; popup_during_fullscreen ignore popup_during_fullscreen leave_fullscreen popup_during_fullscreen SMArt +popup_during_fullscreen aLL EOT $expected = <<'EOT'; cfg_popup_during_fullscreen(ignore) cfg_popup_during_fullscreen(leave_fullscreen) cfg_popup_during_fullscreen(smart) +cfg_popup_during_fullscreen(all) EOT is(parser_calls($config), diff --git a/testcases/t/553-popup_during_fullscreen.t b/testcases/t/553-popup_during_fullscreen.t index 79861d22..764beffa 100644 --- a/testcases/t/553-popup_during_fullscreen.t +++ b/testcases/t/553-popup_during_fullscreen.t @@ -122,6 +122,33 @@ is_num_fullscreen($ws, 1, 'still one fullscreen window'); is($x->input_focus, $w2->id, 'popup still focused'); +exit_gracefully($pid); + +################################################################################ +# Test popup_during_fullscreen all +# See #6062 +################################################################################ + +$config = <input_focus, $w2->id, 'popup focused'); + +# Fullscreen stays when regular windows open +$w1->fullscreen(1); +open_without_map_wait; +is_num_fullscreen($ws, 1, 'still one fullscreen window'); + exit_gracefully($pid); done_testing;