#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowSystem {
Wayland,
X11,
Unknown,
}
#[cfg(all(unix, not(target_os = "macos")))]
fn detect_from_env(
wayland_display: Option<&str>,
wayland_socket: Option<&str>,
display: Option<&str>,
) -> WindowSystem {
let non_empty = |value: Option<&str>| value.is_some_and(|value| !value.is_empty());
if non_empty(wayland_display) || non_empty(wayland_socket) {
WindowSystem::Wayland
} else if non_empty(display) {
WindowSystem::X11
} else {
WindowSystem::Unknown
}
}
pub fn active_window_system() -> WindowSystem {
#[cfg(all(unix, not(target_os = "macos")))]
{
detect_from_env(
std::env::var("WAYLAND_DISPLAY").ok().as_deref(),
std::env::var("WAYLAND_SOCKET").ok().as_deref(),
std::env::var("DISPLAY").ok().as_deref(),
)
}
#[cfg(not(all(unix, not(target_os = "macos"))))]
{
WindowSystem::Unknown
}
}
pub fn window_system_for_display_handle(
handle: &raw_window_handle::RawDisplayHandle,
) -> WindowSystem {
use raw_window_handle::RawDisplayHandle;
match handle {
RawDisplayHandle::Wayland(_) => WindowSystem::Wayland,
RawDisplayHandle::Xlib(_) | RawDisplayHandle::Xcb(_) => WindowSystem::X11,
_ => WindowSystem::Unknown,
}
}
pub fn supports_native_modal_windows() -> bool {
#[cfg(all(unix, not(target_os = "macos")))]
{
false
}
#[cfg(not(all(unix, not(target_os = "macos"))))]
{
true
}
}
pub fn attach_child_window(parent: &winit::window::Window, child: &winit::window::Window) {
#[cfg(target_os = "macos")]
{
use objc2::rc::Retained;
use objc2_app_kit::{NSView, NSWindowOrderingMode};
use winit::raw_window_handle::{HasWindowHandle, RawWindowHandle};
let Ok(parent_handle) = parent.window_handle() else {
return;
};
let Ok(child_handle) = child.window_handle() else {
return;
};
let (RawWindowHandle::AppKit(p), RawWindowHandle::AppKit(c)) =
(parent_handle.as_raw(), child_handle.as_raw())
else {
return;
};
unsafe {
let Some(parent_view): Option<Retained<NSView>> =
Retained::retain(p.ns_view.as_ptr().cast())
else {
return;
};
let Some(child_view): Option<Retained<NSView>> =
Retained::retain(c.ns_view.as_ptr().cast())
else {
return;
};
if let (Some(pw), Some(cw)) = (parent_view.window(), child_view.window()) {
pw.addChildWindow_ordered(&cw, NSWindowOrderingMode::Above);
}
}
}
#[cfg(not(target_os = "macos"))]
{
let _ = (parent, child);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn prefers_wayland_when_both_displays_exist() {
assert_eq!(
detect_from_env(Some("wayland-0"), None, Some(":0")),
WindowSystem::Wayland
);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn wayland_socket_also_selects_wayland() {
assert_eq!(
detect_from_env(None, Some("4"), Some(":0")),
WindowSystem::Wayland
);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn detects_x11_from_display() {
assert_eq!(detect_from_env(None, None, Some(":0")), WindowSystem::X11);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn empty_wayland_display_falls_back_to_x11() {
assert_eq!(
detect_from_env(Some(""), Some(""), Some(":0")),
WindowSystem::X11
);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn returns_unknown_without_display_hints() {
assert_eq!(detect_from_env(None, None, None), WindowSystem::Unknown);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn returns_unknown_when_all_hints_are_empty() {
assert_eq!(
detect_from_env(Some(""), Some(""), Some("")),
WindowSystem::Unknown
);
}
#[test]
fn display_handle_discriminates_the_live_backend() {
use raw_window_handle::{RawDisplayHandle, XcbDisplayHandle, XlibDisplayHandle};
assert_eq!(
window_system_for_display_handle(&RawDisplayHandle::Xlib(XlibDisplayHandle::new(
None, 0
))),
WindowSystem::X11
);
assert_eq!(
window_system_for_display_handle(&RawDisplayHandle::Xcb(XcbDisplayHandle::new(
None, 0
))),
WindowSystem::X11
);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn linux_family_never_uses_native_modals() {
assert!(!supports_native_modal_windows());
}
}