From 310b44f35be8146623d8e5fbbe380ae14f30de72 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Tue, 12 May 2015 22:47:34 +0200 Subject: Make platform::linux generic over X11 and Wayland. --- src/api/glx/mod.rs | 11 +- src/api/wayland/mod.rs | 4 + src/api/x11/mod.rs | 12 +- src/platform/linux/api_dispatch.rs | 324 +++++++++++++++++++++++++++++++++++++ src/platform/linux/mod.rs | 6 +- 5 files changed, 347 insertions(+), 10 deletions(-) create mode 100644 src/platform/linux/api_dispatch.rs diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs index 9cda90e..3c0c8a0 100644 --- a/src/api/glx/mod.rs +++ b/src/api/glx/mod.rs @@ -14,6 +14,8 @@ use std::{mem, ptr}; use api::x11::ffi; +use platform::Window as PlatformWindow; + pub struct Context { glx: ffi::glx::Glx, display: *mut ffi::Display, @@ -80,9 +82,12 @@ impl Context { }); let share = if let Some(win) = builder.sharing { - match win.x.context { - ::api::x11::Context::Glx(ref c) => c.context, - _ => panic!("Cannot share contexts between different APIs") + match win { + &PlatformWindow::X(ref win) => match win.x.context { + ::api::x11::Context::Glx(ref c) => c.context, + _ => panic!("Cannot share contexts between different APIs") + }, + _ => panic!("Cannot use glx on a non-X11 window.") } } else { ptr::null() diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs index f70d62e..4fd0357 100644 --- a/src/api/wayland/mod.rs +++ b/src/api/wayland/mod.rs @@ -147,6 +147,10 @@ lazy_static! { }; } +pub fn is_available() -> bool { + WAYLAND_CONTEXT.is_some() +} + pub struct Window { shell_surface: ShellSurface, pending_events: Arc>>, diff --git a/src/api/x11/mod.rs b/src/api/x11/mod.rs index 0dcf85b..30adadc 100644 --- a/src/api/x11/mod.rs +++ b/src/api/x11/mod.rs @@ -21,6 +21,8 @@ use api::dlopen; use api::glx::Context as GlxContext; use api::egl::Context as EglContext; +use platform::MonitorID as PlatformMonitorID; + pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; mod events; @@ -310,9 +312,9 @@ pub struct Window { impl Window { pub fn new(builder: BuilderAttribs) -> Result { - let xlib = ffi::Xlib::open().unwrap(); // FIXME: gracious handling - let xcursor = ffi::Xcursor::open().unwrap(); // FIXME: gracious handling - let xf86vmode = ffi::Xf86vmode::open().unwrap(); // FIXME: gracious handling + let xlib = try!(ffi::Xlib::open().map_err(|_| CreationError::NotSupported)); + let xcursor = try!(ffi::Xcursor::open().map_err(|_| CreationError::NotSupported)); + let xf86vmode = try!(ffi::Xf86vmode::open().map_err(|_| CreationError::NotSupported)); let glx = { let mut libglx = unsafe { dlopen::dlopen(b"libGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW) }; @@ -342,8 +344,8 @@ impl Window { }; let screen_id = match builder.monitor { - Some(MonitorID(monitor)) => monitor as i32, - None => unsafe { (xlib.XDefaultScreen)(display) }, + Some(PlatformMonitorID::X(MonitorID(monitor))) => monitor as i32, + _ => unsafe { (xlib.XDefaultScreen)(display) }, }; // getting the FBConfig diff --git a/src/platform/linux/api_dispatch.rs b/src/platform/linux/api_dispatch.rs new file mode 100644 index 0000000..c77c464 --- /dev/null +++ b/src/platform/linux/api_dispatch.rs @@ -0,0 +1,324 @@ +/*#[cfg(feature = "window")] +pub use api::x11::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor}; +#[cfg(feature = "window")] +pub use api::x11::{WaitEventsIterator, PollEventsIterator};*/ + +use std::collections::VecDeque; + +use BuilderAttribs; +use CreationError; +use CursorState; +use Event; +use GlContext; +use MouseCursor; +use PixelFormat; +use libc; + +use api::wayland; +use api::x11; + +pub enum Window { + #[doc(hidden)] + X(x11::Window), + #[doc(hidden)] + Wayland(wayland::Window) +} + +#[derive(Clone)] +pub enum WindowProxy { + #[doc(hidden)] + X(x11::WindowProxy), + #[doc(hidden)] + Wayland(wayland::WindowProxy) +} + +impl WindowProxy { + pub fn wakeup_event_loop(&self) { + match self { + &WindowProxy::X(ref wp) => wp.wakeup_event_loop(), + &WindowProxy::Wayland(ref wp) => wp.wakeup_event_loop() + } + } +} + +pub enum MonitorID { + #[doc(hidden)] + X(x11::MonitorID), + #[doc(hidden)] + Wayland(wayland::MonitorID) +} + +pub fn get_available_monitors() -> VecDeque { + if wayland::is_available() { + // We are doing wayland + wayland::get_available_monitors() + .into_iter() + .map(|m| MonitorID::Wayland(m)) + .collect() + } else { + // Fallback on X + x11::get_available_monitors() + .into_iter() + .map(|m| MonitorID::X(m)) + .collect() + } +} +pub fn get_primary_monitor() -> MonitorID { + if wayland::is_available() { + MonitorID::Wayland(wayland::get_primary_monitor()) + } else { + MonitorID::X(x11::get_primary_monitor()) + } +} + +impl MonitorID { + pub fn get_name(&self) -> Option { + match self { + &MonitorID::X(ref m) => m.get_name(), + &MonitorID::Wayland(ref m) => m.get_name() + } + } + + pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId { + match self { + &MonitorID::X(ref m) => m.get_native_identifier(), + &MonitorID::Wayland(ref m) => m.get_native_identifier() + } + } + + pub fn get_dimensions(&self) -> (u32, u32) { + match self { + &MonitorID::X(ref m) => m.get_dimensions(), + &MonitorID::Wayland(ref m) => m.get_dimensions() + } + } +} + + +pub enum PollEventsIterator<'a> { + #[doc(hidden)] + X(x11::PollEventsIterator<'a>), + #[doc(hidden)] + Wayland(wayland::PollEventsIterator<'a>) +} + +impl<'a> Iterator for PollEventsIterator<'a> { + type Item = Event; + + fn next(&mut self) -> Option { + match self { + &mut PollEventsIterator::X(ref mut it) => it.next(), + &mut PollEventsIterator::Wayland(ref mut it) => it.next() + } + } +} + +pub enum WaitEventsIterator<'a> { + #[doc(hidden)] + X(x11::WaitEventsIterator<'a>), + #[doc(hidden)] + Wayland(wayland::WaitEventsIterator<'a>) +} + +impl<'a> Iterator for WaitEventsIterator<'a> { + type Item = Event; + + fn next(&mut self) -> Option { + match self { + &mut WaitEventsIterator::X(ref mut it) => it.next(), + &mut WaitEventsIterator::Wayland(ref mut it) => it.next() + } + } +} + +impl Window { + pub fn new(builder: BuilderAttribs) -> Result { + if wayland::is_available() { + // we have a wayland connection, go for it + let window = try!(wayland::Window::new(builder)); + Ok(Window::Wayland(window)) + } else { + // fallback on X + let window = try!(x11::Window::new(builder)); + Ok(Window::X(window)) + } + } + + pub fn is_closed(&self) -> bool { + match self { + &Window::X(ref w) => w.is_closed(), + &Window::Wayland(ref w) => w.is_closed() + } + } + + 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) + } + } + + pub fn show(&self) { + match self { + &Window::X(ref w) => w.show(), + &Window::Wayland(ref w) => w.show() + } + } + + pub fn hide(&self) { + match self { + &Window::X(ref w) => w.hide(), + &Window::Wayland(ref w) => w.hide() + } + } + + pub fn get_position(&self) -> Option<(i32, i32)> { + match self { + &Window::X(ref w) => w.get_position(), + &Window::Wayland(ref w) => w.get_position() + } + } + + pub fn set_position(&self, x: i32, y: i32) { + match self { + &Window::X(ref w) => w.set_position(x, y), + &Window::Wayland(ref w) => w.set_position(x, y) + } + } + + pub fn get_inner_size(&self) -> Option<(u32, u32)> { + match self { + &Window::X(ref w) => w.get_inner_size(), + &Window::Wayland(ref w) => w.get_inner_size() + } + } + + pub fn get_outer_size(&self) -> Option<(u32, u32)> { + match self { + &Window::X(ref w) => w.get_outer_size(), + &Window::Wayland(ref w) => w.get_outer_size() + } + } + + pub fn set_inner_size(&self, x: u32, y: u32) { + match self { + &Window::X(ref w) => w.set_inner_size(x, y), + &Window::Wayland(ref w) => w.set_inner_size(x, y) + } + } + + pub fn create_window_proxy(&self) -> WindowProxy { + match self { + &Window::X(ref w) => WindowProxy::X(w.create_window_proxy()), + &Window::Wayland(ref w) => WindowProxy::Wayland(w.create_window_proxy()) + } + } + + pub fn poll_events(&self) -> PollEventsIterator { + match self { + &Window::X(ref w) => PollEventsIterator::X(w.poll_events()), + &Window::Wayland(ref w) => PollEventsIterator::Wayland(w.poll_events()) + } + } + + pub fn wait_events(&self) -> WaitEventsIterator { + match self { + &Window::X(ref w) => WaitEventsIterator::X(w.wait_events()), + &Window::Wayland(ref w) => WaitEventsIterator::Wayland(w.wait_events()) + } + } + + pub fn set_window_resize_callback(&mut self, callback: Option) { + match self { + &mut Window::X(ref mut w) => w.set_window_resize_callback(callback), + &mut Window::Wayland(ref mut w) => w.set_window_resize_callback(callback) + } + } + + pub fn set_cursor(&self, cursor: MouseCursor) { + match self { + &Window::X(ref w) => w.set_cursor(cursor), + &Window::Wayland(ref w) => w.set_cursor(cursor) + } + } + + pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { + match self { + &Window::X(ref w) => w.set_cursor_state(state), + &Window::Wayland(ref w) => w.set_cursor_state(state) + } + } + + pub fn hidpi_factor(&self) -> f32 { + match self { + &Window::X(ref w) => w.hidpi_factor(), + &Window::Wayland(ref w) => w.hidpi_factor() + } + } + + pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> { + match self { + &Window::X(ref w) => w.set_cursor_position(x, y), + &Window::Wayland(ref w) => w.set_cursor_position(x, y) + } + } + + pub fn platform_display(&self) -> *mut libc::c_void { + match self { + &Window::X(ref w) => w.platform_display(), + &Window::Wayland(ref w) => w.platform_display() + } + } + + pub fn platform_window(&self) -> *mut libc::c_void { + match self { + &Window::X(ref w) => w.platform_window(), + &Window::Wayland(ref w) => w.platform_window() + } + } +} + +impl GlContext for Window { + + unsafe fn make_current(&self) { + match self { + &Window::X(ref w) => w.make_current(), + &Window::Wayland(ref w) => w.make_current() + } + } + + fn is_current(&self) -> bool { + match self { + &Window::X(ref w) => w.is_current(), + &Window::Wayland(ref w) => w.is_current() + } + } + + fn get_proc_address(&self, addr: &str) -> *const libc::c_void { + match self { + &Window::X(ref w) => w.get_proc_address(addr), + &Window::Wayland(ref w) => w.get_proc_address(addr) + } + } + + fn swap_buffers(&self) { + match self { + &Window::X(ref w) => w.swap_buffers(), + &Window::Wayland(ref w) => w.swap_buffers() + } + } + + fn get_api(&self) -> ::Api { + match self { + &Window::X(ref w) => w.get_api(), + &Window::Wayland(ref w) => w.get_api() + } + } + + fn get_pixel_format(&self) -> PixelFormat { + match self { + &Window::X(ref w) => w.get_pixel_format(), + &Window::Wayland(ref w) => w.get_pixel_format() + } + } +} \ No newline at end of file diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 1e12a80..323a21a 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -10,9 +10,11 @@ use libc; use api::osmesa::{self, OsMesaContext}; #[cfg(feature = "window")] -pub use api::x11::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor}; +pub use self::api_dispatch::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor}; #[cfg(feature = "window")] -pub use api::x11::{WaitEventsIterator, PollEventsIterator}; +pub use self::api_dispatch::{WaitEventsIterator, PollEventsIterator}; +#[cfg(feature = "window")] +mod api_dispatch; #[cfg(not(feature = "window"))] pub type Window = (); // TODO: hack to make things work -- cgit v1.2.3