window: Don't check always-on-top overlap before placing

When we show a window, we'll check if it overlaps with an existing
always-on-top window with the intention to deny focus. However, we did
this potentially before having placed the window, meaning we effectively
checked as if it was placed at (0, 0), which created unexpected results.

Instead check the overlap state after placing. A window placement test
case is added to verify this works as expected.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3879>
This commit is contained in:
Jonas Ådahl 2024-07-11 14:57:15 +02:00 committed by Sebastian Wick
parent c68d6c4958
commit 74f58674e7
5 changed files with 123 additions and 6 deletions

View File

@ -353,7 +353,9 @@ find_most_freespace (MetaWindow *window,
} }
static gboolean static gboolean
window_overlaps_focus_window (MetaWindow *window) window_overlaps_focus_window (MetaWindow *window,
int new_x,
int new_y)
{ {
MetaWindow *focus_window; MetaWindow *focus_window;
MtkRectangle window_frame, focus_frame, overlap; MtkRectangle window_frame, focus_frame, overlap;
@ -363,6 +365,9 @@ window_overlaps_focus_window (MetaWindow *window)
return FALSE; return FALSE;
meta_window_get_frame_rect (window, &window_frame); meta_window_get_frame_rect (window, &window_frame);
window_frame.x = new_x;
window_frame.y = new_y;
meta_window_get_frame_rect (focus_window, &focus_frame); meta_window_get_frame_rect (focus_window, &focus_frame);
return mtk_rectangle_intersect (&window_frame, return mtk_rectangle_intersect (&window_frame,
@ -414,7 +419,7 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
#ifdef HAVE_X11_CLIENT #ifdef HAVE_X11_CLIENT
meta_window_x11_same_application (window, focus_window) && meta_window_x11_same_application (window, focus_window) &&
#endif #endif
window_overlaps_focus_window (window)) window_overlaps_focus_window (window, *x, *y))
{ {
find_most_freespace (window, focus_window, *x, *y, x, y); find_most_freespace (window, focus_window, *x, *y, x, y);
meta_topic (META_DEBUG_PLACEMENT, meta_topic (META_DEBUG_PLACEMENT,
@ -987,7 +992,7 @@ meta_window_place (MetaWindow *window,
g_assert (focus_window != NULL); g_assert (focus_window != NULL);
/* No need to do anything if the window doesn't overlap at all */ /* No need to do anything if the window doesn't overlap at all */
found_fit = !window_overlaps_focus_window (window); found_fit = !window_overlaps_focus_window (window, x, y);
/* Try to do a first fit again, this time only taking into account the /* Try to do a first fit again, this time only taking into account the
* focus window. * focus window.

View File

@ -2284,8 +2284,8 @@ meta_window_show (MetaWindow *window)
if (focus_window && if (focus_window &&
window->showing_for_first_time && window->showing_for_first_time &&
!meta_window_is_ancestor_of_transient (focus_window, window) && !meta_window_is_ancestor_of_transient (focus_window, window) &&
((!place_on_top_on_map && !takes_focus_on_map) || !place_on_top_on_map &&
window_would_be_covered_by_always_above_window (window))) !takes_focus_on_map)
{ {
needs_stacking_adjustment = TRUE; needs_stacking_adjustment = TRUE;
if (!window->placed) if (!window->placed)
@ -2316,6 +2316,12 @@ meta_window_show (MetaWindow *window)
meta_window_force_placement (window, place_flags); meta_window_force_placement (window, place_flags);
} }
if (focus_window &&
window->showing_for_first_time &&
!meta_window_is_ancestor_of_transient (focus_window, window) &&
window_would_be_covered_by_always_above_window (window))
needs_stacking_adjustment = TRUE;
if (needs_stacking_adjustment) if (needs_stacking_adjustment)
{ {
gboolean overlap; gboolean overlap;

View File

@ -726,6 +726,7 @@ stacking_tests = [
'workspace-basic', 'workspace-basic',
'workspace-test', 'workspace-test',
'always-on-top', 'always-on-top',
'always-on-top-map-new-maximized',
'focus-default-window-globally-active-input', 'focus-default-window-globally-active-input',
'workspace-unmanaging-window', 'workspace-unmanaging-window',
'click-to-focus-and-raise', 'click-to-focus-and-raise',
@ -739,7 +740,8 @@ stacking_tests = [
'sticky', 'sticky',
'sticky-modals', 'sticky-modals',
'sticky-transients', 'sticky-transients',
'strut-monitor-changes' 'strut-monitor-changes',
'window-placement',
] ]
foreach stacking_test: stacking_tests foreach stacking_test: stacking_tests

View File

@ -0,0 +1,20 @@
resize_monitor default 400 400
new_client w wayland
create w/1 csd
resize w/1 350 350
show w/1
move w/1 25 25
make_above w/1 true
assert_focused w/1
assert_stacking w/1
# Map a maximized window; it should not gain focus due to being mostly covered.
create w/2 csd
maximize w/2
show w/2
assert_focused w/1
assert_stacking w/2 w/1

View File

@ -0,0 +1,84 @@
new_client w wayland
resize_monitor default 250 250
set_pref center-new-windows false
# Show 4 windows in a row and assert that they are placed in a grid and focused
# correctly.
create w/1 csd
resize w/1 100 100
show w/1
assert_focused w/1
assert_position w/1 24 16
assert_size w/1 100 100
create w/2 csd
resize w/2 100 100
show w/2
assert_focused w/2
assert_position w/2 24 116
assert_size w/2 100 100
create w/3 csd
resize w/3 100 100
show w/3
assert_focused w/3
assert_position w/3 124 16
assert_size w/3 100 100
create w/4 csd
resize w/4 100 100
show w/4
assert_focused w/4
assert_position w/4 124 116
assert_size w/4 100 100
destroy w/1
destroy w/2
destroy w/3
destroy w/4
wait
assert_stacking
# Show 1 window, make it 'always-on-top' and make sure the following windows
# still get placed and focused correctly.
create w/1 csd
resize w/1 100 100
show w/1
assert_focused w/1
assert_position w/1 24 16
assert_size w/1 100 100
make_above w/1 true
create w/2 csd
resize w/2 100 100
show w/2
assert_focused w/2
assert_position w/2 24 116
assert_size w/2 100 100
create w/3 csd
resize w/3 100 100
show w/3
assert_focused w/3
assert_position w/3 124 16
assert_size w/3 100 100
create w/4 csd
resize w/4 100 100
show w/4
assert_focused w/4
assert_position w/4 124 116
assert_size w/4 100 100