linux: move api transition boilerplate to x11/wayland submodules

This commit is contained in:
Victor Berger 2017-03-03 21:41:51 +01:00
parent 4acf437221
commit 624a422f20
5 changed files with 330 additions and 137 deletions

View file

@ -4,7 +4,7 @@ use std::sync::Arc;
use std::ptr; use std::ptr;
use libc; use libc;
use Window; use Window;
use platform::Window as LinuxWindow; use platform::Window2 as LinuxWindow;
use platform::{UnixBackend, UNIX_BACKEND}; use platform::{UnixBackend, UNIX_BACKEND};
use WindowBuilder; use WindowBuilder;
use platform::x11::XConnection; use platform::x11::XConnection;
@ -84,7 +84,7 @@ pub trait WindowExt {
impl WindowExt for Window { impl WindowExt for Window {
#[inline] #[inline]
fn get_xlib_window(&self) -> Option<*mut libc::c_void> { fn get_xlib_window(&self) -> Option<*mut libc::c_void> {
match *self.window.window { match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_window()), LinuxWindow::X(ref w) => Some(w.get_xlib_window()),
_ => None _ => None
} }
@ -92,28 +92,28 @@ impl WindowExt for Window {
#[inline] #[inline]
fn get_xlib_display(&self) -> Option<*mut libc::c_void> { fn get_xlib_display(&self) -> Option<*mut libc::c_void> {
match *self.window.window { match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_display()), LinuxWindow::X(ref w) => Some(w.get_xlib_display()),
_ => None _ => None
} }
} }
fn get_xlib_screen_id(&self) -> Option<*mut libc::c_void> { fn get_xlib_screen_id(&self) -> Option<*mut libc::c_void> {
match *self.window.window { match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_screen_id()), LinuxWindow::X(ref w) => Some(w.get_xlib_screen_id()),
_ => None _ => None
} }
} }
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> { fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
match *self.window.window { match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_xconnection()), LinuxWindow::X(ref w) => Some(w.get_xlib_xconnection()),
_ => None _ => None
} }
} }
fn get_xcb_connection(&self) -> Option<*mut libc::c_void> { fn get_xcb_connection(&self) -> Option<*mut libc::c_void> {
match *self.window.window { match self.window {
LinuxWindow::X(ref w) => Some(w.get_xcb_connection()), LinuxWindow::X(ref w) => Some(w.get_xcb_connection()),
_ => None _ => None
} }
@ -134,7 +134,7 @@ impl WindowExt for Window {
#[inline] #[inline]
fn get_wayland_client_surface(&self) -> Option<&WlSurface> { fn get_wayland_client_surface(&self) -> Option<&WlSurface> {
match *self.window.window { match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_surface()), LinuxWindow::Wayland(ref w) => Some(w.get_surface()),
_ => None _ => None
} }
@ -142,7 +142,7 @@ impl WindowExt for Window {
#[inline] #[inline]
fn get_wayland_client_display(&self) -> Option<&WlDisplay> { fn get_wayland_client_display(&self) -> Option<&WlDisplay> {
match *self.window.window { match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_display()), LinuxWindow::Wayland(ref w) => Some(w.get_display()),
_ => None _ => None
} }

View file

@ -19,9 +19,6 @@ mod dlopen;
pub mod wayland; pub mod wayland;
pub mod x11; pub mod x11;
gen_api_transition!();
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes { pub struct PlatformSpecificWindowBuilderAttributes {
pub visual_infos: Option<XVisualInfo>, pub visual_infos: Option<XVisualInfo>,
@ -48,29 +45,19 @@ lazy_static!(
); );
pub enum Window { pub enum Window2 {
#[doc(hidden)] #[doc(hidden)]
X(x11::Window), X(x11::Window2),
#[doc(hidden)] #[doc(hidden)]
Wayland(wayland::Window) Wayland(wayland::Window2)
} }
#[derive(Clone)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowProxy { pub enum WindowId {
#[doc(hidden)] #[doc(hidden)]
X(x11::WindowProxy), X(x11::WindowId),
#[doc(hidden)] #[doc(hidden)]
Wayland(wayland::WindowProxy) Wayland(wayland::WindowId)
}
impl WindowProxy {
#[inline]
pub fn wakeup_event_loop(&self) {
match self {
&WindowProxy::X(ref wp) => wp.wakeup_event_loop(),
&WindowProxy::Wayland(ref wp) => wp.wakeup_event_loop()
}
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -136,191 +123,126 @@ impl MonitorId {
} }
} }
impl Window2 {
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;
#[inline] #[inline]
fn next(&mut self) -> Option<Event> { pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
match self { pl_attribs: &PlatformSpecificWindowBuilderAttributes)
&mut PollEventsIterator::X(ref mut it) => it.next(), -> Result<Window2, CreationError>
&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;
#[inline]
fn next(&mut self) -> Option<Event> {
match self {
&mut WaitEventsIterator::X(ref mut it) => it.next(),
&mut WaitEventsIterator::Wayland(ref mut it) => it.next()
}
}
}
impl Window {
#[inline]
pub fn new(window: &WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window, CreationError>
{ {
match *UNIX_BACKEND { match *UNIX_BACKEND {
UnixBackend::Wayland(ref ctxt) => { UnixBackend::Wayland(ref ctxt) => {
wayland::Window::new(ctxt.clone(), window).map(Window::Wayland) wayland::Window2::new(events_loop, ctxt.clone(), window).map(Window2::Wayland)
}, },
UnixBackend::X(ref connec) => { UnixBackend::X(ref connec) => {
x11::Window::new(connec, window, pl_attribs).map(Window::X) x11::Window2::new(events_loop, connec, window, pl_attribs).map(Window2::X)
}, },
UnixBackend::Error(_) => {
UnixBackend::Error(ref error) => { // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
panic!() // FIXME: supposed to return an error // thus this function cannot be called!
//Err(CreationError::NoUnixBackendAvailable(Box::new(error.clone()))) unreachable!()
} }
} }
} }
#[inline]
pub fn id(&self) -> WindowId {
unimplemented!()
}
#[inline] #[inline]
pub fn set_title(&self, title: &str) { pub fn set_title(&self, title: &str) {
match self { match self {
&Window::X(ref w) => w.set_title(title), &Window2::X(ref w) => w.set_title(title),
&Window::Wayland(ref w) => w.set_title(title) &Window2::Wayland(ref w) => w.set_title(title)
} }
} }
#[inline] #[inline]
pub fn show(&self) { pub fn show(&self) {
match self { match self {
&Window::X(ref w) => w.show(), &Window2::X(ref w) => w.show(),
&Window::Wayland(ref w) => w.show() &Window2::Wayland(ref w) => w.show()
} }
} }
#[inline] #[inline]
pub fn hide(&self) { pub fn hide(&self) {
match self { match self {
&Window::X(ref w) => w.hide(), &Window2::X(ref w) => w.hide(),
&Window::Wayland(ref w) => w.hide() &Window2::Wayland(ref w) => w.hide()
} }
} }
#[inline] #[inline]
pub fn get_position(&self) -> Option<(i32, i32)> { pub fn get_position(&self) -> Option<(i32, i32)> {
match self { match self {
&Window::X(ref w) => w.get_position(), &Window2::X(ref w) => w.get_position(),
&Window::Wayland(ref w) => w.get_position() &Window2::Wayland(ref w) => w.get_position()
} }
} }
#[inline] #[inline]
pub fn set_position(&self, x: i32, y: i32) { pub fn set_position(&self, x: i32, y: i32) {
match self { match self {
&Window::X(ref w) => w.set_position(x, y), &Window2::X(ref w) => w.set_position(x, y),
&Window::Wayland(ref w) => w.set_position(x, y) &Window2::Wayland(ref w) => w.set_position(x, y)
} }
} }
#[inline] #[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> { pub fn get_inner_size(&self) -> Option<(u32, u32)> {
match self { match self {
&Window::X(ref w) => w.get_inner_size(), &Window2::X(ref w) => w.get_inner_size(),
&Window::Wayland(ref w) => w.get_inner_size() &Window2::Wayland(ref w) => w.get_inner_size()
} }
} }
#[inline] #[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> { pub fn get_outer_size(&self) -> Option<(u32, u32)> {
match self { match self {
&Window::X(ref w) => w.get_outer_size(), &Window2::X(ref w) => w.get_outer_size(),
&Window::Wayland(ref w) => w.get_outer_size() &Window2::Wayland(ref w) => w.get_outer_size()
} }
} }
#[inline] #[inline]
pub fn set_inner_size(&self, x: u32, y: u32) { pub fn set_inner_size(&self, x: u32, y: u32) {
match self { match self {
&Window::X(ref w) => w.set_inner_size(x, y), &Window2::X(ref w) => w.set_inner_size(x, y),
&Window::Wayland(ref w) => w.set_inner_size(x, y) &Window2::Wayland(ref w) => w.set_inner_size(x, y)
}
}
#[inline]
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())
}
}
#[inline]
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())
}
}
#[inline]
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())
}
}
#[inline]
pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
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)
} }
} }
#[inline] #[inline]
pub fn set_cursor(&self, cursor: MouseCursor) { pub fn set_cursor(&self, cursor: MouseCursor) {
match self { match self {
&Window::X(ref w) => w.set_cursor(cursor), &Window2::X(ref w) => w.set_cursor(cursor),
&Window::Wayland(ref w) => w.set_cursor(cursor) &Window2::Wayland(ref w) => w.set_cursor(cursor)
} }
} }
#[inline] #[inline]
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
match self { match self {
&Window::X(ref w) => w.set_cursor_state(state), &Window2::X(ref w) => w.set_cursor_state(state),
&Window::Wayland(ref w) => w.set_cursor_state(state) &Window2::Wayland(ref w) => w.set_cursor_state(state)
} }
} }
#[inline] #[inline]
pub fn hidpi_factor(&self) -> f32 { pub fn hidpi_factor(&self) -> f32 {
match self { match self {
&Window::X(ref w) => w.hidpi_factor(), &Window2::X(ref w) => w.hidpi_factor(),
&Window::Wayland(ref w) => w.hidpi_factor() &Window2::Wayland(ref w) => w.hidpi_factor()
} }
} }
#[inline] #[inline]
pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> { pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
match self { match self {
&Window::X(ref w) => w.set_cursor_position(x, y), &Window2::X(ref w) => w.set_cursor_position(x, y),
&Window::Wayland(ref w) => w.set_cursor_position(x, y) &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
} }
} }
@ -328,8 +250,8 @@ impl Window {
pub fn platform_display(&self) -> *mut libc::c_void { pub fn platform_display(&self) -> *mut libc::c_void {
use wayland_client::Proxy; use wayland_client::Proxy;
match self { match self {
&Window::X(ref w) => w.platform_display(), &Window2::X(ref w) => w.platform_display(),
&Window::Wayland(ref w) => w.get_display().ptr() as *mut _ &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
} }
} }
@ -337,8 +259,8 @@ impl Window {
pub fn platform_window(&self) -> *mut libc::c_void { pub fn platform_window(&self) -> *mut libc::c_void {
use wayland_client::Proxy; use wayland_client::Proxy;
match self { match self {
&Window::X(ref w) => w.platform_window(), &Window2::X(ref w) => w.platform_window(),
&Window::Wayland(ref w) => w.get_surface().ptr() as *mut _ &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
} }
} }
} }
@ -365,3 +287,53 @@ unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x
0 0
} }
pub enum EventsLoop {
#[doc(hidden)]
Wayland(wayland::EventsLoop),
#[doc(hidden)]
X(x11::EventsLoop)
}
impl EventsLoop {
pub fn new() -> EventsLoop {
match *UNIX_BACKEND {
UnixBackend::Wayland(_) => {
EventsLoop::Wayland(wayland::EventsLoop::new())
},
UnixBackend::X(_) => {
EventsLoop::X(x11::EventsLoop::new())
},
UnixBackend::Error(_) => {
panic!("Attempted to create an EventsLoop while no backend was available.")
}
}
}
pub fn interrupt(&self) {
match *self {
EventsLoop::Wayland(ref evlp) => evlp.interrupt(),
EventsLoop::X(ref evlp) => evlp.interrupt()
}
}
pub fn poll_events<F>(&self, callback: F)
where F: FnMut(::Event)
{
match *self {
EventsLoop::Wayland(ref evlp) => evlp.poll_events(callback),
EventsLoop::X(ref evlp) => evlp.poll_events(callback)
}
}
pub fn run_forever<F>(&self, callback: F)
where F: FnMut(::Event)
{
match *self {
EventsLoop::Wayland(ref evlp) => evlp.run_forever(callback),
EventsLoop::X(ref evlp) => evlp.run_forever(callback)
}
}
}

View file

@ -7,6 +7,117 @@ pub use self::context::{WaylandContext, MonitorId, get_available_monitors,
extern crate wayland_kbd; extern crate wayland_kbd;
extern crate wayland_window; extern crate wayland_window;
use platform::PlatformSpecificWindowBuilderAttributes;
use CreationError;
use std::sync::Arc;
mod context; mod context;
mod keyboard; mod keyboard;
mod window; mod window;
// API TRANSITION
//
// We don't use the gen_api_transistion!() macro but rather do the expansion manually:
//
// As this module is nested into platform/linux, its code is not _exactly_ the same as
// the one generated by the macro.
pub struct EventsLoop {
windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
interrupted: ::std::sync::atomic::AtomicBool,
}
impl EventsLoop {
pub fn new() -> EventsLoop {
EventsLoop {
windows: ::std::sync::Mutex::new(vec![]),
interrupted: ::std::sync::atomic::AtomicBool::new(false),
}
}
pub fn interrupt(&self) {
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
}
pub fn poll_events<F>(&self, mut callback: F)
where F: FnMut(::Event)
{
let mut windows = self.windows.lock().unwrap();
for window in windows.iter() {
for event in window.poll_events() {
callback(::Event::WindowEvent {
window_id: ::WindowId(::platform::WindowId::Wayland(WindowId(&**window as *const Window as usize))),
event: event,
})
}
}
}
pub fn run_forever<F>(&self, mut callback: F)
where F: FnMut(::Event)
{
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
// Yeah that's a very bad implementation.
loop {
self.poll_events(|e| callback(e));
::std::thread::sleep_ms(5);
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
break;
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(usize);
pub struct Window2 {
pub window: ::std::sync::Arc<Window>,
events_loop: ::std::sync::Weak<::platform::EventsLoop>,
}
impl ::std::ops::Deref for Window2 {
type Target = Window;
#[inline]
fn deref(&self) -> &Window {
&*self.window
}
}
impl Window2 {
pub fn new(events_loop: ::std::sync::Arc<::platform::EventsLoop>, ctxt: Arc<WaylandContext>,
window: &::WindowAttributes)
-> Result<Window2, CreationError>
{
let win = ::std::sync::Arc::new(try!(Window::new(ctxt, window)));
if let ::platform::EventsLoop::Wayland(ref ev) = *events_loop {
ev.windows.lock().unwrap().push(win.clone());
} else {
// It should not be possible to create an eventloop not matching the backend
// in use
unreachable!()
}
Ok(Window2 {
window: win,
events_loop: ::std::sync::Arc::downgrade(&events_loop),
})
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId(&*self.window as *const Window as usize)
}
}
impl Drop for Window2 {
fn drop(&mut self) {
if let Some(ev) = self.events_loop.upgrade() {
if let ::platform::EventsLoop::Wayland(ref ev) = *ev {
let mut windows = ev.windows.lock().unwrap();
windows.retain(|w| &**w as *const Window != &*self.window as *const _);
}
}
}
}

View file

@ -6,8 +6,119 @@ pub use self::xdisplay::{XConnection, XNotSupported, XError};
pub mod ffi; pub mod ffi;
use platform::PlatformSpecificWindowBuilderAttributes;
use CreationError;
use std::sync::Arc;
mod events; mod events;
mod input; mod input;
mod monitor; mod monitor;
mod window; mod window;
mod xdisplay; mod xdisplay;
// API TRANSITION
//
// We don't use the gen_api_transistion!() macro but rather do the expansion manually:
//
// As this module is nested into platform/linux, its code is not _exactly_ the same as
// the one generated by the macro.
pub struct EventsLoop {
windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
interrupted: ::std::sync::atomic::AtomicBool,
}
impl EventsLoop {
pub fn new() -> EventsLoop {
EventsLoop {
windows: ::std::sync::Mutex::new(vec![]),
interrupted: ::std::sync::atomic::AtomicBool::new(false),
}
}
pub fn interrupt(&self) {
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
}
pub fn poll_events<F>(&self, mut callback: F)
where F: FnMut(::Event)
{
let mut windows = self.windows.lock().unwrap();
for window in windows.iter() {
for event in window.poll_events() {
callback(::Event::WindowEvent {
window_id: ::WindowId(::platform::WindowId::X(WindowId(&**window as *const Window as usize))),
event: event,
})
}
}
}
pub fn run_forever<F>(&self, mut callback: F)
where F: FnMut(::Event)
{
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
// Yeah that's a very bad implementation.
loop {
self.poll_events(|e| callback(e));
::std::thread::sleep_ms(5);
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
break;
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(usize);
pub struct Window2 {
pub window: ::std::sync::Arc<Window>,
events_loop: ::std::sync::Weak<::platform::EventsLoop>,
}
impl ::std::ops::Deref for Window2 {
type Target = Window;
#[inline]
fn deref(&self) -> &Window {
&*self.window
}
}
impl Window2 {
pub fn new(events_loop: ::std::sync::Arc<::platform::EventsLoop>, display: &Arc<XConnection>,
window: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window2, CreationError>
{
let win = ::std::sync::Arc::new(try!(Window::new(display, window, pl_attribs)));
if let ::platform::EventsLoop::X(ref ev) = *events_loop {
ev.windows.lock().unwrap().push(win.clone());
} else {
// It should not be possible to create an eventloop not matching the backend
// in use
unreachable!()
}
Ok(Window2 {
window: win,
events_loop: ::std::sync::Arc::downgrade(&events_loop),
})
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId(&*self.window as *const Window as usize)
}
}
impl Drop for Window2 {
fn drop(&mut self) {
if let Some(ev) = self.events_loop.upgrade() {
if let ::platform::EventsLoop::X(ref ev) = *ev {
let mut windows = ev.windows.lock().unwrap();
windows.retain(|w| &**w as *const Window != &*self.window as *const _);
}
}
}
}

View file

@ -7,7 +7,6 @@ use std::sync::Mutex;
use libc; use libc;
use super::ffi; use super::ffi;
use super::super::dlopen;
/// A connection to an X server. /// A connection to an X server.
pub struct XConnection { pub struct XConnection {