diff --git a/Base/etc/WindowServer.ini b/Base/etc/WindowServer.ini index 3d10400e70..aba49b8962 100644 --- a/Base/etc/WindowServer.ini +++ b/Base/etc/WindowServer.ini @@ -2,6 +2,7 @@ MainScreen=0 [Screen0] +Mode=Device Device=/dev/fb0 Left=0 Top=0 diff --git a/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp b/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp index e3de3f8029..7d384a1b59 100644 --- a/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp +++ b/Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp @@ -144,14 +144,22 @@ void MonitorSettingsWidget::load_current_settings() m_screens.clear(); m_screen_edids.clear(); + + size_t virtual_screen_count = 0; for (size_t i = 0; i < m_screen_layout.screens.size(); i++) { String screen_display_name; - if (auto edid = EDID::Parser::from_framebuffer_device(m_screen_layout.screens[i].device, 0); !edid.is_error()) { // TODO: multihead - screen_display_name = display_name_from_edid(edid.value()); - m_screen_edids.append(edid.release_value()); + if (m_screen_layout.screens[i].mode == WindowServer::ScreenLayout::Screen::Mode::Device) { + if (auto edid = EDID::Parser::from_framebuffer_device(m_screen_layout.screens[i].device.value(), 0); !edid.is_error()) { // TODO: multihead + screen_display_name = display_name_from_edid(edid.value()); + m_screen_edids.append(edid.release_value()); + } else { + dbgln("Error getting EDID from device {}: {}", m_screen_layout.screens[i].device.value(), edid.error()); + screen_display_name = m_screen_layout.screens[i].device.value(); + m_screen_edids.append({}); + } } else { - dbgln("Error getting EDID from device {}: {}", m_screen_layout.screens[i].device, edid.error()); - screen_display_name = m_screen_layout.screens[i].device; + dbgln("Frame buffer {} is virtual.", i); + screen_display_name = String::formatted("Virtual screen {}", virtual_screen_count++); m_screen_edids.append({}); } if (i == m_screen_layout.main_screen_index) diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index 52200b9afc..816dec3ea9 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -98,7 +98,7 @@ bool Screen::apply_layout(ScreenLayout&& screen_layout, String& error_msg) for (auto& it : screens_with_resolution_change) { auto& existing_screen = *it.key; - dbgln("Closing device {} in preparation for resolution change", layout_backup.screens[existing_screen.index()].device); + dbgln("Closing device {} in preparation for resolution change", layout_backup.screens[existing_screen.index()].device.value_or("")); existing_screen.close_device(); } @@ -229,15 +229,20 @@ bool Screen::open_device() auto& info = screen_layout_info(); // TODO: Support other backends - m_backend = make(info.device); - auto return_value = m_backend->open(); - if (return_value.is_error()) { - dbgln("Screen #{}: Failed to open backend: {}", index(), return_value.error()); - return false; + if (info.mode == ScreenLayout::Screen::Mode::Device) { + m_backend = make(info.device.value()); + auto return_value = m_backend->open(); + if (return_value.is_error()) { + dbgln("Screen #{}: Failed to open backend: {}", index(), return_value.error()); + return false; + } + + set_resolution(true); + return true; } - set_resolution(true); - return true; + dbgln("Unsupported screen type {}", ScreenLayout::Screen::mode_to_string(info.mode)); + return false; } void Screen::close_device() diff --git a/Userland/Services/WindowServer/ScreenLayout.h b/Userland/Services/WindowServer/ScreenLayout.h index 4e4becc7bf..5fb3eddee8 100644 --- a/Userland/Services/WindowServer/ScreenLayout.h +++ b/Userland/Services/WindowServer/ScreenLayout.h @@ -18,7 +18,12 @@ namespace WindowServer { class ScreenLayout { public: struct Screen { - String device; + enum class Mode { + Invalid, + Device, + Virtual, + } mode; + Optional device; Gfx::IntPoint location; Gfx::IntSize resolution; int scale_factor; @@ -28,6 +33,22 @@ public: return { location, { resolution.width() / scale_factor, resolution.height() / scale_factor } }; } + static StringView mode_to_string(Mode mode) + { +#define __ENUMERATE_MODE_ENUM(val) \ + case Mode::val: \ + return #val; + + switch (mode) { + __ENUMERATE_MODE_ENUM(Invalid) + __ENUMERATE_MODE_ENUM(Device) + __ENUMERATE_MODE_ENUM(Virtual) + } + VERIFY_NOT_REACHED(); + +#undef __ENUMERATE_MODE_ENUM + } + bool operator==(Screen const&) const = default; }; diff --git a/Userland/Services/WindowServer/ScreenLayout.ipp b/Userland/Services/WindowServer/ScreenLayout.ipp index 9de1512b51..2c8d8b4b87 100644 --- a/Userland/Services/WindowServer/ScreenLayout.ipp +++ b/Userland/Services/WindowServer/ScreenLayout.ipp @@ -33,7 +33,7 @@ bool ScreenLayout::is_valid(String* error_msg) const int smallest_y = 0; for (size_t i = 0; i < screens.size(); i++) { auto& screen = screens[i]; - if (screen.device.is_null() || screen.device.is_empty()) { + if (screen.mode == Screen::Mode::Device && (screen.device->is_empty() || screen.device->is_null())) { if (error_msg) *error_msg = String::formatted("Screen #{} has no path", i); return false; @@ -235,7 +235,16 @@ bool ScreenLayout::load_config(const Core::ConfigFile& config_file, String* erro auto group_name = String::formatted("Screen{}", index); if (!config_file.has_group(group_name)) break; - screens.append({ config_file.read_entry(group_name, "Device"), + auto str_mode = config_file.read_entry(group_name, "Mode"); + auto mode = str_mode == "Device" ? Screen::Mode::Device : str_mode == "Virtual" ? Screen::Mode::Virtual + : Screen::Mode::Invalid; + if (mode == Screen::Mode::Invalid) { + *error_msg = String::formatted("Invalid screen mode '{}'", str_mode); + *this = {}; + return false; + } + auto device = (mode == Screen::Mode::Device) ? config_file.read_entry(group_name, "Device") : Optional {}; + screens.append({ mode, device, { config_file.read_num_entry(group_name, "Left"), config_file.read_num_entry(group_name, "Top") }, { config_file.read_num_entry(group_name, "Width"), config_file.read_num_entry(group_name, "Height") }, config_file.read_num_entry(group_name, "ScaleFactor", 1) }); @@ -255,7 +264,9 @@ bool ScreenLayout::save_config(Core::ConfigFile& config_file, bool sync) const while (index < screens.size()) { auto& screen = screens[index]; auto group_name = String::formatted("Screen{}", index); - config_file.write_entry(group_name, "Device", screen.device); + config_file.write_entry(group_name, "Mode", Screen::mode_to_string(screen.mode)); + if (screen.mode == Screen::Mode::Device) + config_file.write_entry(group_name, "Device", screen.device.value()); config_file.write_num_entry(group_name, "Left", screen.location.x()); config_file.write_num_entry(group_name, "Top", screen.location.y()); config_file.write_num_entry(group_name, "Width", screen.resolution.width()); @@ -321,7 +332,8 @@ bool ScreenLayout::try_auto_add_framebuffer(String const& device_path) } auto append_screen = [&](Gfx::IntRect const& new_screen_rect) { - screens.append({ .device = device_path, + screens.append({ .mode = Screen::Mode::Device, + .device = device_path, .location = new_screen_rect.location(), .resolution = new_screen_rect.size(), .scale_factor = 1 }); @@ -379,13 +391,15 @@ namespace IPC { bool encode(Encoder& encoder, const WindowServer::ScreenLayout::Screen& screen) { - encoder << screen.device << screen.location << screen.resolution << screen.scale_factor; + encoder << screen.mode << screen.device << screen.location << screen.resolution << screen.scale_factor; return true; } ErrorOr decode(Decoder& decoder, WindowServer::ScreenLayout::Screen& screen) { - String device; + WindowServer::ScreenLayout::Screen::Mode mode; + TRY(decoder.decode(mode)); + Optional device; TRY(decoder.decode(device)); Gfx::IntPoint location; TRY(decoder.decode(location)); @@ -393,7 +407,7 @@ ErrorOr decode(Decoder& decoder, WindowServer::ScreenLayout::Screen& scree TRY(decoder.decode(resolution)); int scale_factor = 0; TRY(decoder.decode(scale_factor)); - screen = { device, location, resolution, scale_factor }; + screen = { mode, device, location, resolution, scale_factor }; return {}; } diff --git a/Userland/Services/WindowServer/main.cpp b/Userland/Services/WindowServer/main.cpp index 2c56729bd7..6f3511c17a 100644 --- a/Userland/Services/WindowServer/main.cpp +++ b/Userland/Services/WindowServer/main.cpp @@ -92,7 +92,8 @@ ErrorOr serenity_main(Main::Arguments) if (screen_layout.load_config(*wm_config, &error_msg)) { for (auto& screen_info : screen_layout.screens) - fb_devices_configured.set(screen_info.device); + if (screen_info.mode == WindowServer::ScreenLayout::Screen::Mode::Device) + fb_devices_configured.set(screen_info.device.value()); add_unconfigured_devices();