diff --git a/CHANGELOG.md b/CHANGELOG.md index 808a3c37..c586be8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Unreleased +- On Unix, X11 and Wayland are now optional features (enabled by default) - On X11, fix deadlock when calling `set_fullscreen_inner`. - On Web, prevent the webpage from scrolling when the user is focused on a winit canvas diff --git a/Cargo.toml b/Cargo.toml index 2f4903d9..017e5927 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,11 @@ default-target = "x86_64-unknown-linux-gnu" targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "wasm32-unknown-unknown"] [features] +default = ["x11", "wayland"] web-sys = ["web_sys", "wasm-bindgen", "instant/wasm-bindgen"] stdweb = ["std_web", "instant/stdweb"] +x11 = ["x11-dl"] +wayland = ["wayland-client", "smithay-client-toolkit"] [dependencies] instant = "0.1" @@ -78,11 +81,11 @@ features = [ ] [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] -wayland-client = { version = "0.23.0", features = [ "dlopen", "egl", "cursor", "eventloop"] } +wayland-client = { version = "0.23.0", features = [ "dlopen", "egl", "cursor", "eventloop"] , optional = true } mio = "0.6" mio-extras = "2.0" -smithay-client-toolkit = "^0.6.6" -x11-dl = "2.18.5" +smithay-client-toolkit = { version = "^0.6.6", optional = true } +x11-dl = { version = "2.18.5", optional = true } percent-encoding = "2.0" [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "windows"))'.dependencies.parking_lot] diff --git a/README.md b/README.md index 5e489631..c7b312f6 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ Winit is only officially supported on the latest stable version of the Rust comp Winit provides the following features, which can be enabled in your `Cargo.toml` file: * `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde). +* `x11` (enabled by default): On Unix platform, compiles with the X11 backend +* `wayland` (enabled by default): On Unix platform, compiles with the Wayland backend ### Platform-specific usage diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..f1c4e9bf --- /dev/null +++ b/build.rs @@ -0,0 +1,21 @@ +#[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + not(feature = "x11"), + not(feature = "wayland") +))] +compile_error!("at least one of the \"x11\"/\"wayland\" features must be enabled"); + +#[cfg(all( + target_arch = "wasm32", + not(feature = "web-sys"), + not(feature = "stdweb") +))] +compile_error!("at least one of the \"web-sys\"/\"stdweb\" features must be enabled"); + +fn main() {} diff --git a/src/platform/unix.rs b/src/platform/unix.rs index 6ab2d7df..13346a86 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -1,37 +1,46 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] -use std::{os::raw, ptr, sync::Arc}; +use std::os::raw; +#[cfg(feature = "x11")] +use std::{ptr, sync::Arc}; +#[cfg(feature = "wayland")] use smithay_client_toolkit::window::{ButtonState as SCTKButtonState, Theme as SCTKTheme}; use crate::{ - dpi::Size, event_loop::{EventLoop, EventLoopWindowTarget}, monitor::MonitorHandle, window::{Window, WindowBuilder}, }; +#[cfg(feature = "x11")] +use crate::dpi::Size; +#[cfg(feature = "x11")] +use crate::platform_impl::x11::{ffi::XVisualInfo, XConnection}; use crate::platform_impl::{ - x11::{ffi::XVisualInfo, XConnection}, EventLoop as LinuxEventLoop, EventLoopWindowTarget as LinuxEventLoopWindowTarget, Window as LinuxWindow, }; // TODO: stupid hack so that glutin can do its work #[doc(hidden)] +#[cfg(feature = "x11")] pub use crate::platform_impl::x11; - +#[cfg(feature = "x11")] pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported}; /// Additional methods on `EventLoopWindowTarget` that are specific to Unix. pub trait EventLoopWindowTargetExtUnix { /// True if the `EventLoopWindowTarget` uses Wayland. + #[cfg(feature = "wayland")] fn is_wayland(&self) -> bool; - /// + /// True if the `EventLoopWindowTarget` uses X11. + #[cfg(feature = "x11")] fn is_x11(&self) -> bool; #[doc(hidden)] + #[cfg(feature = "x11")] fn xlib_xconnection(&self) -> Option>; /// Returns a pointer to the `wl_display` object of wayland that is used by this @@ -40,35 +49,42 @@ pub trait EventLoopWindowTargetExtUnix { /// Returns `None` if the `EventLoop` doesn't use wayland (if it uses xlib for example). /// /// The pointer will become invalid when the winit `EventLoop` is destroyed. + #[cfg(feature = "wayland")] fn wayland_display(&self) -> Option<*mut raw::c_void>; } impl EventLoopWindowTargetExtUnix for EventLoopWindowTarget { #[inline] + #[cfg(feature = "wayland")] fn is_wayland(&self) -> bool { self.p.is_wayland() } #[inline] + #[cfg(feature = "x11")] fn is_x11(&self) -> bool { !self.p.is_wayland() } #[inline] #[doc(hidden)] + #[cfg(feature = "x11")] fn xlib_xconnection(&self) -> Option> { match self.p { LinuxEventLoopWindowTarget::X(ref e) => Some(e.x_connection().clone()), + #[cfg(feature = "wayland")] _ => None, } } #[inline] + #[cfg(feature = "wayland")] fn wayland_display(&self) -> Option<*mut raw::c_void> { match self.p { LinuxEventLoopWindowTarget::Wayland(ref p) => { Some(p.display().get_display_ptr() as *mut _) } + #[cfg(feature = "x11")] _ => None, } } @@ -82,6 +98,7 @@ pub trait EventLoopExtUnix { /// /// If called outside the main thread. To initialize an X11 event loop outside /// the main thread, use [`new_x11_any_thread`](#tymethod.new_x11_any_thread). + #[cfg(feature = "x11")] fn new_x11() -> Result where Self: Sized; @@ -92,6 +109,7 @@ pub trait EventLoopExtUnix { /// /// If called outside the main thread. To initialize a Wayland event loop outside /// the main thread, use [`new_wayland_any_thread`](#tymethod.new_wayland_any_thread). + #[cfg(feature = "wayland")] fn new_wayland() -> Self where Self: Sized; @@ -108,6 +126,7 @@ pub trait EventLoopExtUnix { /// /// This method bypasses the cross-platform compatibility requirement /// that `EventLoop` be created on the main thread. + #[cfg(feature = "x11")] fn new_x11_any_thread() -> Result where Self: Sized; @@ -116,6 +135,7 @@ pub trait EventLoopExtUnix { /// /// This method bypasses the cross-platform compatibility requirement /// that `EventLoop` be created on the main thread. + #[cfg(feature = "wayland")] fn new_wayland_any_thread() -> Self where Self: Sized; @@ -135,11 +155,13 @@ impl EventLoopExtUnix for EventLoop { } #[inline] + #[cfg(feature = "x11")] fn new_x11_any_thread() -> Result { LinuxEventLoop::new_x11_any_thread().map(wrap_ev) } #[inline] + #[cfg(feature = "wayland")] fn new_wayland_any_thread() -> Self { wrap_ev( LinuxEventLoop::new_wayland_any_thread() @@ -149,11 +171,13 @@ impl EventLoopExtUnix for EventLoop { } #[inline] + #[cfg(feature = "x11")] fn new_x11() -> Result { LinuxEventLoop::new_x11().map(wrap_ev) } #[inline] + #[cfg(feature = "wayland")] fn new_wayland() -> Self { wrap_ev( LinuxEventLoop::new_wayland() @@ -168,6 +192,7 @@ pub trait WindowExtUnix { /// Returns the ID of the `Window` xlib object that is used by this window. /// /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). + #[cfg(feature = "x11")] fn xlib_window(&self) -> Option; /// Returns a pointer to the `Display` object of xlib that is used by this window. @@ -175,14 +200,18 @@ pub trait WindowExtUnix { /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). /// /// The pointer will become invalid when the glutin `Window` is destroyed. + #[cfg(feature = "x11")] fn xlib_display(&self) -> Option<*mut raw::c_void>; + #[cfg(feature = "x11")] fn xlib_screen_id(&self) -> Option; #[doc(hidden)] + #[cfg(feature = "x11")] fn xlib_xconnection(&self) -> Option>; /// Set window urgency hint (`XUrgencyHint`). Only relevant on X. + #[cfg(feature = "x11")] fn set_urgent(&self, is_urgent: bool); /// This function returns the underlying `xcb_connection_t` of an xlib `Display`. @@ -190,6 +219,7 @@ pub trait WindowExtUnix { /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). /// /// The pointer will become invalid when the glutin `Window` is destroyed. + #[cfg(feature = "x11")] fn xcb_connection(&self) -> Option<*mut raw::c_void>; /// Returns a pointer to the `wl_surface` object of wayland that is used by this window. @@ -197,6 +227,7 @@ pub trait WindowExtUnix { /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). /// /// The pointer will become invalid when the glutin `Window` is destroyed. + #[cfg(feature = "wayland")] fn wayland_surface(&self) -> Option<*mut raw::c_void>; /// Returns a pointer to the `wl_display` object of wayland that is used by this window. @@ -204,9 +235,11 @@ pub trait WindowExtUnix { /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). /// /// The pointer will become invalid when the glutin `Window` is destroyed. + #[cfg(feature = "wayland")] fn wayland_display(&self) -> Option<*mut raw::c_void>; /// Sets the color theme of the client side window decorations on wayland + #[cfg(feature = "wayland")] fn set_wayland_theme(&self, theme: T); /// Check if the window is ready for drawing @@ -221,73 +254,92 @@ pub trait WindowExtUnix { impl WindowExtUnix for Window { #[inline] + #[cfg(feature = "x11")] fn xlib_window(&self) -> Option { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_window()), + #[cfg(feature = "wayland")] _ => None, } } #[inline] + #[cfg(feature = "x11")] fn xlib_display(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_display()), + #[cfg(feature = "wayland")] _ => None, } } #[inline] + #[cfg(feature = "x11")] fn xlib_screen_id(&self) -> Option { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_screen_id()), + #[cfg(feature = "wayland")] _ => None, } } #[inline] #[doc(hidden)] + #[cfg(feature = "x11")] fn xlib_xconnection(&self) -> Option> { match self.window { LinuxWindow::X(ref w) => Some(w.xlib_xconnection()), + #[cfg(feature = "wayland")] _ => None, } } #[inline] + #[cfg(feature = "x11")] fn set_urgent(&self, is_urgent: bool) { - if let LinuxWindow::X(ref w) = self.window { - w.set_urgent(is_urgent); + match self.window { + LinuxWindow::X(ref w) => w.set_urgent(is_urgent), + #[cfg(feature = "wayland")] + _ => (), } } #[inline] + #[cfg(feature = "x11")] fn xcb_connection(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::X(ref w) => Some(w.xcb_connection()), + #[cfg(feature = "wayland")] _ => None, } } #[inline] + #[cfg(feature = "wayland")] fn wayland_surface(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _), + #[cfg(feature = "x11")] _ => None, } } #[inline] + #[cfg(feature = "wayland")] fn wayland_display(&self) -> Option<*mut raw::c_void> { match self.window { LinuxWindow::Wayland(ref w) => Some(w.display().as_ref().c_ptr() as *mut _), + #[cfg(feature = "x11")] _ => None, } } #[inline] + #[cfg(feature = "wayland")] fn set_wayland_theme(&self, theme: T) { match self.window { LinuxWindow::Wayland(ref w) => w.set_theme(WaylandTheme(theme)), + #[cfg(feature = "x11")] _ => {} } } @@ -300,20 +352,28 @@ impl WindowExtUnix for Window { /// Additional methods on `WindowBuilder` that are specific to Unix. pub trait WindowBuilderExtUnix { + #[cfg(feature = "x11")] fn with_x11_visual(self, visual_infos: *const T) -> Self; + #[cfg(feature = "x11")] fn with_x11_screen(self, screen_id: i32) -> Self; /// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on X11. + #[cfg(feature = "x11")] fn with_class(self, class: String, instance: String) -> Self; /// Build window with override-redirect flag; defaults to false. Only relevant on X11. + #[cfg(feature = "x11")] fn with_override_redirect(self, override_redirect: bool) -> Self; /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11. + #[cfg(feature = "x11")] fn with_x11_window_type(self, x11_window_type: Vec) -> Self; /// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11. + #[cfg(feature = "x11")] fn with_gtk_theme_variant(self, variant: String) -> Self; /// Build window with resize increment hint. Only implemented on X11. + #[cfg(feature = "x11")] fn with_resize_increments>(self, increments: S) -> Self; /// Build window with base size hint. Only implemented on X11. + #[cfg(feature = "x11")] fn with_base_size>(self, base_size: S) -> Self; /// Build window with a given application ID. It should match the `.desktop` file distributed with @@ -321,60 +381,72 @@ pub trait WindowBuilderExtUnix { /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) + #[cfg(feature = "wayland")] fn with_app_id(self, app_id: String) -> Self; } impl WindowBuilderExtUnix for WindowBuilder { #[inline] + #[cfg(feature = "x11")] fn with_x11_visual(mut self, visual_infos: *const T) -> Self { - self.platform_specific.visual_infos = - Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) }); + { + self.platform_specific.visual_infos = + Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) }); + } self } #[inline] + #[cfg(feature = "x11")] fn with_x11_screen(mut self, screen_id: i32) -> Self { self.platform_specific.screen_id = Some(screen_id); self } #[inline] + #[cfg(feature = "x11")] fn with_class(mut self, instance: String, class: String) -> Self { self.platform_specific.class = Some((instance, class)); self } #[inline] + #[cfg(feature = "x11")] fn with_override_redirect(mut self, override_redirect: bool) -> Self { self.platform_specific.override_redirect = override_redirect; self } #[inline] + #[cfg(feature = "x11")] fn with_x11_window_type(mut self, x11_window_types: Vec) -> Self { self.platform_specific.x11_window_types = x11_window_types; self } #[inline] + #[cfg(feature = "x11")] fn with_gtk_theme_variant(mut self, variant: String) -> Self { self.platform_specific.gtk_theme_variant = Some(variant); self } #[inline] + #[cfg(feature = "x11")] fn with_resize_increments>(mut self, increments: S) -> Self { self.platform_specific.resize_increments = Some(increments.into()); self } #[inline] + #[cfg(feature = "x11")] fn with_base_size>(mut self, base_size: S) -> Self { self.platform_specific.base_size = Some(base_size.into()); self } #[inline] + #[cfg(feature = "wayland")] fn with_app_id(mut self, app_id: String) -> Self { self.platform_specific.app_id = Some(app_id); self @@ -395,6 +467,7 @@ impl MonitorHandleExtUnix for MonitorHandle { } /// Wrapper for implementing SCTK's theme trait. +#[cfg(feature = "wayland")] struct WaylandTheme(T); pub trait Theme: Send + 'static { @@ -432,6 +505,7 @@ pub trait Theme: Send + 'static { } } +#[cfg(feature = "wayland")] impl SCTKTheme for WaylandTheme { fn get_primary_color(&self, active: bool) -> [u8; 4] { self.0.primary_color(active) @@ -478,6 +552,7 @@ pub enum ButtonState { Disabled, } +#[cfg(feature = "wayland")] impl ButtonState { fn from_sctk(button_state: SCTKButtonState) -> Self { match button_state { diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 4713038f..613d0e23 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -1,12 +1,27 @@ -#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] +#![cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] -use std::{collections::VecDeque, env, ffi::CStr, fmt, mem::MaybeUninit, os::raw::*, sync::Arc}; +#[cfg(all(not(feature = "x11"), not(feature = "wayland")))] +compile_error!("Please select a feature to build for unix: `x11`, `wayland`"); +use std::{collections::VecDeque, env, fmt}; +#[cfg(feature = "x11")] +use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Arc}; + +#[cfg(feature = "x11")] use parking_lot::Mutex; use raw_window_handle::RawWindowHandle; +#[cfg(feature = "wayland")] use smithay_client_toolkit::reexports::client::ConnectError; +#[cfg(feature = "x11")] pub use self::x11::XNotSupported; +#[cfg(feature = "x11")] use self::x11::{ffi::XVisualInfo, util::WindowType as XWindowType, XConnection, XError}; use crate::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, @@ -20,7 +35,9 @@ use crate::{ pub(crate) use crate::icon::RgbaIcon as PlatformIcon; +#[cfg(feature = "wayland")] pub mod wayland; +#[cfg(feature = "x11")] pub mod x11; /// Environment variable specifying which backend should be used on unix platform. @@ -34,33 +51,52 @@ const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND"; #[derive(Clone)] pub struct PlatformSpecificWindowBuilderAttributes { + #[cfg(feature = "x11")] pub visual_infos: Option, + #[cfg(feature = "x11")] pub screen_id: Option, + #[cfg(feature = "x11")] pub resize_increments: Option, + #[cfg(feature = "x11")] pub base_size: Option, + #[cfg(feature = "x11")] pub class: Option<(String, String)>, + #[cfg(feature = "x11")] pub override_redirect: bool, + #[cfg(feature = "x11")] pub x11_window_types: Vec, + #[cfg(feature = "x11")] pub gtk_theme_variant: Option, + #[cfg(feature = "wayland")] pub app_id: Option, } impl Default for PlatformSpecificWindowBuilderAttributes { fn default() -> Self { Self { + #[cfg(feature = "x11")] visual_infos: None, + #[cfg(feature = "x11")] screen_id: None, + #[cfg(feature = "x11")] resize_increments: None, + #[cfg(feature = "x11")] base_size: None, + #[cfg(feature = "x11")] class: None, + #[cfg(feature = "x11")] override_redirect: false, + #[cfg(feature = "x11")] x11_window_types: vec![XWindowType::Normal], + #[cfg(feature = "x11")] gtk_theme_variant: None, + #[cfg(feature = "wayland")] app_id: None, } } } +#[cfg(feature = "x11")] lazy_static! { pub static ref X11_BACKEND: Mutex, XNotSupported>> = Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)); @@ -68,141 +104,159 @@ lazy_static! { #[derive(Debug, Clone)] pub enum OsError { + #[cfg(feature = "x11")] XError(XError), + #[cfg(feature = "x11")] XMisc(&'static str), } impl fmt::Display for OsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match self { - OsError::XError(e) => f.pad(&e.description), - OsError::XMisc(e) => f.pad(e), + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + match *self { + #[cfg(feature = "x11")] + OsError::XError(ref e) => _f.pad(&e.description), + #[cfg(feature = "x11")] + OsError::XMisc(ref e) => _f.pad(e), } } } pub enum Window { + #[cfg(feature = "x11")] X(x11::Window), + #[cfg(feature = "wayland")] Wayland(wayland::Window), } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum WindowId { + #[cfg(feature = "x11")] X(x11::WindowId), + #[cfg(feature = "wayland")] Wayland(wayland::WindowId), } impl WindowId { pub unsafe fn dummy() -> Self { - WindowId::Wayland(wayland::WindowId::dummy()) + #[cfg(feature = "wayland")] + return WindowId::Wayland(wayland::WindowId::dummy()); + #[cfg(all(not(feature = "wayland"), feature = "x11"))] + return WindowId::X(x11::WindowId::dummy()); } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum DeviceId { + #[cfg(feature = "x11")] X(x11::DeviceId), + #[cfg(feature = "wayland")] Wayland(wayland::DeviceId), } impl DeviceId { pub unsafe fn dummy() -> Self { - DeviceId::Wayland(wayland::DeviceId::dummy()) + #[cfg(feature = "wayland")] + return DeviceId::Wayland(wayland::DeviceId::dummy()); + #[cfg(all(not(feature = "wayland"), feature = "x11"))] + return DeviceId::X(x11::DeviceId::dummy()); } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum MonitorHandle { + #[cfg(feature = "x11")] X(x11::MonitorHandle), + #[cfg(feature = "wayland")] Wayland(wayland::MonitorHandle), } +/// `x11_or_wayland!(match expr; Enum(foo) => foo.something())` +/// expands to the equivalent of +/// ```ignore +/// match self { +/// Enum::X(foo) => foo.something(), +/// Enum::Wayland(foo) => foo.something(), +/// } +/// ``` +/// The result can be converted to another enum by adding `; as AnotherEnum` +macro_rules! x11_or_wayland { + (match $what:expr; $enum:ident ( $($c1:tt)* ) => $x:expr; as $enum2:ident ) => { + match $what { + #[cfg(feature = "x11")] + $enum::X($($c1)*) => $enum2::X($x), + #[cfg(feature = "wayland")] + $enum::Wayland($($c1)*) => $enum2::Wayland($x), + } + }; + (match $what:expr; $enum:ident ( $($c1:tt)* ) => $x:expr) => { + match $what { + #[cfg(feature = "x11")] + $enum::X($($c1)*) => $x, + #[cfg(feature = "wayland")] + $enum::Wayland($($c1)*) => $x, + } + }; +} + impl MonitorHandle { #[inline] pub fn name(&self) -> Option { - match self { - &MonitorHandle::X(ref m) => m.name(), - &MonitorHandle::Wayland(ref m) => m.name(), - } + x11_or_wayland!(match self; MonitorHandle(m) => m.name()) } #[inline] pub fn native_identifier(&self) -> u32 { - match self { - &MonitorHandle::X(ref m) => m.native_identifier(), - &MonitorHandle::Wayland(ref m) => m.native_identifier(), - } + x11_or_wayland!(match self; MonitorHandle(m) => m.native_identifier()) } #[inline] pub fn size(&self) -> PhysicalSize { - match self { - &MonitorHandle::X(ref m) => m.size(), - &MonitorHandle::Wayland(ref m) => m.size(), - } + x11_or_wayland!(match self; MonitorHandle(m) => m.size()) } #[inline] pub fn position(&self) -> PhysicalPosition { - match self { - &MonitorHandle::X(ref m) => m.position(), - &MonitorHandle::Wayland(ref m) => m.position(), - } + x11_or_wayland!(match self; MonitorHandle(m) => m.position()) } #[inline] pub fn scale_factor(&self) -> f64 { - match self { - &MonitorHandle::X(ref m) => m.scale_factor(), - &MonitorHandle::Wayland(ref m) => m.scale_factor() as f64, - } + x11_or_wayland!(match self; MonitorHandle(m) => m.scale_factor() as f64) } #[inline] pub fn video_modes(&self) -> Box> { - match self { - MonitorHandle::X(m) => Box::new(m.video_modes()), - MonitorHandle::Wayland(m) => Box::new(m.video_modes()), - } + x11_or_wayland!(match self; MonitorHandle(m) => Box::new(m.video_modes())) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum VideoMode { + #[cfg(feature = "x11")] X(x11::VideoMode), + #[cfg(feature = "wayland")] Wayland(wayland::VideoMode), } impl VideoMode { #[inline] pub fn size(&self) -> PhysicalSize { - match self { - &VideoMode::X(ref m) => m.size(), - &VideoMode::Wayland(ref m) => m.size(), - } + x11_or_wayland!(match self; VideoMode(m) => m.size()) } #[inline] pub fn bit_depth(&self) -> u16 { - match self { - &VideoMode::X(ref m) => m.bit_depth(), - &VideoMode::Wayland(ref m) => m.bit_depth(), - } + x11_or_wayland!(match self; VideoMode(m) => m.bit_depth()) } #[inline] pub fn refresh_rate(&self) -> u16 { - match self { - &VideoMode::X(ref m) => m.refresh_rate(), - &VideoMode::Wayland(ref m) => m.refresh_rate(), - } + x11_or_wayland!(match self; VideoMode(m) => m.refresh_rate()) } #[inline] pub fn monitor(&self) -> RootMonitorHandle { - match self { - &VideoMode::X(ref m) => m.monitor(), - &VideoMode::Wayland(ref m) => m.monitor(), - } + x11_or_wayland!(match self; VideoMode(m) => m.monitor()) } } @@ -214,9 +268,11 @@ impl Window { pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { match *window_target { + #[cfg(feature = "wayland")] EventLoopWindowTarget::Wayland(ref window_target) => { wayland::Window::new(window_target, attribs, pl_attribs).map(Window::Wayland) } + #[cfg(feature = "x11")] EventLoopWindowTarget::X(ref window_target) => { x11::Window::new(window_target, attribs, pl_attribs).map(Window::X) } @@ -225,232 +281,166 @@ impl Window { #[inline] pub fn id(&self) -> WindowId { - match self { - &Window::X(ref w) => WindowId::X(w.id()), - &Window::Wayland(ref w) => WindowId::Wayland(w.id()), - } + x11_or_wayland!(match self; Window(w) => w.id(); as WindowId) } #[inline] pub fn set_title(&self, title: &str) { - match self { - &Window::X(ref w) => w.set_title(title), - &Window::Wayland(ref w) => w.set_title(title), - } + x11_or_wayland!(match self; Window(w) => w.set_title(title)); } #[inline] pub fn set_visible(&self, visible: bool) { - match self { - &Window::X(ref w) => w.set_visible(visible), - &Window::Wayland(ref w) => w.set_visible(visible), - } + x11_or_wayland!(match self; Window(w) => w.set_visible(visible)) } #[inline] pub fn outer_position(&self) -> Result, NotSupportedError> { - match self { - &Window::X(ref w) => w.outer_position(), - &Window::Wayland(ref w) => w.outer_position(), - } + x11_or_wayland!(match self; Window(w) => w.outer_position()) } #[inline] pub fn inner_position(&self) -> Result, NotSupportedError> { - match self { - &Window::X(ref m) => m.inner_position(), - &Window::Wayland(ref m) => m.inner_position(), - } + x11_or_wayland!(match self; Window(w) => w.inner_position()) } #[inline] pub fn set_outer_position(&self, position: Position) { - match self { - &Window::X(ref w) => w.set_outer_position(position), - &Window::Wayland(ref w) => w.set_outer_position(position), - } + x11_or_wayland!(match self; Window(w) => w.set_outer_position(position)) } #[inline] pub fn inner_size(&self) -> PhysicalSize { - match self { - &Window::X(ref w) => w.inner_size(), - &Window::Wayland(ref w) => w.inner_size(), - } + x11_or_wayland!(match self; Window(w) => w.inner_size()) } #[inline] pub fn outer_size(&self) -> PhysicalSize { - match self { - &Window::X(ref w) => w.outer_size(), - &Window::Wayland(ref w) => w.outer_size(), - } + x11_or_wayland!(match self; Window(w) => w.outer_size()) } #[inline] pub fn set_inner_size(&self, size: Size) { - match self { - &Window::X(ref w) => w.set_inner_size(size), - &Window::Wayland(ref w) => w.set_inner_size(size), - } + x11_or_wayland!(match self; Window(w) => w.set_inner_size(size)) } #[inline] pub fn set_min_inner_size(&self, dimensions: Option) { - match self { - &Window::X(ref w) => w.set_min_inner_size(dimensions), - &Window::Wayland(ref w) => w.set_min_inner_size(dimensions), - } + x11_or_wayland!(match self; Window(w) => w.set_min_inner_size(dimensions)) } #[inline] pub fn set_max_inner_size(&self, dimensions: Option) { - match self { - &Window::X(ref w) => w.set_max_inner_size(dimensions), - &Window::Wayland(ref w) => w.set_max_inner_size(dimensions), - } + x11_or_wayland!(match self; Window(w) => w.set_max_inner_size(dimensions)) } #[inline] pub fn set_resizable(&self, resizable: bool) { - match self { - &Window::X(ref w) => w.set_resizable(resizable), - &Window::Wayland(ref w) => w.set_resizable(resizable), - } + x11_or_wayland!(match self; Window(w) => w.set_resizable(resizable)) } #[inline] pub fn set_cursor_icon(&self, cursor: CursorIcon) { - match self { - &Window::X(ref w) => w.set_cursor_icon(cursor), - &Window::Wayland(ref w) => w.set_cursor_icon(cursor), - } + x11_or_wayland!(match self; Window(w) => w.set_cursor_icon(cursor)) } #[inline] pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { - match self { - &Window::X(ref window) => window.set_cursor_grab(grab), - &Window::Wayland(ref window) => window.set_cursor_grab(grab), - } + x11_or_wayland!(match self; Window(window) => window.set_cursor_grab(grab)) } #[inline] pub fn set_cursor_visible(&self, visible: bool) { - match self { - &Window::X(ref window) => window.set_cursor_visible(visible), - &Window::Wayland(ref window) => window.set_cursor_visible(visible), - } + x11_or_wayland!(match self; Window(window) => window.set_cursor_visible(visible)) } #[inline] pub fn scale_factor(&self) -> f64 { - match self { - &Window::X(ref w) => w.scale_factor(), - &Window::Wayland(ref w) => w.scale_factor() as f64, - } + x11_or_wayland!(match self; Window(w) => w.scale_factor() as f64) } #[inline] pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { - match self { - &Window::X(ref w) => w.set_cursor_position(position), - &Window::Wayland(ref w) => w.set_cursor_position(position), - } + x11_or_wayland!(match self; Window(w) => w.set_cursor_position(position)) } #[inline] pub fn set_maximized(&self, maximized: bool) { - match self { - &Window::X(ref w) => w.set_maximized(maximized), - &Window::Wayland(ref w) => w.set_maximized(maximized), - } + x11_or_wayland!(match self; Window(w) => w.set_maximized(maximized)) } #[inline] pub fn set_minimized(&self, minimized: bool) { - match self { - &Window::X(ref w) => w.set_minimized(minimized), - &Window::Wayland(ref w) => w.set_minimized(minimized), - } + x11_or_wayland!(match self; Window(w) => w.set_minimized(minimized)) } #[inline] pub fn fullscreen(&self) -> Option { - match self { - &Window::X(ref w) => w.fullscreen(), - &Window::Wayland(ref w) => w.fullscreen(), - } + x11_or_wayland!(match self; Window(w) => w.fullscreen()) } #[inline] pub fn set_fullscreen(&self, monitor: Option) { - match self { - &Window::X(ref w) => w.set_fullscreen(monitor), - &Window::Wayland(ref w) => w.set_fullscreen(monitor), - } + x11_or_wayland!(match self; Window(w) => w.set_fullscreen(monitor)) } #[inline] pub fn set_decorations(&self, decorations: bool) { + x11_or_wayland!(match self; Window(w) => w.set_decorations(decorations)) + } + + #[inline] + pub fn set_always_on_top(&self, _always_on_top: bool) { match self { - &Window::X(ref w) => w.set_decorations(decorations), - &Window::Wayland(ref w) => w.set_decorations(decorations), + #[cfg(feature = "x11")] + &Window::X(ref w) => w.set_always_on_top(_always_on_top), + #[cfg(feature = "wayland")] + _ => (), } } #[inline] - pub fn set_always_on_top(&self, always_on_top: bool) { + pub fn set_window_icon(&self, _window_icon: Option) { match self { - &Window::X(ref w) => w.set_always_on_top(always_on_top), - &Window::Wayland(_) => (), + #[cfg(feature = "x11")] + &Window::X(ref w) => w.set_window_icon(_window_icon), + #[cfg(feature = "wayland")] + _ => (), } } #[inline] - pub fn set_window_icon(&self, window_icon: Option) { + pub fn set_ime_position(&self, _position: Position) { match self { - &Window::X(ref w) => w.set_window_icon(window_icon), - &Window::Wayland(_) => (), - } - } - - #[inline] - pub fn set_ime_position(&self, position: Position) { - match self { - &Window::X(ref w) => w.set_ime_position(position), - &Window::Wayland(_) => (), + #[cfg(feature = "x11")] + &Window::X(ref w) => w.set_ime_position(_position), + #[cfg(feature = "wayland")] + _ => (), } } #[inline] pub fn request_redraw(&self) { - match self { - &Window::X(ref w) => w.request_redraw(), - &Window::Wayland(ref w) => w.request_redraw(), - } + x11_or_wayland!(match self; Window(w) => w.request_redraw()) } #[inline] pub fn current_monitor(&self) -> RootMonitorHandle { - match self { - &Window::X(ref window) => RootMonitorHandle { - inner: MonitorHandle::X(window.current_monitor()), - }, - &Window::Wayland(ref window) => RootMonitorHandle { - inner: MonitorHandle::Wayland(window.current_monitor()), - }, + RootMonitorHandle { + inner: x11_or_wayland!(match self; Window(window) => window.current_monitor(); as MonitorHandle), } } #[inline] pub fn available_monitors(&self) -> VecDeque { match self { + #[cfg(feature = "x11")] &Window::X(ref window) => window .available_monitors() .into_iter() .map(MonitorHandle::X) .collect(), + #[cfg(feature = "wayland")] &Window::Wayland(ref window) => window .available_monitors() .into_iter() @@ -461,20 +451,20 @@ impl Window { #[inline] pub fn primary_monitor(&self) -> MonitorHandle { - match self { - &Window::X(ref window) => MonitorHandle::X(window.primary_monitor()), - &Window::Wayland(ref window) => MonitorHandle::Wayland(window.primary_monitor()), - } + x11_or_wayland!(match self; Window(window) => window.primary_monitor(); as MonitorHandle) } pub fn raw_window_handle(&self) -> RawWindowHandle { match self { + #[cfg(feature = "x11")] &Window::X(ref window) => RawWindowHandle::Xlib(window.raw_window_handle()), + #[cfg(feature = "wayland")] &Window::Wayland(ref window) => RawWindowHandle::Wayland(window.raw_window_handle()), } } } +#[cfg(feature = "x11")] unsafe extern "C" fn x_error_callback( display: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent, @@ -508,21 +498,22 @@ unsafe extern "C" fn x_error_callback( } pub enum EventLoop { + #[cfg(feature = "wayland")] Wayland(wayland::EventLoop), + #[cfg(feature = "x11")] X(x11::EventLoop), } pub enum EventLoopProxy { + #[cfg(feature = "x11")] X(x11::EventLoopProxy), + #[cfg(feature = "wayland")] Wayland(wayland::EventLoopProxy), } impl Clone for EventLoopProxy { fn clone(&self) -> Self { - match self { - EventLoopProxy::X(proxy) => EventLoopProxy::X(proxy.clone()), - EventLoopProxy::Wayland(proxy) => EventLoopProxy::Wayland(proxy.clone()), - } + x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.clone(); as EventLoopProxy) } } @@ -538,12 +529,18 @@ impl EventLoop { match env_var.as_str() { "x11" => { // TODO: propagate + #[cfg(feature = "x11")] return EventLoop::new_x11_any_thread() .expect("Failed to initialize X11 backend"); + #[cfg(not(feature = "x11"))] + panic!("x11 feature is not enabled") } "wayland" => { + #[cfg(feature = "wayland")] return EventLoop::new_wayland_any_thread() .expect("Failed to initialize Wayland backend"); + #[cfg(not(feature = "wayland"))] + panic!("wayland feature is not enabled"); } _ => panic!( "Unknown environment variable value for {}, try one of `x11`,`wayland`", @@ -552,16 +549,23 @@ impl EventLoop { } } + #[cfg(feature = "wayland")] let wayland_err = match EventLoop::new_wayland_any_thread() { Ok(event_loop) => return event_loop, Err(err) => err, }; + #[cfg(feature = "x11")] let x11_err = match EventLoop::new_x11_any_thread() { Ok(event_loop) => return event_loop, Err(err) => err, }; + #[cfg(not(feature = "wayland"))] + let wayland_err = "backend disabled"; + #[cfg(not(feature = "x11"))] + let x11_err = "backend disabled"; + let err_string = format!( "Failed to initialize any backend! Wayland status: {:?} X11 status: {:?}", wayland_err, x11_err, @@ -569,22 +573,26 @@ impl EventLoop { panic!(err_string); } + #[cfg(feature = "wayland")] pub fn new_wayland() -> Result, ConnectError> { assert_is_main_thread("new_wayland_any_thread"); EventLoop::new_wayland_any_thread() } + #[cfg(feature = "wayland")] pub fn new_wayland_any_thread() -> Result, ConnectError> { wayland::EventLoop::new().map(EventLoop::Wayland) } + #[cfg(feature = "x11")] pub fn new_x11() -> Result, XNotSupported> { assert_is_main_thread("new_x11_any_thread"); EventLoop::new_x11_any_thread() } + #[cfg(feature = "x11")] pub fn new_x11_any_thread() -> Result, XNotSupported> { let xconn = match X11_BACKEND.lock().as_ref() { Ok(xconn) => xconn.clone(), @@ -597,11 +605,13 @@ impl EventLoop { #[inline] pub fn available_monitors(&self) -> VecDeque { match *self { + #[cfg(feature = "wayland")] EventLoop::Wayland(ref evlp) => evlp .available_monitors() .into_iter() .map(MonitorHandle::Wayland) .collect(), + #[cfg(feature = "x11")] EventLoop::X(ref evlp) => evlp .x_connection() .available_monitors() @@ -614,57 +624,46 @@ impl EventLoop { #[inline] pub fn primary_monitor(&self) -> MonitorHandle { match *self { + #[cfg(feature = "wayland")] EventLoop::Wayland(ref evlp) => MonitorHandle::Wayland(evlp.primary_monitor()), + #[cfg(feature = "x11")] EventLoop::X(ref evlp) => MonitorHandle::X(evlp.x_connection().primary_monitor()), } } pub fn create_proxy(&self) -> EventLoopProxy { - match *self { - EventLoop::Wayland(ref evlp) => EventLoopProxy::Wayland(evlp.create_proxy()), - EventLoop::X(ref evlp) => EventLoopProxy::X(evlp.create_proxy()), - } + x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy) } pub fn run_return(&mut self, callback: F) where F: FnMut(crate::event::Event<'_, T>, &RootELW, &mut ControlFlow), { - match *self { - EventLoop::Wayland(ref mut evlp) => evlp.run_return(callback), - EventLoop::X(ref mut evlp) => evlp.run_return(callback), - } + x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_return(callback)) } pub fn run(self, callback: F) -> ! where F: 'static + FnMut(crate::event::Event<'_, T>, &RootELW, &mut ControlFlow), { - match self { - EventLoop::Wayland(evlp) => evlp.run(callback), - EventLoop::X(evlp) => evlp.run(callback), - } + x11_or_wayland!(match self; EventLoop(evlp) => evlp.run(callback)) } pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget { - match *self { - EventLoop::Wayland(ref evl) => evl.window_target(), - EventLoop::X(ref evl) => evl.window_target(), - } + x11_or_wayland!(match self; EventLoop(evl) => evl.window_target()) } } impl EventLoopProxy { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { - match *self { - EventLoopProxy::Wayland(ref proxy) => proxy.send_event(event), - EventLoopProxy::X(ref proxy) => proxy.send_event(event), - } + x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.send_event(event)) } } pub enum EventLoopWindowTarget { + #[cfg(feature = "wayland")] Wayland(wayland::EventLoopWindowTarget), + #[cfg(feature = "x11")] X(x11::EventLoopWindowTarget), } @@ -672,8 +671,10 @@ impl EventLoopWindowTarget { #[inline] pub fn is_wayland(&self) -> bool { match *self { + #[cfg(feature = "wayland")] EventLoopWindowTarget::Wayland(_) => true, - EventLoopWindowTarget::X(_) => false, + #[cfg(feature = "x11")] + _ => false, } } } diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index 3262fe1e..737fcc78 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -554,6 +554,7 @@ impl EventLoop { let instant_wakeup = { let window_target = match self.window_target.p { crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, + #[cfg(feature = "x11")] _ => unreachable!(), }; let dispatched = window_target @@ -662,6 +663,7 @@ impl EventLoop { { let window_target = match self.window_target.p { crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, + #[cfg(feature = "x11")] _ => unreachable!(), }; window_target.store.lock().unwrap().for_each_redraw_trigger( @@ -689,6 +691,7 @@ impl EventLoop { { let window_target = match self.window_target.p { crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, + #[cfg(feature = "x11")] _ => unreachable!(), }; @@ -803,6 +806,7 @@ impl EventLoop { fn get_target(target: &RootELW) -> &EventLoopWindowTarget { match target.p { crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt, + #[cfg(feature = "x11")] _ => unreachable!(), } } diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index 5b680999..a0be1e9d 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -158,6 +158,7 @@ impl Window { Some(Fullscreen::Borderless(RootMonitorHandle { inner: PlatformMonitorHandle::Wayland(ref monitor_id), })) => frame.set_fullscreen(Some(&monitor_id.proxy)), + #[cfg(feature = "x11")] Some(Fullscreen::Borderless(_)) => unreachable!(), None => { if attributes.maximized { @@ -354,6 +355,7 @@ impl Window { .unwrap() .set_fullscreen(Some(&monitor_id.proxy)); } + #[cfg(feature = "x11")] Some(Fullscreen::Borderless(_)) => unreachable!(), None => self.frame.lock().unwrap().unset_fullscreen(), } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 93a386f2..186e9c01 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -426,6 +426,7 @@ impl EventLoop { pub(crate) fn get_xtarget(target: &RootELW) -> &EventLoopWindowTarget { match target.p { super::EventLoopWindowTarget::X(ref target) => target, + #[cfg(feature = "wayland")] _ => unreachable!(), } } @@ -493,9 +494,21 @@ impl<'a> Deref for DeviceInfo<'a> { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId(ffi::Window); +impl WindowId { + pub unsafe fn dummy() -> Self { + WindowId(0) + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId(c_int); +impl DeviceId { + pub unsafe fn dummy() -> Self { + DeviceId(0) + } +} + pub struct Window(Arc); impl Deref for Window { diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index f4cb3d45..a7e31980 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -653,6 +653,7 @@ impl UnownedWindow { Fullscreen::Borderless(RootMonitorHandle { inner: PlatformMonitorHandle::X(ref monitor), }) => (None, monitor), + #[cfg(feature = "wayland")] _ => unreachable!(), };