mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:17:34 +00:00
WindowServer: Improve occlusion calculations
This solves two problems: * A window was sometimes deemed occluded when the window rect was entirely covered by other rectangles, transparent or opaque. This caused a window to stop rendering even if a small portion was still visible, e.g. when it was merely covered by a window shadow. * The window switcher is interested in window updates even when a window is entirely covered by another one, or when it is on another desktop. This forces windows to be not occluded in those cases.
This commit is contained in:
parent
c06e765a5a
commit
6ec35c91bc
2 changed files with 26 additions and 47 deletions
|
@ -921,35 +921,6 @@ void Compositor::decrement_show_screen_number(Badge<ClientConnection>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compositor::any_opaque_window_above_this_one_contains_rect(Window& a_window, const Gfx::IntRect& rect)
|
|
||||||
{
|
|
||||||
auto* window_stack = a_window.outer_stack();
|
|
||||||
if (!window_stack)
|
|
||||||
return false;
|
|
||||||
bool found_containing_window = false;
|
|
||||||
bool checking = false;
|
|
||||||
WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& window) {
|
|
||||||
if (&window == &a_window) {
|
|
||||||
checking = true;
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
}
|
|
||||||
if (!checking)
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
if (!window.is_visible())
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
if (window.is_minimized())
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
if (!window.is_opaque())
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
if (window.frame().render_rect().contains(rect)) {
|
|
||||||
found_containing_window = true;
|
|
||||||
return IterationDecision::Break;
|
|
||||||
}
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
});
|
|
||||||
return found_containing_window;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Compositor::overlays_theme_changed()
|
void Compositor::overlays_theme_changed()
|
||||||
{
|
{
|
||||||
for (auto& overlay : m_overlay_list)
|
for (auto& overlay : m_overlay_list)
|
||||||
|
@ -1000,31 +971,30 @@ void Compositor::recompute_occlusions()
|
||||||
{
|
{
|
||||||
auto& wm = WindowManager::the();
|
auto& wm = WindowManager::the();
|
||||||
bool is_switcher_visible = wm.m_switcher.is_visible();
|
bool is_switcher_visible = wm.m_switcher.is_visible();
|
||||||
wm.for_each_window_stack([&](WindowStack& window_stack) {
|
auto never_occlude = [&](WindowStack& window_stack) {
|
||||||
if (is_switcher_visible) {
|
if (is_switcher_visible) {
|
||||||
switch (wm.m_switcher.mode()) {
|
switch (wm.m_switcher.mode()) {
|
||||||
case WindowSwitcher::Mode::ShowCurrentDesktop:
|
case WindowSwitcher::Mode::ShowCurrentDesktop:
|
||||||
window_stack.set_all_occluded(!(&window_stack == m_current_window_stack || &window_stack == m_transitioning_to_window_stack));
|
// Any window on the currently rendered desktop should not be occluded, even if it's behind
|
||||||
break;
|
// another window entirely.
|
||||||
|
return &window_stack == m_current_window_stack || &window_stack == m_transitioning_to_window_stack;
|
||||||
case WindowSwitcher::Mode::ShowAllWindows:
|
case WindowSwitcher::Mode::ShowAllWindows:
|
||||||
window_stack.set_all_occluded(false);
|
// The window switcher wants to know about all windows, even those on other desktops
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
window_stack.set_all_occluded(!(&window_stack == m_current_window_stack || &window_stack == m_transitioning_to_window_stack));
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
wm.for_each_window_stack([&](WindowStack& window_stack) {
|
||||||
|
if (&window_stack == m_current_window_stack || &window_stack == m_transitioning_to_window_stack) {
|
||||||
|
// We'll calculate precise occlusions for these further down. Changing occlusions right now
|
||||||
|
// may trigger an additional unnecessary notification
|
||||||
|
} else {
|
||||||
|
window_stack.set_all_occluded(!never_occlude(window_stack));
|
||||||
|
}
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
if (!is_switcher_visible) {
|
|
||||||
wm.for_each_visible_window_from_back_to_front([&](Window& window) {
|
|
||||||
if (any_opaque_window_above_this_one_contains_rect(window, window.frame().rect()))
|
|
||||||
window.set_occluded(true);
|
|
||||||
else
|
|
||||||
window.set_occluded(false);
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_overlay_rects_changed) {
|
if (m_overlay_rects_changed) {
|
||||||
m_overlay_rects_changed = false;
|
m_overlay_rects_changed = false;
|
||||||
|
@ -1109,6 +1079,7 @@ void Compositor::recompute_occlusions()
|
||||||
|
|
||||||
auto render_rect = w.frame().render_rect();
|
auto render_rect = w.frame().render_rect();
|
||||||
auto render_rect_on_screen = render_rect;
|
auto render_rect_on_screen = render_rect;
|
||||||
|
auto visible_window_rects = visible_rects.intersected(w.rect().translated(transition_offset));
|
||||||
if (window_stack_transition_in_progress)
|
if (window_stack_transition_in_progress)
|
||||||
render_rect_on_screen.translate_by(transition_offset);
|
render_rect_on_screen.translate_by(transition_offset);
|
||||||
Gfx::DisjointRectSet opaque_covering;
|
Gfx::DisjointRectSet opaque_covering;
|
||||||
|
@ -1144,8 +1115,11 @@ void Compositor::recompute_occlusions()
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
for (auto& covering : opaque_rects.rects()) {
|
for (auto& covering : opaque_rects.rects()) {
|
||||||
opaque_covering.add(covering);
|
opaque_covering.add(covering);
|
||||||
|
if (!visible_window_rects.is_empty())
|
||||||
|
visible_window_rects = visible_window_rects.shatter(covering);
|
||||||
if (opaque_covering.contains(render_rect_on_screen)) {
|
if (opaque_covering.contains(render_rect_on_screen)) {
|
||||||
// This window (including frame) is entirely covered by another opaque window
|
// This entire window (including frame) is entirely covered by other opaque window areas
|
||||||
|
visible_window_rects.clear();
|
||||||
visible_opaque.clear();
|
visible_opaque.clear();
|
||||||
transparency_rects.clear();
|
transparency_rects.clear();
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
|
@ -1160,6 +1134,7 @@ void Compositor::recompute_occlusions()
|
||||||
transparency_rects = move(uncovered_transparency);
|
transparency_rects = move(uncovered_transparency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& covering : transparent_rects.rects()) {
|
for (auto& covering : transparent_rects.rects()) {
|
||||||
visible_rects.for_each_intersected(covering, [&](const Gfx::IntRect& intersected) {
|
visible_rects.for_each_intersected(covering, [&](const Gfx::IntRect& intersected) {
|
||||||
transparency_rects.add(intersected);
|
transparency_rects.add(intersected);
|
||||||
|
@ -1174,6 +1149,11 @@ void Compositor::recompute_occlusions()
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This window should not be occluded while the window switcher is interested in it (depending
|
||||||
|
// on the mode it's in). If it isn't then determine occlusions based on whether the window
|
||||||
|
// rect has any visible areas at all.
|
||||||
|
w.set_occluded(never_occlude(*w.outer_stack()) ? false : visible_window_rects.is_empty());
|
||||||
|
|
||||||
if (!m_overlay_rects.is_empty() && m_overlay_rects.intersects(visible_opaque)) {
|
if (!m_overlay_rects.is_empty() && m_overlay_rects.intersects(visible_opaque)) {
|
||||||
// In order to render overlays flicker-free we need to force these area into the
|
// In order to render overlays flicker-free we need to force these area into the
|
||||||
// temporary transparency rendering buffer
|
// temporary transparency rendering buffer
|
||||||
|
|
|
@ -138,7 +138,6 @@ private:
|
||||||
void start_compose_async_timer();
|
void start_compose_async_timer();
|
||||||
void recompute_overlay_rects();
|
void recompute_overlay_rects();
|
||||||
void recompute_occlusions();
|
void recompute_occlusions();
|
||||||
bool any_opaque_window_above_this_one_contains_rect(Window&, const Gfx::IntRect&);
|
|
||||||
void change_cursor(const Cursor*);
|
void change_cursor(const Cursor*);
|
||||||
void flush(Screen&);
|
void flush(Screen&);
|
||||||
Gfx::IntPoint window_transition_offset(Window&);
|
Gfx::IntPoint window_transition_offset(Window&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue