Wayland: Add relative pointer movement (#973)

* Add relative pointer movement for Wayland

* Format changed code with rustfmt

* Wayland: merge window and device event queues into one

* Replace map_or_else call for simplification
This commit is contained in:
Cherser-s 2019-06-25 12:00:41 +03:00 committed by Hal Gentz
parent dbe6a1bcdf
commit 3555de114a
3 changed files with 113 additions and 48 deletions

View file

@ -7,6 +7,11 @@ use std::{
time::Instant, time::Instant,
}; };
use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
zwp_relative_pointer_v1::ZwpRelativePointerV1,
};
use crate::{ use crate::{
dpi::{PhysicalPosition, PhysicalSize}, dpi::{PhysicalPosition, PhysicalSize},
event::ModifiersState, event::ModifiersState,
@ -15,7 +20,7 @@ use crate::{
platform_impl::platform::sticky_exit_callback, platform_impl::platform::sticky_exit_callback,
}; };
use super::{window::WindowStore, WindowId}; use super::{window::WindowStore, DeviceId, WindowId};
use smithay_client_toolkit::{ use smithay_client_toolkit::{
output::OutputMgr, output::OutputMgr,
@ -26,33 +31,37 @@ use smithay_client_toolkit::{
Environment, Environment,
}; };
pub struct WindowEventsSink { pub struct WindowEventsSink<T> {
buffer: VecDeque<(crate::event::WindowEvent, crate::window::WindowId)>, buffer: VecDeque<crate::event::Event<T>>,
} }
impl WindowEventsSink { impl<T> WindowEventsSink<T> {
pub fn new() -> WindowEventsSink { pub fn new() -> WindowEventsSink<T> {
WindowEventsSink { WindowEventsSink {
buffer: VecDeque::new(), buffer: VecDeque::new(),
} }
} }
pub fn send_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) { pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
self.buffer.push_back(( self.buffer.push_back(crate::event::Event::WindowEvent {
evt, event: evt,
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)), window_id: crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)),
)); });
} }
fn empty_with<F, T>(&mut self, mut callback: F) pub fn send_device_event(&mut self, evt: crate::event::DeviceEvent, dev_id: DeviceId) {
self.buffer.push_back(crate::event::Event::DeviceEvent {
event: evt,
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(dev_id)),
});
}
fn empty_with<F>(&mut self, mut callback: F)
where where
F: FnMut(crate::event::Event<T>), F: FnMut(crate::event::Event<T>),
{ {
for (evt, wid) in self.buffer.drain(..) { for evt in self.buffer.drain(..) {
callback(crate::event::Event::WindowEvent { callback(evt)
event: evt,
window_id: wid,
})
} }
} }
} }
@ -65,7 +74,7 @@ pub struct EventLoop<T: 'static> {
// the output manager // the output manager
pub outputs: OutputMgr, pub outputs: OutputMgr,
// our sink, shared with some handlers, buffering the events // our sink, shared with some handlers, buffering the events
sink: Arc<Mutex<WindowEventsSink>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
pending_user_events: Rc<RefCell<VecDeque<T>>>, pending_user_events: Rc<RefCell<VecDeque<T>>>,
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>, _user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
user_sender: ::calloop::channel::Sender<T>, user_sender: ::calloop::channel::Sender<T>,
@ -122,13 +131,14 @@ impl<T: 'static> EventLoop<T> {
.handle() .handle()
.insert_source(kbd_channel, move |evt, &mut ()| { .insert_source(kbd_channel, move |evt, &mut ()| {
if let ::calloop::channel::Event::Msg((evt, wid)) = evt { if let ::calloop::channel::Event::Msg((evt, wid)) = evt {
kbd_sink.lock().unwrap().send_event(evt, wid); kbd_sink.lock().unwrap().send_window_event(evt, wid);
} }
}) })
.unwrap(); .unwrap();
let mut seat_manager = SeatManager { let mut seat_manager = SeatManager {
sink: sink.clone(), sink: sink.clone(),
relative_pointer_manager_proxy: None,
store: store.clone(), store: store.clone(),
seats: seats.clone(), seats: seats.clone(),
kbd_sender, kbd_sender,
@ -143,6 +153,15 @@ impl<T: 'static> EventLoop<T> {
ref interface, ref interface,
version, version,
} => { } => {
if interface == "zwp_relative_pointer_manager_v1" {
seat_manager.relative_pointer_manager_proxy = Some(
registry
.bind(version, id, move |pointer_manager| {
pointer_manager.implement_closure(|_, _| (), ())
})
.unwrap(),
)
}
if interface == "wl_seat" { if interface == "wl_seat" {
seat_manager.add_seat(id, version, registry) seat_manager.add_seat(id, version, registry)
} }
@ -388,7 +407,7 @@ impl<T> EventLoop<T> {
let pruned = window_target.store.lock().unwrap().cleanup(); let pruned = window_target.store.lock().unwrap().cleanup();
*cleanup_needed = false; *cleanup_needed = false;
for wid in pruned { for wid in pruned {
sink.send_event(crate::event::WindowEvent::Destroyed, wid); sink.send_window_event(crate::event::WindowEvent::Destroyed, wid);
} }
} }
} }
@ -400,7 +419,10 @@ impl<T> EventLoop<T> {
frame.resize(w, h); frame.resize(w, h);
frame.refresh(); frame.refresh();
let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64); let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64);
sink.send_event(crate::event::WindowEvent::Resized(logical_size), wid); sink.send_window_event(
crate::event::WindowEvent::Resized(logical_size),
wid,
);
*size = (w, h); *size = (w, h);
} else if frame_refresh { } else if frame_refresh {
frame.refresh(); frame.refresh();
@ -410,16 +432,16 @@ impl<T> EventLoop<T> {
} }
} }
if let Some(dpi) = new_dpi { if let Some(dpi) = new_dpi {
sink.send_event( sink.send_window_event(
crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64), crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64),
wid, wid,
); );
} }
if refresh { if refresh {
sink.send_event(crate::event::WindowEvent::RedrawRequested, wid); sink.send_window_event(crate::event::WindowEvent::RedrawRequested, wid);
} }
if closed { if closed {
sink.send_event(crate::event::WindowEvent::CloseRequested, wid); sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid);
} }
}, },
) )
@ -430,14 +452,15 @@ impl<T> EventLoop<T> {
* Wayland protocol implementations * Wayland protocol implementations
*/ */
struct SeatManager { struct SeatManager<T: 'static> {
sink: Arc<Mutex<WindowEventsSink>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>, seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
relative_pointer_manager_proxy: Option<ZwpRelativePointerManagerV1>,
} }
impl SeatManager { impl<T: 'static> SeatManager<T> {
fn add_seat(&mut self, id: u32, version: u32, registry: wl_registry::WlRegistry) { fn add_seat(&mut self, id: u32, version: u32, registry: wl_registry::WlRegistry) {
use std::cmp::min; use std::cmp::min;
@ -445,6 +468,8 @@ impl SeatManager {
sink: self.sink.clone(), sink: self.sink.clone(),
store: self.store.clone(), store: self.store.clone(),
pointer: None, pointer: None,
relative_pointer: None,
relative_pointer_manager_proxy: self.relative_pointer_manager_proxy.as_ref().cloned(),
keyboard: None, keyboard: None,
touch: None, touch: None,
kbd_sender: self.kbd_sender.clone(), kbd_sender: self.kbd_sender.clone(),
@ -470,17 +495,19 @@ impl SeatManager {
} }
} }
struct SeatData { struct SeatData<T> {
sink: Arc<Mutex<WindowEventsSink>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
pointer: Option<wl_pointer::WlPointer>, pointer: Option<wl_pointer::WlPointer>,
relative_pointer: Option<ZwpRelativePointerV1>,
relative_pointer_manager_proxy: Option<ZwpRelativePointerManagerV1>,
keyboard: Option<wl_keyboard::WlKeyboard>, keyboard: Option<wl_keyboard::WlKeyboard>,
touch: Option<wl_touch::WlTouch>, touch: Option<wl_touch::WlTouch>,
modifiers_tracker: Arc<Mutex<ModifiersState>>, modifiers_tracker: Arc<Mutex<ModifiersState>>,
} }
impl SeatData { impl<T: 'static> SeatData<T> {
fn receive(&mut self, evt: wl_seat::Event, seat: wl_seat::WlSeat) { fn receive(&mut self, evt: wl_seat::Event, seat: wl_seat::WlSeat) {
match evt { match evt {
wl_seat::Event::Name { .. } => (), wl_seat::Event::Name { .. } => (),
@ -492,7 +519,19 @@ impl SeatData {
self.sink.clone(), self.sink.clone(),
self.store.clone(), self.store.clone(),
self.modifiers_tracker.clone(), self.modifiers_tracker.clone(),
)) ));
self.relative_pointer =
self.relative_pointer_manager_proxy
.as_ref()
.and_then(|manager| {
super::pointer::implement_relative_pointer(
self.sink.clone(),
self.pointer.as_ref().unwrap(),
manager,
)
.ok()
})
} }
// destroy pointer if applicable // destroy pointer if applicable
if !capabilities.contains(wl_seat::Capability::Pointer) { if !capabilities.contains(wl_seat::Capability::Pointer) {
@ -540,7 +579,7 @@ impl SeatData {
} }
} }
impl Drop for SeatData { impl<T> Drop for SeatData<T> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(pointer) = self.pointer.take() { if let Some(pointer) = self.pointer.take() {
if pointer.as_ref().version() >= 3 { if pointer.as_ref().version() >= 3 {

View file

@ -1,7 +1,8 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::event::{ use crate::event::{
ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent, DeviceEvent, ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase,
WindowEvent,
}; };
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId}; use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId};
@ -11,9 +12,14 @@ use smithay_client_toolkit::reexports::client::protocol::{
wl_seat, wl_seat,
}; };
pub fn implement_pointer( use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, zwp_relative_pointer_v1::Event,
zwp_relative_pointer_v1::ZwpRelativePointerV1,
};
pub fn implement_pointer<T: 'static>(
seat: &wl_seat::WlSeat, seat: &wl_seat::WlSeat,
sink: Arc<Mutex<WindowEventsSink>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
modifiers_tracker: Arc<Mutex<ModifiersState>>, modifiers_tracker: Arc<Mutex<ModifiersState>>,
) -> WlPointer { ) -> WlPointer {
@ -37,7 +43,7 @@ pub fn implement_pointer(
let wid = store.find_wid(&surface); let wid = store.find_wid(&surface);
if let Some(wid) = wid { if let Some(wid) = wid {
mouse_focus = Some(wid); mouse_focus = Some(wid);
sink.send_event( sink.send_window_event(
WindowEvent::CursorEntered { WindowEvent::CursorEntered {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -45,7 +51,7 @@ pub fn implement_pointer(
}, },
wid, wid,
); );
sink.send_event( sink.send_window_event(
WindowEvent::CursorMoved { WindowEvent::CursorMoved {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -61,7 +67,7 @@ pub fn implement_pointer(
mouse_focus = None; mouse_focus = None;
let wid = store.find_wid(&surface); let wid = store.find_wid(&surface);
if let Some(wid) = wid { if let Some(wid) = wid {
sink.send_event( sink.send_window_event(
WindowEvent::CursorLeft { WindowEvent::CursorLeft {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -77,7 +83,7 @@ pub fn implement_pointer(
.. ..
} => { } => {
if let Some(wid) = mouse_focus { if let Some(wid) = mouse_focus {
sink.send_event( sink.send_window_event(
WindowEvent::CursorMoved { WindowEvent::CursorMoved {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -103,7 +109,7 @@ pub fn implement_pointer(
// TODO figure out the translation ? // TODO figure out the translation ?
_ => return, _ => return,
}; };
sink.send_event( sink.send_window_event(
WindowEvent::MouseInput { WindowEvent::MouseInput {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -127,7 +133,7 @@ pub fn implement_pointer(
wl_pointer::Axis::HorizontalScroll => x += value as f32, wl_pointer::Axis::HorizontalScroll => x += value as f32,
_ => unreachable!(), _ => unreachable!(),
} }
sink.send_event( sink.send_window_event(
WindowEvent::MouseWheel { WindowEvent::MouseWheel {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -161,7 +167,7 @@ pub fn implement_pointer(
let axis_discrete_buffer = axis_discrete_buffer.take(); let axis_discrete_buffer = axis_discrete_buffer.take();
if let Some(wid) = mouse_focus { if let Some(wid) = mouse_focus {
if let Some((x, y)) = axis_discrete_buffer { if let Some((x, y)) = axis_discrete_buffer {
sink.send_event( sink.send_window_event(
WindowEvent::MouseWheel { WindowEvent::MouseWheel {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -173,7 +179,7 @@ pub fn implement_pointer(
wid, wid,
); );
} else if let Some((x, y)) = axis_buffer { } else if let Some((x, y)) = axis_buffer {
sink.send_event( sink.send_window_event(
WindowEvent::MouseWheel { WindowEvent::MouseWheel {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -215,3 +221,23 @@ pub fn implement_pointer(
}) })
.unwrap() .unwrap()
} }
pub fn implement_relative_pointer<T: 'static>(
sink: Arc<Mutex<WindowEventsSink<T>>>,
pointer: &WlPointer,
manager: &ZwpRelativePointerManagerV1,
) -> Result<ZwpRelativePointerV1, ()> {
manager.get_relative_pointer(pointer, |rel_pointer| {
rel_pointer.implement_closure(
move |evt, _rel_pointer| {
let mut sink = sink.lock().unwrap();
match evt {
Event::RelativeMotion { dx, dy, .. } => sink
.send_device_event(DeviceEvent::MouseMotion { delta: (dx, dy) }, DeviceId),
_ => unreachable!(),
}
},
(),
)
})
}

View file

@ -15,9 +15,9 @@ struct TouchPoint {
id: i32, id: i32,
} }
pub(crate) fn implement_touch( pub(crate) fn implement_touch<T: 'static>(
seat: &wl_seat::WlSeat, seat: &wl_seat::WlSeat,
sink: Arc<Mutex<WindowEventsSink>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
) -> WlTouch { ) -> WlTouch {
let mut pending_ids = Vec::new(); let mut pending_ids = Vec::new();
@ -32,7 +32,7 @@ pub(crate) fn implement_touch(
} => { } => {
let wid = store.find_wid(&surface); let wid = store.find_wid(&surface);
if let Some(wid) = wid { if let Some(wid) = wid {
sink.send_event( sink.send_window_event(
WindowEvent::Touch(crate::event::Touch { WindowEvent::Touch(crate::event::Touch {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -54,7 +54,7 @@ pub(crate) fn implement_touch(
let idx = pending_ids.iter().position(|p| p.id == id); let idx = pending_ids.iter().position(|p| p.id == id);
if let Some(idx) = idx { if let Some(idx) = idx {
let pt = pending_ids.remove(idx); let pt = pending_ids.remove(idx);
sink.send_event( sink.send_window_event(
WindowEvent::Touch(crate::event::Touch { WindowEvent::Touch(crate::event::Touch {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -71,7 +71,7 @@ pub(crate) fn implement_touch(
let pt = pending_ids.iter_mut().find(|p| p.id == id); let pt = pending_ids.iter_mut().find(|p| p.id == id);
if let Some(pt) = pt { if let Some(pt) = pt {
pt.location = (x, y); pt.location = (x, y);
sink.send_event( sink.send_window_event(
WindowEvent::Touch(crate::event::Touch { WindowEvent::Touch(crate::event::Touch {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),
@ -87,7 +87,7 @@ pub(crate) fn implement_touch(
TouchEvent::Frame => (), TouchEvent::Frame => (),
TouchEvent::Cancel => { TouchEvent::Cancel => {
for pt in pending_ids.drain(..) { for pt in pending_ids.drain(..) {
sink.send_event( sink.send_window_event(
WindowEvent::Touch(crate::event::Touch { WindowEvent::Touch(crate::event::Touch {
device_id: crate::event::DeviceId( device_id: crate::event::DeviceId(
crate::platform_impl::DeviceId::Wayland(DeviceId), crate::platform_impl::DeviceId::Wayland(DeviceId),