summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2021-06-26 13:20:41 -0600
committerAndreas Kling <kling@serenityos.org>2021-06-27 09:46:27 +0200
commita9906cfcd166e67305bc95f0a5a9b54a53e9afec (patch)
treeb0d4e70a0e0ddbd8306664cae0823f054667e608
parent38af4c29e69326c5aa7fab82f4870d03bc4f71f6 (diff)
downloadserenity-a9906cfcd166e67305bc95f0a5a9b54a53e9afec.zip
WindowServer: Try to auto-add unconfigured framebuffer devices
This will try to auto-add framebuffer devices that haven't been explicitly configured to the right-hand side.
-rw-r--r--Userland/Services/WindowServer/ScreenLayout.h1
-rw-r--r--Userland/Services/WindowServer/ScreenLayout.ipp76
-rw-r--r--Userland/Services/WindowServer/main.cpp17
3 files changed, 93 insertions, 1 deletions
diff --git a/Userland/Services/WindowServer/ScreenLayout.h b/Userland/Services/WindowServer/ScreenLayout.h
index e9d52bc43b..a2a44299c0 100644
--- a/Userland/Services/WindowServer/ScreenLayout.h
+++ b/Userland/Services/WindowServer/ScreenLayout.h
@@ -38,6 +38,7 @@ public:
void normalize();
bool load_config(const Core::ConfigFile& config_file, String* error_msg = nullptr);
bool save_config(Core::ConfigFile& config_file, bool sync = true) const;
+ bool try_auto_add_framebuffer(String const&);
// TODO: spaceship operator
bool operator!=(const ScreenLayout& other) const;
diff --git a/Userland/Services/WindowServer/ScreenLayout.ipp b/Userland/Services/WindowServer/ScreenLayout.ipp
index b2c55a3a59..6478724de4 100644
--- a/Userland/Services/WindowServer/ScreenLayout.ipp
+++ b/Userland/Services/WindowServer/ScreenLayout.ipp
@@ -4,7 +4,10 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <Kernel/API/FB.h>
#include <Services/WindowServer/ScreenLayout.h>
+#include <errno.h>
+#include <fcntl.h>
// Must be included after LibIPC/Forward.h
#include <LibIPC/Decoder.h>
@@ -183,6 +186,79 @@ bool ScreenLayout::operator!=(const ScreenLayout& other) const
return false;
}
+bool ScreenLayout::try_auto_add_framebuffer(String const& device_path)
+{
+ int framebuffer_fd = open(device_path.characters(), O_RDWR | O_CLOEXEC);
+ if (framebuffer_fd < 0) {
+ int err = errno;
+ dbgln("Error ({}) opening framebuffer device {}", err, device_path);
+ return false;
+ }
+ ScopeGuard fd_guard([&] {
+ close(framebuffer_fd);
+ });
+ FBResolution resolution {};
+ if (fb_get_resolution(framebuffer_fd, &resolution) < 0) {
+ int err = errno;
+ dbgln("Error ({}) querying resolution from framebuffer device {}", err, device_path);
+ return false;
+ }
+ if (resolution.width == 0 || resolution.height == 0) {
+ // Looks like the display is not turned on. Since we don't know what the desired
+ // resolution should be, use the main display as reference.
+ if (screens.is_empty())
+ return false;
+ auto& main_screen = screens[main_screen_index];
+ resolution.width = main_screen.resolution.width();
+ resolution.height = main_screen.resolution.height();
+ }
+
+ auto original_screens = move(screens);
+ screens = original_screens;
+ ArmedScopeGuard screens_guard([&] {
+ screens = move(original_screens);
+ });
+ // Now that we know the current resolution, try to find a location that we can add onto
+ // TODO: make this a little more sophisticated in case a more complex layout is already configured
+ for (auto& screen : screens) {
+ auto screen_rect = screen.virtual_rect();
+ Gfx::IntRect new_screen_rect {
+ screen_rect.right() + 1,
+ screen_rect.top(),
+ (int)resolution.width,
+ (int)resolution.height
+ };
+
+ bool collision = false;
+ for (auto& other_screen : screens) {
+ if (&screen == &other_screen)
+ continue;
+ if (other_screen.virtual_rect().intersects(new_screen_rect)) {
+ collision = true;
+ break;
+ }
+ }
+
+ if (!collision) {
+ screens.append({
+ device : device_path,
+ location : new_screen_rect.location(),
+ resolution : new_screen_rect.size(),
+ scale_factor : 1
+ });
+
+ if (is_valid()) {
+ // We got lucky!
+ screens_guard.disarm();
+ return true;
+ }
+ }
+ }
+
+ dbgln("Failed to add framebuffer device {} with resolution {}x{} to screen layout", device_path, resolution.width, resolution.height);
+ return false;
+}
+
}
namespace IPC {
diff --git a/Userland/Services/WindowServer/main.cpp b/Userland/Services/WindowServer/main.cpp
index bad6afb571..5977f657ed 100644
--- a/Userland/Services/WindowServer/main.cpp
+++ b/Userland/Services/WindowServer/main.cpp
@@ -10,6 +10,8 @@
#include "Screen.h"
#include "WindowManager.h"
#include <LibCore/ConfigFile.h>
+#include <LibCore/DirIterator.h>
+#include <LibCore/File.h>
#include <LibGfx/Palette.h>
#include <LibGfx/SystemTheme.h>
#include <signal.h>
@@ -88,7 +90,20 @@ int main(int, char**)
for (auto& screen_info : screen_layout.screens)
fb_devices_configured.set(screen_info.device);
- // TODO: Enumerate the /dev/fbX devices and set up any ones we find that we haven't already used
+ // Enumerate the /dev/fbX devices and try to set up any ones we find that we haven't already used
+ Core::DirIterator di("/dev", Core::DirIterator::SkipParentAndBaseDir);
+ while (di.has_next()) {
+ auto path = di.next_path();
+ if (!path.starts_with("fb"))
+ continue;
+ auto full_path = String::formatted("/dev/{}", path);
+ if (!Core::File::is_device(full_path))
+ continue;
+ if (fb_devices_configured.find(full_path) != fb_devices_configured.end())
+ continue;
+ if (!screen_layout.try_auto_add_framebuffer(full_path))
+ dbgln("Could not auto-add framebuffer device {} to screen layout", full_path);
+ }
if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
dbgln("Error applying screen layout: {}", error_msg);