Serenity Operating System
1/*
2 * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
3 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include "MonitorWidget.h"
9#include <LibGUI/Desktop.h>
10#include <LibGUI/Painter.h>
11#include <LibGfx/Bitmap.h>
12#include <LibGfx/Font/Font.h>
13#include <LibThreading/BackgroundAction.h>
14
15REGISTER_WIDGET(DisplaySettings, MonitorWidget)
16
17namespace DisplaySettings {
18
19MonitorWidget::MonitorWidget()
20{
21 m_desktop_resolution = GUI::Desktop::the().rect().size();
22 m_monitor_bitmap = Gfx::Bitmap::load_from_file("/res/graphics/monitor.png"sv).release_value_but_fixme_should_propagate_errors();
23 m_desktop_bitmap = Gfx::Bitmap::create(m_monitor_bitmap->format(), { 280, 158 }).release_value_but_fixme_should_propagate_errors();
24 m_monitor_rect = { { 12, 13 }, m_desktop_bitmap->size() };
25 set_fixed_size(304, 201);
26}
27
28bool MonitorWidget::set_wallpaper(DeprecatedString path)
29{
30 if (!is_different_to_current_wallpaper_path(path))
31 return false;
32
33 (void)Threading::BackgroundAction<NonnullRefPtr<Gfx::Bitmap>>::construct(
34 [path](auto&) -> ErrorOr<NonnullRefPtr<Gfx::Bitmap>> {
35 if (path.is_empty())
36 return Error::from_errno(ENOENT);
37 return Gfx::Bitmap::load_from_file(path);
38 },
39
40 [this, path](NonnullRefPtr<Gfx::Bitmap> bitmap) -> ErrorOr<void> {
41 // If we've been requested to change while we were loading the bitmap, don't bother spending the cost to
42 // move and render the now stale bitmap.
43 if (is_different_to_current_wallpaper_path(path))
44 return {};
45 m_wallpaper_bitmap = move(bitmap);
46 m_desktop_dirty = true;
47 update();
48 return {};
49 },
50 [this, path](Error) -> void {
51 m_wallpaper_bitmap = nullptr;
52 });
53
54 if (path.is_empty())
55 m_desktop_wallpaper_path = nullptr;
56 else
57 m_desktop_wallpaper_path = move(path);
58
59 return true;
60}
61
62StringView MonitorWidget::wallpaper() const
63{
64 return m_desktop_wallpaper_path;
65}
66
67void MonitorWidget::set_wallpaper_mode(DeprecatedString mode)
68{
69 if (m_desktop_wallpaper_mode == mode)
70 return;
71 m_desktop_wallpaper_mode = move(mode);
72 m_desktop_dirty = true;
73 update();
74}
75
76StringView MonitorWidget::wallpaper_mode() const
77{
78 return m_desktop_wallpaper_mode;
79}
80
81void MonitorWidget::set_desktop_resolution(Gfx::IntSize resolution)
82{
83 if (m_desktop_resolution == resolution)
84 return;
85 m_desktop_resolution = resolution;
86 m_desktop_dirty = true;
87 update();
88}
89
90Gfx::IntSize MonitorWidget::desktop_resolution()
91{
92 return m_desktop_resolution;
93}
94
95void MonitorWidget::set_background_color(Gfx::Color color)
96{
97 if (m_desktop_color == color)
98 return;
99 m_desktop_color = color;
100 m_desktop_dirty = true;
101 update();
102}
103
104Gfx::Color MonitorWidget::background_color()
105{
106 return m_desktop_color;
107}
108
109void MonitorWidget::redraw_desktop_if_needed()
110{
111 if (!m_desktop_dirty)
112 return;
113
114 m_desktop_dirty = false;
115
116 GUI::Painter painter(*m_desktop_bitmap);
117 painter.fill_rect(m_desktop_bitmap->rect(), m_desktop_color);
118
119 if (!m_wallpaper_bitmap)
120 return;
121
122 float sw = (float)m_desktop_bitmap->width() / (float)m_desktop_resolution.width();
123 float sh = (float)m_desktop_bitmap->height() / (float)m_desktop_resolution.height();
124
125 auto scaled_size = m_wallpaper_bitmap->size().to_type<float>().scaled_by(sw, sh).to_type<int>();
126 auto scaled_bitmap = m_wallpaper_bitmap->scaled(sw, sh).release_value_but_fixme_should_propagate_errors();
127
128 if (m_desktop_wallpaper_mode == "Center") {
129 auto centered_rect = Gfx::IntRect({}, scaled_size).centered_within(m_desktop_bitmap->rect());
130 painter.blit(centered_rect.location(), *scaled_bitmap, scaled_bitmap->rect());
131 } else if (m_desktop_wallpaper_mode == "Tile") {
132 painter.draw_tiled_bitmap(m_desktop_bitmap->rect(), *scaled_bitmap);
133 } else if (m_desktop_wallpaper_mode == "Stretch") {
134 painter.draw_scaled_bitmap(m_desktop_bitmap->rect(), *m_wallpaper_bitmap, m_wallpaper_bitmap->rect());
135 } else {
136 VERIFY_NOT_REACHED();
137 }
138}
139
140void MonitorWidget::paint_event(GUI::PaintEvent& event)
141{
142 redraw_desktop_if_needed();
143
144 GUI::Painter painter(*this);
145 painter.add_clip_rect(event.rect());
146
147 painter.blit({ 0, 0 }, *m_monitor_bitmap, m_monitor_bitmap->rect());
148 painter.blit(m_monitor_rect.location(), *m_desktop_bitmap, m_desktop_bitmap->rect());
149
150#if 0
151 if (!m_desktop_resolution.is_null()) {
152 auto displayed_resolution_string = Gfx::IntSize { m_desktop_resolution.width(), m_desktop_resolution.height() }.to_deprecated_string();
153
154 // Render text label scaled with scale factor to hint at its effect.
155 // FIXME: Once bitmaps have intrinsic scale factors, we could create a bitmap with an intrinsic scale factor of m_desktop_scale_factor
156 // and that should give us the same effect with less code.
157 auto text_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::IntSize { painter.font().width(displayed_resolution_string) + 1, painter.font().pixel_size_rounded_up() + 1 });
158 GUI::Painter text_painter(*text_bitmap);
159 text_painter.set_font(painter.font());
160
161 text_painter.draw_text({}, displayed_resolution_string, Gfx::TextAlignment::BottomRight, Color::Black);
162 text_painter.draw_text({}, displayed_resolution_string, Gfx::TextAlignment::TopLeft, Color::White);
163
164 Gfx::IntRect text_rect = text_bitmap->rect();
165 text_rect.set_width(text_rect.width() * m_desktop_scale_factor);
166 text_rect.set_height(text_rect.height() * m_desktop_scale_factor);
167 text_rect.center_within(m_monitor_rect);
168 painter.draw_scaled_bitmap(text_rect, *text_bitmap, text_bitmap->rect());
169 }
170#endif
171}
172
173}