Skip to content

Commit

Permalink
Merge pull request #199 from alexheretic/xwayland-env-var
Browse files Browse the repository at this point in the history
Add a `WINIT_UNIX_BACKEND` environment variable to all the user to control the choice of x11/wayland backend.
  • Loading branch information
vberger authored Jun 25, 2017
2 parents 09d0867 + 3a89843 commit 05cd9f2
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 14 deletions.
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
//!
Expand Down Expand Up @@ -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,
}
Expand Down
55 changes: 44 additions & 11 deletions src/platform/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::collections::VecDeque;
use std::sync::Arc;
use std::env;

use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc;
Expand All @@ -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<XVisualInfo>,
Expand All @@ -24,19 +34,42 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub enum UnixBackend {
X(Arc<XConnection>),
Wayland(Arc<wayland::WaylandContext>),
Error(XNotSupported),
}
Error(Option<XNotSupported>, Option<String>),
}

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<UnixBackend, XNotSupported> {
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<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()))
})
})
},
}
};
);

Expand Down Expand Up @@ -85,7 +118,7 @@ pub fn get_available_monitors() -> VecDeque<MonitorId> {
.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},
}
}

Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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!()
Expand Down Expand Up @@ -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.")
}
}
Expand Down
20 changes: 18 additions & 2 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -320,13 +320,29 @@ 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();
AvailableMonitorsIter{ data: data.into_iter() }
}

/// 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())
Expand Down

0 comments on commit 05cd9f2

Please sign in to comment.