Add popup_during_fullscreen all option (#6068)

Fixes #6062
This commit is contained in:
Orestis Floros 2024-05-21 17:19:11 +02:00 committed by GitHub
commit 822477cb35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 209 additions and 39 deletions

View File

@ -1229,19 +1229,21 @@ mouse_warping none
When you are in fullscreen mode, some applications still open popup windows 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 (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). 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 1. +smart+: Display the popup if it belongs to the fullscreen application only.
the default and should be reasonable behavior for most users. This is the default and should be reasonable behavior for most users.
2. Just ignore the popup (dont map it). This wont interrupt you while you are 2. +ignore+: Just ignore the popup (dont map it). This wont interrupt you
in fullscreen. However, some apps might react badly to this (deadlock until while you are in fullscreen. However, some apps might react badly to this
you go out of fullscreen). (deadlock until you go out of fullscreen).
3. Leave fullscreen mode. 3. +leave_fullscreen+: Leave fullscreen mode.
4. +all+: Since i3 4.24: Display all floating windows regardless to which
application they belong to.
*Syntax*: *Syntax*:
----------------------------------------------------- ---------------------------------------------------------
popup_during_fullscreen smart|ignore|leave_fullscreen popup_during_fullscreen smart|ignore|leave_fullscreen|all
----------------------------------------------------- ---------------------------------------------------------
*Example*: *Example*:
------------------------------ ------------------------------

View File

@ -262,6 +262,9 @@ struct Config {
/* just ignore the popup, that is, dont map it */ /* just ignore the popup, that is, dont map it */
PDF_IGNORE = 2, PDF_IGNORE = 2,
/* display all floating windows */
PDF_ALL = 3,
} popup_during_fullscreen; } popup_during_fullscreen;
/* The number of currently parsed barconfigs */ /* The number of currently parsed barconfigs */

View File

@ -366,7 +366,7 @@ state RESTART_STATE:
# popup_during_fullscreen # popup_during_fullscreen
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) -> call cfg_popup_during_fullscreen($value)
state TILING_DRAG_MODE: state TILING_DRAG_MODE:

View File

@ -0,0 +1 @@
Add popup_during_fullscreen all option

View File

@ -579,6 +579,8 @@ CFGFUN(popup_during_fullscreen, const char *value) {
config.popup_during_fullscreen = PDF_IGNORE; config.popup_during_fullscreen = PDF_IGNORE;
} else if (strcmp(value, "leave_fullscreen") == 0) { } else if (strcmp(value, "leave_fullscreen") == 0) {
config.popup_during_fullscreen = PDF_LEAVE_FULLSCREEN; config.popup_during_fullscreen = PDF_LEAVE_FULLSCREEN;
} else if (strcmp(value, "all") == 0) {
config.popup_during_fullscreen = PDF_ALL;
} else { } else {
config.popup_during_fullscreen = PDF_SMART; config.popup_during_fullscreen = PDF_SMART;
} }

View File

@ -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 && if (config.popup_during_fullscreen == PDF_LEAVE_FULLSCREEN &&
fs != NULL) { fs != NULL) {
DLOG("There is a fullscreen window, leaving fullscreen mode\n"); 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 && } else if (config.popup_during_fullscreen == PDF_SMART &&
fs != NULL && fs != NULL &&
fs->window != 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}; 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) { if (want_floating) {
DLOG("geometry = %d x %d\n", nc->geometry.width, nc->geometry.height); DLOG("geometry = %d x %d\n", nc->geometry.width, nc->geometry.height);
if (floating_enable(nc, true)) { 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); 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
/* 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
* container to not break focus workflows. Our handling towards X will * care of not setting the input focus. However, one exception to this are
* take care of not setting the input focus. However, one exception to * clients using the globally active input model which we don't want to
* this are clients using the globally active input model which we * focus at all. */
* don't want to focus at all. */ if (nc->window->doesnt_accept_focus && !nc->window->needs_take_focus) {
if (nc->window->doesnt_accept_focus && !nc->window->needs_take_focus) { set_focus = false;
set_focus = false;
}
} }
/* Defer setting focus after the 'new' event has been sent to ensure the /* Defer setting focus after the 'new' event has been sent to ensure the

View File

@ -250,6 +250,26 @@ static int *precalculate_sizes(Con *con, render_params *p) {
return sizes; return sizes;
} }
static bool fullscreen_blocks_floating_render(Con *fullscreen, Con *floating) {
if (fullscreen == NULL) {
return false;
}
/* Dont 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) { static void render_root(Con *con, Con *fullscreen) {
Con *output; Con *output;
if (!fullscreen) { if (!fullscreen) {
@ -277,24 +297,8 @@ static void render_root(Con *con, Con *fullscreen) {
Con *fullscreen = con_get_fullscreen_covering_ws(workspace); Con *fullscreen = con_get_fullscreen_covering_ws(workspace);
Con *child; Con *child;
TAILQ_FOREACH (child, &(workspace->floating_head), floating_windows) { TAILQ_FOREACH (child, &(workspace->floating_head), floating_windows) {
if (fullscreen != NULL) { if (fullscreen_blocks_floating_render(fullscreen, child)) {
/* Dont render floating windows when there is a fullscreen continue;
* 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;
}
} }
DLOG("floating child at (%d,%d) with %d x %d\n", DLOG("floating child at (%d,%d) with %d x %d\n",
child->rect.x, child->rect.y, child->rect.width, child->rect.height); child->rect.x, child->rect.y, child->rect.width, child->rect.height);

View File

@ -202,12 +202,14 @@ $config = <<'EOT';
popup_during_fullscreen ignore popup_during_fullscreen ignore
popup_during_fullscreen leave_fullscreen popup_during_fullscreen leave_fullscreen
popup_during_fullscreen SMArt popup_during_fullscreen SMArt
popup_during_fullscreen aLL
EOT EOT
$expected = <<'EOT'; $expected = <<'EOT';
cfg_popup_during_fullscreen(ignore) cfg_popup_during_fullscreen(ignore)
cfg_popup_during_fullscreen(leave_fullscreen) cfg_popup_during_fullscreen(leave_fullscreen)
cfg_popup_during_fullscreen(smart) cfg_popup_during_fullscreen(smart)
cfg_popup_during_fullscreen(all)
EOT EOT
is(parser_calls($config), is(parser_calls($config),

View File

@ -0,0 +1,154 @@
#!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 = <<EOT;
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
popup_during_fullscreen ignore
EOT
my $pid = launch_with_config($config);
my ($ws, $w1) = setup;
my $w2 = open_transient_for($w1);
is_num_fullscreen($ws, 1, 'still one fullscren window');
is($x->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 = <<EOT;
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
popup_during_fullscreen leave_fullscreen
EOT
$pid = launch_with_config($config);
($ws, $w1) = setup;
# Fullscreen disabled when transient windows open
$w2 = open_transient_for($w1);
is_num_fullscreen($ws, 0, 'no fullscren window');
# XXX: Arguably a bug but leave_fullscreen does not change focus
is($x->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 = <<EOT;
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
popup_during_fullscreen smart
EOT
$pid = launch_with_config($config);
($ws, $w1) = setup;
# Fullscreen stays when transient windows open
$w2 = open_transient_for($w1);
is_num_fullscreen($ws, 1, 'still one fullscreen window');
is($x->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);
################################################################################
# Test popup_during_fullscreen all
# See #6062
################################################################################
$config = <<EOT;
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
popup_during_fullscreen all
EOT
$pid = launch_with_config($config);
($ws, $w1) = setup;
# Fullscreen stays when transient windows open
$w2 = open_transient_for($w1);
is_num_fullscreen($ws, 1, 'still one fullscreen window');
is($x->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;