diff --git a/Userland/Applications/DisplaySettings/DisplaySettings.cpp b/Userland/Applications/DisplaySettings/DisplaySettings.cpp index 7c3bdeed5b..de8c00cc6f 100644 --- a/Userland/Applications/DisplaySettings/DisplaySettings.cpp +++ b/Userland/Applications/DisplaySettings/DisplaySettings.cpp @@ -246,7 +246,8 @@ void DisplaySettingsWidget::load_current_settings() void DisplaySettingsWidget::send_settings_to_window_server() { - auto result = GUI::WindowServerConnection::the().send_sync(m_monitor_widget->desktop_resolution()); + // FIXME: Add UI for changing the scale factor. + auto result = GUI::WindowServerConnection::the().send_sync(m_monitor_widget->desktop_resolution(), 1); if (!result->success()) { GUI::MessageBox::show(nullptr, String::formatted("Reverting to resolution {}x{}", result->resolution().width(), result->resolution().height()), "Unable to set resolution", GUI::MessageBox::Type::Error); diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index 33ce6e9bcb..a561a1290c 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -340,7 +340,7 @@ OwnPtr ClientConnection::handle(co OwnPtr ClientConnection::handle(const Messages::WindowServer::SetResolution& message) { - return make(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height()), WindowManager::the().resolution()); + return make(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height(), message.scale_factor()), WindowManager::the().resolution(), WindowManager::the().scale_factor()); } OwnPtr ClientConnection::handle(const Messages::WindowServer::SetWindowTitle& message) diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index 4bea8d81a8..f564c4070b 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -710,19 +710,19 @@ void Compositor::run_animations(Gfx::DisjointRectSet& flush_rects) }); } -bool Compositor::set_resolution(int desired_width, int desired_height) +bool Compositor::set_resolution(int desired_width, int desired_height, int scale_factor) { auto screen_rect = Screen::the().rect(); - if (screen_rect.width() == desired_width && screen_rect.height() == desired_height) + if (screen_rect.width() == desired_width && screen_rect.height() == desired_height && Screen::the().scale_factor() == scale_factor) return true; // Make sure it's impossible to set an invalid resolution - if (!(desired_width >= 640 && desired_height >= 480)) { - dbg() << "Compositor: Tried to set invalid resolution: " << desired_width << "x" << desired_height; + if (!(desired_width >= 640 && desired_height >= 480 && scale_factor >= 1)) { + dbg() << "Compositor: Tried to set invalid resolution: " << desired_width << "x" << desired_height << " @ " << scale_factor << "x"; return false; } - bool success = Screen::the().set_resolution(desired_width, desired_height, 1); + bool success = Screen::the().set_resolution(desired_width, desired_height, scale_factor); init_bitmaps(); invalidate_occlusions(); compose(); diff --git a/Userland/Services/WindowServer/Compositor.h b/Userland/Services/WindowServer/Compositor.h index 1e6a3e2014..b15ea4b666 100644 --- a/Userland/Services/WindowServer/Compositor.h +++ b/Userland/Services/WindowServer/Compositor.h @@ -57,7 +57,7 @@ public: void invalidate_screen(); void invalidate_screen(const Gfx::IntRect&); - bool set_resolution(int desired_width, int desired_height); + bool set_resolution(int desired_width, int desired_height, int scale_factor); bool set_background_color(const String& background_color); diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index 1100fb2dd7..2c5d47108c 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -69,43 +69,53 @@ Screen::~Screen() close(m_framebuffer_fd); } -bool Screen::set_resolution(int width, int height, int scale_factor) +bool Screen::set_resolution(int width, int height, int new_scale_factor) { - FBResolution physical_resolution { 0, (unsigned)(width * scale_factor), (unsigned)(height * scale_factor) }; + int new_physical_width = width * new_scale_factor; + int new_physical_height = height * new_scale_factor; + if (physical_width() == new_physical_width && physical_height() == new_physical_height) { + assert(scale_factor() != new_scale_factor); + on_change_resolution(m_pitch, physical_width(), physical_height(), new_scale_factor); + return true; + } + + FBResolution physical_resolution { 0, (unsigned)new_physical_width, (unsigned)new_physical_height }; int rc = fb_set_resolution(m_framebuffer_fd, &physical_resolution); #ifdef WSSCREEN_DEBUG dbg() << "fb_set_resolution() - return code " << rc; #endif if (rc == 0) { - on_change_resolution(physical_resolution.pitch, physical_resolution.width, physical_resolution.height, scale_factor); + on_change_resolution(physical_resolution.pitch, physical_resolution.width, physical_resolution.height, new_scale_factor); return true; } if (rc == -1) { dbg() << "Invalid resolution " << width << "x" << height; - on_change_resolution(physical_resolution.pitch, physical_resolution.width, physical_resolution.height, scale_factor); + on_change_resolution(physical_resolution.pitch, physical_resolution.width, physical_resolution.height, new_scale_factor); return false; } ASSERT_NOT_REACHED(); } -void Screen::on_change_resolution(int pitch, int physical_width, int physical_height, int scale_factor) +void Screen::on_change_resolution(int pitch, int new_physical_width, int new_physical_height, int new_scale_factor) { - if (m_framebuffer) { - size_t previous_size_in_bytes = m_size_in_bytes; - int rc = munmap(m_framebuffer, previous_size_in_bytes); + if (physical_width() != new_physical_width || physical_height() != new_physical_height) { + if (m_framebuffer) { + size_t previous_size_in_bytes = m_size_in_bytes; + int rc = munmap(m_framebuffer, previous_size_in_bytes); + ASSERT(rc == 0); + } + + int rc = fb_get_size_in_bytes(m_framebuffer_fd, &m_size_in_bytes); ASSERT(rc == 0); + + m_framebuffer = (Gfx::RGBA32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0); + ASSERT(m_framebuffer && m_framebuffer != (void*)-1); } - int rc = fb_get_size_in_bytes(m_framebuffer_fd, &m_size_in_bytes); - ASSERT(rc == 0); - - m_framebuffer = (Gfx::RGBA32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0); - ASSERT(m_framebuffer && m_framebuffer != (void*)-1); - m_pitch = pitch; - m_width = physical_width / scale_factor; - m_height = physical_height / scale_factor; - m_scale_factor = scale_factor; + m_width = new_physical_width / new_scale_factor; + m_height = new_physical_height / new_scale_factor; + m_scale_factor = new_scale_factor; m_physical_cursor_location.constrain(physical_rect()); } diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index b96ae13698..8ced98b4fe 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -124,9 +124,9 @@ const Gfx::Font& WindowManager::window_title_font() const return Gfx::FontDatabase::default_bold_font(); } -bool WindowManager::set_resolution(int width, int height) +bool WindowManager::set_resolution(int width, int height, int scale) { - bool success = Compositor::the().set_resolution(width, height); + bool success = Compositor::the().set_resolution(width, height, scale); MenuManager::the().set_needs_window_resize(); ClientConnection::for_each_client([&](ClientConnection& client) { client.notify_about_new_screen_rect(Screen::the().rect()); @@ -139,14 +139,16 @@ bool WindowManager::set_resolution(int width, int height) } if (m_config) { if (success) { - dbg() << "Saving resolution: " << Gfx::IntSize(width, height) << " to config file at " << m_config->file_name(); + dbg() << "Saving resolution: " << Gfx::IntSize(width, height) << " @ " << scale << "x to config file at " << m_config->file_name(); m_config->write_num_entry("Screen", "Width", width); m_config->write_num_entry("Screen", "Height", height); + m_config->write_num_entry("Screen", "ScaleFactor", scale); m_config->sync(); } else { - dbg() << "Saving fallback resolution: " << resolution() << " to config file at " << m_config->file_name(); + dbg() << "Saving fallback resolution: " << resolution() << " @ 1x to config file at " << m_config->file_name(); m_config->write_num_entry("Screen", "Width", resolution().width()); m_config->write_num_entry("Screen", "Height", resolution().height()); + m_config->write_num_entry("Screen", "ScaleFactor", 1); m_config->sync(); } } @@ -174,6 +176,11 @@ void WindowManager::set_scroll_step_size(unsigned step_size) m_config->sync(); } +int WindowManager::scale_factor() const +{ + return Screen::the().scale_factor(); +} + void WindowManager::add_window(Window& window) { bool is_first_window = m_windows_in_order.is_empty(); diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 82f52464a5..7c0735784b 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -142,8 +142,9 @@ public: const Gfx::Font& font() const; const Gfx::Font& window_title_font() const; - bool set_resolution(int width, int height); + bool set_resolution(int width, int height, int scale); Gfx::IntSize resolution() const; + int scale_factor() const; void set_acceleration_factor(double); void set_scroll_step_size(unsigned); diff --git a/Userland/Services/WindowServer/WindowServer.ipc b/Userland/Services/WindowServer/WindowServer.ipc index 20f4d946bd..efda3e41b1 100644 --- a/Userland/Services/WindowServer/WindowServer.ipc +++ b/Userland/Services/WindowServer/WindowServer.ipc @@ -87,7 +87,7 @@ endpoint WindowServer = 2 SetBackgroundColor(String background_color) => () SetWallpaperMode(String mode) => () - SetResolution(Gfx::IntSize resolution) => (bool success, Gfx::IntSize resolution) + SetResolution(Gfx::IntSize resolution, int scale_factor) => (bool success, Gfx::IntSize resolution, int scale_factor) SetWindowIconBitmap(i32 window_id, Gfx::ShareableBitmap icon) => () GetWallpaper() => (String path) diff --git a/Userland/Utilities/chres.cpp b/Userland/Utilities/chres.cpp index a972e22c39..6f5573bd36 100644 --- a/Userland/Utilities/chres.cpp +++ b/Userland/Utilities/chres.cpp @@ -32,17 +32,19 @@ int main(int argc, char** argv) { int width = -1; int height = -1; + int scale = 1; Core::ArgsParser args_parser; args_parser.set_general_help("Change the screen resolution."); args_parser.add_positional_argument(width, "Width", "width"); args_parser.add_positional_argument(height, "Height", "height"); + args_parser.add_positional_argument(scale, "Scale Factor", "scale", Core::ArgsParser::Required::No); args_parser.parse(argc, argv); // A Core::EventLoop is all we need, but WindowServerConnection needs a full Application object. char* dummy_argv[] = { argv[0] }; auto app = GUI::Application::construct(1, dummy_argv); - auto result = GUI::WindowServerConnection::the().send_sync(Gfx::IntSize { width, height }); + auto result = GUI::WindowServerConnection::the().send_sync(Gfx::IntSize { width, height }, scale); if (!result->success()) { warnln("failed to set resolution"); return 1;