mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:17:45 +00:00
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.
This commit is contained in:
parent
d0008409a8
commit
5bccb16e61
3 changed files with 59 additions and 12 deletions
|
@ -550,10 +550,14 @@ ErrorOr<int> run_in_desktop_mode()
|
||||||
} wallpaper_listener;
|
} wallpaper_listener;
|
||||||
|
|
||||||
auto selected_wallpaper = Config::read_string("WindowManager"sv, "Background"sv, "Wallpaper"sv, ""sv);
|
auto selected_wallpaper = Config::read_string("WindowManager"sv, "Background"sv, "Wallpaper"sv, ""sv);
|
||||||
|
RefPtr<Gfx::Bitmap> wallpaper_bitmap {};
|
||||||
if (!selected_wallpaper.is_empty()) {
|
if (!selected_wallpaper.is_empty()) {
|
||||||
auto wallpaper_bitmap = TRY(Gfx::Bitmap::try_load_from_file(selected_wallpaper));
|
wallpaper_bitmap = TRY(Gfx::Bitmap::try_load_from_file(selected_wallpaper));
|
||||||
GUI::Desktop::the().set_wallpaper(wallpaper_bitmap, {});
|
|
||||||
}
|
}
|
||||||
|
// This sets the wallpaper at startup, even if there is no wallpaper, the
|
||||||
|
// desktop should still show the background color. It's fine to pass a
|
||||||
|
// nullptr to Desktop::set_wallpaper.
|
||||||
|
GUI::Desktop::the().set_wallpaper(wallpaper_bitmap, {});
|
||||||
|
|
||||||
window->show();
|
window->show();
|
||||||
return GUI::Application::the()->exec();
|
return GUI::Application::the()->exec();
|
||||||
|
|
|
@ -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_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 = make<Gfx::Painter>(*m_temp_bitmap);
|
||||||
m_temp_painter->translate(-screen.rect().location());
|
m_temp_painter->translate(-screen.rect().location());
|
||||||
|
|
||||||
|
clear_wallpaper_bitmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compositor::init_bitmaps()
|
void Compositor::init_bitmaps()
|
||||||
|
@ -303,25 +305,23 @@ void Compositor::compose()
|
||||||
check_restore_cursor_back(cursor_screen, cursor_rect);
|
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) {
|
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) {
|
||||||
if (m_wallpaper_mode == WallpaperMode::Center) {
|
if (m_wallpaper_mode == WallpaperMode::Center) {
|
||||||
Gfx::IntPoint offset { (screen.width() - m_wallpaper->width()) / 2, (screen.height() - m_wallpaper->height()) / 2 };
|
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);
|
painter.blit_offset(rect.location(), *m_wallpaper, rect.translated(-screen_rect.location()), offset);
|
||||||
} else if (m_wallpaper_mode == WallpaperMode::Tile) {
|
} else if (m_wallpaper_mode == WallpaperMode::Tile) {
|
||||||
painter.draw_tiled_bitmap(rect, *m_wallpaper);
|
painter.draw_tiled_bitmap(rect, *m_wallpaper);
|
||||||
} else if (m_wallpaper_mode == WallpaperMode::Stretch) {
|
} else if (m_wallpaper_mode == WallpaperMode::Stretch) {
|
||||||
float hscale = (float)m_wallpaper->width() / (float)screen.width();
|
VERIFY(screen.compositor_screen_data().m_wallpaper_bitmap);
|
||||||
float vscale = (float)m_wallpaper->height() / (float)screen.height();
|
painter.blit(rect.location(), *screen.compositor_screen_data().m_wallpaper_bitmap, rect);
|
||||||
|
|
||||||
// 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);
|
|
||||||
} else {
|
} else {
|
||||||
VERIFY_NOT_REACHED();
|
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);
|
wm.config()->write_entry("Background", "Color", background_color);
|
||||||
bool succeeded = !wm.config()->sync().is_error();
|
bool succeeded = !wm.config()->sync().is_error();
|
||||||
|
|
||||||
if (succeeded)
|
if (succeeded) {
|
||||||
|
update_wallpaper_bitmap();
|
||||||
Compositor::invalidate_screen();
|
Compositor::invalidate_screen();
|
||||||
|
}
|
||||||
|
|
||||||
return succeeded;
|
return succeeded;
|
||||||
}
|
}
|
||||||
|
@ -805,6 +807,7 @@ bool Compositor::set_wallpaper_mode(String const& mode)
|
||||||
|
|
||||||
if (succeeded) {
|
if (succeeded) {
|
||||||
m_wallpaper_mode = mode_to_enum(mode);
|
m_wallpaper_mode = mode_to_enum(mode);
|
||||||
|
update_wallpaper_bitmap();
|
||||||
Compositor::invalidate_screen();
|
Compositor::invalidate_screen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,11 +820,45 @@ bool Compositor::set_wallpaper(RefPtr<Gfx::Bitmap> bitmap)
|
||||||
m_wallpaper = nullptr;
|
m_wallpaper = nullptr;
|
||||||
else
|
else
|
||||||
m_wallpaper = bitmap;
|
m_wallpaper = bitmap;
|
||||||
|
update_wallpaper_bitmap();
|
||||||
invalidate_screen();
|
invalidate_screen();
|
||||||
|
|
||||||
return true;
|
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)
|
void CompositorScreenData::flip_buffers(Screen& screen)
|
||||||
{
|
{
|
||||||
VERIFY(m_screen_can_set_buffer);
|
VERIFY(m_screen_can_set_buffer);
|
||||||
|
@ -839,6 +876,7 @@ void Compositor::screen_resolution_changed()
|
||||||
init_bitmaps();
|
init_bitmaps();
|
||||||
invalidate_occlusions();
|
invalidate_occlusions();
|
||||||
overlay_rects_changed();
|
overlay_rects_changed();
|
||||||
|
update_wallpaper_bitmap();
|
||||||
compose();
|
compose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,11 @@ struct CompositorScreenData {
|
||||||
RefPtr<Gfx::Bitmap> m_front_bitmap;
|
RefPtr<Gfx::Bitmap> m_front_bitmap;
|
||||||
RefPtr<Gfx::Bitmap> m_back_bitmap;
|
RefPtr<Gfx::Bitmap> m_back_bitmap;
|
||||||
RefPtr<Gfx::Bitmap> m_temp_bitmap;
|
RefPtr<Gfx::Bitmap> m_temp_bitmap;
|
||||||
|
RefPtr<Gfx::Bitmap> m_wallpaper_bitmap;
|
||||||
OwnPtr<Gfx::Painter> m_back_painter;
|
OwnPtr<Gfx::Painter> m_back_painter;
|
||||||
OwnPtr<Gfx::Painter> m_front_painter;
|
OwnPtr<Gfx::Painter> m_front_painter;
|
||||||
OwnPtr<Gfx::Painter> m_temp_painter;
|
OwnPtr<Gfx::Painter> m_temp_painter;
|
||||||
|
OwnPtr<Gfx::Painter> m_wallpaper_painter;
|
||||||
RefPtr<Gfx::Bitmap> m_cursor_back_bitmap;
|
RefPtr<Gfx::Bitmap> m_cursor_back_bitmap;
|
||||||
OwnPtr<Gfx::Painter> m_cursor_back_painter;
|
OwnPtr<Gfx::Painter> m_cursor_back_painter;
|
||||||
Gfx::IntRect m_last_cursor_rect;
|
Gfx::IntRect m_last_cursor_rect;
|
||||||
|
@ -60,6 +62,8 @@ struct CompositorScreenData {
|
||||||
void flip_buffers(Screen&);
|
void flip_buffers(Screen&);
|
||||||
void draw_cursor(Screen&, Gfx::IntRect const&);
|
void draw_cursor(Screen&, Gfx::IntRect const&);
|
||||||
bool restore_cursor_back(Screen&, Gfx::IntRect&);
|
bool restore_cursor_back(Screen&, Gfx::IntRect&);
|
||||||
|
void init_wallpaper_bitmap(Screen&);
|
||||||
|
void clear_wallpaper_bitmap();
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
IterationDecision for_each_intersected_flushing_rect(Gfx::IntRect const& intersecting_rect, F 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 stop_window_stack_switch_overlay_timer();
|
||||||
void start_window_stack_switch_overlay_timer();
|
void start_window_stack_switch_overlay_timer();
|
||||||
void finish_window_stack_switch();
|
void finish_window_stack_switch();
|
||||||
|
void update_wallpaper_bitmap();
|
||||||
|
|
||||||
RefPtr<Core::Timer> m_compose_timer;
|
RefPtr<Core::Timer> m_compose_timer;
|
||||||
RefPtr<Core::Timer> m_immediate_compose_timer;
|
RefPtr<Core::Timer> m_immediate_compose_timer;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue