diff --git a/src/os/unix.rs b/src/os/unix.rs index 06f57a6b..194864a2 100644 --- a/src/os/unix.rs +++ b/src/os/unix.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use std::ptr; use libc; use Window; -use platform::Window as LinuxWindow; +use platform::Window2 as LinuxWindow; use platform::{UnixBackend, UNIX_BACKEND}; use WindowBuilder; use platform::x11::XConnection; @@ -84,7 +84,7 @@ pub trait WindowExt { impl WindowExt for Window { #[inline] 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()), _ => None } @@ -92,28 +92,28 @@ impl WindowExt for Window { #[inline] 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()), _ => None } } 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()), _ => None } } fn get_xlib_xconnection(&self) -> Option> { - match *self.window.window { + match self.window { LinuxWindow::X(ref w) => Some(w.get_xlib_xconnection()), _ => None } } 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()), _ => None } @@ -134,7 +134,7 @@ impl WindowExt for Window { #[inline] fn get_wayland_client_surface(&self) -> Option<&WlSurface> { - match *self.window.window { + match self.window { LinuxWindow::Wayland(ref w) => Some(w.get_surface()), _ => None } @@ -142,7 +142,7 @@ impl WindowExt for Window { #[inline] fn get_wayland_client_display(&self) -> Option<&WlDisplay> { - match *self.window.window { + match self.window { LinuxWindow::Wayland(ref w) => Some(w.get_display()), _ => None } diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index e55462d4..3ec96681 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -19,9 +19,6 @@ mod dlopen; pub mod wayland; pub mod x11; - -gen_api_transition!(); - #[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes { pub visual_infos: Option, @@ -48,29 +45,19 @@ lazy_static!( ); -pub enum Window { +pub enum Window2 { #[doc(hidden)] - X(x11::Window), + X(x11::Window2), #[doc(hidden)] - Wayland(wayland::Window) + Wayland(wayland::Window2) } -#[derive(Clone)] -pub enum WindowProxy { +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum WindowId { #[doc(hidden)] - X(x11::WindowProxy), + X(x11::WindowId), #[doc(hidden)] - Wayland(wayland::WindowProxy) -} - -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() - } - } + Wayland(wayland::WindowId) } #[derive(Clone)] @@ -136,191 +123,126 @@ impl MonitorId { } } - -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; - +impl Window2 { #[inline] - 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; - - #[inline] - 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 { - #[inline] - pub fn new(window: &WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes) - -> Result + pub fn new(events_loop: ::std::sync::Arc, window: &::WindowAttributes, + pl_attribs: &PlatformSpecificWindowBuilderAttributes) + -> Result { match *UNIX_BACKEND { 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) => { - x11::Window::new(connec, window, pl_attribs).map(Window::X) + x11::Window2::new(events_loop, connec, window, pl_attribs).map(Window2::X) }, - - UnixBackend::Error(ref error) => { - panic!() // FIXME: supposed to return an error - //Err(CreationError::NoUnixBackendAvailable(Box::new(error.clone()))) + UnixBackend::Error(_) => { + // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all, + // thus this function cannot be called! + unreachable!() } } } + #[inline] + pub fn id(&self) -> WindowId { + unimplemented!() + } + #[inline] 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) + &Window2::X(ref w) => w.set_title(title), + &Window2::Wayland(ref w) => w.set_title(title) } } #[inline] pub fn show(&self) { match self { - &Window::X(ref w) => w.show(), - &Window::Wayland(ref w) => w.show() + &Window2::X(ref w) => w.show(), + &Window2::Wayland(ref w) => w.show() } } #[inline] pub fn hide(&self) { match self { - &Window::X(ref w) => w.hide(), - &Window::Wayland(ref w) => w.hide() + &Window2::X(ref w) => w.hide(), + &Window2::Wayland(ref w) => w.hide() } } #[inline] pub fn get_position(&self) -> Option<(i32, i32)> { match self { - &Window::X(ref w) => w.get_position(), - &Window::Wayland(ref w) => w.get_position() + &Window2::X(ref w) => w.get_position(), + &Window2::Wayland(ref w) => w.get_position() } } #[inline] 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) + &Window2::X(ref w) => w.set_position(x, y), + &Window2::Wayland(ref w) => w.set_position(x, y) } } #[inline] 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() + &Window2::X(ref w) => w.get_inner_size(), + &Window2::Wayland(ref w) => w.get_inner_size() } } #[inline] 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() + &Window2::X(ref w) => w.get_outer_size(), + &Window2::Wayland(ref w) => w.get_outer_size() } } #[inline] 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) - } - } - - #[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) { - 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) + &Window2::X(ref w) => w.set_inner_size(x, y), + &Window2::Wayland(ref w) => w.set_inner_size(x, y) } } #[inline] 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) + &Window2::X(ref w) => w.set_cursor(cursor), + &Window2::Wayland(ref w) => w.set_cursor(cursor) } } #[inline] 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) + &Window2::X(ref w) => w.set_cursor_state(state), + &Window2::Wayland(ref w) => w.set_cursor_state(state) } } #[inline] pub fn hidpi_factor(&self) -> f32 { match self { - &Window::X(ref w) => w.hidpi_factor(), - &Window::Wayland(ref w) => w.hidpi_factor() + &Window2::X(ref w) => w.hidpi_factor(), + &Window2::Wayland(ref w) => w.hidpi_factor() } } #[inline] 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) + &Window2::X(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 { use wayland_client::Proxy; match self { - &Window::X(ref w) => w.platform_display(), - &Window::Wayland(ref w) => w.get_display().ptr() as *mut _ + &Window2::X(ref w) => w.platform_display(), + &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 { use wayland_client::Proxy; match self { - &Window::X(ref w) => w.platform_window(), - &Window::Wayland(ref w) => w.get_surface().ptr() as *mut _ + &Window2::X(ref w) => w.platform_window(), + &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 } + +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(&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(&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) + } + } +} diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index cb0c5b5b..9cf6751c 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -7,6 +7,117 @@ pub use self::context::{WaylandContext, MonitorId, get_available_monitors, extern crate wayland_kbd; extern crate wayland_window; +use platform::PlatformSpecificWindowBuilderAttributes; +use CreationError; + +use std::sync::Arc; + mod context; mod keyboard; 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>>, + 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(&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(&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, + 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, + window: &::WindowAttributes) + -> Result + { + 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 _); + } + } + } +} diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index d5f9470b..a4f59c8a 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -6,8 +6,119 @@ pub use self::xdisplay::{XConnection, XNotSupported, XError}; pub mod ffi; +use platform::PlatformSpecificWindowBuilderAttributes; +use CreationError; + +use std::sync::Arc; + mod events; mod input; mod monitor; mod window; 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>>, + 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(&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(&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, + 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, + window: &::WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes) + -> Result + { + 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 _); + } + } + } +} diff --git a/src/platform/linux/x11/xdisplay.rs b/src/platform/linux/x11/xdisplay.rs index 4024adb8..14e058f8 100644 --- a/src/platform/linux/x11/xdisplay.rs +++ b/src/platform/linux/x11/xdisplay.rs @@ -7,7 +7,6 @@ use std::sync::Mutex; use libc; use super::ffi; -use super::super::dlopen; /// A connection to an X server. pub struct XConnection {