diff --git a/src/core/window.c b/src/core/window.c index d6e8406be..eefd8813c 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -2034,6 +2034,20 @@ windows_overlap (const MetaWindow *w1, const MetaWindow *w2) return mtk_rectangle_overlap (&w1rect, &w2rect); } +static int +calculate_region_area (MtkRegion *region) +{ + MtkRegionIterator iter; + int area = 0; + + for (mtk_region_iterator_init (&iter, region); + !mtk_region_iterator_at_end (&iter); + mtk_region_iterator_next (&iter)) + area += iter.rectangle.width * iter.rectangle.height; + + return area; +} + /* Returns whether a new window would be covered by any * existing window on the same workspace that is set * to be "above" ("always on top"). A window that is not @@ -2046,25 +2060,35 @@ windows_overlap (const MetaWindow *w1, const MetaWindow *w2) * (say) ninety per cent and almost indistinguishable from total. */ static gboolean -window_would_be_covered_by_always_above_window (MetaWindow *window) +window_would_mostly_be_covered_by_always_above_window (MetaWindow *window) { MetaWorkspace *workspace = meta_window_get_workspace (window); g_autoptr (GList) windows = NULL; GList *l; + g_autoptr (MtkRegion) region = NULL; + int window_area, intersection_area, visible_area; + region = mtk_region_create (); windows = meta_workspace_list_windows (workspace); for (l = windows; l; l = l->next) { MetaWindow *other_window = l->data; if (other_window->wm_state_above && other_window != window) - { - if (windows_overlap (other_window, window)) - return TRUE; - } + mtk_region_union_rectangle (region, &other_window->rect); } - return FALSE; + window_area = window->rect.width * window->rect.height; + + mtk_region_intersect_rectangle (region, &window->rect); + intersection_area = calculate_region_area (region); + visible_area = window_area - intersection_area; + +#define REQUIRED_VISIBLE_AREA_PERCENT 40 + if ((100 * visible_area) / window_area > REQUIRED_VISIBLE_AREA_PERCENT) + return FALSE; + else + return TRUE; } void @@ -2319,7 +2343,7 @@ meta_window_show (MetaWindow *window) 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)) + window_would_mostly_be_covered_by_always_above_window (window)) needs_stacking_adjustment = TRUE; if (needs_stacking_adjustment) diff --git a/src/tests/meson.build b/src/tests/meson.build index 6b5048490..d57514778 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -727,6 +727,7 @@ stacking_tests = [ 'workspace-test', 'always-on-top', 'always-on-top-map-new-maximized', + 'always-on-top-map-new-partial', 'focus-default-window-globally-active-input', 'workspace-unmanaging-window', 'click-to-focus-and-raise', diff --git a/src/tests/stacking/always-on-top-map-new-partial.metatest b/src/tests/stacking/always-on-top-map-new-partial.metatest new file mode 100644 index 000000000..44e64252e --- /dev/null +++ b/src/tests/stacking/always-on-top-map-new-partial.metatest @@ -0,0 +1,59 @@ +resize_monitor default 400 400 +set_pref center-new-windows true + +new_client w wayland +create w/1 csd +resize w/1 100 100 +show w/1 + +assert_focused w/1 +assert_stacking w/1 + +create w/2 csd +resize w/2 100 100 +show w/2 + +assert_focused w/2 +assert_stacking w/1 w/2 + +create w/3 csd +resize w/3 100 100 +show w/3 + +assert_focused w/3 +assert_stacking w/1 w/2 w/3 + +# Mark two windows as always-above + +make_above w/1 true +move w/1 201 150 +assert_stacking w/2 w/3 w/1 + +make_above w/3 true +move w/3 0 0 +assert_stacking w/2 w/1 w/3 + +# Map another window while the other non-aways-on-top window has focus. +# It will be mostly visible, so will take focus. + +local_activate w/2 +assert_focused w/2 + +create w/4 csd +resize w/4 100 100 +show w/4 + +assert_focused w/4 +assert_stacking w/2 w/4 w/1 w/3 + +# Move one of the always-on-top window so that the next mapped one will be +# mostly non-visible, thus not take focus. + +move w/1 180 150 + +create w/5 csd +resize w/5 100 100 +show w/5 + +assert_focused w/4 +assert_stacking w/2 w/5 w/4 w/1 w/3