From 3046b3467c4121bf262a53f46ba6244426c83b70 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 20 May 2021 17:43:33 +0200 Subject: [PATCH] DisplaySettings: Improve wallpaper preview code Previously, this code would create a bitmap with the size of the screen resolution, draw the new wallpaper into it, and then scale it down for display inside the MonitorWidget. This was done on every paint event, which made the code quite slow and allocation-happy. Instead of this, we now scale down the new wallpaper to a miniature of the same scale as the little MonitorWidget screen. The miniature is then used for tiling, etc. The miniature is cached and reused across paint events if nothing else changes. --- .../DisplaySettings/MonitorWidget.cpp | 74 +++++++++++++------ .../DisplaySettings/MonitorWidget.h | 6 +- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/Userland/Applications/DisplaySettings/MonitorWidget.cpp b/Userland/Applications/DisplaySettings/MonitorWidget.cpp index a916cb5f66..4a7676c932 100644 --- a/Userland/Applications/DisplaySettings/MonitorWidget.cpp +++ b/Userland/Applications/DisplaySettings/MonitorWidget.cpp @@ -19,17 +19,21 @@ MonitorWidget::MonitorWidget() { m_desktop_resolution = GUI::Desktop::the().rect().size(); m_monitor_bitmap = Gfx::Bitmap::load_from_file("/res/graphics/monitor.png"); - m_monitor_rect = { 12, 13, 280, 158 }; + m_desktop_bitmap = Gfx::Bitmap::create(m_monitor_bitmap->format(), { 280, 158 }); + m_monitor_rect = { { 12, 13 }, m_desktop_bitmap->size() }; set_fixed_size(304, 201); } bool MonitorWidget::set_wallpaper(String path) { - auto bitmap_ptr = Gfx::Bitmap::load_from_file(path); - if (!bitmap_ptr && !path.is_empty()) + if (path.is_empty()) + return false; + auto bitmap = Gfx::Bitmap::load_from_file(path); + if (!bitmap) return false; m_desktop_wallpaper_path = move(path); - m_desktop_wallpaper_bitmap = bitmap_ptr; + m_wallpaper_bitmap = move(bitmap); + m_desktop_dirty = true; update(); return true; } @@ -44,6 +48,7 @@ void MonitorWidget::set_wallpaper_mode(String mode) if (m_desktop_wallpaper_mode == mode) return; m_desktop_wallpaper_mode = move(mode); + m_desktop_dirty = true; update(); } @@ -54,7 +59,11 @@ String MonitorWidget::wallpaper_mode() void MonitorWidget::set_desktop_resolution(Gfx::IntSize resolution) { + if (m_desktop_resolution == resolution) + return; m_desktop_resolution = resolution; + m_desktop_dirty = true; + update(); } Gfx::IntSize MonitorWidget::desktop_resolution() @@ -67,6 +76,7 @@ void MonitorWidget::set_background_color(Gfx::Color color) if (m_desktop_color == color) return; m_desktop_color = color; + m_desktop_dirty = true; update(); } @@ -75,33 +85,49 @@ Gfx::Color MonitorWidget::background_color() return m_desktop_color; } +void MonitorWidget::redraw_desktop_if_needed() +{ + if (!m_desktop_dirty) + return; + + m_desktop_dirty = false; + + GUI::Painter painter(*m_desktop_bitmap); + painter.fill_rect(m_desktop_bitmap->rect(), m_desktop_color); + + if (!m_wallpaper_bitmap) + return; + + float sw = (float)m_desktop_bitmap->width() / (float)m_desktop_resolution.width(); + float sh = (float)m_desktop_bitmap->height() / (float)m_desktop_resolution.height(); + + auto scaled_size = m_wallpaper_bitmap->size().to_type().scaled_by(sw, sh).to_type(); + auto scaled_bitmap = m_wallpaper_bitmap->scaled(sw, sh); + + if (m_desktop_wallpaper_mode == "simple") { + painter.blit({}, *scaled_bitmap, scaled_bitmap->rect()); + } else if (m_desktop_wallpaper_mode == "center") { + Gfx::IntRect centered_rect { {}, scaled_size }; + centered_rect.center_within(m_desktop_bitmap->rect()); + painter.blit(centered_rect.location(), *scaled_bitmap, scaled_bitmap->rect()); + } else if (m_desktop_wallpaper_mode == "tile") { + painter.draw_tiled_bitmap(m_desktop_bitmap->rect(), *scaled_bitmap); + } else if (m_desktop_wallpaper_mode == "stretch") { + painter.draw_scaled_bitmap(m_desktop_bitmap->rect(), *m_wallpaper_bitmap, m_wallpaper_bitmap->rect()); + } else { + VERIFY_NOT_REACHED(); + } +} + void MonitorWidget::paint_event(GUI::PaintEvent& event) { - Gfx::IntRect screen_rect = { { 0, 0 }, m_desktop_resolution }; - auto screen_bitmap = Gfx::Bitmap::create(m_monitor_bitmap->format(), m_desktop_resolution); - GUI::Painter screen_painter(*screen_bitmap); - screen_painter.fill_rect(screen_rect, m_desktop_color); - - if (!m_desktop_wallpaper_bitmap.is_null()) { - if (m_desktop_wallpaper_mode == "simple") { - screen_painter.blit({ 0, 0 }, *m_desktop_wallpaper_bitmap, m_desktop_wallpaper_bitmap->rect()); - } else if (m_desktop_wallpaper_mode == "center") { - Gfx::IntPoint offset { (screen_rect.width() - m_desktop_wallpaper_bitmap->width()) / 2, (screen_rect.height() - m_desktop_wallpaper_bitmap->height()) / 2 }; - screen_painter.blit_offset(screen_rect.location(), *m_desktop_wallpaper_bitmap, screen_rect, offset); - } else if (m_desktop_wallpaper_mode == "tile") { - screen_painter.draw_tiled_bitmap(screen_bitmap->rect(), *m_desktop_wallpaper_bitmap); - } else if (m_desktop_wallpaper_mode == "stretch") { - screen_painter.draw_scaled_bitmap(screen_bitmap->rect(), *m_desktop_wallpaper_bitmap, m_desktop_wallpaper_bitmap->rect()); - } else { - VERIFY_NOT_REACHED(); - } - } + redraw_desktop_if_needed(); GUI::Painter painter(*this); painter.add_clip_rect(event.rect()); painter.blit({ 0, 0 }, *m_monitor_bitmap, m_monitor_bitmap->rect()); - painter.draw_scaled_bitmap(m_monitor_rect, *screen_bitmap, screen_bitmap->rect()); + painter.blit(m_monitor_rect.location(), *m_desktop_bitmap, m_desktop_bitmap->rect()); #if 0 if (!m_desktop_resolution.is_null()) { diff --git a/Userland/Applications/DisplaySettings/MonitorWidget.h b/Userland/Applications/DisplaySettings/MonitorWidget.h index 1e9bbb7a8d..272eaa5156 100644 --- a/Userland/Applications/DisplaySettings/MonitorWidget.h +++ b/Userland/Applications/DisplaySettings/MonitorWidget.h @@ -32,13 +32,17 @@ public: private: MonitorWidget(); + void redraw_desktop_if_needed(); + virtual void paint_event(GUI::PaintEvent& event) override; Gfx::IntRect m_monitor_rect; RefPtr m_monitor_bitmap; + RefPtr m_desktop_bitmap; + bool m_desktop_dirty { true }; String m_desktop_wallpaper_path; - RefPtr m_desktop_wallpaper_bitmap; + RefPtr m_wallpaper_bitmap; String m_desktop_wallpaper_mode; Gfx::IntSize m_desktop_resolution; int m_desktop_scale_factor { 1 };