Serenity Operating System
at master 173 lines 5.9 kB view raw
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}