From 9aaa78843495608684428943ffada15ea1bf73e3 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sat, 4 Mar 2017 11:14:08 +0100 Subject: [PATCH 1/5] linux: Remove dead code from wayland & fix some trivial warnings. --- src/platform/linux/mod.rs | 2 - src/platform/linux/wayland/context.rs | 12 ++-- src/platform/linux/wayland/mod.rs | 7 +-- src/platform/linux/wayland/window.rs | 86 ++++----------------------- src/platform/linux/x11/mod.rs | 4 +- src/platform/linux/x11/window.rs | 2 +- src/platform/linux/x11/xdisplay.rs | 1 - 7 files changed, 25 insertions(+), 89 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 0712469f..3669a3ce 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -5,9 +5,7 @@ use std::sync::Arc; use CreationError; use CursorState; -use WindowEvent as Event; use MouseCursor; -use WindowAttributes; use libc; use self::x11::XConnection; diff --git a/src/platform/linux/wayland/context.rs b/src/platform/linux/wayland/context.rs index c767056a..90b4027a 100644 --- a/src/platform/linux/wayland/context.rs +++ b/src/platform/linux/wayland/context.rs @@ -94,7 +94,9 @@ impl WaylandEnv { fn get_seat(&self) -> Option { for &(name, ref interface, version) in self.inner.globals() { if interface == "wl_seat" { - // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) + if version < 5 { + panic!("Winit requires at least version 5 of the wl_seat global."); + } let seat = self.registry.bind::(5, name).expect("Seat cannot be destroyed"); return Some(seat) } @@ -209,7 +211,7 @@ impl WaylandContext { // this handles both "no libwayland" and "no compositor" cases let (display, mut event_queue) = match default_connect() { Ok(ret) => ret, - Err(e) => return None + Err(_) => return None }; // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) @@ -237,7 +239,7 @@ impl WaylandContext { } pub fn flush(&self) { - self.display.flush(); + let _ = self.display.flush(); } pub fn with_output(&self, id: MonitorId, f: F) where F: FnOnce(&wl_output::WlOutput) { @@ -512,7 +514,7 @@ impl wl_pointer::Handler for WaylandEnv { fn axis_source(&mut self, _evqh: &mut EventQueueHandle, _proxy: &wl_pointer::WlPointer, - axis_source: wl_pointer::AxisSource) + _axis_source: wl_pointer::AxisSource) { } @@ -520,7 +522,7 @@ impl wl_pointer::Handler for WaylandEnv { _evqh: &mut EventQueueHandle, _proxy: &wl_pointer::WlPointer, _time: u32, - axis: wl_pointer::Axis) + _axis: wl_pointer::Axis) { self.axis_state = TouchPhase::Ended; } diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index 9cf6751c..c3ab1c4b 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -1,13 +1,12 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] -pub use self::window::{PollEventsIterator, WaitEventsIterator, Window, WindowProxy}; +use self::window::Window; pub use self::context::{WaylandContext, MonitorId, get_available_monitors, get_primary_monitor}; extern crate wayland_kbd; extern crate wayland_window; -use platform::PlatformSpecificWindowBuilderAttributes; use CreationError; use std::sync::Arc; @@ -43,7 +42,7 @@ impl EventsLoop { pub fn poll_events(&self, mut callback: F) where F: FnMut(::Event) { - let mut windows = self.windows.lock().unwrap(); + let windows = self.windows.lock().unwrap(); for window in windows.iter() { for event in window.poll_events() { callback(::Event::WindowEvent { @@ -62,7 +61,7 @@ impl EventsLoop { // Yeah that's a very bad implementation. loop { self.poll_events(|e| callback(e)); - ::std::thread::sleep_ms(5); + ::std::thread::sleep(::std::time::Duration::from_millis(5)); if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) { break; } diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index f4977451..9994cf09 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -11,21 +11,6 @@ use super::WaylandContext; use super::wayland_window; use super::wayland_window::DecoratedSurface; -#[derive(Clone)] -pub struct WindowProxy { - ctxt: Arc, - eviter: Arc>>, -} - -impl WindowProxy { - #[inline] - pub fn wakeup_event_loop(&self) { - // Send a sync event, so that any waiting "dispatch" will return - self.ctxt.display.sync(); - self.eviter.lock().unwrap().push_back(Event::Awakened); - } -} - pub struct Window { ctxt: Arc, evq: Mutex, @@ -48,18 +33,6 @@ impl<'a> Iterator for PollEventsIterator<'a> { } } -pub struct WaitEventsIterator<'a> { - window: &'a Window, -} - -impl<'a> Iterator for WaitEventsIterator<'a> { - type Item = Event; - - fn next(&mut self) -> Option { - self.window.next_event(true) - } -} - impl Window { pub fn new(ctxt: Arc, attributes: &WindowAttributes) -> Result { @@ -107,24 +80,12 @@ impl Window { } fn process_resize(&self) { - use std::cmp::max; let mut evq_guard = self.evq.lock().unwrap(); let mut state = evq_guard.state(); - let newsize = { - let decorated = state.get_mut_handler::>(self.decorated_id); - let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize()); - if let Some((w, h)) = newsize { - decorated.resize(w as i32, h as i32); - *self.size.lock().unwrap() = (w, h); - } - newsize - }; - // callback_resize if any - if let Some((w, h)) = newsize { - let mut handler = state.get_mut_handler::(self.handler_id); - if let Some(ref callback) = handler.resize_callback { - callback(w, h); - } + let decorated = state.get_mut_handler::>(self.decorated_id); + if let Some((w, h)) = decorated.handler().as_mut().and_then(|h| h.take_newsize()) { + decorated.resize(w as i32, h as i32); + *self.size.lock().unwrap() = (w, h); self.eviter.lock().unwrap().push_back(Event::Resized(w,h)); } } @@ -143,18 +104,19 @@ impl Window { // read some events if some are waiting & queue is empty if let Some(guard) = self.evq.lock().unwrap().prepare_read() { - guard.read_events(); + guard.read_events().expect("Wayland connection unexpectedly lost"); } // try a pending dispatch { self.ctxt.dispatch_pending(); - self.evq.lock().unwrap().dispatch_pending(); + self.evq.lock().unwrap().dispatch_pending() + .expect("Wayland connection unexpectedly lost"); // some events were dispatched, need to process a potential resising self.process_resize(); } - let mut evt = { + evt = { let mut guard = self.eviter.lock().unwrap(); guard.pop_front() }; @@ -164,7 +126,8 @@ impl Window { { self.ctxt.flush(); self.ctxt.dispatch(); - self.evq.lock().unwrap().dispatch_pending(); + self.evq.lock().unwrap().dispatch_pending() + .expect("Wayland connection unexpectedly lost"); // some events were dispatched, need to process a potential resising self.process_resize(); } @@ -178,7 +141,7 @@ impl Window { pub fn set_title(&self, title: &str) { let mut guard = self.evq.lock().unwrap(); let mut state = guard.state(); - let mut decorated = state.get_mut_handler::>(self.decorated_id); + let decorated = state.get_mut_handler::>(self.decorated_id); decorated.set_title(title.into()) } @@ -223,14 +186,6 @@ impl Window { decorated.resize(x as i32, y as i32); } - #[inline] - pub fn create_window_proxy(&self) -> WindowProxy { - WindowProxy { - ctxt: self.ctxt.clone(), - eviter: self.eviter.clone() - } - } - #[inline] pub fn poll_events(&self) -> PollEventsIterator { PollEventsIterator { @@ -238,21 +193,6 @@ impl Window { } } - #[inline] - pub fn wait_events(&self) -> WaitEventsIterator { - WaitEventsIterator { - window: self - } - } - - #[inline] - pub fn set_window_resize_callback(&mut self, callback: Option) { - let mut guard = self.evq.lock().unwrap(); - let mut state = guard.state(); - let mut handler = state.get_mut_handler::(self.handler_id); - handler.resize_callback = callback; - } - #[inline] pub fn set_cursor(&self, _cursor: MouseCursor) { // TODO @@ -321,20 +261,18 @@ impl wayland_window::Handler for DecoratedHandler { struct WindowHandler { my_id: usize, - resize_callback: Option, } impl WindowHandler { fn new() -> WindowHandler { WindowHandler { my_id: 0, - resize_callback: None } } } impl Init for WindowHandler { - fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) { + fn init(&mut self, _evqh: &mut EventQueueHandle, index: usize) { self.my_id = index; } } diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index a4f59c8a..43721b7b 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -44,7 +44,7 @@ impl EventsLoop { pub fn poll_events(&self, mut callback: F) where F: FnMut(::Event) { - let mut windows = self.windows.lock().unwrap(); + let windows = self.windows.lock().unwrap(); for window in windows.iter() { for event in window.poll_events() { callback(::Event::WindowEvent { @@ -63,7 +63,7 @@ impl EventsLoop { // Yeah that's a very bad implementation. loop { self.poll_events(|e| callback(e)); - ::std::thread::sleep_ms(5); + ::std::thread::sleep(::std::time::Duration::from_millis(5)); if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) { break; } diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index 7bf0a9fc..233892f9 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -793,7 +793,7 @@ impl Window { // differs on the desktop environments or themes. // // Try the better looking (or more suiting) names first. - let mut xcursor = match cursor { + let xcursor = match cursor { MouseCursor::Alias => load("link"), MouseCursor::Arrow => load("arrow"), MouseCursor::Cell => load("plus"), diff --git a/src/platform/linux/x11/xdisplay.rs b/src/platform/linux/x11/xdisplay.rs index 14e058f8..05a29f40 100644 --- a/src/platform/linux/x11/xdisplay.rs +++ b/src/platform/linux/x11/xdisplay.rs @@ -1,7 +1,6 @@ use std::ptr; use std::fmt; use std::error::Error; -use std::ffi::CString; use std::sync::Mutex; use libc; From 7336cacf0733967ee711e09ecd466eddab9b9465 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sat, 4 Mar 2017 14:04:01 +0100 Subject: [PATCH 2/5] wayland: mugrate to new API --- src/platform/linux/mod.rs | 11 +- src/platform/linux/wayland/context.rs | 106 +++++++------ src/platform/linux/wayland/event_loop.rs | 184 +++++++++++++++++++++++ src/platform/linux/wayland/keyboard.rs | 18 +-- src/platform/linux/wayland/mod.rs | 117 +------------- src/platform/linux/wayland/window.rs | 179 ++++++---------------- 6 files changed, 310 insertions(+), 305 deletions(-) create mode 100644 src/platform/linux/wayland/event_loop.rs diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 3669a3ce..fd820225 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -129,7 +129,12 @@ impl Window2 { { match *UNIX_BACKEND { UnixBackend::Wayland(ref ctxt) => { - wayland::Window2::new(events_loop, ctxt.clone(), window).map(Window2::Wayland) + if let EventsLoop::Wayland(ref evlp) = *events_loop { + wayland::Window2::new(evlp, ctxt.clone(), window).map(Window2::Wayland) + } else { + // It is not possible to instanciate an EventsLoop not matching its backend + unreachable!() + } }, UnixBackend::X(ref connec) => { @@ -299,8 +304,8 @@ pub enum EventsLoop { impl EventsLoop { pub fn new() -> EventsLoop { match *UNIX_BACKEND { - UnixBackend::Wayland(_) => { - EventsLoop::Wayland(wayland::EventsLoop::new()) + UnixBackend::Wayland(ref ctxt) => { + EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone())) }, UnixBackend::X(_) => { diff --git a/src/platform/linux/wayland/context.rs b/src/platform/linux/wayland/context.rs index 90b4027a..4641f39f 100644 --- a/src/platform/linux/wayland/context.rs +++ b/src/platform/linux/wayland/context.rs @@ -10,7 +10,7 @@ use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subc wl_display, wl_registry, wl_output, wl_surface, wl_pointer, wl_keyboard}; -use super::wayland_window; +use super::{wayland_window, EventsLoopSink, make_wid}; use super::wayland_kbd::MappedKeyboard; use super::keyboard::KbdHandler; @@ -27,7 +27,7 @@ wayland_env!(InnerEnv, enum KbdType { Mapped(MappedKeyboard), - Plain(Option>>>) + Plain(Option<(Arc,Arc>)>) } struct WaylandEnv { @@ -35,10 +35,10 @@ struct WaylandEnv { inner: EnvHandler, monitors: Vec, my_id: usize, - windows: Vec<(Arc,Arc>>)>, + windows: Vec<(Arc,Arc>)>, seat: Option, mouse: Option, - mouse_focus: Option>>>, + mouse_focus: Option<(Arc,Arc>)>, mouse_location: (i32, i32), axis_buffer: Option<(f32, f32)>, axis_discrete_buffer: Option<(i32, i32)>, @@ -252,16 +252,15 @@ impl WaylandContext { } } - pub fn create_window(&self) - -> (Arc, Arc>>, wayland_window::DecoratedSurface) + pub fn create_window(&self, sink: Arc>) + -> (Arc, wayland_window::DecoratedSurface) { let mut guard = self.evq.lock().unwrap(); let mut state = guard.state(); let env = state.get_mut_handler::(self.env_id); // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) let surface = Arc::new(env.inner.compositor.create_surface().expect("Compositor cannot be dead")); - let eventiter = Arc::new(Mutex::new(VecDeque::new())); - env.windows.push((surface.clone(), eventiter.clone())); + env.windows.push((surface.clone(), sink)); let decorated = wayland_window::DecoratedSurface::new( &*surface, 800, 600, &env.inner.compositor, @@ -271,7 +270,7 @@ impl WaylandContext { env.get_seat(), false ).expect("Failed to create a tmpfile buffer."); - (surface, eventiter, decorated) + (surface, decorated) } pub fn prune_dead_windows(&self) { @@ -397,13 +396,13 @@ impl wl_pointer::Handler for WaylandEnv { surface_y: f64) { self.mouse_location = (surface_x as i32, surface_y as i32); - for &(ref window, ref eviter) in &self.windows { + for &(ref window, ref sink) in &self.windows { if window.equals(surface) { - self.mouse_focus = Some(eviter.clone()); + self.mouse_focus = Some((window.clone(), sink.clone())); let (w, h) = self.mouse_location; - let mut event_queue = eviter.lock().unwrap(); - event_queue.push_back(Event::MouseEntered); - event_queue.push_back(Event::MouseMoved(w, h)); + let mut event_queue = sink.lock().unwrap(); + event_queue.push_event(Event::MouseEntered, make_wid(window)); + event_queue.push_event(Event::MouseMoved(w, h), make_wid(window)); break; } } @@ -416,10 +415,10 @@ impl wl_pointer::Handler for WaylandEnv { surface: &wl_surface::WlSurface) { self.mouse_focus = None; - for &(ref window, ref eviter) in &self.windows { + for &(ref window, ref sink) in &self.windows { if window.equals(surface) { - let mut event_queue = eviter.lock().unwrap(); - event_queue.push_back(Event::MouseLeft); + let mut event_queue = sink.lock().unwrap(); + event_queue.push_event(Event::MouseLeft, make_wid(window)); break; } } @@ -433,10 +432,11 @@ impl wl_pointer::Handler for WaylandEnv { surface_y: f64) { self.mouse_location = (surface_x as i32, surface_y as i32); - if let Some(ref eviter) = self.mouse_focus { + if let Some((ref window, ref sink)) = self.mouse_focus { let (w,h) = self.mouse_location; - eviter.lock().unwrap().push_back( - Event::MouseMoved(w, h) + sink.lock().unwrap().push_event( + Event::MouseMoved(w, h), + make_wid(window) ); } } @@ -449,7 +449,7 @@ impl wl_pointer::Handler for WaylandEnv { button: u32, state: wl_pointer::ButtonState) { - if let Some(ref eviter) = self.mouse_focus { + if let Some((ref window, ref sink)) = self.mouse_focus { let state = match state { wl_pointer::ButtonState::Pressed => ElementState::Pressed, wl_pointer::ButtonState::Released => ElementState::Released @@ -461,8 +461,9 @@ impl wl_pointer::Handler for WaylandEnv { // TODO figure out the translation ? _ => return }; - eviter.lock().unwrap().push_back( - Event::MouseInput(state, button) + sink.lock().unwrap().push_event( + Event::MouseInput(state, button), + make_wid(window) ); } } @@ -492,20 +493,22 @@ impl wl_pointer::Handler for WaylandEnv { { let axis_buffer = self.axis_buffer.take(); let axis_discrete_buffer = self.axis_discrete_buffer.take(); - if let Some(ref eviter) = self.mouse_focus { + if let Some((ref window, ref sink)) = self.mouse_focus { if let Some((x, y)) = axis_discrete_buffer { - eviter.lock().unwrap().push_back( + sink.lock().unwrap().push_event( Event::MouseWheel( MouseScrollDelta::LineDelta(x as f32, y as f32), self.axis_state - ) + ), + make_wid(window) ); } else if let Some((x, y)) = axis_buffer { - eviter.lock().unwrap().push_back( + sink.lock().unwrap().push_event( Event::MouseWheel( MouseScrollDelta::PixelDelta(x as f32, y as f32), self.axis_state - ) + ), + make_wid(window) ); } } @@ -574,24 +577,24 @@ impl wl_keyboard::Handler for WaylandEnv { surface: &wl_surface::WlSurface, keys: Vec) { - let mut opt_eviter = None; - for &(ref window, ref eviter) in &self.windows { + let mut opt_sink = None; + for &(ref window, ref sink) in &self.windows { if window.equals(surface) { - opt_eviter = Some(eviter.clone()); + opt_sink = Some((window.clone(), sink.clone())); break; } } - if let Some(ref eviter) = opt_eviter { + if let Some((ref window, ref sink)) = opt_sink { // send focused event - let mut guard = eviter.lock().unwrap(); - guard.push_back(Event::Focused(true)); + let mut guard = sink.lock().unwrap(); + guard.push_event(Event::Focused(true), make_wid(window)); } match self.kbd_handler { KbdType::Mapped(ref mut h) => { - h.handler().target = opt_eviter; + h.handler().target = opt_sink; h.enter(evqh, proxy, serial, surface, keys); }, - KbdType::Plain(ref mut opt) => { *opt = opt_eviter; } + KbdType::Plain(ref mut opt) => { *opt = opt_sink; } } } @@ -601,17 +604,17 @@ impl wl_keyboard::Handler for WaylandEnv { serial: u32, surface: &wl_surface::WlSurface) { - let opt_eviter = match self.kbd_handler { + let opt_sink = match self.kbd_handler { KbdType::Mapped(ref mut h) => { - let eviter = h.handler().target.take(); + let sink = h.handler().target.take(); h.leave(evqh, proxy, serial, surface); - eviter + sink }, KbdType::Plain(ref mut opt) => opt.take() }; - if let Some(eviter) = opt_eviter { - let mut guard = eviter.lock().unwrap(); - guard.push_back(Event::Focused(false)); + if let Some((ref window, ref sink)) = opt_sink { + let mut guard = sink.lock().unwrap(); + guard.push_event(Event::Focused(false), make_wid(window)); } } @@ -625,12 +628,12 @@ impl wl_keyboard::Handler for WaylandEnv { { match self.kbd_handler { KbdType::Mapped(ref mut h) => h.key(evqh, proxy, serial, time, key, state), - KbdType::Plain(Some(ref eviter)) => { + KbdType::Plain(Some((ref window, ref sink))) => { let state = match state { wl_keyboard::KeyState::Pressed => ElementState::Pressed, wl_keyboard::KeyState::Released => ElementState::Released, }; - let mut guard = eviter.lock().unwrap(); + let mut guard = sink.lock().unwrap(); // This is fallback impl if libxkbcommon was not available // This case should probably never happen, as most wayland // compositors _need_ libxkbcommon anyway... @@ -638,12 +641,15 @@ impl wl_keyboard::Handler for WaylandEnv { // In this case, we don't have the modifiers state information // anyway, as we need libxkbcommon to interpret it (it is // supposed to be serialized by the compositor using libxkbcommon) - guard.push_back(Event::KeyboardInput( - state, - key as u8, - None, - ModifiersState::default() - )); + guard.push_event( + Event::KeyboardInput( + state, + key as u8, + None, + ModifiersState::default() + ), + make_wid(window) + ); }, KbdType::Plain(None) => () } diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs new file mode 100644 index 00000000..0477d7b9 --- /dev/null +++ b/src/platform/linux/wayland/event_loop.rs @@ -0,0 +1,184 @@ +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; +use std::sync::atomic::AtomicBool; + +use super::{DecoratedHandler, WindowId, WaylandContext}; + +use wayland_client::EventQueue; +use super::wayland_window::DecoratedSurface; + +pub struct EventsLoopSink { + callback: Option<*mut FnMut(::Event)>, + queue: VecDeque<::Event> +} + +unsafe impl Send for EventsLoopSink { } + +impl EventsLoopSink { + pub fn new() -> EventsLoopSink { + EventsLoopSink { + callback: None, + queue: VecDeque::new() + } + } + + pub fn push_event(&mut self, evt: ::WindowEvent, wid: WindowId) { + let evt = ::Event::WindowEvent { + event: evt, + window_id: ::WindowId(::platform::WindowId::Wayland(wid)) + }; + if let Some(cb) = self.callback { + unsafe { (&mut *cb)(evt) } + } else { + self.queue.push_back(evt) + } + } + + // This function is only safe of the set callback is unset before exclusive + // access to the wayland EventQueue is finished. + // + // The callback also cannot be used any longer as long as it has not been + // cleared from the Sink. + unsafe fn set_callback(&mut self, cb: &mut FnMut(::Event)) { + let cb: &mut FnMut(::Event) = ::std::mem::transmute(cb); + self.callback = Some(cb as *mut _); + } + + fn with_callback(&mut self, f: F) { + if let Some(cb) = self.callback { + f(unsafe {&mut *cb}) + } + } + + fn clear_callback(&mut self) { + self.callback = None + } + + fn drain_queue(&mut self, cb: &mut F) { + for evt in self.queue.drain(..) { + cb(evt) + } + } +} + +pub struct EventsLoop { + ctxt: Arc, + evq: Arc>, + decorated_ids: Mutex>, + sink: Arc>, + interrupted: AtomicBool, +} + +impl EventsLoop { + pub fn new(ctxt: Arc) -> EventsLoop { + let evq = ctxt.display.create_event_queue(); + EventsLoop { + ctxt: ctxt, + evq: Arc::new(Mutex::new(evq)), + decorated_ids: Mutex::new(Vec::new()), + sink: Arc::new(Mutex::new(EventsLoopSink::new())), + interrupted: AtomicBool::new(false) + } + } + + pub fn get_sink(&self) -> Arc> { + self.sink.clone() + } + + pub fn get_event_queue(&self) -> Arc> { + self.evq.clone() + } + + pub fn register_window(&self, decorated_id: usize, wid: WindowId) { + self.decorated_ids.lock().unwrap().push((decorated_id, wid)); + } + + fn process_resize(evq: &mut EventQueue, ids: &[(usize, WindowId)], callback: &mut FnMut(::Event)) + { + let mut state = evq.state(); + for &(decorated_id, window_id) in ids { + let decorated = state.get_mut_handler::>(decorated_id); + if let Some((w, h)) = decorated.handler().as_mut().and_then(|h| h.take_newsize()) { + decorated.resize(w as i32, h as i32); + callback( + ::Event::WindowEvent { + window_id: ::WindowId(::platform::WindowId::Wayland(window_id)), + event: ::WindowEvent::Resized(w,h) + } + ); + } + } + } + + 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) + { + // send pending requests to the server... + self.ctxt.flush(); + + // first of all, get exclusive access to this event queue + let mut evq_guard = self.evq.lock().unwrap(); + + // dispatch stored events: + self.sink.lock().unwrap().drain_queue(&mut callback); + + // read some events from the socket if some are waiting & queue is empty + if let Some(guard) = evq_guard.prepare_read() { + guard.read_events().expect("Wayland connection unexpectedly lost"); + } + + // set the callback into the sink + unsafe { self.sink.lock().unwrap().set_callback(&mut callback) }; + + // then do the actual dispatching + self.ctxt.dispatch_pending(); + evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost"); + + let mut sink_guard = self.sink.lock().unwrap(); + + // events where probably dispatched, process resize + let ids_guard = self.decorated_ids.lock().unwrap(); + sink_guard.with_callback( + |cb| Self::process_resize(&mut evq_guard, &ids_guard, cb) + ); + + sink_guard.clear_callback(); + // we must keep callback alive up to this point! + drop(callback); + + } + + pub fn run_forever(&self, mut callback: F) + where F: FnMut(::Event) + { + // send pending requests to the server... + self.ctxt.flush(); + + // first of all, get exclusive access to this event queue + let mut evq_guard = self.evq.lock().unwrap(); + + // dispatch stored events: + self.sink.lock().unwrap().drain_queue(&mut callback); + + // set the callback into the sink + unsafe { self.sink.lock().unwrap().set_callback(&mut callback) }; + + while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) { + self.ctxt.dispatch(); + evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost"); + let ids_guard = self.decorated_ids.lock().unwrap(); + self.sink.lock().unwrap().with_callback( + |cb| Self::process_resize(&mut evq_guard, &ids_guard, cb) + ); + self.ctxt.flush(); + } + + self.sink.lock().unwrap().clear_callback(); + // we must keep callback alive up to this point! + drop(callback) + } +} diff --git a/src/platform/linux/wayland/keyboard.rs b/src/platform/linux/wayland/keyboard.rs index 98b8e1bd..3a73f43a 100644 --- a/src/platform/linux/wayland/keyboard.rs +++ b/src/platform/linux/wayland/keyboard.rs @@ -1,16 +1,15 @@ -use std::collections::VecDeque; use std::sync::{Arc, Mutex}; use {VirtualKeyCode, ElementState, WindowEvent as Event}; use events::ModifiersState; -use super::wayland_kbd; +use super::{wayland_kbd, make_wid, EventsLoopSink}; use wayland_client::EventQueueHandle; -use wayland_client::protocol::wl_keyboard; +use wayland_client::protocol::{wl_keyboard, wl_surface}; pub struct KbdHandler { - pub target: Option>>> + pub target: Option<(Arc,Arc>)> } impl KbdHandler { @@ -31,14 +30,14 @@ impl wayland_kbd::Handler for KbdHandler { state: wl_keyboard::KeyState, utf8: Option) { - if let Some(ref eviter) = self.target { + if let Some((ref window, ref sink)) = self.target { let state = match state { wl_keyboard::KeyState::Pressed => ElementState::Pressed, wl_keyboard::KeyState::Released => ElementState::Released, }; let vkcode = key_to_vkey(rawkey, keysym); - let mut guard = eviter.lock().unwrap(); - guard.push_back( + let mut guard = sink.lock().unwrap(); + guard.push_event( Event::KeyboardInput( state, rawkey as u8, @@ -49,13 +48,14 @@ impl wayland_kbd::Handler for KbdHandler { alt: mods.alt, logo: mods.logo } - ) + ), + make_wid(window) ); // send char event only on key press, not release if let ElementState::Released = state { return } if let Some(txt) = utf8 { for chr in txt.chars() { - guard.push_back(Event::ReceivedCharacter(chr)); + guard.push_event(Event::ReceivedCharacter(chr), make_wid(window)); } } } diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index c3ab1c4b..1f5a6411 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -1,122 +1,17 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] -use self::window::Window; +pub use self::window::{Window as Window2, WindowId}; +pub use self::event_loop::EventsLoop; pub use self::context::{WaylandContext, MonitorId, get_available_monitors, get_primary_monitor}; +use self::window::{make_wid, DecoratedHandler}; +use self::event_loop::EventsLoopSink; + extern crate wayland_kbd; extern crate wayland_window; -use CreationError; - -use std::sync::Arc; - mod context; +mod event_loop; 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 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(::std::time::Duration::from_millis(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/wayland/window.rs b/src/platform/linux/wayland/window.rs index 9994cf09..76f4c44f 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -1,141 +1,80 @@ -use std::collections::VecDeque; use std::sync::{Arc, Mutex}; -use wayland_client::{EventQueue, EventQueueHandle, Init}; +use wayland_client::{EventQueue, EventQueueHandle, Init, Proxy}; use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface}; -use {CreationError, MouseCursor, CursorState, WindowEvent as Event, WindowAttributes}; +use {CreationError, MouseCursor, CursorState, WindowAttributes}; use platform::MonitorId as PlatformMonitorId; -use super::WaylandContext; +use super::{WaylandContext, EventsLoop}; use super::wayland_window; use super::wayland_window::DecoratedSurface; pub struct Window { ctxt: Arc, - evq: Mutex, - eviter: Arc>>, + evq: Arc>, surface: Arc, size: Mutex<(u32, u32)>, - handler_id: usize, decorated_id: usize } -pub struct PollEventsIterator<'a> { - window: &'a Window, -} +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WindowId(usize); -impl<'a> Iterator for PollEventsIterator<'a> { - type Item = Event; - - fn next(&mut self) -> Option { - self.window.next_event(false) - } +#[inline] +pub fn make_wid(s: &wl_surface::WlSurface) -> WindowId { + WindowId(s.ptr() as usize) } impl Window { - pub fn new(ctxt: Arc, attributes: &WindowAttributes) -> Result + pub fn new(evlp: &EventsLoop, ctxt: Arc, attributes: &WindowAttributes) -> Result { let (width, height) = attributes.dimensions.unwrap_or((800,600)); - let mut evq = ctxt.display.create_event_queue(); - - let (surface, eviter, decorated) = ctxt.create_window::(); + let (surface, decorated) = ctxt.create_window::(evlp.get_sink()); // init DecoratedSurface - let decorated_id = evq.add_handler_with_init(decorated); - { - let mut state = evq.state(); - let decorated = state.get_mut_handler::>(decorated_id); - *(decorated.handler()) = Some(DecoratedHandler::new()); + let evq = evlp.get_event_queue(); + let decorated_id = { + let mut evq_guard = evq.lock().unwrap(); + let decorated_id = evq_guard.add_handler_with_init(decorated); + { + let mut state = evq_guard.state(); + let decorated = state.get_mut_handler::>(decorated_id); + *(decorated.handler()) = Some(DecoratedHandler::new()); - if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor { - ctxt.with_output(monitor_id.clone(), |output| { - decorated.set_fullscreen( - wl_shell_surface::FullscreenMethod::Default, - 0, - Some(output) - ) - }); - } else if attributes.decorations { - decorated.set_decorate(true); + if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor { + ctxt.with_output(monitor_id.clone(), |output| { + decorated.set_fullscreen( + wl_shell_surface::FullscreenMethod::Default, + 0, + Some(output) + ) + }); + } else if attributes.decorations { + decorated.set_decorate(true); + } + // Finally, set the decorations size + decorated.resize(width as i32, height as i32); } - // Finally, set the decorations size - decorated.resize(width as i32, height as i32); - } - - // init general handler - let handler = WindowHandler::new(); - let handler_id = evq.add_handler_with_init(handler); - - Ok(Window { + decorated_id + }; + let me = Window { ctxt: ctxt, - evq: Mutex::new(evq), - eviter: eviter, + evq: evq, surface: surface, size: Mutex::new((width, height)), - handler_id: handler_id, decorated_id: decorated_id - }) - } - - fn process_resize(&self) { - let mut evq_guard = self.evq.lock().unwrap(); - let mut state = evq_guard.state(); - let decorated = state.get_mut_handler::>(self.decorated_id); - if let Some((w, h)) = decorated.handler().as_mut().and_then(|h| h.take_newsize()) { - decorated.resize(w as i32, h as i32); - *self.size.lock().unwrap() = (w, h); - self.eviter.lock().unwrap().push_back(Event::Resized(w,h)); - } - } - - fn next_event(&self, block: bool) -> Option { - let mut evt = { - let mut guard = self.eviter.lock().unwrap(); - guard.pop_front() - }; - if evt.is_some() { return evt } - - // There is no event in the queue, we need to fetch more - - // flush the display - self.ctxt.flush(); - - // read some events if some are waiting & queue is empty - if let Some(guard) = self.evq.lock().unwrap().prepare_read() { - guard.read_events().expect("Wayland connection unexpectedly lost"); - } - - // try a pending dispatch - { - self.ctxt.dispatch_pending(); - self.evq.lock().unwrap().dispatch_pending() - .expect("Wayland connection unexpectedly lost"); - // some events were dispatched, need to process a potential resising - self.process_resize(); - } - - evt = { - let mut guard = self.eviter.lock().unwrap(); - guard.pop_front() }; - while block && evt.is_none() { - // no event waiting, need to repopulate! - { - self.ctxt.flush(); - self.ctxt.dispatch(); - self.evq.lock().unwrap().dispatch_pending() - .expect("Wayland connection unexpectedly lost"); - // some events were dispatched, need to process a potential resising - self.process_resize(); - } - // try again - let mut guard = self.eviter.lock().unwrap(); - evt = guard.pop_front(); - } - evt + evlp.register_window(me.decorated_id, me.id()); + + Ok(me) + } + + #[inline] + pub fn id(&self) -> WindowId { + make_wid(&self.surface) } pub fn set_title(&self, title: &str) { @@ -186,13 +125,6 @@ impl Window { decorated.resize(x as i32, y as i32); } - #[inline] - pub fn poll_events(&self) -> PollEventsIterator { - PollEventsIterator { - window: self - } - } - #[inline] pub fn set_cursor(&self, _cursor: MouseCursor) { // TODO @@ -237,13 +169,14 @@ impl Drop for Window { } } -struct DecoratedHandler { +pub struct DecoratedHandler { newsize: Option<(u32, u32)> } impl DecoratedHandler { fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }} - fn take_newsize(&mut self) -> Option<(u32, u32)> { + + pub fn take_newsize(&mut self) -> Option<(u32, u32)> { self.newsize.take() } } @@ -258,21 +191,3 @@ impl wayland_window::Handler for DecoratedHandler { self.newsize = Some((max(width,1) as u32, max(height,1) as u32)); } } - -struct WindowHandler { - my_id: usize, -} - -impl WindowHandler { - fn new() -> WindowHandler { - WindowHandler { - my_id: 0, - } - } -} - -impl Init for WindowHandler { - fn init(&mut self, _evqh: &mut EventQueueHandle, index: usize) { - self.my_id = index; - } -} From 17fde48ed725c86495cb8835dd3c790371c5956e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 10 Mar 2017 23:22:59 +0100 Subject: [PATCH 3/5] wayland: move input logic to the event loop --- src/platform/linux/wayland/context.rs | 407 +------------------ src/platform/linux/wayland/event_loop.rs | 482 ++++++++++++++++++++--- src/platform/linux/wayland/keyboard.rs | 21 +- src/platform/linux/wayland/window.rs | 7 +- 4 files changed, 450 insertions(+), 467 deletions(-) diff --git a/src/platform/linux/wayland/context.rs b/src/platform/linux/wayland/context.rs index 4641f39f..1c3ca7eb 100644 --- a/src/platform/linux/wayland/context.rs +++ b/src/platform/linux/wayland/context.rs @@ -1,18 +1,11 @@ -use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase}; - -use events::ModifiersState; - use std::collections::VecDeque; use std::sync::{Arc, Mutex}; use wayland_client::{EnvHandler, default_connect, EventQueue, EventQueueHandle, Init, Proxy}; use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor, - wl_display, wl_registry, wl_output, wl_surface, wl_pointer, - wl_keyboard}; + wl_display, wl_registry, wl_output, wl_surface}; -use super::{wayland_window, EventsLoopSink, make_wid}; -use super::wayland_kbd::MappedKeyboard; -use super::keyboard::KbdHandler; +use super::wayland_window; /* * Registry and globals handling @@ -25,26 +18,11 @@ wayland_env!(InnerEnv, subcompositor: wl_subcompositor::WlSubcompositor ); -enum KbdType { - Mapped(MappedKeyboard), - Plain(Option<(Arc,Arc>)>) -} - struct WaylandEnv { registry: wl_registry::WlRegistry, inner: EnvHandler, monitors: Vec, my_id: usize, - windows: Vec<(Arc,Arc>)>, - seat: Option, - mouse: Option, - mouse_focus: Option<(Arc,Arc>)>, - mouse_location: (i32, i32), - axis_buffer: Option<(f32, f32)>, - axis_discrete_buffer: Option<(i32, i32)>, - axis_state: TouchPhase, - kbd: Option, - kbd_handler: KbdType } struct OutputInfo { @@ -69,25 +47,11 @@ impl OutputInfo { impl WaylandEnv { fn new(registry: wl_registry::WlRegistry) -> WaylandEnv { - let kbd_handler = match MappedKeyboard::new(KbdHandler::new()) { - Ok(h) => KbdType::Mapped(h), - Err(_) => KbdType::Plain(None) - }; WaylandEnv { registry: registry, inner: EnvHandler::new(), monitors: Vec::new(), my_id: 0, - windows: Vec::new(), - seat: None, - mouse: None, - mouse_focus: None, - mouse_location: (0,0), - axis_buffer: None, - axis_discrete_buffer: None, - axis_state: TouchPhase::Started, - kbd: None, - kbd_handler: kbd_handler } } @@ -127,14 +91,6 @@ impl wl_registry::Handler for WaylandEnv { .expect("Registry cannot be dead"); evqh.register::<_, WaylandEnv>(&output, self.my_id); self.monitors.push(OutputInfo::new(output, name)); - } else if interface == "wl_seat" && self.seat.is_none() { - // Only grab the first seat - // TODO: Handle multi-seat-setup? - assert!(version >= 5, "Version 5 of seat interface is needed by glutin."); - let seat = self.registry.bind::(5, name) - .expect("Registry cannot be dead"); - evqh.register::<_, WaylandEnv>(&seat, self.my_id); - self.seat = Some(seat); } self.inner.global(evqh, registry, name, interface, version); } @@ -242,6 +198,12 @@ impl WaylandContext { let _ = self.display.flush(); } + pub fn get_seat(&self) -> Option { + let mut guard = self.evq.lock().unwrap(); + let state = guard.state(); + state.get_handler::(self.env_id).get_seat() + } + pub fn with_output(&self, id: MonitorId, f: F) where F: FnOnce(&wl_output::WlOutput) { let mut guard = self.evq.lock().unwrap(); let state = guard.state(); @@ -252,7 +214,7 @@ impl WaylandContext { } } - pub fn create_window(&self, sink: Arc>) + pub fn create_window(&self) -> (Arc, wayland_window::DecoratedSurface) { let mut guard = self.evq.lock().unwrap(); @@ -260,7 +222,6 @@ impl WaylandContext { let env = state.get_mut_handler::(self.env_id); // this "expect" cannot trigger (see https://github.com/vberger/wayland-client-rs/issues/69) let surface = Arc::new(env.inner.compositor.create_surface().expect("Compositor cannot be dead")); - env.windows.push((surface.clone(), sink)); let decorated = wayland_window::DecoratedSurface::new( &*surface, 800, 600, &env.inner.compositor, @@ -272,13 +233,6 @@ impl WaylandContext { ).expect("Failed to create a tmpfile buffer."); (surface, decorated) } - - pub fn prune_dead_windows(&self) { - let mut guard = self.evq.lock().unwrap(); - let mut state = guard.state(); - let env = state.get_mut_handler::(self.env_id); - env.windows.retain(|w| w.0.is_alive()); - } } /* @@ -342,346 +296,3 @@ impl MonitorId { (0,0) } } - -/* - * Input Handling - */ - -impl wl_seat::Handler for WaylandEnv { - fn capabilities(&mut self, - evqh: &mut EventQueueHandle, - seat: &wl_seat::WlSeat, - capabilities: wl_seat::Capability) - { - // create pointer if applicable - if capabilities.contains(wl_seat::Pointer) && self.mouse.is_none() { - let pointer = seat.get_pointer().expect("Seat is not dead"); - evqh.register::<_, WaylandEnv>(&pointer, self.my_id); - self.mouse = Some(pointer); - } - // destroy pointer if applicable - if !capabilities.contains(wl_seat::Pointer) { - if let Some(pointer) = self.mouse.take() { - pointer.release(); - } - } - // create keyboard if applicable - if capabilities.contains(wl_seat::Keyboard) && self.kbd.is_none() { - let kbd = seat.get_keyboard().expect("Seat is not dead"); - evqh.register::<_, WaylandEnv>(&kbd, self.my_id); - self.kbd = Some(kbd); - } - // destroy keyboard if applicable - if !capabilities.contains(wl_seat::Keyboard) { - if let Some(kbd) = self.kbd.take() { - kbd.release(); - } - } - } -} - -declare_handler!(WaylandEnv, wl_seat::Handler, wl_seat::WlSeat); - -/* - * Pointer Handling - */ - -impl wl_pointer::Handler for WaylandEnv { - fn enter(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _serial: u32, - surface: &wl_surface::WlSurface, - surface_x: f64, - surface_y: f64) - { - self.mouse_location = (surface_x as i32, surface_y as i32); - for &(ref window, ref sink) in &self.windows { - if window.equals(surface) { - self.mouse_focus = Some((window.clone(), sink.clone())); - let (w, h) = self.mouse_location; - let mut event_queue = sink.lock().unwrap(); - event_queue.push_event(Event::MouseEntered, make_wid(window)); - event_queue.push_event(Event::MouseMoved(w, h), make_wid(window)); - break; - } - } - } - - fn leave(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _serial: u32, - surface: &wl_surface::WlSurface) - { - self.mouse_focus = None; - for &(ref window, ref sink) in &self.windows { - if window.equals(surface) { - let mut event_queue = sink.lock().unwrap(); - event_queue.push_event(Event::MouseLeft, make_wid(window)); - break; - } - } - } - - fn motion(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _time: u32, - surface_x: f64, - surface_y: f64) - { - self.mouse_location = (surface_x as i32, surface_y as i32); - if let Some((ref window, ref sink)) = self.mouse_focus { - let (w,h) = self.mouse_location; - sink.lock().unwrap().push_event( - Event::MouseMoved(w, h), - make_wid(window) - ); - } - } - - fn button(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _serial: u32, - _time: u32, - button: u32, - state: wl_pointer::ButtonState) - { - if let Some((ref window, ref sink)) = self.mouse_focus { - let state = match state { - wl_pointer::ButtonState::Pressed => ElementState::Pressed, - wl_pointer::ButtonState::Released => ElementState::Released - }; - let button = match button { - 0x110 => MouseButton::Left, - 0x111 => MouseButton::Right, - 0x112 => MouseButton::Middle, - // TODO figure out the translation ? - _ => return - }; - sink.lock().unwrap().push_event( - Event::MouseInput(state, button), - make_wid(window) - ); - } - } - - fn axis(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _time: u32, - axis: wl_pointer::Axis, - value: f64) - { - let (mut x, mut y) = self.axis_buffer.unwrap_or((0.0, 0.0)); - match axis { - wl_pointer::Axis::VerticalScroll => y += value as f32, - wl_pointer::Axis::HorizontalScroll => x += value as f32 - } - self.axis_buffer = Some((x,y)); - self.axis_state = match self.axis_state { - TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, - _ => TouchPhase::Started - } - } - - fn frame(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer) - { - let axis_buffer = self.axis_buffer.take(); - let axis_discrete_buffer = self.axis_discrete_buffer.take(); - if let Some((ref window, ref sink)) = self.mouse_focus { - if let Some((x, y)) = axis_discrete_buffer { - sink.lock().unwrap().push_event( - Event::MouseWheel( - MouseScrollDelta::LineDelta(x as f32, y as f32), - self.axis_state - ), - make_wid(window) - ); - } else if let Some((x, y)) = axis_buffer { - sink.lock().unwrap().push_event( - Event::MouseWheel( - MouseScrollDelta::PixelDelta(x as f32, y as f32), - self.axis_state - ), - make_wid(window) - ); - } - } - } - - fn axis_source(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _axis_source: wl_pointer::AxisSource) - { - } - - fn axis_stop(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - _time: u32, - _axis: wl_pointer::Axis) - { - self.axis_state = TouchPhase::Ended; - } - - fn axis_discrete(&mut self, - _evqh: &mut EventQueueHandle, - _proxy: &wl_pointer::WlPointer, - axis: wl_pointer::Axis, - discrete: i32) - { - let (mut x, mut y) = self.axis_discrete_buffer.unwrap_or((0,0)); - match axis { - wl_pointer::Axis::VerticalScroll => y += discrete, - wl_pointer::Axis::HorizontalScroll => x += discrete - } - self.axis_discrete_buffer = Some((x,y)); - self.axis_state = match self.axis_state { - TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, - _ => TouchPhase::Started - } - } -} - -declare_handler!(WaylandEnv, wl_pointer::Handler, wl_pointer::WlPointer); - -/* - * Keyboard Handling - */ - -impl wl_keyboard::Handler for WaylandEnv { - // mostly pass-through - fn keymap(&mut self, - evqh: &mut EventQueueHandle, - proxy: &wl_keyboard::WlKeyboard, - format: wl_keyboard::KeymapFormat, - fd: ::std::os::unix::io::RawFd, - size: u32) - { - match self.kbd_handler { - KbdType::Mapped(ref mut h) => h.keymap(evqh, proxy, format, fd, size), - _ => () - } - } - - fn enter(&mut self, - evqh: &mut EventQueueHandle, - proxy: &wl_keyboard::WlKeyboard, - serial: u32, - surface: &wl_surface::WlSurface, - keys: Vec) - { - let mut opt_sink = None; - for &(ref window, ref sink) in &self.windows { - if window.equals(surface) { - opt_sink = Some((window.clone(), sink.clone())); - break; - } - } - if let Some((ref window, ref sink)) = opt_sink { - // send focused event - let mut guard = sink.lock().unwrap(); - guard.push_event(Event::Focused(true), make_wid(window)); - } - match self.kbd_handler { - KbdType::Mapped(ref mut h) => { - h.handler().target = opt_sink; - h.enter(evqh, proxy, serial, surface, keys); - }, - KbdType::Plain(ref mut opt) => { *opt = opt_sink; } - } - } - - fn leave(&mut self, - evqh: &mut EventQueueHandle, - proxy: &wl_keyboard::WlKeyboard, - serial: u32, - surface: &wl_surface::WlSurface) - { - let opt_sink = match self.kbd_handler { - KbdType::Mapped(ref mut h) => { - let sink = h.handler().target.take(); - h.leave(evqh, proxy, serial, surface); - sink - }, - KbdType::Plain(ref mut opt) => opt.take() - }; - if let Some((ref window, ref sink)) = opt_sink { - let mut guard = sink.lock().unwrap(); - guard.push_event(Event::Focused(false), make_wid(window)); - } - } - - fn key(&mut self, - evqh: &mut EventQueueHandle, - proxy: &wl_keyboard::WlKeyboard, - serial: u32, - time: u32, - key: u32, - state: wl_keyboard::KeyState) - { - match self.kbd_handler { - KbdType::Mapped(ref mut h) => h.key(evqh, proxy, serial, time, key, state), - KbdType::Plain(Some((ref window, ref sink))) => { - let state = match state { - wl_keyboard::KeyState::Pressed => ElementState::Pressed, - wl_keyboard::KeyState::Released => ElementState::Released, - }; - let mut guard = sink.lock().unwrap(); - // This is fallback impl if libxkbcommon was not available - // This case should probably never happen, as most wayland - // compositors _need_ libxkbcommon anyway... - // - // In this case, we don't have the modifiers state information - // anyway, as we need libxkbcommon to interpret it (it is - // supposed to be serialized by the compositor using libxkbcommon) - guard.push_event( - Event::KeyboardInput( - state, - key as u8, - None, - ModifiersState::default() - ), - make_wid(window) - ); - }, - KbdType::Plain(None) => () - } - } - - fn modifiers(&mut self, - evqh: &mut EventQueueHandle, - proxy: &wl_keyboard::WlKeyboard, - serial: u32, - mods_depressed: u32, - mods_latched: u32, - mods_locked: u32, - group: u32) - { - match self.kbd_handler { - KbdType::Mapped(ref mut h) => h.modifiers(evqh, proxy, serial, mods_depressed, - mods_latched, mods_locked, group), - _ => () - } - } - - fn repeat_info(&mut self, - evqh: &mut EventQueueHandle, - proxy: &wl_keyboard::WlKeyboard, - rate: i32, - delay: i32) - { - match self.kbd_handler { - KbdType::Mapped(ref mut h) => h.repeat_info(evqh, proxy, rate, delay), - _ => () - } - } -} - -declare_handler!(WaylandEnv, wl_keyboard::Handler, wl_keyboard::WlKeyboard); diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index 0477d7b9..9cdcc33f 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -1,15 +1,23 @@ +use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState}; + +use std::cell::UnsafeCell; use std::collections::VecDeque; use std::sync::{Arc, Mutex}; use std::sync::atomic::AtomicBool; use super::{DecoratedHandler, WindowId, WaylandContext}; -use wayland_client::EventQueue; + +use wayland_client::{EventQueue, EventQueueHandle, Init, Proxy}; +use wayland_client::protocol::{wl_seat, wl_surface, wl_pointer, wl_keyboard}; + +use super::make_wid; use super::wayland_window::DecoratedSurface; +use super::wayland_kbd::MappedKeyboard; +use super::keyboard::KbdHandler; pub struct EventsLoopSink { - callback: Option<*mut FnMut(::Event)>, - queue: VecDeque<::Event> + callback: Box } unsafe impl Send for EventsLoopSink { } @@ -17,21 +25,16 @@ unsafe impl Send for EventsLoopSink { } impl EventsLoopSink { pub fn new() -> EventsLoopSink { EventsLoopSink { - callback: None, - queue: VecDeque::new() + callback: Box::new(|_| {}), } } - pub fn push_event(&mut self, evt: ::WindowEvent, wid: WindowId) { + pub fn send_event(&mut self, evt: ::WindowEvent, wid: WindowId) { let evt = ::Event::WindowEvent { event: evt, window_id: ::WindowId(::platform::WindowId::Wayland(wid)) }; - if let Some(cb) = self.callback { - unsafe { (&mut *cb)(evt) } - } else { - self.queue.push_back(evt) - } + (self.callback)(evt) } // This function is only safe of the set callback is unset before exclusive @@ -39,25 +42,12 @@ impl EventsLoopSink { // // The callback also cannot be used any longer as long as it has not been // cleared from the Sink. - unsafe fn set_callback(&mut self, cb: &mut FnMut(::Event)) { - let cb: &mut FnMut(::Event) = ::std::mem::transmute(cb); - self.callback = Some(cb as *mut _); + unsafe fn set_callback(&mut self, cb: Box) -> Box { + ::std::mem::replace(&mut self.callback, cb) } fn with_callback(&mut self, f: F) { - if let Some(cb) = self.callback { - f(unsafe {&mut *cb}) - } - } - - fn clear_callback(&mut self) { - self.callback = None - } - - fn drain_queue(&mut self, cb: &mut F) { - for evt in self.queue.drain(..) { - cb(evt) - } + f(&mut *self.callback) } } @@ -67,30 +57,33 @@ pub struct EventsLoop { decorated_ids: Mutex>, sink: Arc>, interrupted: AtomicBool, + hid: usize } impl EventsLoop { pub fn new(ctxt: Arc) -> EventsLoop { - let evq = ctxt.display.create_event_queue(); + let mut evq = ctxt.display.create_event_queue(); + let sink = Arc::new(Mutex::new(EventsLoopSink::new())); + let hid = evq.add_handler_with_init(InputHandler::new(&ctxt, sink.clone())); EventsLoop { ctxt: ctxt, evq: Arc::new(Mutex::new(evq)), decorated_ids: Mutex::new(Vec::new()), - sink: Arc::new(Mutex::new(EventsLoopSink::new())), - interrupted: AtomicBool::new(false) + sink: sink, + interrupted: AtomicBool::new(false), + hid: hid } } - - pub fn get_sink(&self) -> Arc> { - self.sink.clone() - } pub fn get_event_queue(&self) -> Arc> { self.evq.clone() } - - pub fn register_window(&self, decorated_id: usize, wid: WindowId) { - self.decorated_ids.lock().unwrap().push((decorated_id, wid)); + + pub fn register_window(&self, decorated_id: usize, surface: Arc) { + self.decorated_ids.lock().unwrap().push((decorated_id, make_wid(&surface))); + let mut guard = self.evq.lock().unwrap(); + let mut state = guard.state(); + state.get_mut_handler::(self.hid).windows.push(surface); } fn process_resize(evq: &mut EventQueue, ids: &[(usize, WindowId)], callback: &mut FnMut(::Event)) @@ -123,33 +116,32 @@ impl EventsLoop { // first of all, get exclusive access to this event queue let mut evq_guard = self.evq.lock().unwrap(); - // dispatch stored events: - self.sink.lock().unwrap().drain_queue(&mut callback); - // read some events from the socket if some are waiting & queue is empty if let Some(guard) = evq_guard.prepare_read() { guard.read_events().expect("Wayland connection unexpectedly lost"); } // set the callback into the sink - unsafe { self.sink.lock().unwrap().set_callback(&mut callback) }; + // we extend the lifetime of the closure to 'static to be able to put it in + // the sink, but we'll explicitly drop it at the end of this function, so it's fine + let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box) }; + let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) }; // then do the actual dispatching self.ctxt.dispatch_pending(); evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost"); - + let mut sink_guard = self.sink.lock().unwrap(); - + // events where probably dispatched, process resize let ids_guard = self.decorated_ids.lock().unwrap(); sink_guard.with_callback( |cb| Self::process_resize(&mut evq_guard, &ids_guard, cb) ); - - sink_guard.clear_callback(); - // we must keep callback alive up to this point! - drop(callback); - + + // replace the old noop callback + unsafe { self.sink.lock().unwrap().set_callback(old_cb) }; + } pub fn run_forever(&self, mut callback: F) @@ -161,11 +153,11 @@ impl EventsLoop { // first of all, get exclusive access to this event queue let mut evq_guard = self.evq.lock().unwrap(); - // dispatch stored events: - self.sink.lock().unwrap().drain_queue(&mut callback); - // set the callback into the sink - unsafe { self.sink.lock().unwrap().set_callback(&mut callback) }; + // we extend the lifetime of the closure to 'static to be able to put it in + // the sink, but we'll explicitly drop it at the end of this function, so it's fine + let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box) }; + let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) }; while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) { self.ctxt.dispatch(); @@ -177,8 +169,388 @@ impl EventsLoop { self.ctxt.flush(); } - self.sink.lock().unwrap().clear_callback(); - // we must keep callback alive up to this point! - drop(callback) + // replace the old noop callback + unsafe { self.sink.lock().unwrap().set_callback(old_cb) }; } } + +enum KbdType { + Mapped(MappedKeyboard), + Plain(Option) +} + +struct InputHandler { + my_id: usize, + windows: Vec>, + seat: Option, + mouse: Option, + mouse_focus: Option>, + mouse_location: (i32, i32), + axis_buffer: Option<(f32, f32)>, + axis_discrete_buffer: Option<(i32, i32)>, + axis_state: TouchPhase, + kbd: Option, + kbd_handler: KbdType, + callback: Arc> +} + +impl InputHandler { + fn new(ctxt: &WaylandContext, sink: Arc>) -> InputHandler { + let kbd_handler = match MappedKeyboard::new(KbdHandler::new(sink.clone())) { + Ok(h) => KbdType::Mapped(h), + Err(_) => KbdType::Plain(None) + }; + InputHandler { + my_id: 0, + windows: Vec::new(), + seat: ctxt.get_seat(), + mouse: None, + mouse_focus: None, + mouse_location: (0,0), + axis_buffer: None, + axis_discrete_buffer: None, + axis_state: TouchPhase::Started, + kbd: None, + kbd_handler: kbd_handler, + callback: sink + } + } +} + +impl Init for InputHandler { + fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) { + if let Some(ref seat) = self.seat { + evqh.register::<_, InputHandler>(seat, index); + } + self.my_id = index; + } +} + +impl wl_seat::Handler for InputHandler { + fn capabilities(&mut self, + evqh: &mut EventQueueHandle, + seat: &wl_seat::WlSeat, + capabilities: wl_seat::Capability) + { + // create pointer if applicable + if capabilities.contains(wl_seat::Pointer) && self.mouse.is_none() { + let pointer = seat.get_pointer().expect("Seat is not dead"); + evqh.register::<_, InputHandler>(&pointer, self.my_id); + self.mouse = Some(pointer); + } + // destroy pointer if applicable + if !capabilities.contains(wl_seat::Pointer) { + if let Some(pointer) = self.mouse.take() { + pointer.release(); + } + } + // create keyboard if applicable + if capabilities.contains(wl_seat::Keyboard) && self.kbd.is_none() { + let kbd = seat.get_keyboard().expect("Seat is not dead"); + evqh.register::<_, InputHandler>(&kbd, self.my_id); + self.kbd = Some(kbd); + } + // destroy keyboard if applicable + if !capabilities.contains(wl_seat::Keyboard) { + if let Some(kbd) = self.kbd.take() { + kbd.release(); + } + } + } +} + +declare_handler!(InputHandler, wl_seat::Handler, wl_seat::WlSeat); + +/* + * Pointer Handling + */ + +impl wl_pointer::Handler for InputHandler { + fn enter(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _serial: u32, + surface: &wl_surface::WlSurface, + surface_x: f64, + surface_y: f64) + { + self.mouse_location = (surface_x as i32, surface_y as i32); + for window in &self.windows { + if window.equals(surface) { + self.mouse_focus = Some(window.clone()); + let (w, h) = self.mouse_location; + let mut guard = self.callback.lock().unwrap(); + guard.send_event(Event::MouseEntered, make_wid(window)); + guard.send_event(Event::MouseMoved(w, h), make_wid(window)); + break; + } + } + } + + fn leave(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _serial: u32, + surface: &wl_surface::WlSurface) + { + self.mouse_focus = None; + for window in &self.windows { + if window.equals(surface) { + self.callback.lock().unwrap().send_event(Event::MouseLeft, make_wid(window)); + } + } + } + + fn motion(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _time: u32, + surface_x: f64, + surface_y: f64) + { + self.mouse_location = (surface_x as i32, surface_y as i32); + if let Some(ref window) = self.mouse_focus { + let (w,h) = self.mouse_location; + self.callback.lock().unwrap().send_event(Event::MouseMoved(w, h), make_wid(window)); + } + } + + fn button(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _serial: u32, + _time: u32, + button: u32, + state: wl_pointer::ButtonState) + { + if let Some(ref window) = self.mouse_focus { + let state = match state { + wl_pointer::ButtonState::Pressed => ElementState::Pressed, + wl_pointer::ButtonState::Released => ElementState::Released + }; + let button = match button { + 0x110 => MouseButton::Left, + 0x111 => MouseButton::Right, + 0x112 => MouseButton::Middle, + // TODO figure out the translation ? + _ => return + }; + self.callback.lock().unwrap().send_event(Event::MouseInput(state, button), make_wid(window)); + } + } + + fn axis(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _time: u32, + axis: wl_pointer::Axis, + value: f64) + { + let (mut x, mut y) = self.axis_buffer.unwrap_or((0.0, 0.0)); + match axis { + wl_pointer::Axis::VerticalScroll => y += value as f32, + wl_pointer::Axis::HorizontalScroll => x += value as f32 + } + self.axis_buffer = Some((x,y)); + self.axis_state = match self.axis_state { + TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, + _ => TouchPhase::Started + } + } + + fn frame(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer) + { + let axis_buffer = self.axis_buffer.take(); + let axis_discrete_buffer = self.axis_discrete_buffer.take(); + if let Some(ref window) = self.mouse_focus { + if let Some((x, y)) = axis_discrete_buffer { + self.callback.lock().unwrap().send_event( + Event::MouseWheel( + MouseScrollDelta::LineDelta(x as f32, y as f32), + self.axis_state + ), + make_wid(window) + ); + } else if let Some((x, y)) = axis_buffer { + self.callback.lock().unwrap().send_event( + Event::MouseWheel( + MouseScrollDelta::PixelDelta(x as f32, y as f32), + self.axis_state + ), + make_wid(window) + ); + } + } + } + + fn axis_source(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _axis_source: wl_pointer::AxisSource) + { + } + + fn axis_stop(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + _time: u32, + _axis: wl_pointer::Axis) + { + self.axis_state = TouchPhase::Ended; + } + + fn axis_discrete(&mut self, + _evqh: &mut EventQueueHandle, + _proxy: &wl_pointer::WlPointer, + axis: wl_pointer::Axis, + discrete: i32) + { + let (mut x, mut y) = self.axis_discrete_buffer.unwrap_or((0,0)); + match axis { + wl_pointer::Axis::VerticalScroll => y += discrete, + wl_pointer::Axis::HorizontalScroll => x += discrete + } + self.axis_discrete_buffer = Some((x,y)); + self.axis_state = match self.axis_state { + TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, + _ => TouchPhase::Started + } + } +} + +declare_handler!(InputHandler, wl_pointer::Handler, wl_pointer::WlPointer); + +/* + * Keyboard Handling + */ + +impl wl_keyboard::Handler for InputHandler { + // mostly pass-through + fn keymap(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + format: wl_keyboard::KeymapFormat, + fd: ::std::os::unix::io::RawFd, + size: u32) + { + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.keymap(evqh, proxy, format, fd, size), + _ => () + } + } + + fn enter(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + surface: &wl_surface::WlSurface, + keys: Vec) + { + for window in &self.windows { + if window.equals(surface) { + self.callback.lock().unwrap().send_event(Event::Focused(true), make_wid(window)); + match self.kbd_handler { + KbdType::Mapped(ref mut h) => { + h.handler().target = Some(make_wid(window)); + h.enter(evqh, proxy, serial, surface, keys); + }, + KbdType::Plain(ref mut target) => { + *target = Some(make_wid(window)) + } + } + break; + } + } + } + + fn leave(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + surface: &wl_surface::WlSurface) + { + for window in &self.windows { + if window.equals(surface) { + self.callback.lock().unwrap().send_event(Event::Focused(false), make_wid(window)); + match self.kbd_handler { + KbdType::Mapped(ref mut h) => { + h.handler().target = None; + h.leave(evqh, proxy, serial, surface); + }, + KbdType::Plain(ref mut target) => { + *target = None + } + } + break; + } + } + } + + fn key(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + time: u32, + key: u32, + state: wl_keyboard::KeyState) + { + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.key(evqh, proxy, serial, time, key, state), + KbdType::Plain(Some(wid)) => { + let state = match state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + }; + // This is fallback impl if libxkbcommon was not available + // This case should probably never happen, as most wayland + // compositors _need_ libxkbcommon anyway... + // + // In this case, we don't have the modifiers state information + // anyway, as we need libxkbcommon to interpret it (it is + // supposed to be serialized by the compositor using libxkbcommon) + self.callback.lock().unwrap().send_event( + Event::KeyboardInput( + state, + key as u8, + None, + ModifiersState::default() + ), + wid + ); + }, + KbdType::Plain(None) => () + } + } + + fn modifiers(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + serial: u32, + mods_depressed: u32, + mods_latched: u32, + mods_locked: u32, + group: u32) + { + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.modifiers(evqh, proxy, serial, mods_depressed, + mods_latched, mods_locked, group), + _ => () + } + } + + fn repeat_info(&mut self, + evqh: &mut EventQueueHandle, + proxy: &wl_keyboard::WlKeyboard, + rate: i32, + delay: i32) + { + match self.kbd_handler { + KbdType::Mapped(ref mut h) => h.repeat_info(evqh, proxy, rate, delay), + _ => () + } + } +} + +declare_handler!(InputHandler, wl_keyboard::Handler, wl_keyboard::WlKeyboard); diff --git a/src/platform/linux/wayland/keyboard.rs b/src/platform/linux/wayland/keyboard.rs index 3a73f43a..95e70b03 100644 --- a/src/platform/linux/wayland/keyboard.rs +++ b/src/platform/linux/wayland/keyboard.rs @@ -4,17 +4,18 @@ use {VirtualKeyCode, ElementState, WindowEvent as Event}; use events::ModifiersState; -use super::{wayland_kbd, make_wid, EventsLoopSink}; +use super::{wayland_kbd, EventsLoopSink, WindowId}; use wayland_client::EventQueueHandle; -use wayland_client::protocol::{wl_keyboard, wl_surface}; +use wayland_client::protocol::wl_keyboard; pub struct KbdHandler { - pub target: Option<(Arc,Arc>)> + sink: Arc>, + pub target: Option } impl KbdHandler { - pub fn new() -> KbdHandler { - KbdHandler { target: None } + pub fn new(sink: Arc>) -> KbdHandler { + KbdHandler { sink: sink, target: None } } } @@ -30,14 +31,14 @@ impl wayland_kbd::Handler for KbdHandler { state: wl_keyboard::KeyState, utf8: Option) { - if let Some((ref window, ref sink)) = self.target { + if let Some(wid) = self.target { let state = match state { wl_keyboard::KeyState::Pressed => ElementState::Pressed, wl_keyboard::KeyState::Released => ElementState::Released, }; let vkcode = key_to_vkey(rawkey, keysym); - let mut guard = sink.lock().unwrap(); - guard.push_event( + let mut guard = self.sink.lock().unwrap(); + guard.send_event( Event::KeyboardInput( state, rawkey as u8, @@ -49,13 +50,13 @@ impl wayland_kbd::Handler for KbdHandler { logo: mods.logo } ), - make_wid(window) + wid ); // send char event only on key press, not release if let ElementState::Released = state { return } if let Some(txt) = utf8 { for chr in txt.chars() { - guard.push_event(Event::ReceivedCharacter(chr), make_wid(window)); + guard.send_event(Event::ReceivedCharacter(chr), wid); } } } diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index 76f4c44f..af07adbd 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, Mutex}; -use wayland_client::{EventQueue, EventQueueHandle, Init, Proxy}; +use wayland_client::{EventQueue, EventQueueHandle, Proxy}; use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface}; use {CreationError, MouseCursor, CursorState, WindowAttributes}; @@ -31,7 +31,7 @@ impl Window { { let (width, height) = attributes.dimensions.unwrap_or((800,600)); - let (surface, decorated) = ctxt.create_window::(evlp.get_sink()); + let (surface, decorated) = ctxt.create_window::(); // init DecoratedSurface let evq = evlp.get_event_queue(); @@ -67,7 +67,7 @@ impl Window { decorated_id: decorated_id }; - evlp.register_window(me.decorated_id, me.id()); + evlp.register_window(me.decorated_id, me.surface.clone()); Ok(me) } @@ -165,7 +165,6 @@ impl Window { impl Drop for Window { fn drop(&mut self) { self.surface.destroy(); - self.ctxt.prune_dead_windows(); } } From 3ff9eb08e8e370da6505c0560c53233b0399edaa Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 10 Mar 2017 23:40:31 +0100 Subject: [PATCH 4/5] wayland: cleanup signal to prune dead windows --- src/platform/linux/wayland/event_loop.rs | 42 +++++++++++++++++------- src/platform/linux/wayland/window.rs | 6 +++- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index 9cdcc33f..ea86dd58 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -1,7 +1,5 @@ use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState}; -use std::cell::UnsafeCell; -use std::collections::VecDeque; use std::sync::{Arc, Mutex}; use std::sync::atomic::AtomicBool; @@ -54,9 +52,10 @@ impl EventsLoopSink { pub struct EventsLoop { ctxt: Arc, evq: Arc>, - decorated_ids: Mutex>, + decorated_ids: Mutex)>>, sink: Arc>, interrupted: AtomicBool, + cleanup_needed: Arc, hid: usize } @@ -71,31 +70,32 @@ impl EventsLoop { decorated_ids: Mutex::new(Vec::new()), sink: sink, interrupted: AtomicBool::new(false), + cleanup_needed: Arc::new(AtomicBool::new(false)), hid: hid } } - pub fn get_event_queue(&self) -> Arc> { - self.evq.clone() + pub fn get_window_init(&self) -> (Arc>, Arc) { + (self.evq.clone(), self.cleanup_needed.clone()) } pub fn register_window(&self, decorated_id: usize, surface: Arc) { - self.decorated_ids.lock().unwrap().push((decorated_id, make_wid(&surface))); + self.decorated_ids.lock().unwrap().push((decorated_id, surface.clone())); let mut guard = self.evq.lock().unwrap(); let mut state = guard.state(); state.get_mut_handler::(self.hid).windows.push(surface); } - fn process_resize(evq: &mut EventQueue, ids: &[(usize, WindowId)], callback: &mut FnMut(::Event)) + fn process_resize(evq: &mut EventQueue, ids: &[(usize, Arc)], callback: &mut FnMut(::Event)) { let mut state = evq.state(); - for &(decorated_id, window_id) in ids { + for &(decorated_id, ref window) in ids { let decorated = state.get_mut_handler::>(decorated_id); if let Some((w, h)) = decorated.handler().as_mut().and_then(|h| h.take_newsize()) { decorated.resize(w as i32, h as i32); callback( ::Event::WindowEvent { - window_id: ::WindowId(::platform::WindowId::Wayland(window_id)), + window_id: ::WindowId(::platform::WindowId::Wayland(make_wid(&window))), event: ::WindowEvent::Resized(w,h) } ); @@ -107,7 +107,20 @@ impl EventsLoop { self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed); } - pub fn poll_events(&self, mut callback: F) + fn prune_dead_windows(&self) { + self.decorated_ids.lock().unwrap().retain(|&(_, ref w)| w.is_alive()); + let mut evq_guard = self.evq.lock().unwrap(); + let mut state = evq_guard.state(); + let handler = state.get_mut_handler::(self.hid); + handler.windows.retain(|w| w.is_alive()); + if let Some(w) = handler.mouse_focus.take() { + if w.is_alive() { + handler.mouse_focus = Some(w) + } + } + } + + pub fn poll_events(&self, callback: F) where F: FnMut(::Event) { // send pending requests to the server... @@ -142,9 +155,12 @@ impl EventsLoop { // replace the old noop callback unsafe { self.sink.lock().unwrap().set_callback(old_cb) }; + if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) { + self.prune_dead_windows() + } } - pub fn run_forever(&self, mut callback: F) + pub fn run_forever(&self, callback: F) where F: FnMut(::Event) { // send pending requests to the server... @@ -171,6 +187,10 @@ impl EventsLoop { // replace the old noop callback unsafe { self.sink.lock().unwrap().set_callback(old_cb) }; + + if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) { + self.prune_dead_windows() + } } } diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index af07adbd..30d192b4 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -1,4 +1,5 @@ use std::sync::{Arc, Mutex}; +use std::sync::atomic::AtomicBool; use wayland_client::{EventQueue, EventQueueHandle, Proxy}; use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface}; @@ -13,6 +14,7 @@ use super::wayland_window::DecoratedSurface; pub struct Window { ctxt: Arc, evq: Arc>, + cleanup_signal: Arc, surface: Arc, size: Mutex<(u32, u32)>, decorated_id: usize @@ -34,7 +36,7 @@ impl Window { let (surface, decorated) = ctxt.create_window::(); // init DecoratedSurface - let evq = evlp.get_event_queue(); + let (evq, cleanup_signal) = evlp.get_window_init(); let decorated_id = { let mut evq_guard = evq.lock().unwrap(); let decorated_id = evq_guard.add_handler_with_init(decorated); @@ -62,6 +64,7 @@ impl Window { let me = Window { ctxt: ctxt, evq: evq, + cleanup_signal: cleanup_signal, surface: surface, size: Mutex::new((width, height)), decorated_id: decorated_id @@ -165,6 +168,7 @@ impl Window { impl Drop for Window { fn drop(&mut self) { self.surface.destroy(); + self.cleanup_signal.store(true, ::std::sync::atomic::Ordering::Relaxed); } } From d3356763dc166e515106302e6b28081bb5f214ad Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 10 Mar 2017 23:56:31 +0100 Subject: [PATCH 5/5] wayland: add some comments --- src/platform/linux/mod.rs | 4 ++-- src/platform/linux/wayland/event_loop.rs | 24 ++++++++++++++++++++---- src/platform/linux/wayland/mod.rs | 2 +- src/platform/linux/wayland/window.rs | 9 +++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index fd820225..6e12ffe1 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -47,7 +47,7 @@ pub enum Window2 { #[doc(hidden)] X(x11::Window2), #[doc(hidden)] - Wayland(wayland::Window2) + Wayland(wayland::Window) } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -130,7 +130,7 @@ impl Window2 { match *UNIX_BACKEND { UnixBackend::Wayland(ref ctxt) => { if let EventsLoop::Wayland(ref evlp) = *events_loop { - wayland::Window2::new(evlp, ctxt.clone(), window).map(Window2::Wayland) + wayland::Window::new(evlp, ctxt.clone(), window).map(Window2::Wayland) } else { // It is not possible to instanciate an EventsLoop not matching its backend unreachable!() diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index ea86dd58..efc9411d 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -14,6 +14,15 @@ use super::wayland_window::DecoratedSurface; use super::wayland_kbd::MappedKeyboard; use super::keyboard::KbdHandler; +/// This struct is used as a holder for the callback +/// during the dispatching of events. +/// +/// The proper ay to use it is: +/// - set a callback in it (and retrieve the noop one it contains) +/// - dispatch the EventQueue +/// - put back the noop callback in it +/// +/// Failure to do so is unsafeā„¢ pub struct EventsLoopSink { callback: Box } @@ -50,11 +59,17 @@ impl EventsLoopSink { } pub struct EventsLoop { + // the global wayland context ctxt: Arc, + // our EventQueue evq: Arc>, + // ids of the DecoratedHandlers of the surfaces we know decorated_ids: Mutex)>>, + // our sink, receiver of callbacks, shared with some handlers sink: Arc>, + // trigger interruption of the run interrupted: AtomicBool, + // trigger cleanup of the dead surfaces cleanup_needed: Arc, hid: usize } @@ -75,6 +90,7 @@ impl EventsLoop { } } + // some internals that Window needs access to pub fn get_window_init(&self) -> (Arc>, Arc) { (self.evq.clone(), self.cleanup_needed.clone()) } @@ -183,14 +199,14 @@ impl EventsLoop { |cb| Self::process_resize(&mut evq_guard, &ids_guard, cb) ); self.ctxt.flush(); + + if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) { + self.prune_dead_windows() + } } // replace the old noop callback unsafe { self.sink.lock().unwrap().set_callback(old_cb) }; - - if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) { - self.prune_dead_windows() - } } } diff --git a/src/platform/linux/wayland/mod.rs b/src/platform/linux/wayland/mod.rs index 1f5a6411..f2ae3477 100644 --- a/src/platform/linux/wayland/mod.rs +++ b/src/platform/linux/wayland/mod.rs @@ -1,6 +1,6 @@ #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] -pub use self::window::{Window as Window2, WindowId}; +pub use self::window::{Window, WindowId}; pub use self::event_loop::EventsLoop; pub use self::context::{WaylandContext, MonitorId, get_available_monitors, get_primary_monitor}; diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index 30d192b4..6486c710 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -12,11 +12,17 @@ use super::wayland_window; use super::wayland_window::DecoratedSurface; pub struct Window { + // the global wayland context ctxt: Arc, + // the EventQueue of our EventsLoop evq: Arc>, + // signal to advertize the EventsLoop when we are destroyed cleanup_signal: Arc, + // our wayland surface surface: Arc, + // our current inner dimensions size: Mutex<(u32, u32)>, + // the id of our DecoratedHandler in the EventQueue decorated_id: usize } @@ -41,10 +47,12 @@ impl Window { let mut evq_guard = evq.lock().unwrap(); let decorated_id = evq_guard.add_handler_with_init(decorated); { + // initialize the DecoratedHandler let mut state = evq_guard.state(); let decorated = state.get_mut_handler::>(decorated_id); *(decorated.handler()) = Some(DecoratedHandler::new()); + // set fullscreen if necessary if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor { ctxt.with_output(monitor_id.clone(), |output| { decorated.set_fullscreen( @@ -70,6 +78,7 @@ impl Window { decorated_id: decorated_id }; + // register ourselves to the EventsLoop evlp.register_window(me.decorated_id, me.surface.clone()); Ok(me)