diff options
author | Chun Ngai Au <chunngaiau@gmail.com> | 2022-08-06 01:21:06 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-10-17 01:12:51 +0200 |
commit | 5bccb16e617b222b8a05d20ca82adad2b4c88f7e (patch) | |
tree | 186dde98b3c8c59841c0c4ec51d4c6ae924c50fa /Userland/Services | |
parent | d0008409a8b41479eb46b5cb3162ade7c971a9d2 (diff) | |
download | serenity-5bccb16e617b222b8a05d20ca82adad2b4c88f7e.zip |
WindowServer: Add wallpaper backing bitmap
Fixes inconsistencies in redrawing the wallpaper when in stretch mode by
first drawing to a backing bitmap. To reduce unnecessary allocations,
the backing bitmap is only used for stretch mode.
Diffstat (limited to 'Userland/Services')
-rw-r--r-- | Userland/Services/WindowServer/Compositor.cpp | 58 | ||||
-rw-r--r-- | Userland/Services/WindowServer/Compositor.h | 5 |
2 files changed, 53 insertions, 10 deletions
diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index 0baa88a656..d44f321d4f 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -121,6 +121,8 @@ void CompositorScreenData::init_bitmaps(Compositor& compositor, Screen& screen) m_temp_bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor()).release_value_but_fixme_should_propagate_errors(); m_temp_painter = make<Gfx::Painter>(*m_temp_bitmap); m_temp_painter->translate(-screen.rect().location()); + + clear_wallpaper_bitmap(); } void Compositor::init_bitmaps() @@ -303,25 +305,23 @@ void Compositor::compose() check_restore_cursor_back(cursor_screen, cursor_rect); auto paint_wallpaper = [&](Screen& screen, Gfx::Painter& painter, Gfx::IntRect const& rect, Gfx::IntRect const& screen_rect) { - // FIXME: If the wallpaper is opaque and covers the whole rect, no need to fill with color! - painter.fill_rect(rect, background_color); if (m_wallpaper) { if (m_wallpaper_mode == WallpaperMode::Center) { Gfx::IntPoint offset { (screen.width() - m_wallpaper->width()) / 2, (screen.height() - m_wallpaper->height()) / 2 }; + + // FIXME: If the wallpaper is opaque and covers the whole rect, no need to fill with color! + painter.fill_rect(rect, background_color); painter.blit_offset(rect.location(), *m_wallpaper, rect.translated(-screen_rect.location()), offset); } else if (m_wallpaper_mode == WallpaperMode::Tile) { painter.draw_tiled_bitmap(rect, *m_wallpaper); } else if (m_wallpaper_mode == WallpaperMode::Stretch) { - float hscale = (float)m_wallpaper->width() / (float)screen.width(); - float vscale = (float)m_wallpaper->height() / (float)screen.height(); - - // TODO: this may look ugly, we should scale to a backing bitmap and then blit - auto relative_rect = rect.translated(-screen_rect.location()); - auto src_rect = Gfx::FloatRect { relative_rect.x() * hscale, relative_rect.y() * vscale, relative_rect.width() * hscale, relative_rect.height() * vscale }; - painter.draw_scaled_bitmap(rect, *m_wallpaper, src_rect); + VERIFY(screen.compositor_screen_data().m_wallpaper_bitmap); + painter.blit(rect.location(), *screen.compositor_screen_data().m_wallpaper_bitmap, rect); } else { VERIFY_NOT_REACHED(); } + } else { + painter.fill_rect(rect, background_color); } }; @@ -791,8 +791,10 @@ bool Compositor::set_background_color(String const& background_color) wm.config()->write_entry("Background", "Color", background_color); bool succeeded = !wm.config()->sync().is_error(); - if (succeeded) + if (succeeded) { + update_wallpaper_bitmap(); Compositor::invalidate_screen(); + } return succeeded; } @@ -805,6 +807,7 @@ bool Compositor::set_wallpaper_mode(String const& mode) if (succeeded) { m_wallpaper_mode = mode_to_enum(mode); + update_wallpaper_bitmap(); Compositor::invalidate_screen(); } @@ -817,11 +820,45 @@ bool Compositor::set_wallpaper(RefPtr<Gfx::Bitmap> bitmap) m_wallpaper = nullptr; else m_wallpaper = bitmap; + update_wallpaper_bitmap(); invalidate_screen(); return true; } +void Compositor::update_wallpaper_bitmap() +{ + Screen::for_each([&](Screen& screen) { + auto& screen_data = screen.compositor_screen_data(); + if (m_wallpaper_mode != WallpaperMode::Stretch || !m_wallpaper) { + screen_data.clear_wallpaper_bitmap(); + return IterationDecision::Continue; + } + if (!screen_data.m_wallpaper_bitmap) + screen_data.init_wallpaper_bitmap(screen); + + auto rect = screen_data.m_wallpaper_bitmap->rect(); + auto& painter = *screen_data.m_wallpaper_painter; + + painter.draw_scaled_bitmap(rect, *m_wallpaper, m_wallpaper->rect()); + + return IterationDecision::Continue; + }); +} + +void CompositorScreenData::init_wallpaper_bitmap(Screen& screen) +{ + m_wallpaper_bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, screen.size(), screen.scale_factor()).release_value_but_fixme_should_propagate_errors(); + m_wallpaper_painter = make<Gfx::Painter>(*m_wallpaper_bitmap); + m_wallpaper_painter->translate(-screen.rect().location()); +} + +void CompositorScreenData::clear_wallpaper_bitmap() +{ + m_wallpaper_painter = nullptr; + m_wallpaper_bitmap = nullptr; +} + void CompositorScreenData::flip_buffers(Screen& screen) { VERIFY(m_screen_can_set_buffer); @@ -839,6 +876,7 @@ void Compositor::screen_resolution_changed() init_bitmaps(); invalidate_occlusions(); overlay_rects_changed(); + update_wallpaper_bitmap(); compose(); } diff --git a/Userland/Services/WindowServer/Compositor.h b/Userland/Services/WindowServer/Compositor.h index e23268910a..32924bb8c0 100644 --- a/Userland/Services/WindowServer/Compositor.h +++ b/Userland/Services/WindowServer/Compositor.h @@ -36,9 +36,11 @@ struct CompositorScreenData { RefPtr<Gfx::Bitmap> m_front_bitmap; RefPtr<Gfx::Bitmap> m_back_bitmap; RefPtr<Gfx::Bitmap> m_temp_bitmap; + RefPtr<Gfx::Bitmap> m_wallpaper_bitmap; OwnPtr<Gfx::Painter> m_back_painter; OwnPtr<Gfx::Painter> m_front_painter; OwnPtr<Gfx::Painter> m_temp_painter; + OwnPtr<Gfx::Painter> m_wallpaper_painter; RefPtr<Gfx::Bitmap> m_cursor_back_bitmap; OwnPtr<Gfx::Painter> m_cursor_back_painter; Gfx::IntRect m_last_cursor_rect; @@ -60,6 +62,8 @@ struct CompositorScreenData { void flip_buffers(Screen&); void draw_cursor(Screen&, Gfx::IntRect const&); bool restore_cursor_back(Screen&, Gfx::IntRect&); + void init_wallpaper_bitmap(Screen&); + void clear_wallpaper_bitmap(); template<typename F> IterationDecision for_each_intersected_flushing_rect(Gfx::IntRect const& intersecting_rect, F f) @@ -211,6 +215,7 @@ private: void stop_window_stack_switch_overlay_timer(); void start_window_stack_switch_overlay_timer(); void finish_window_stack_switch(); + void update_wallpaper_bitmap(); RefPtr<Core::Timer> m_compose_timer; RefPtr<Core::Timer> m_immediate_compose_timer; |