From 1b7e2eb970f73d310ea5bb2cf1c5e83604949771 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 18 Jul 2021 10:28:19 -0600 Subject: [PATCH] DisplaySettings: Add ComboBox to allow selecting other screens This enables changing monitor settings for each monitor individually. In the event that changing a resolution causes screens to overlap we now try to disperse the screens, although the algorithm currently implemented may result in some rather unexpected layouts in certain cases. We can still improve this logic, and eventually we're going to have a widget where the screens can be arranged as desired. --- .../DisplaySettings/MonitorSettings.gml | 17 +++++++ .../DisplaySettings/MonitorSettingsWidget.cpp | 44 ++++++++++++++++--- .../DisplaySettings/MonitorSettingsWidget.h | 5 +++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Userland/Applications/DisplaySettings/MonitorSettings.gml b/Userland/Applications/DisplaySettings/MonitorSettings.gml index 5883f64ca4..2f545c9a47 100644 --- a/Userland/Applications/DisplaySettings/MonitorSettings.gml +++ b/Userland/Applications/DisplaySettings/MonitorSettings.gml @@ -15,6 +15,23 @@ fixed_height: 20 } + @GUI::Widget { + shrink_to_fit: true + layout: @GUI::HorizontalBoxLayout { + margins: [16, 8, 8, 6] + } + + @GUI::Label { + text: "Screen:" + text_alignment: "CenterLeft" + fixed_width: 95 + } + + @GUI::ComboBox { + name: "screen_combo" + } + } + @GUI::GroupBox { layout: @GUI::VerticalBoxLayout { margins: [16, 24, 16, 6] diff --git a/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp b/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp index 40c41c95b5..f3f637ece3 100644 --- a/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp +++ b/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp @@ -54,17 +54,33 @@ void MonitorSettingsWidget::create_frame() m_monitor_widget = *find_descendant_of_type_named("monitor_widget"); + m_screen_combo = *find_descendant_of_type_named("screen_combo"); + m_screen_combo->set_only_allow_values_from_model(true); + m_screen_combo->set_model(*GUI::ItemListModel::create(m_screens)); + m_screen_combo->on_change = [this](auto&, const GUI::ModelIndex& index) { + m_selected_screen_index = index.row(); + selected_screen_index_changed(); + }; + m_resolution_combo = *find_descendant_of_type_named("resolution_combo"); m_resolution_combo->set_only_allow_values_from_model(true); m_resolution_combo->set_model(*GUI::ItemListModel::create(m_resolutions)); m_resolution_combo->on_change = [this](auto&, const GUI::ModelIndex& index) { - m_monitor_widget->set_desktop_resolution(m_resolutions.at(index.row())); + auto& selected_screen = m_screen_layout.screens[m_selected_screen_index]; + selected_screen.resolution = m_resolutions.at(index.row()); + // Try to auto re-arrange things if there are overlaps or disconnected screens + m_screen_layout.normalize(); + m_monitor_widget->set_desktop_resolution(selected_screen.resolution); m_monitor_widget->update(); }; m_display_scale_radio_1x = *find_descendant_of_type_named("scale_1x"); m_display_scale_radio_1x->on_checked = [this](bool checked) { if (checked) { + auto& selected_screen = m_screen_layout.screens[m_selected_screen_index]; + selected_screen.scale_factor = 1; + // Try to auto re-arrange things if there are overlaps or disconnected screens + m_screen_layout.normalize(); m_monitor_widget->set_desktop_scale_factor(1); m_monitor_widget->update(); } @@ -72,6 +88,10 @@ void MonitorSettingsWidget::create_frame() m_display_scale_radio_2x = *find_descendant_of_type_named("scale_2x"); m_display_scale_radio_2x->on_checked = [this](bool checked) { if (checked) { + auto& selected_screen = m_screen_layout.screens[m_selected_screen_index]; + selected_screen.scale_factor = 2; + // Try to auto re-arrange things if there are overlaps or disconnected screens + m_screen_layout.normalize(); m_monitor_widget->set_desktop_scale_factor(2); m_monitor_widget->update(); } @@ -81,7 +101,22 @@ void MonitorSettingsWidget::create_frame() void MonitorSettingsWidget::load_current_settings() { m_screen_layout = GUI::WindowServerConnection::the().get_screen_layout(); - auto& screen = m_screen_layout.screens[m_screen_layout.main_screen_index]; + + m_screens.clear(); + for (size_t i = 0; i < m_screen_layout.screens.size(); i++) { + if (i == m_screen_layout.main_screen_index) + m_screens.append(String::formatted("{}: {} (main screen)", i + 1, m_screen_layout.screens[i].device)); + else + m_screens.append(String::formatted("{}: {}", i + 1, m_screen_layout.screens[i].device)); + } + m_selected_screen_index = m_screen_layout.main_screen_index; + m_screen_combo->set_selected_index(m_selected_screen_index); + selected_screen_index_changed(); +} + +void MonitorSettingsWidget::selected_screen_index_changed() +{ + auto& screen = m_screen_layout.screens[m_selected_screen_index]; if (screen.scale_factor != 1 && screen.scale_factor != 2) { dbgln("unexpected ScaleFactor {}, setting to 1", screen.scale_factor); screen.scale_factor = 1; @@ -100,11 +135,6 @@ void MonitorSettingsWidget::load_current_settings() void MonitorSettingsWidget::apply_settings() { - // TODO: implement multi-screen support - auto& main_screen = m_screen_layout.screens[m_screen_layout.main_screen_index]; - main_screen.resolution = m_monitor_widget->desktop_resolution(); - main_screen.scale_factor = (m_display_scale_radio_2x->is_checked() ? 2 : 1); - // Fetch the latest configuration again, in case it has been changed by someone else. // This isn't technically race free, but if the user automates changing settings we can't help... auto current_layout = GUI::WindowServerConnection::the().get_screen_layout(); diff --git a/Userland/Applications/DisplaySettings/MonitorSettingsWidget.h b/Userland/Applications/DisplaySettings/MonitorSettingsWidget.h index 689cc2688f..28144bd4e2 100644 --- a/Userland/Applications/DisplaySettings/MonitorSettingsWidget.h +++ b/Userland/Applications/DisplaySettings/MonitorSettingsWidget.h @@ -34,11 +34,16 @@ private: void create_frame(); void create_resolution_list(); void load_current_settings(); + void selected_screen_index_changed(); + + size_t m_selected_screen_index { 0 }; WindowServer::ScreenLayout m_screen_layout; + Vector m_screens; Vector m_resolutions; RefPtr m_monitor_widget; + RefPtr m_screen_combo; RefPtr m_resolution_combo; RefPtr m_display_scale_radio_1x; RefPtr m_display_scale_radio_2x;