diff --git a/src/lib.rs b/src/lib.rs index 03825e61..55e92c4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! Winit allows you to build a window on as many platforms as possible. +//! Winit allows you to build a window on as many platforms as possible. //! //! # Building a window //! @@ -181,6 +181,14 @@ pub struct ButtonId(u32); /// Provides a way to retreive events from the windows that were registered to it. /// /// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs. +/// +/// Usage will result in display backend initialisation, this can be controlled on linux +/// using an environment variable `WINIT_UNIX_BACKEND`. +/// > Legal values are `x11` and `wayland`. If this variable is set only the named backend +/// > will be tried by winit. If it is not set, winit will try to connect to a wayland connection, +/// > and if it fails will fallback on x11. +/// > +/// > If this variable is set with any other value, winit will panic. pub struct EventsLoop { events_loop: platform::EventsLoop, } diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 6bc4719d..af431a10 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -2,6 +2,7 @@ use std::collections::VecDeque; use std::sync::Arc; +use std::env; use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow}; use libc; @@ -15,6 +16,15 @@ mod dlopen; pub mod wayland; pub mod x11; +/// Environment variable specifying which backend should be used on unix platform. +/// +/// Legal values are x11 and wayland. If this variable is set only the named backend +/// will be tried by winit. If it is not set, winit will try to connect to a wayland connection, +/// and if it fails will fallback on x11. +/// +/// If this variable is set with any other value, winit will panic. +const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND"; + #[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes { pub visual_infos: Option, @@ -24,19 +34,42 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub enum UnixBackend { X(Arc), Wayland(Arc), - Error(XNotSupported), -} + Error(Option, Option), +} lazy_static!( pub static ref UNIX_BACKEND: UnixBackend = { - if let Some(ctxt) = wayland::WaylandContext::init() { - UnixBackend::Wayland(Arc::new(ctxt)) - } else { + #[inline] + fn x_backend() -> Result { match XConnection::new(Some(x_error_callback)) { - Ok(x) => UnixBackend::X(Arc::new(x)), - Err(e) => UnixBackend::Error(e), + Ok(x) => Ok(UnixBackend::X(Arc::new(x))), + Err(e) => Err(e), } } + #[inline] + fn wayland_backend() -> Result { + wayland::WaylandContext::init() + .map(|ctx| UnixBackend::Wayland(Arc::new(ctx))) + .ok_or(()) + } + match env::var(BACKEND_PREFERENCE_ENV_VAR) { + Ok(s) => match s.as_str() { + "x11" => x_backend().unwrap_or_else(|e| UnixBackend::Error(Some(e), None)), + "wayland" => wayland_backend().unwrap_or_else(|_| { + UnixBackend::Error(None, Some("Wayland not available".into())) + }), + _ => panic!("Unknown environment variable value for {}, try one of `x11`,`wayland`", + BACKEND_PREFERENCE_ENV_VAR), + }, + Err(_) => { + // Try wayland, fallback to X11 + wayland_backend().unwrap_or_else(|_| { + x_backend().unwrap_or_else(|x_err| { + UnixBackend::Error(Some(x_err), Some("Wayland not available".into())) + }) + }) + }, + } }; ); @@ -85,7 +118,7 @@ pub fn get_available_monitors() -> VecDeque { .into_iter() .map(MonitorId::X) .collect(), - UnixBackend::Error(_) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d}, + UnixBackend::Error(..) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d}, } } @@ -94,7 +127,7 @@ pub fn get_primary_monitor() -> MonitorId { match *UNIX_BACKEND { UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)), UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)), - UnixBackend::Error(_) => MonitorId::None, + UnixBackend::Error(..) => MonitorId::None, } } @@ -147,7 +180,7 @@ impl Window2 { UnixBackend::X(_) => { x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X) }, - UnixBackend::Error(_) => { + UnixBackend::Error(..) => { // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all, // thus this function cannot be called! unreachable!() @@ -324,7 +357,7 @@ impl EventsLoop { EventsLoop::X(x11::EventsLoop::new(ctxt.clone())) }, - UnixBackend::Error(_) => { + UnixBackend::Error(..) => { panic!("Attempted to create an EventsLoop while no backend was available.") } } diff --git a/src/window.rs b/src/window.rs index 94c677b0..d93ee470 100644 --- a/src/window.rs +++ b/src/window.rs @@ -30,7 +30,7 @@ impl WindowBuilder { self.window.dimensions = Some((width, height)); self } - + /// Sets a minimum dimension size for the window /// /// Width and height are in pixels. @@ -197,7 +197,7 @@ impl Window { pub fn get_inner_size(&self) -> Option<(u32, u32)> { self.window.get_inner_size() } - + /// Returns the size in points of the client area of the window. /// /// The client area is the content of the window, excluding the title bar and borders. @@ -320,6 +320,14 @@ impl Iterator for AvailableMonitorsIter { } /// Returns the list of all available monitors. +/// +/// Usage will result in display backend initialisation, this can be controlled on linux +/// using an environment variable `WINIT_UNIX_BACKEND`. +/// > Legal values are `x11` and `wayland`. If this variable is set only the named backend +/// > will be tried by winit. If it is not set, winit will try to connect to a wayland connection, +/// > and if it fails will fallback on x11. +/// > +/// > If this variable is set with any other value, winit will panic. #[inline] pub fn get_available_monitors() -> AvailableMonitorsIter { let data = platform::get_available_monitors(); @@ -327,6 +335,14 @@ pub fn get_available_monitors() -> AvailableMonitorsIter { } /// Returns the primary monitor of the system. +/// +/// Usage will result in display backend initialisation, this can be controlled on linux +/// using an environment variable `WINIT_UNIX_BACKEND`. +/// > Legal values are `x11` and `wayland`. If this variable is set only the named backend +/// > will be tried by winit. If it is not set, winit will try to connect to a wayland connection, +/// > and if it fails will fallback on x11. +/// > +/// > If this variable is set with any other value, winit will panic. #[inline] pub fn get_primary_monitor() -> MonitorId { MonitorId(platform::get_primary_monitor())