window: Only deny focus if mostly overlapped with always-on-top window
Having an always-on-top window affects focus granting logic if the to be showing window overlaps with any of them. Instead of triggering the focus denying logic if a new window ever so slightly touches an always-on-top window to only triggering if it's covered more than 60% by always-on-top windows. This is intended to make using always-on-top windows a bit less annoying and not cause as many unintended focus-on-map denials. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3879>
This commit is contained in:
parent
74f58674e7
commit
c7ddc839f1
@ -2034,6 +2034,20 @@ windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
|
|||||||
return mtk_rectangle_overlap (&w1rect, &w2rect);
|
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
|
/* Returns whether a new window would be covered by any
|
||||||
* existing window on the same workspace that is set
|
* existing window on the same workspace that is set
|
||||||
* to be "above" ("always on top"). A window that is not
|
* 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.
|
* (say) ninety per cent and almost indistinguishable from total.
|
||||||
*/
|
*/
|
||||||
static gboolean
|
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);
|
MetaWorkspace *workspace = meta_window_get_workspace (window);
|
||||||
g_autoptr (GList) windows = NULL;
|
g_autoptr (GList) windows = NULL;
|
||||||
GList *l;
|
GList *l;
|
||||||
|
g_autoptr (MtkRegion) region = NULL;
|
||||||
|
int window_area, intersection_area, visible_area;
|
||||||
|
|
||||||
|
region = mtk_region_create ();
|
||||||
windows = meta_workspace_list_windows (workspace);
|
windows = meta_workspace_list_windows (workspace);
|
||||||
for (l = windows; l; l = l->next)
|
for (l = windows; l; l = l->next)
|
||||||
{
|
{
|
||||||
MetaWindow *other_window = l->data;
|
MetaWindow *other_window = l->data;
|
||||||
|
|
||||||
if (other_window->wm_state_above && other_window != window)
|
if (other_window->wm_state_above && other_window != window)
|
||||||
{
|
mtk_region_union_rectangle (region, &other_window->rect);
|
||||||
if (windows_overlap (other_window, window))
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
void
|
||||||
@ -2319,7 +2343,7 @@ 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) &&
|
||||||
window_would_be_covered_by_always_above_window (window))
|
window_would_mostly_be_covered_by_always_above_window (window))
|
||||||
needs_stacking_adjustment = TRUE;
|
needs_stacking_adjustment = TRUE;
|
||||||
|
|
||||||
if (needs_stacking_adjustment)
|
if (needs_stacking_adjustment)
|
||||||
|
@ -727,6 +727,7 @@ stacking_tests = [
|
|||||||
'workspace-test',
|
'workspace-test',
|
||||||
'always-on-top',
|
'always-on-top',
|
||||||
'always-on-top-map-new-maximized',
|
'always-on-top-map-new-maximized',
|
||||||
|
'always-on-top-map-new-partial',
|
||||||
'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',
|
||||||
|
59
src/tests/stacking/always-on-top-map-new-partial.metatest
Normal file
59
src/tests/stacking/always-on-top-map-new-partial.metatest
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user