diff options
author | Tom <tomut@yahoo.com> | 2021-06-13 17:39:28 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-20 14:57:26 +0200 |
commit | 229b541e5dc9952fe21114c695ab37f024562664 (patch) | |
tree | 04e320988c52579760b186d71a78abe9e588f7e6 | |
parent | 4392da970ac0fc433530579b13030a41ff4a8f59 (diff) | |
download | serenity-229b541e5dc9952fe21114c695ab37f024562664.zip |
WindowServer: Constrain rendering windows to one screen in some cases
When a window is maximized or tiled then we want to constrain rendering
that window to the screen it's on. This prevents "bleeding" of the
window frame and shadow onto the adjacent screen(s).
-rw-r--r-- | Userland/Services/WindowServer/Window.cpp | 5 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowFrame.cpp | 37 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowFrame.h | 3 |
3 files changed, 34 insertions, 11 deletions
diff --git a/Userland/Services/WindowServer/Window.cpp b/Userland/Services/WindowServer/Window.cpp index 3ec39650ad..657605a803 100644 --- a/Userland/Services/WindowServer/Window.cpp +++ b/Userland/Services/WindowServer/Window.cpp @@ -988,7 +988,10 @@ Optional<HitTestResult> Window::hit_test(Gfx::IntPoint const& position, bool inc { if (!m_hit_testing_enabled) return {}; - if (!frame().rect().contains(position)) + // We need to check the (possibly constrained) render rect to make sure + // we don't hit-test on a window that is constrained to a screen, but somehow + // (partially) moved into another screen where it's not rendered + if (!frame().rect().intersected(frame().render_rect()).contains(position)) return {}; if (!rect().contains(position)) { if (include_frame) diff --git a/Userland/Services/WindowServer/WindowFrame.cpp b/Userland/Services/WindowServer/WindowFrame.cpp index add33622ef..c2cec7ccba 100644 --- a/Userland/Services/WindowServer/WindowFrame.cpp +++ b/Userland/Services/WindowServer/WindowFrame.cpp @@ -319,7 +319,7 @@ void WindowFrame::paint(Screen& screen, Gfx::Painter& painter, const Gfx::IntRec void WindowFrame::RenderedCache::paint(WindowFrame& frame, Gfx::Painter& painter, const Gfx::IntRect& rect) { - auto frame_rect = frame.render_rect(); + auto frame_rect = frame.unconstrained_render_rect(); auto window_rect = frame.window().rect(); if (m_top_bottom) { auto top_bottom_height = frame_rect.height() - window_rect.height(); @@ -546,8 +546,20 @@ Gfx::IntRect WindowFrame::rect() const return frame_rect_for_window(m_window, m_window.rect()); } +Gfx::IntRect WindowFrame::constrained_render_rect_to_screen(const Gfx::IntRect& render_rect) const +{ + if (m_window.is_maximized() || m_window.tiled() != WindowTileType::None) + return render_rect.intersected(Screen::closest_to_rect(rect()).rect()); + return render_rect; +} + Gfx::IntRect WindowFrame::render_rect() const { + return constrained_render_rect_to_screen(inflated_for_shadow(rect())); +} + +Gfx::IntRect WindowFrame::unconstrained_render_rect() const +{ return inflated_for_shadow(rect()); } @@ -555,13 +567,13 @@ Gfx::DisjointRectSet WindowFrame::opaque_render_rects() const { if (has_alpha_channel()) { if (m_window.is_opaque()) - return m_window.rect(); + return constrained_render_rect_to_screen(m_window.rect()); return {}; } if (m_window.is_opaque()) - return rect(); + return constrained_render_rect_to_screen(rect()); Gfx::DisjointRectSet opaque_rects; - opaque_rects.add_many(rect().shatter(m_window.rect())); + opaque_rects.add_many(constrained_render_rect_to_screen(rect()).shatter(m_window.rect())); return opaque_rects; } @@ -576,11 +588,12 @@ Gfx::DisjointRectSet WindowFrame::transparent_render_rects() const return render_rect(); } + auto total_render_rect = render_rect(); Gfx::DisjointRectSet transparent_rects; if (has_shadow()) - transparent_rects.add_many(render_rect().shatter(rect())); + transparent_rects.add_many(total_render_rect.shatter(rect())); if (!m_window.is_opaque()) - transparent_rects.add(m_window.rect()); + transparent_rects.add(m_window.rect().intersected(total_render_rect)); return transparent_rects; } @@ -634,11 +647,15 @@ void WindowFrame::layout_buttons() Optional<HitTestResult> WindowFrame::hit_test(Gfx::IntPoint const& position) { - if (m_window.is_frameless()) + if (m_window.is_frameless() || m_window.is_fullscreen()) return {}; - auto frame_rect = rect(); - if (!frame_rect.contains(position)) + if (!constrained_render_rect_to_screen(rect()).contains(position)) { + // Checking just frame_rect is not enough. If we constrain rendering + // a window to one screen (e.g. when it's maximized or tiled) so that + // the frame doesn't bleed into the adjacent screen(s), then we need + // to also check that we're within these bounds. return {}; + } auto window_rect = m_window.rect(); if (window_rect.contains(position)) return {}; @@ -650,7 +667,7 @@ Optional<HitTestResult> WindowFrame::hit_test(Gfx::IntPoint const& position) if (!cached) return {}; - auto window_relative_position = position.translated(-render_rect().location()); + auto window_relative_position = position.translated(-unconstrained_render_rect().location()); return cached->hit_test(*this, position, window_relative_position); } diff --git a/Userland/Services/WindowServer/WindowFrame.h b/Userland/Services/WindowServer/WindowFrame.h index ee7f3f55a5..b35143378b 100644 --- a/Userland/Services/WindowServer/WindowFrame.h +++ b/Userland/Services/WindowServer/WindowFrame.h @@ -54,6 +54,7 @@ public: Gfx::IntRect rect() const; Gfx::IntRect render_rect() const; + Gfx::IntRect unconstrained_render_rect() const; Gfx::DisjointRectSet opaque_render_rects() const; Gfx::DisjointRectSet transparent_render_rects() const; @@ -131,6 +132,8 @@ private: Gfx::WindowTheme::WindowState window_state_for_theme() const; String computed_title() const; + Gfx::IntRect constrained_render_rect_to_screen(const Gfx::IntRect&) const; + Window& m_window; NonnullOwnPtrVector<Button> m_buttons; Button* m_close_button { nullptr }; |