From 17fde48ed725c86495cb8835dd3c790371c5956e Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Fri, 10 Mar 2017 23:22:59 +0100 Subject: [PATCH] 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(); } }