summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2021-06-13 17:39:28 -0600
committerAndreas Kling <kling@serenityos.org>2021-06-20 14:57:26 +0200
commit229b541e5dc9952fe21114c695ab37f024562664 (patch)
tree04e320988c52579760b186d71a78abe9e588f7e6
parent4392da970ac0fc433530579b13030a41ff4a8f59 (diff)
downloadserenity-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.cpp5
-rw-r--r--Userland/Services/WindowServer/WindowFrame.cpp37
-rw-r--r--Userland/Services/WindowServer/WindowFrame.h3
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 };