1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 15:57:35 +00:00

WindowServer: Add a "scale" parameter to the SetResolution message and plumb it through

Now, `chres 640 480 2` can set the UI to HighDPI 640x480 at runtime. A
real GUI for changing the display factor will come later.

(`chres 640 480 2` followed by `chres 1280 960` is very fast since
we don't have to re-allocate the framebuffer since both modes use
the exact same number of physical pixels.)
This commit is contained in:
Nico Weber 2021-01-15 14:53:53 -05:00 committed by Andreas Kling
parent 248d75e13b
commit 63ac9462ad
9 changed files with 53 additions and 32 deletions

View file

@ -246,7 +246,8 @@ void DisplaySettingsWidget::load_current_settings()
void DisplaySettingsWidget::send_settings_to_window_server()
{
auto result = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetResolution>(m_monitor_widget->desktop_resolution());
// FIXME: Add UI for changing the scale factor.
auto result = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetResolution>(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);

View file

@ -340,7 +340,7 @@ OwnPtr<Messages::WindowServer::GetWallpaperResponse> ClientConnection::handle(co
OwnPtr<Messages::WindowServer::SetResolutionResponse> ClientConnection::handle(const Messages::WindowServer::SetResolution& message)
{
return make<Messages::WindowServer::SetResolutionResponse>(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height()), WindowManager::the().resolution());
return make<Messages::WindowServer::SetResolutionResponse>(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height(), message.scale_factor()), WindowManager::the().resolution(), WindowManager::the().scale_factor());
}
OwnPtr<Messages::WindowServer::SetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowTitle& message)

View file

@ -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();

View file

@ -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);

View file

@ -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());
}

View file

@ -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();

View file

@ -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);

View file

@ -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)

View file

@ -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<Messages::WindowServer::SetResolution>(Gfx::IntSize { width, height });
auto result = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetResolution>(Gfx::IntSize { width, height }, scale);
if (!result->success()) {
warnln("failed to set resolution");
return 1;