x11: fix WindowAttributesExtX11::with_x11_screen()

Based on https://github.com/rust-windowing/winit/pull/3973, which should
be merged first.

There's an API to programmatically specify X11 screen id (override what
is determined from the `DISPLAY` env variable), but it doesn't work.

Seeting up X Server with 2 screens and calling `DISPLAY=:0
X11_SCREEN_ID=1 cargo run --example window` should be equivalent to
calling `DISPLAY=:0.1 cargo run --example window`

The latter works (and places the window on the correct screen), but the
former yields

`failed to create initial window: Os(OsError { line: 620, file:
"src/platform_impl/linux/x11/window.rs", error: X11Error(X11Error {
error_kind: Match, error_code: 8, sequence: 219, bad_value: 1319,
minor_opcode: 0, major_opcode: 1, extension_name: None, request_name:
Some("CreateWindow") }) })`

_Here `1319` is the root window id for screen 0, which doesn't match the
screen 1 that we request._

The problem is that we need to factor in the screen id when determining
the parent (root) window when not explicitly set. This patch does that.

---

Also: Extend the window example with X11_{SCREEN,VISUAL}_ID env variables
This commit is contained in:
Matěj Laitl
2024-10-28 15:15:52 +01:00
committed by Kirill Chibisov
parent b02a70e6bb
commit bbab3d8e35
3 changed files with 42 additions and 14 deletions

View File

@@ -31,6 +31,8 @@ use winit::platform::macos::{OptionAsAlt, WindowAttributesExtMacOS, WindowExtMac
use winit::platform::startup_notify::{ use winit::platform::startup_notify::{
self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, WindowExtStartupNotify, self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, WindowExtStartupNotify,
}; };
#[cfg(x11_platform)]
use winit::platform::x11::WindowAttributesExtX11;
#[path = "util/tracing.rs"] #[path = "util/tracing.rs"]
mod tracing; mod tracing;
@@ -140,6 +142,28 @@ impl Application {
window_attributes = window_attributes.with_activation_token(token); window_attributes = window_attributes.with_activation_token(token);
} }
#[cfg(x11_platform)]
match std::env::var("X11_VISUAL_ID") {
Ok(visual_id_str) => {
info!("Using X11 visual id {visual_id_str}");
let visual_id = visual_id_str.parse()?;
window_attributes = window_attributes.with_x11_visual(visual_id);
},
Err(_) => info!("Set the X11_VISUAL_ID env variable to request specific X11 visual"),
}
#[cfg(x11_platform)]
match std::env::var("X11_SCREEN_ID") {
Ok(screen_id_str) => {
info!("Placing the window on X11 screen {screen_id_str}");
let screen_id = screen_id_str.parse()?;
window_attributes = window_attributes.with_x11_screen(screen_id);
},
Err(_) => info!(
"Set the X11_SCREEN_ID env variable to place the window on non-default screen"
),
}
#[cfg(macos_platform)] #[cfg(macos_platform)]
if let Some(tab_id) = _tab_id { if let Some(tab_id) = _tab_id {
window_attributes = window_attributes.with_tabbing_identifier(&tab_id); window_attributes = window_attributes.with_tabbing_identifier(&tab_id);

View File

@@ -44,6 +44,8 @@ changelog entry.
- On macOS, add `WindowExtMacOS::set_borderless_game` and `WindowAttributesExtMacOS::with_borderless_game` - On macOS, add `WindowExtMacOS::set_borderless_game` and `WindowAttributesExtMacOS::with_borderless_game`
to fully disable the menu bar and dock in Borderless Fullscreen as commonly done in games. to fully disable the menu bar and dock in Borderless Fullscreen as commonly done in games.
- On X11, the `window` example now understands the `X11_VISUAL_ID` and `X11_SCREEN_ID` env
variables to test the respective modifiers of window creation.
### Fixed ### Fixed
@@ -54,3 +56,4 @@ changelog entry.
- On X11, key events forward to IME anyway, even when it's disabled. - On X11, key events forward to IME anyway, even when it's disabled.
- On Windows, make `ControlFlow::WaitUntil` work more precisely using `CREATE_WAITABLE_TIMER_HIGH_RESOLUTION`. - On Windows, make `ControlFlow::WaitUntil` work more precisely using `CREATE_WAITABLE_TIMER_HIGH_RESOLUTION`.
- On X11, creating windows on screen that is not the first one (e.g. `DISPLAY=:0.1`) works again. - On X11, creating windows on screen that is not the first one (e.g. `DISPLAY=:0.1`) works again.
- On X11, creating windows while passing `with_x11_screen(non_default_screen)` works again.

View File

@@ -144,12 +144,26 @@ impl UnownedWindow {
) -> Result<UnownedWindow, RootOsError> { ) -> Result<UnownedWindow, RootOsError> {
let xconn = &event_loop.xconn; let xconn = &event_loop.xconn;
let atoms = xconn.atoms(); let atoms = xconn.atoms();
let screen_id = match window_attrs.platform_specific.x11.screen_id {
Some(id) => id,
None => xconn.default_screen_index() as c_int,
};
let screen = {
let screen_id_usize = usize::try_from(screen_id)
.map_err(|_| os_error!(OsError::Misc("screen id must be non-negative")))?;
xconn.xcb_connection().setup().roots.get(screen_id_usize).ok_or(os_error!(
OsError::Misc("requested screen id not present in server's response")
))?
};
#[cfg(feature = "rwh_06")] #[cfg(feature = "rwh_06")]
let root = match window_attrs.parent_window.as_ref().map(|handle| handle.0) { let root = match window_attrs.parent_window.as_ref().map(|handle| handle.0) {
Some(rwh_06::RawWindowHandle::Xlib(handle)) => handle.window as xproto::Window, Some(rwh_06::RawWindowHandle::Xlib(handle)) => handle.window as xproto::Window,
Some(rwh_06::RawWindowHandle::Xcb(handle)) => handle.window.get(), Some(rwh_06::RawWindowHandle::Xcb(handle)) => handle.window.get(),
Some(raw) => unreachable!("Invalid raw window handle {raw:?} on X11"), Some(raw) => unreachable!("Invalid raw window handle {raw:?} on X11"),
None => event_loop.root, None => screen.root,
}; };
#[cfg(not(feature = "rwh_06"))] #[cfg(not(feature = "rwh_06"))]
let root = event_loop.root; let root = event_loop.root;
@@ -207,19 +221,6 @@ impl UnownedWindow {
dimensions dimensions
}; };
let screen_id = match window_attrs.platform_specific.x11.screen_id {
Some(id) => id,
None => xconn.default_screen_index() as c_int,
};
let screen = {
let screen_id_usize = usize::try_from(screen_id)
.map_err(|_| os_error!(OsError::Misc("screen id must be non-negative")))?;
xconn.xcb_connection().setup().roots.get(screen_id_usize).ok_or(os_error!(
OsError::Misc("requested screen id not present in server's response")
))?
};
// An iterator over the visuals matching screen id combined with their depths. // An iterator over the visuals matching screen id combined with their depths.
let mut all_visuals = screen let mut all_visuals = screen
.allowed_depths .allowed_depths