summaryrefslogtreecommitdiff
path: root/Userland/Services
diff options
context:
space:
mode:
authorChun Ngai Au <chunngaiau@gmail.com>2022-08-06 01:21:06 +0100
committerLinus Groh <mail@linusgroh.de>2022-10-17 01:12:51 +0200
commit5bccb16e617b222b8a05d20ca82adad2b4c88f7e (patch)
tree186dde98b3c8c59841c0c4ec51d4c6ae924c50fa /Userland/Services
parentd0008409a8b41479eb46b5cb3162ade7c971a9d2 (diff)
downloadserenity-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.cpp58
-rw-r--r--Userland/Services/WindowServer/Compositor.h5
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;