Merge pull request #199 from alexheretic/xwayland-env-var

Add a `WINIT_UNIX_BACKEND` environment variable to all the user to control the choice of x11/wayland backend.
This commit is contained in:
Victor Berger 2017-06-25 10:40:05 +02:00 committed by GitHub
commit 05cd9f2114
3 changed files with 71 additions and 14 deletions

View file

@ -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 //! # 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. /// 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. /// 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 { pub struct EventsLoop {
events_loop: platform::EventsLoop, events_loop: platform::EventsLoop,
} }

View file

@ -2,6 +2,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::Arc; use std::sync::Arc;
use std::env;
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow}; use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc; use libc;
@ -15,6 +16,15 @@ mod dlopen;
pub mod wayland; pub mod wayland;
pub mod x11; 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)] #[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes { pub struct PlatformSpecificWindowBuilderAttributes {
pub visual_infos: Option<XVisualInfo>, pub visual_infos: Option<XVisualInfo>,
@ -24,19 +34,42 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub enum UnixBackend { pub enum UnixBackend {
X(Arc<XConnection>), X(Arc<XConnection>),
Wayland(Arc<wayland::WaylandContext>), Wayland(Arc<wayland::WaylandContext>),
Error(XNotSupported), Error(Option<XNotSupported>, Option<String>),
} }
lazy_static!( lazy_static!(
pub static ref UNIX_BACKEND: UnixBackend = { pub static ref UNIX_BACKEND: UnixBackend = {
if let Some(ctxt) = wayland::WaylandContext::init() { #[inline]
UnixBackend::Wayland(Arc::new(ctxt)) fn x_backend() -> Result<UnixBackend, XNotSupported> {
} else {
match XConnection::new(Some(x_error_callback)) { match XConnection::new(Some(x_error_callback)) {
Ok(x) => UnixBackend::X(Arc::new(x)), Ok(x) => Ok(UnixBackend::X(Arc::new(x))),
Err(e) => UnixBackend::Error(e), Err(e) => Err(e),
} }
} }
#[inline]
fn wayland_backend() -> Result<UnixBackend, ()> {
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<MonitorId> {
.into_iter() .into_iter()
.map(MonitorId::X) .map(MonitorId::X)
.collect(), .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 { match *UNIX_BACKEND {
UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)), UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)), 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(_) => { UnixBackend::X(_) => {
x11::Window2::new(events_loop, window, pl_attribs).map(Window2::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, // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
// thus this function cannot be called! // thus this function cannot be called!
unreachable!() unreachable!()
@ -324,7 +357,7 @@ impl EventsLoop {
EventsLoop::X(x11::EventsLoop::new(ctxt.clone())) EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
}, },
UnixBackend::Error(_) => { UnixBackend::Error(..) => {
panic!("Attempted to create an EventsLoop while no backend was available.") panic!("Attempted to create an EventsLoop while no backend was available.")
} }
} }

View file

@ -30,7 +30,7 @@ impl WindowBuilder {
self.window.dimensions = Some((width, height)); self.window.dimensions = Some((width, height));
self self
} }
/// Sets a minimum dimension size for the window /// Sets a minimum dimension size for the window
/// ///
/// Width and height are in pixels. /// Width and height are in pixels.
@ -197,7 +197,7 @@ impl Window {
pub fn get_inner_size(&self) -> Option<(u32, u32)> { pub fn get_inner_size(&self) -> Option<(u32, u32)> {
self.window.get_inner_size() self.window.get_inner_size()
} }
/// Returns the size in points of the client area of the window. /// 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. /// 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. /// 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] #[inline]
pub fn get_available_monitors() -> AvailableMonitorsIter { pub fn get_available_monitors() -> AvailableMonitorsIter {
let data = platform::get_available_monitors(); let data = platform::get_available_monitors();
@ -327,6 +335,14 @@ pub fn get_available_monitors() -> AvailableMonitorsIter {
} }
/// Returns the primary monitor of the system. /// 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] #[inline]
pub fn get_primary_monitor() -> MonitorId { pub fn get_primary_monitor() -> MonitorId {
MonitorId(platform::get_primary_monitor()) MonitorId(platform::get_primary_monitor())