From e1077ebbadc9767fbdb320236aba4a3884b59146 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 4 Apr 2023 10:32:37 -0600 Subject: [PATCH] WindowServer: Prevent some overdraw by the window geometry overlay While the window geometry overlay is centered inside the tile overlay neither the text nor the location change, so there is no need to re-render and update it every time the window moves. --- Userland/Services/WindowServer/Overlays.cpp | 58 ++++++++++----------- Userland/Services/WindowServer/Overlays.h | 15 +++++- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Userland/Services/WindowServer/Overlays.cpp b/Userland/Services/WindowServer/Overlays.cpp index 6a2a0869c7..990b1f2468 100644 --- a/Userland/Services/WindowServer/Overlays.cpp +++ b/Userland/Services/WindowServer/Overlays.cpp @@ -228,7 +228,7 @@ Gfx::IntRect ScreenNumberOverlay::calculate_content_rect_for_screen(Screen& scre WindowGeometryOverlay::WindowGeometryOverlay(Window& window) : m_window(window) { - update_rect(); + window_rect_changed(); } void WindowGeometryOverlay::set_actual_rect() @@ -291,35 +291,39 @@ void WindowGeometryOverlay::start_or_stop_move_to_tile_overlay_animation(TileWin } } -void WindowGeometryOverlay::update_rect() +void WindowGeometryOverlay::window_rect_changed() { if (auto* window = m_window.ptr()) { auto& wm = WindowManager::the(); auto* tile_window_overlay = wm.get_tile_window_overlay(*window); auto geometry_rect = tile_window_overlay ? tile_window_overlay->tiled_frame_rect() : window->rect(); - if (!window->size_increment().is_empty()) { - int width_steps = (window->width() - window->base_size().width()) / window->size_increment().width(); - int height_steps = (window->height() - window->base_size().height()) / window->size_increment().height(); - m_label = DeprecatedString::formatted("{} ({}x{})", geometry_rect, width_steps, height_steps); - } else { - m_label = geometry_rect.to_deprecated_string(); + UpdateState new_update_state = { geometry_rect, tile_window_overlay != nullptr }; + if (m_last_updated != new_update_state) { + m_last_updated = new_update_state; + + if (!window->size_increment().is_empty()) { + int width_steps = (window->width() - window->base_size().width()) / window->size_increment().width(); + int height_steps = (window->height() - window->base_size().height()) / window->size_increment().height(); + m_label = DeprecatedString::formatted("{} ({}x{})", geometry_rect, width_steps, height_steps); + } else { + m_label = geometry_rect.to_deprecated_string(); + } + m_label_rect = Gfx::IntRect { 0, 0, static_cast(ceilf(wm.font().width(m_label))) + 16, wm.font().pixel_size_rounded_up() + 10 }; + + auto rect = calculate_frame_rect(m_label_rect).centered_within(window->frame().rect()); + auto desktop_rect = wm.desktop_rect(ScreenInput::the().cursor_location_screen()); + if (rect.left() < desktop_rect.left()) + rect.set_left(desktop_rect.left()); + if (rect.top() < desktop_rect.top()) + rect.set_top(desktop_rect.top()); + if (rect.right() > desktop_rect.right()) + rect.set_right_without_resize(desktop_rect.right()); + if (rect.bottom() > desktop_rect.bottom()) + rect.set_bottom_without_resize(desktop_rect.bottom()); + m_ideal_overlay_rect = rect; + set_actual_rect(); + invalidate_content(); // Needed in case the rectangle itself doesn't change, but the contents did. } - m_label_rect = Gfx::IntRect { 0, 0, static_cast(ceilf(wm.font().width(m_label))) + 16, wm.font().pixel_size_rounded_up() + 10 }; - - auto rect = calculate_frame_rect(m_label_rect).centered_within(window->frame().rect()); - auto desktop_rect = wm.desktop_rect(ScreenInput::the().cursor_location_screen()); - if (rect.left() < desktop_rect.left()) - rect.set_left(desktop_rect.left()); - if (rect.top() < desktop_rect.top()) - rect.set_top(desktop_rect.top()); - if (rect.right() > desktop_rect.right()) - rect.set_right_without_resize(desktop_rect.right()); - if (rect.bottom() > desktop_rect.bottom()) - rect.set_bottom_without_resize(desktop_rect.bottom()); - - m_ideal_overlay_rect = rect; - set_actual_rect(); - invalidate_content(); // needed in case the rectangle itself doesn't change. But the contents did. start_or_stop_move_to_tile_overlay_animation(tile_window_overlay); } else { @@ -332,12 +336,6 @@ void WindowGeometryOverlay::render_overlay_bitmap(Gfx::Painter& painter) painter.draw_text(Gfx::IntRect { {}, rect().size() }, m_label, WindowManager::the().font(), Gfx::TextAlignment::Center, Color::White); } -void WindowGeometryOverlay::window_rect_changed() -{ - update_rect(); - invalidate_content(); -} - DndOverlay::DndOverlay(DeprecatedString const& text, Gfx::Bitmap const* bitmap) : m_bitmap(bitmap) , m_text(text) diff --git a/Userland/Services/WindowServer/Overlays.h b/Userland/Services/WindowServer/Overlays.h index 69a0b1c11f..7aab875359 100644 --- a/Userland/Services/WindowServer/Overlays.h +++ b/Userland/Services/WindowServer/Overlays.h @@ -151,13 +151,24 @@ public: void start_or_stop_move_to_tile_overlay_animation(TileWindowOverlay*); private: - void update_rect(); - WeakPtr m_window; DeprecatedString m_label; Gfx::IntRect m_label_rect; Gfx::IntRect m_ideal_overlay_rect; + struct UpdateState { + Gfx::IntRect geometry; + bool is_for_tile_overlay; + + bool operator==(UpdateState const& other) const + { + if (this == &other) + return true; + return geometry == other.geometry && is_for_tile_overlay == other.is_for_tile_overlay; + } + }; + UpdateState m_last_updated; + struct { RefPtr animation; float progress { 0.0f };