From 9804cad7dd86a3661bc9f3996f8fc1a84e7af5ab Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Wed, 21 Jun 2017 18:34:16 +0100 Subject: [PATCH 1/5] Allow usage of XWayland Will prefer X11 over wayland when the environment variable `WINIT_PREFER_UNIX_BACKEND=x11` is set. --- src/platform/linux/mod.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 6bc4719d..f914a2b0 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,10 @@ mod dlopen; pub mod wayland; pub mod x11; +/// Environment variable that indicates the X11 backend should be used +/// even if Wayland is available. In this case XWayland will be used. +const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_PREFER_UNIX_BACKEND"; + #[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes { pub visual_infos: Option, @@ -25,18 +30,30 @@ pub enum UnixBackend { X(Arc), Wayland(Arc), Error(XNotSupported), -} +} 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() -> UnixBackend { match XConnection::new(Some(x_error_callback)) { Ok(x) => UnixBackend::X(Arc::new(x)), Err(e) => UnixBackend::Error(e), } } + match env::var(BACKEND_PREFERENCE_ENV_VAR) { + Ok(ref s) if s == "x11" => { + println!("{}: using x11 backend", BACKEND_PREFERENCE_ENV_VAR); + x_backend() + }, + _ => { + if let Some(ctxt) = wayland::WaylandContext::init() { + UnixBackend::Wayland(Arc::new(ctxt)) + } else { + x_backend() + } + }, + } }; ); From 7a19ef19071df84fdc47bc9e4f4438373cac44ae Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Wed, 21 Jun 2017 19:41:26 +0100 Subject: [PATCH 2/5] Make usage of env vars strict Using `BACKEND_PREFERENCE_ENV_VAR=$backend` will no longer fallback on any other backend --- src/platform/linux/mod.rs | 45 ++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index f914a2b0..9daae7d4 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -29,29 +29,40 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub enum UnixBackend { X(Arc), Wayland(Arc), - Error(XNotSupported), + Error(Option, Option), } lazy_static!( pub static ref UNIX_BACKEND: UnixBackend = { #[inline] - fn x_backend() -> UnixBackend { + 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(ref s) if s == "x11" => { - println!("{}: using x11 backend", BACKEND_PREFERENCE_ENV_VAR); - x_backend() + 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), }, - _ => { - if let Some(ctxt) = wayland::WaylandContext::init() { - UnixBackend::Wayland(Arc::new(ctxt)) - } else { - x_backend() - } + 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())) + }) + }) }, } }; @@ -102,7 +113,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}, } } @@ -111,7 +122,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, } } @@ -164,7 +175,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!() @@ -341,7 +352,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.") } } From 789598fa84256b7a38ebfdaabb0a33c9c65e97f5 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Wed, 21 Jun 2017 19:54:21 +0100 Subject: [PATCH 3/5] Rename unix backend env var Rename inline with stricter behaviour Add docs explaining behaviour --- src/platform/linux/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 9daae7d4..2b8e53cd 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -16,9 +16,12 @@ mod dlopen; pub mod wayland; pub mod x11; -/// Environment variable that indicates the X11 backend should be used -/// even if Wayland is available. In this case XWayland will be used. -const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_PREFER_UNIX_BACKEND"; +/// Environment variable that indicates a backend preference +/// `WINIT_UNIX_BACKEND=x11` : Will try to use an X11 backend +/// `WINIT_UNIX_BACKEND=wayland` : Will try to use a wayland backend +/// When used is selected backends will not fallback to one another +/// (Current default behaviour is wayland, fallback to X) +const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND"; #[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes { From eaa92a428263832d01ebd8cf1b486b5cc0b2d708 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Wed, 21 Jun 2017 19:59:56 +0100 Subject: [PATCH 4/5] Improve unix backend env var docs --- src/platform/linux/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 2b8e53cd..909ca1e3 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -19,8 +19,8 @@ pub mod x11; /// Environment variable that indicates a backend preference /// `WINIT_UNIX_BACKEND=x11` : Will try to use an X11 backend /// `WINIT_UNIX_BACKEND=wayland` : Will try to use a wayland backend -/// When used is selected backends will not fallback to one another -/// (Current default behaviour is wayland, fallback to X) +/// When the variable is present the indicated backend will not fallback to another +/// (Current default behaviour, without the env var, is try wayland then fallback to X) const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND"; #[derive(Clone, Default)] From 3a898437671796e865db8b7ba37dd90ce8f2fbed Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Wed, 21 Jun 2017 20:10:23 +0100 Subject: [PATCH 5/5] Add `WINIT_UNIX_BACKEND` documentation --- src/lib.rs | 10 +++++++++- src/platform/linux/mod.rs | 12 +++++++----- src/window.rs | 20 ++++++++++++++++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d4b91c40..291bfb37 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 909ca1e3..af431a10 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -16,11 +16,13 @@ mod dlopen; pub mod wayland; pub mod x11; -/// Environment variable that indicates a backend preference -/// `WINIT_UNIX_BACKEND=x11` : Will try to use an X11 backend -/// `WINIT_UNIX_BACKEND=wayland` : Will try to use a wayland backend -/// When the variable is present the indicated backend will not fallback to another -/// (Current default behaviour, without the env var, is try wayland then fallback to X) +/// 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)] 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())