mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:17:44 +00:00
WindowServer: Add API to set/get screen layouts
This sets the stage so that DisplaySettings can configure the screen layout and set various screen resolutions in one go. It also allows for an easy "atomic" revert of the previous settings.
This commit is contained in:
parent
34394044b3
commit
aa15bf81e4
23 changed files with 558 additions and 228 deletions
|
@ -76,84 +76,26 @@ int main(int, char**)
|
|||
}
|
||||
|
||||
// First check which screens are explicitly configured
|
||||
AK::HashTable<String> fb_devices_configured;
|
||||
int main_screen_index = wm_config->read_num_entry("Screens", "MainScreen", 0);
|
||||
for (int screen_index = 0;; screen_index++) {
|
||||
auto group_name = String::formatted("Screen{}", screen_index);
|
||||
if (!wm_config->has_group(group_name))
|
||||
break;
|
||||
|
||||
int scale = wm_config->read_num_entry(group_name, "ScaleFactor", 1);
|
||||
auto device_path = wm_config->read_entry(group_name, "Device", {});
|
||||
if (device_path.is_null() || device_path.is_empty()) {
|
||||
dbgln("Screen {} misses Device setting", screen_index);
|
||||
break;
|
||||
}
|
||||
|
||||
Gfx::IntRect virtual_rect {
|
||||
wm_config->read_num_entry(group_name, "Left", 0 / scale),
|
||||
wm_config->read_num_entry(group_name, "Top", 0 / scale),
|
||||
wm_config->read_num_entry(group_name, "Width", 1024 / scale),
|
||||
wm_config->read_num_entry("Screen", "Height", 768 / scale)
|
||||
};
|
||||
|
||||
// Check if the screen would be overlapping with another one
|
||||
if (WindowServer::Screen::for_each([&](auto& screen) {
|
||||
if (screen.rect().intersects(virtual_rect)) {
|
||||
dbgln("Screen {} rect {} overlaps with screen {} rect {}: Ignoring configuration", screen.index(), screen.rect(), screen_index, virtual_rect);
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
})
|
||||
== IterationDecision::Break) {
|
||||
// Ignore the configuration
|
||||
break;
|
||||
}
|
||||
|
||||
auto* screen = WindowServer::Screen::create(device_path, virtual_rect, scale);
|
||||
if (!screen) {
|
||||
dbgln("Screen {} failed to be created", screen_index);
|
||||
break;
|
||||
}
|
||||
|
||||
if (main_screen_index == screen_index)
|
||||
screen->make_main_screen();
|
||||
|
||||
// Remember that we used this device for a screen already
|
||||
fb_devices_configured.set(device_path);
|
||||
}
|
||||
|
||||
// Check that all screens are contiguous and can be "reached" from the main screen
|
||||
{
|
||||
Vector<WindowServer::Screen*, 16> reachable_screens { &WindowServer::Screen::main() };
|
||||
bool did_reach_another_screen;
|
||||
do {
|
||||
did_reach_another_screen = false;
|
||||
auto* latest_reachable_screen = reachable_screens[reachable_screens.size() - 1];
|
||||
WindowServer::Screen::for_each([&](auto& screen) {
|
||||
if (&screen == latest_reachable_screen || reachable_screens.contains_slow(&screen))
|
||||
return IterationDecision::Continue;
|
||||
if (screen.rect().is_adjacent(latest_reachable_screen->rect())) {
|
||||
reachable_screens.append(&screen);
|
||||
did_reach_another_screen = true;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
} while (did_reach_another_screen);
|
||||
if (reachable_screens.size() != WindowServer::Screen::count()) {
|
||||
WindowServer::Screen::for_each([&](auto& screen) {
|
||||
if (!reachable_screens.contains_slow(&screen))
|
||||
dbgln("Screen {} cannot be reached from main screen {}: Bad configuration!", screen.index(), WindowServer::Screen::main().index());
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
dbgln("At least one screen is not adjacent to another screen, exiting!");
|
||||
AK::HashTable<String> fb_devices_configured;
|
||||
WindowServer::ScreenLayout screen_layout;
|
||||
String error_msg;
|
||||
if (!screen_layout.load_config(*wm_config, &error_msg)) {
|
||||
dbgln("Error loading screen configuration: {}", error_msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
|
||||
dbgln("Error applying screen layout: {}", error_msg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Enumerate the /dev/fbX devices and set up any ones we find that we haven't already used
|
||||
|
||||
auto& screen_input = WindowServer::ScreenInput::the();
|
||||
screen_input.set_cursor_location(WindowServer::Screen::main().rect().center());
|
||||
screen_input.set_acceleration_factor(atof(wm_config->read_entry("Mouse", "AccelerationFactor", "1.0").characters()));
|
||||
|
@ -169,10 +111,9 @@ int main(int, char**)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (unveil("/dev", "") < 0) {
|
||||
perror("unveil /dev");
|
||||
return 1;
|
||||
}
|
||||
// NOTE: Because we dynamically need to be able to open new /dev/fb*
|
||||
// devices we can't really unveil all of /dev unless we have some
|
||||
// other mechanism that can hand us file descriptors for these.
|
||||
|
||||
if (unveil(nullptr, nullptr) < 0) {
|
||||
perror("unveil");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue