From 8f543eb59790ba0b055727cbe6fff1c157354acb Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Mon, 4 May 2020 13:03:36 +0200 Subject: [PATCH] backend.input: rework libinput as a calloop source --- anvil/src/input_handler.rs | 54 ++---- anvil/src/udev.rs | 16 +- anvil/src/winit.rs | 12 +- src/backend/input.rs | 257 +++++++++++----------------- src/backend/libinput/helpers.rs | 245 +++++++++++++++------------ src/backend/libinput/mod.rs | 137 ++++++++------- src/backend/winit.rs | 291 +++++++++++++------------------- 7 files changed, 471 insertions(+), 541 deletions(-) diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 31939cf..798e295 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -14,7 +14,7 @@ use slog::Logger; use smithay::backend::session::{auto::AutoSession, Session}; use smithay::{ backend::input::{ - self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent, + self, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent, }, reexports::wayland_server::protocol::wl_pointer, @@ -77,20 +77,21 @@ impl AnvilInputHandler { } } -impl InputHandler for AnvilInputHandler { - fn on_seat_created(&mut self, _: &input::Seat) { - /* currently we just create a single static one */ +impl AnvilInputHandler { + pub fn process_event(&mut self, event: InputEvent) { + match event { + InputEvent::Keyboard { event, .. } => self.on_keyboard_key::(event), + InputEvent::PointerMotion { event, .. } => self.on_pointer_move::(event), + InputEvent::PointerMotionAbsolute { event, .. } => self.on_pointer_move_absolute::(event), + InputEvent::PointerButton { event, .. } => self.on_pointer_button::(event), + InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::(event), + _ => { + // other events are not handled in anvil (yet) + } + } } - fn on_seat_destroyed(&mut self, _: &input::Seat) { - /* currently we just create a single static one */ - } - - fn on_seat_changed(&mut self, _: &input::Seat) { - /* currently we just create a single static one */ - } - - fn on_keyboard_key(&mut self, _: &input::Seat, evt: B::KeyboardKeyEvent) { + fn on_keyboard_key(&mut self, evt: B::KeyboardKeyEvent) { let keycode = evt.key_code(); let state = evt.state(); debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); @@ -146,7 +147,7 @@ impl InputHandler for AnvilInputHandler { } } - fn on_pointer_move(&mut self, _: &input::Seat, evt: B::PointerMotionEvent) { + fn on_pointer_move(&mut self, evt: B::PointerMotionEvent) { let (x, y) = (evt.delta_x(), evt.delta_y()); let serial = SCOUNTER.next_serial(); let mut location = self.pointer_location.borrow_mut(); @@ -163,7 +164,7 @@ impl InputHandler for AnvilInputHandler { self.pointer.motion(*location, under, serial, evt.time()); } - fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) { + fn on_pointer_move_absolute(&mut self, evt: B::PointerMotionAbsoluteEvent) { // different cases depending on the context: let (x, y) = { #[cfg(feature = "udev")] @@ -188,7 +189,7 @@ impl InputHandler for AnvilInputHandler { self.pointer.motion((x, y), under, serial, evt.time()); } - fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) { + fn on_pointer_button(&mut self, evt: B::PointerButtonEvent) { let serial = SCOUNTER.next_serial(); let button = match evt.button() { input::MouseButton::Left => 0x110, @@ -214,7 +215,7 @@ impl InputHandler for AnvilInputHandler { self.pointer.button(button, state, serial, evt.time()); } - fn on_pointer_axis(&mut self, _: &input::Seat, evt: B::PointerAxisEvent) { + fn on_pointer_axis(&mut self, evt: B::PointerAxisEvent) { let source = match evt.source() { input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous, input::AxisSource::Finger => wl_pointer::AxisSource::Finger, @@ -250,25 +251,6 @@ impl InputHandler for AnvilInputHandler { self.pointer.axis(frame); } } - - fn on_touch_down(&mut self, _: &input::Seat, _: B::TouchDownEvent) { - /* not done in this example */ - } - fn on_touch_motion(&mut self, _: &input::Seat, _: B::TouchMotionEvent) { - /* not done in this example */ - } - fn on_touch_up(&mut self, _: &input::Seat, _: B::TouchUpEvent) { - /* not done in this example */ - } - fn on_touch_cancel(&mut self, _: &input::Seat, _: B::TouchCancelEvent) { - /* not done in this example */ - } - fn on_touch_frame(&mut self, _: &input::Seat, _: B::TouchFrameEvent) { - /* not done in this example */ - } - fn on_input_config_changed(&mut self, _: &mut B::InputConfig) { - /* not done in this example */ - } } /// Possible results of a keyboard action diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index e4e5d16..4cdc311 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -26,8 +26,7 @@ use smithay::{ DevPath, Device, DeviceHandler, Surface, }, graphics::CursorBackend, - input::InputBackend, - libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, + libinput::{LibinputInputBackend, LibinputSessionInterface}, session::{ auto::{auto_session_bind, AutoSession}, notify_multiplexer, AsSessionObserver, Session, SessionNotifier, @@ -202,8 +201,8 @@ pub fn run_udev( Libinput::new_with_udev::>(session.clone().into()); let libinput_session_id = notifier.register(libinput_context.observer()); libinput_context.udev_assign_seat(&seat).unwrap(); - let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); - libinput_backend.set_handler(AnvilInputHandler::new_with_session( + let libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); + let mut input_handler = AnvilInputHandler::new_with_session( log.clone(), InputInitData { pointer, @@ -214,13 +213,16 @@ pub fn run_udev( pointer_location, }, session, - )); + ); /* * Bind all our objects that get driven by the event loop */ - let libinput_event_source = libinput_bind(libinput_backend, event_loop.handle()) - .map_err(|e| -> IoError { e.into() }) + let libinput_event_source = event_loop + .handle() + .insert_source(libinput_backend, move |event, _, _anvil_state| { + input_handler.process_event(event) + }) .unwrap(); let session_event_source = auto_session_bind(notifier, event_loop.handle()) .map_err(|(e, _)| e) diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index a0f7479..0ac9fc3 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -31,7 +31,9 @@ pub fn run_winit( event_loop: &mut EventLoop, log: Logger, ) -> Result<(), ()> { - let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?; + let (renderer, mut input) = winit::init(log.clone()).map_err(|err| { + slog::crit!(log, "Failed to initialize Winit backend: {}", err); + })?; #[cfg(feature = "egl")] let egl_buffer_reader = Rc::new(RefCell::new( @@ -111,7 +113,7 @@ pub fn run_winit( let pointer_location = Rc::new(RefCell::new((0.0, 0.0))); - input.set_handler(AnvilInputHandler::new( + let mut input_handler = AnvilInputHandler::new( log.clone(), InputInitData { pointer, @@ -121,12 +123,14 @@ pub fn run_winit( running: state.running.clone(), pointer_location: pointer_location.clone(), }, - )); + ); info!(log, "Initialization completed, starting the main loop."); while state.running.load(Ordering::SeqCst) { - input.dispatch_new_events().unwrap(); + input + .dispatch_new_events(|event, _| input_handler.process_event(event)) + .unwrap(); // drawing logic { diff --git a/src/backend/input.rs b/src/backend/input.rs index fd230d1..e9b64b2 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -491,9 +491,6 @@ impl TouchFrameEvent for UnusedEvent {} /// need to implement this and provide the same base guarantees about the precision of /// given events. pub trait InputBackend: Sized { - /// Type of input device associated with the backend - type InputConfig: ?Sized; - /// Type representing errors that may be returned when processing events type EventError: Error; @@ -518,168 +515,108 @@ pub trait InputBackend: Sized { /// Type representing touch frame events type TouchFrameEvent: TouchFrameEvent; - /// Sets a new handler for this [`InputBackend`] - fn set_handler + 'static>(&mut self, handler: H); - /// Get a reference to the currently set handler, if any - fn get_handler(&mut self) -> Option<&mut dyn InputHandler>; - /// Clears the currently handler, if one is set - fn clear_handler(&mut self); + /// Special events that are custom to this backend + type SpecialEvent; - /// Get current `InputConfig` + /// Backend-specific type allowing you to configure it + type InputConfig: ?Sized; + + /// Get the list of currently known Seats + fn seats(&self) -> Vec; + + /// Access the input configuration interface fn input_config(&mut self) -> &mut Self::InputConfig; /// Processes new events of the underlying backend and drives the [`InputHandler`]. - fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>; + /// + /// The callback can only assume its second argument to be usable if the event is + /// `InputEvent::ConfigChanged`. + fn dispatch_new_events(&mut self, callback: F) -> Result<(), Self::EventError> + where + F: FnMut(InputEvent, &mut Self::InputConfig); } -/// Implement to receive input events from any [`InputBackend`]. -pub trait InputHandler { - /// Called when a new [`Seat`] has been created - fn on_seat_created(&mut self, seat: &Seat); - /// Called when an existing [`Seat`] has been destroyed. - fn on_seat_destroyed(&mut self, seat: &Seat); - /// Called when a [`Seat`]'s properties have changed. +/// Different events that can be generated by an input backend +pub enum InputEvent { + /// A new seat has been created + NewSeat(Seat), + /// A seat has changed + SeatChanged(Seat), + /// A seat has been removed + SeatRemoved(Seat), + /// A keyboard event occured + Keyboard { + /// Seat that generated the event + seat: Seat, + /// The keyboard event + event: B::KeyboardKeyEvent, + }, + /// A relative pointer motion occured + PointerMotion { + /// Seat that generated the event + seat: Seat, + /// The pointer motion event + event: B::PointerMotionEvent, + }, + /// An absolute pointer motion occures + PointerMotionAbsolute { + /// Seat that generated the event + seat: Seat, + /// The absolute pointer motion event + event: B::PointerMotionAbsoluteEvent, + }, + /// A pointer button was pressed or released + PointerButton { + /// Seat that generated the event + seat: Seat, + /// The pointer button event + event: B::PointerButtonEvent, + }, + /// A pointer axis was actionned + PointerAxis { + /// Seat that generated the event + seat: Seat, + /// The pointer axis event + event: B::PointerAxisEvent, + }, + /// A new touchpoint appeared + TouchDown { + /// Seat that generated the event + seat: Seat, + /// The touch down event + event: B::TouchDownEvent, + }, + /// A touchpoint moved + TouchMotion { + /// Seat that generated the event + seat: Seat, + /// The touch motion event + event: B::TouchMotionEvent, + }, + /// A touchpoint was removed + TouchUp { + /// Seat that generated the event + seat: Seat, + /// The touch up event + event: B::TouchUpEvent, + }, + /// A touch sequence was cancelled + TouchCancel { + /// Seat that generated the event + seat: Seat, + /// The touch cancel event + event: B::TouchCancelEvent, + }, + /// A touch frame was emmited /// - /// ## Note: - /// - /// It is not guaranteed that any change has actually happened. - fn on_seat_changed(&mut self, seat: &Seat); - - /// Called when a new keyboard event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The keyboard event - /// - fn on_keyboard_key(&mut self, seat: &Seat, event: B::KeyboardKeyEvent); - - /// Called when a new pointer movement event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The pointer movement event - fn on_pointer_move(&mut self, seat: &Seat, event: B::PointerMotionEvent); - /// Called when a new pointer absolute movement event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The pointer absolute movement event - fn on_pointer_move_absolute(&mut self, seat: &Seat, event: B::PointerMotionAbsoluteEvent); - /// Called when a new pointer button event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The pointer button event - fn on_pointer_button(&mut self, seat: &Seat, event: B::PointerButtonEvent); - /// Called when a new pointer scroll event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - A upward counting variable useful for event ordering. Makes no guarantees about actual time passed between events. - fn on_pointer_axis(&mut self, seat: &Seat, event: B::PointerAxisEvent); - - /// Called when a new touch down event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The touch down event - fn on_touch_down(&mut self, seat: &Seat, event: B::TouchDownEvent); - /// Called when a new touch motion event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The touch motion event. - fn on_touch_motion(&mut self, seat: &Seat, event: B::TouchMotionEvent); - /// Called when a new touch up event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The touch up event. - fn on_touch_up(&mut self, seat: &Seat, event: B::TouchUpEvent); - /// Called when a new touch cancel event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The touch cancel event. - fn on_touch_cancel(&mut self, seat: &Seat, event: B::TouchCancelEvent); - /// Called when a new touch frame event was received. - /// - /// # Arguments - /// - /// - `seat` - The [`Seat`] the event belongs to - /// - `event` - The touch frame event. - fn on_touch_frame(&mut self, seat: &Seat, event: B::TouchFrameEvent); - - /// Called when the `InputConfig` was changed through an external event. - /// - /// What kind of events can trigger this call is completely backend dependent. - /// E.g. an input devices was attached/detached or changed it's own configuration. - fn on_input_config_changed(&mut self, config: &mut B::InputConfig); -} - -impl InputHandler for Box> { - fn on_seat_created(&mut self, seat: &Seat) { - (**self).on_seat_created(seat) - } - - fn on_seat_destroyed(&mut self, seat: &Seat) { - (**self).on_seat_destroyed(seat) - } - - fn on_seat_changed(&mut self, seat: &Seat) { - (**self).on_seat_changed(seat) - } - - fn on_keyboard_key(&mut self, seat: &Seat, event: B::KeyboardKeyEvent) { - (**self).on_keyboard_key(seat, event) - } - - fn on_pointer_move(&mut self, seat: &Seat, event: B::PointerMotionEvent) { - (**self).on_pointer_move(seat, event) - } - - fn on_pointer_move_absolute(&mut self, seat: &Seat, event: B::PointerMotionAbsoluteEvent) { - (**self).on_pointer_move_absolute(seat, event) - } - - fn on_pointer_button(&mut self, seat: &Seat, event: B::PointerButtonEvent) { - (**self).on_pointer_button(seat, event) - } - - fn on_pointer_axis(&mut self, seat: &Seat, event: B::PointerAxisEvent) { - (**self).on_pointer_axis(seat, event) - } - - fn on_touch_down(&mut self, seat: &Seat, event: B::TouchDownEvent) { - (**self).on_touch_down(seat, event) - } - - fn on_touch_motion(&mut self, seat: &Seat, event: B::TouchMotionEvent) { - (**self).on_touch_motion(seat, event) - } - - fn on_touch_up(&mut self, seat: &Seat, event: B::TouchUpEvent) { - (**self).on_touch_up(seat, event) - } - - fn on_touch_cancel(&mut self, seat: &Seat, event: B::TouchCancelEvent) { - (**self).on_touch_cancel(seat, event) - } - - fn on_touch_frame(&mut self, seat: &Seat, event: B::TouchFrameEvent) { - (**self).on_touch_frame(seat, event) - } - - fn on_input_config_changed(&mut self, config: &mut B::InputConfig) { - (**self).on_input_config_changed(config) - } + /// A set of two events received on the same seat between two frames should + /// be interpreted as an atomic event. + TouchFrame { + /// Seat that generated the event + seat: Seat, + /// The touch frame event + event: B::TouchFrameEvent, + }, + /// Special event specific of this backend + Special(B::SpecialEvent), } diff --git a/src/backend/libinput/helpers.rs b/src/backend/libinput/helpers.rs index 9f79116..85cbc8b 100644 --- a/src/backend/libinput/helpers.rs +++ b/src/backend/libinput/helpers.rs @@ -1,25 +1,25 @@ -use crate::backend::input::{self as backend}; +use crate::backend::input::{self as backend, InputEvent}; use input as libinput; use input::event::{ device::DeviceEvent, keyboard::KeyboardEvent, pointer::PointerEvent, touch::TouchEvent, EventTrait, }; use slog::Logger; -use super::LibinputInputBackend; +use super::{LibinputConfig, LibinputEvent, LibinputInputBackend}; use std::{ collections::hash_map::{DefaultHasher, Entry, HashMap}, hash::{Hash, Hasher}, }; #[inline(always)] -pub fn on_device_event( - handler: &mut Option, +pub fn on_device_event( + callback: &mut F, seats: &mut HashMap, - devices: &mut Vec, + config: &mut LibinputConfig, event: DeviceEvent, logger: &Logger, ) where - H: backend::InputHandler, + F: FnMut(InputEvent, &mut LibinputConfig), { match event { DeviceEvent::Added(device_added_event) => { @@ -38,7 +38,7 @@ pub fn on_device_event( added.sysname(), device_seat.logical_name() ); - devices.push(added); + config.devices.push(added.clone()); match seats.entry(device_seat.clone()) { Entry::Occupied(mut seat_entry) => { @@ -49,10 +49,7 @@ pub fn on_device_event( caps.keyboard = new_caps.keyboard || caps.keyboard; caps.touch = new_caps.touch || caps.touch; } - if let Some(ref mut handler) = handler { - trace!(logger, "Calling on_seat_changed with {:?}", old_seat); - handler.on_seat_changed(old_seat); - } + callback(InputEvent::SeatChanged(old_seat.clone()), config); } Entry::Vacant(seat_entry) => { let mut hasher = DefaultHasher::default(); @@ -62,18 +59,17 @@ pub fn on_device_event( format!("{}:{}", device_seat.physical_name(), device_seat.logical_name()), new_caps, )); - if let Some(ref mut handler) = handler { - trace!(logger, "Calling on_seat_created with {:?}", seat); - handler.on_seat_created(seat); - } + callback(InputEvent::NewSeat(seat.clone()), config); } } + + callback(InputEvent::Special(LibinputEvent::NewDevice(added)), config); } DeviceEvent::Removed(device_removed_event) => { let removed = device_removed_event.device(); // remove device - devices.retain(|dev| *dev != removed); + config.devices.retain(|dev| *dev != removed); let device_seat = removed.seat(); info!( @@ -86,15 +82,18 @@ pub fn on_device_event( // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`. if let Some(seat) = seats.get_mut(&device_seat) { let caps = seat.capabilities_mut(); - caps.pointer = devices + caps.pointer = config + .devices .iter() .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Pointer)); - caps.keyboard = devices + caps.keyboard = config + .devices .iter() .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Keyboard)); - caps.touch = devices + caps.touch = config + .devices .iter() .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Touch)); @@ -104,7 +103,7 @@ pub fn on_device_event( } // check if the seat has any other devices - if !devices.iter().any(|x| x.seat() == device_seat) { + if !config.devices.iter().any(|x| x.seat() == device_seat) { // it has not, lets destroy it if let Some(seat) = seats.remove(&device_seat) { info!( @@ -112,133 +111,167 @@ pub fn on_device_event( "Removing seat {} which no longer has any device", device_seat.logical_name() ); - if let Some(ref mut handler) = handler { - trace!(logger, "Calling on_seat_destroyed with {:?}", seat); - handler.on_seat_destroyed(&seat); - } + callback(InputEvent::SeatRemoved(seat), config); } else { warn!(logger, "Seat destroyed that was never created"); return; } // it has, notify about updates - } else if let Some(ref mut handler) = handler { - if let Some(seat) = seats.get(&device_seat) { - trace!(logger, "Calling on_seat_changed with {:?}", seat); - handler.on_seat_changed(&seat); - } else { - warn!(logger, "Seat changed that was never created"); - return; - } + } else if let Some(seat) = seats.get(&device_seat) { + callback(InputEvent::SeatChanged(seat.clone()), config); + } else { + warn!(logger, "Seat changed that was never created"); + return; } + + callback(InputEvent::Special(LibinputEvent::RemovedDevice(removed)), config); } } - if let Some(ref mut handler) = handler { - handler.on_input_config_changed(devices); - } } #[inline(always)] -pub fn on_touch_event( - handler: &mut Option, +pub fn on_touch_event( + callback: &mut F, seats: &HashMap, + config: &mut LibinputConfig, event: TouchEvent, logger: &Logger, ) where - H: backend::InputHandler, + F: FnMut(InputEvent, &mut LibinputConfig), { - if let Some(ref mut handler) = handler { - let device_seat = event.device().seat(); - if let Some(ref seat) = seats.get(&device_seat) { - match event { - TouchEvent::Down(down_event) => { - trace!(logger, "Calling on_touch_down with {:?}", down_event); - handler.on_touch_down(seat, down_event) - } - TouchEvent::Motion(motion_event) => { - trace!(logger, "Calling on_touch_motion with {:?}", motion_event); - handler.on_touch_motion(seat, motion_event) - } - TouchEvent::Up(up_event) => { - trace!(logger, "Calling on_touch_up with {:?}", up_event); - handler.on_touch_up(seat, up_event) - } - TouchEvent::Cancel(cancel_event) => { - trace!(logger, "Calling on_touch_cancel with {:?}", cancel_event); - handler.on_touch_cancel(seat, cancel_event) - } - TouchEvent::Frame(frame_event) => { - trace!(logger, "Calling on_touch_frame with {:?}", frame_event); - handler.on_touch_frame(seat, frame_event) - } + let device_seat = event.device().seat(); + if let Some(seat) = seats.get(&device_seat).cloned() { + match event { + TouchEvent::Down(down_event) => { + callback( + InputEvent::TouchDown { + seat, + event: down_event, + }, + config, + ); + } + TouchEvent::Motion(motion_event) => { + callback( + InputEvent::TouchMotion { + seat, + event: motion_event, + }, + config, + ); + } + TouchEvent::Up(up_event) => { + callback( + InputEvent::TouchUp { + seat, + event: up_event, + }, + config, + ); + } + TouchEvent::Cancel(cancel_event) => { + callback( + InputEvent::TouchCancel { + seat, + event: cancel_event, + }, + config, + ); + } + TouchEvent::Frame(frame_event) => { + callback( + InputEvent::TouchFrame { + seat, + event: frame_event, + }, + config, + ); } - } else { - warn!(logger, "Received touch event of non existing Seat"); - return; } + } else { + warn!(logger, "Received touch event of non existing Seat"); } } #[inline(always)] -pub fn on_keyboard_event( - handler: &mut Option, +pub fn on_keyboard_event( + callback: &mut F, seats: &HashMap, + config: &mut LibinputConfig, event: KeyboardEvent, logger: &Logger, ) where - H: backend::InputHandler, + F: FnMut(InputEvent, &mut LibinputConfig), { match event { KeyboardEvent::Key(key_event) => { - if let Some(ref mut handler) = handler { - let device_seat = key_event.device().seat(); - if let Some(ref seat) = seats.get(&device_seat) { - trace!(logger, "Calling on_keyboard_key with {:?}", key_event); - handler.on_keyboard_key(seat, key_event); - } else { - warn!(logger, "Received key event of non existing Seat"); - return; - } + let device_seat = key_event.device().seat(); + if let Some(seat) = seats.get(&device_seat).cloned() { + callback( + InputEvent::Keyboard { + seat, + event: key_event, + }, + config, + ); + } else { + warn!(logger, "Received key event of non existing Seat"); } } } } #[inline(always)] -pub fn on_pointer_event( - handler: &mut Option, +pub fn on_pointer_event( + callback: &mut F, seats: &HashMap, + config: &mut LibinputConfig, event: PointerEvent, logger: &Logger, ) where - H: backend::InputHandler, + F: FnMut(InputEvent, &mut LibinputConfig), { - if let Some(ref mut handler) = handler { - let device_seat = event.device().seat(); - if let Some(ref seat) = seats.get(&device_seat) { - match event { - PointerEvent::Motion(motion_event) => { - trace!(logger, "Calling on_pointer_move with {:?}", motion_event); - handler.on_pointer_move(seat, motion_event); - } - PointerEvent::MotionAbsolute(motion_abs_event) => { - trace!( - logger, - "Calling on_pointer_move_absolute with {:?}", - motion_abs_event - ); - handler.on_pointer_move_absolute(seat, motion_abs_event); - } - PointerEvent::Axis(axis_event) => { - trace!(logger, "Calling on_pointer_axis with {:?}", axis_event); - handler.on_pointer_axis(seat, axis_event); - } - PointerEvent::Button(button_event) => { - trace!(logger, "Calling on_pointer_button with {:?}", button_event); - handler.on_pointer_button(seat, button_event); - } + let device_seat = event.device().seat(); + if let Some(seat) = seats.get(&device_seat).cloned() { + match event { + PointerEvent::Motion(motion_event) => { + callback( + InputEvent::PointerMotion { + seat, + event: motion_event, + }, + config, + ); + } + PointerEvent::MotionAbsolute(motion_abs_event) => { + callback( + InputEvent::PointerMotionAbsolute { + seat, + event: motion_abs_event, + }, + config, + ); + } + PointerEvent::Axis(axis_event) => { + callback( + InputEvent::PointerAxis { + seat, + event: axis_event, + }, + config, + ); + } + PointerEvent::Button(button_event) => { + callback( + InputEvent::PointerButton { + seat, + event: button_event, + }, + config, + ); } - } else { - warn!(logger, "Received pointer event of non existing Seat"); } + } else { + warn!(logger, "Received pointer event of non existing Seat"); } } diff --git a/src/backend/libinput/mod.rs b/src/backend/libinput/mod.rs index eb0b13b..8284e30 100644 --- a/src/backend/libinput/mod.rs +++ b/src/backend/libinput/mod.rs @@ -3,7 +3,7 @@ mod helpers; use helpers::{on_device_event, on_keyboard_event, on_pointer_event, on_touch_event}; -use crate::backend::input::{self as backend, Axis, InputBackend}; +use crate::backend::input::{self as backend, Axis, InputBackend, InputEvent}; #[cfg(feature = "backend_session")] use crate::backend::session::{AsErrno, Session, SessionObserver}; use input as libinput; @@ -17,7 +17,7 @@ use std::{ os::unix::io::{AsRawFd, RawFd}, }; -use calloop::{generic::Generic, InsertError, LoopHandle, Source}; +use calloop::{EventSource, Interest, Mode, Poll, Readiness, Token}; // No idea if this is the same across unix platforms // Lets make this linux exclusive for now, once someone tries to build it for @@ -31,9 +31,8 @@ const INPUT_MAJOR: u32 = 13; /// context. pub struct LibinputInputBackend { context: libinput::Libinput, - devices: Vec, + config: LibinputConfig, seats: HashMap, - handler: Option + 'static>>, logger: ::slog::Logger, } @@ -48,9 +47,8 @@ impl LibinputInputBackend { info!(log, "Initializing a libinput backend"); LibinputInputBackend { context, - devices: Vec::new(), + config: LibinputConfig { devices: Vec::new() }, seats: HashMap::new(), - handler: None, logger: log, } } @@ -246,8 +244,30 @@ impl backend::Event for event::touch::TouchFrameEvent { impl backend::TouchFrameEvent for event::touch::TouchFrameEvent {} +/// Special events generated by Libinput +pub enum LibinputEvent { + /// A new device was plugged in + NewDevice(libinput::Device), + /// A device was plugged out + RemovedDevice(libinput::Device), +} + +/// Configuration handle for libinput +/// +/// This type allows you to access the list of know devices to configure them +/// if relevant +pub struct LibinputConfig { + devices: Vec, +} + +impl LibinputConfig { + /// Access the list of current devices + pub fn devices(&mut self) -> &mut [libinput::Device] { + &mut self.devices + } +} + impl InputBackend for LibinputInputBackend { - type InputConfig = [libinput::Device]; type EventError = IoError; type KeyboardKeyEvent = event::keyboard::KeyboardKeyEvent; @@ -261,60 +281,60 @@ impl InputBackend for LibinputInputBackend { type TouchCancelEvent = event::touch::TouchCancelEvent; type TouchFrameEvent = event::touch::TouchFrameEvent; - fn set_handler + 'static>(&mut self, mut handler: H) { - if self.handler.is_some() { - self.clear_handler(); - } - info!(self.logger, "New input handler set"); - for seat in self.seats.values() { - trace!(self.logger, "Calling on_seat_created with {:?}", seat); - handler.on_seat_created(seat); - } - self.handler = Some(Box::new(handler)); - } + type SpecialEvent = LibinputEvent; + type InputConfig = LibinputConfig; - fn get_handler(&mut self) -> Option<&mut dyn backend::InputHandler> { - self.handler - .as_mut() - .map(|handler| handler as &mut dyn backend::InputHandler) - } - - fn clear_handler(&mut self) { - if let Some(mut handler) = self.handler.take() { - for seat in self.seats.values() { - trace!(self.logger, "Calling on_seat_destroyed with {:?}", seat); - handler.on_seat_destroyed(seat); - } - info!(self.logger, "Removing input handler"); - } + fn seats(&self) -> Vec { + self.seats.values().cloned().collect() } fn input_config(&mut self) -> &mut Self::InputConfig { - &mut self.devices + &mut self.config } - fn dispatch_new_events(&mut self) -> Result<(), IoError> { + fn dispatch_new_events(&mut self, mut callback: F) -> Result<(), IoError> + where + F: FnMut(InputEvent, &mut LibinputConfig), + { self.context.dispatch()?; for event in &mut self.context { match event { libinput::Event::Device(device_event) => { on_device_event( - &mut self.handler, + &mut callback, &mut self.seats, - &mut self.devices, + &mut self.config, device_event, &self.logger, ); } libinput::Event::Touch(touch_event) => { - on_touch_event(&mut self.handler, &self.seats, touch_event, &self.logger); + on_touch_event( + &mut callback, + &self.seats, + &mut self.config, + touch_event, + &self.logger, + ); } libinput::Event::Keyboard(keyboard_event) => { - on_keyboard_event(&mut self.handler, &self.seats, keyboard_event, &self.logger); + on_keyboard_event( + &mut callback, + &self.seats, + &mut self.config, + keyboard_event, + &self.logger, + ); } libinput::Event::Pointer(pointer_event) => { - on_pointer_event(&mut self.handler, &self.seats, pointer_event, &self.logger); + on_pointer_event( + &mut callback, + &self.seats, + &mut self.config, + pointer_event, + &self.logger, + ); } _ => {} //FIXME: What to do with the rest. } @@ -421,24 +441,27 @@ impl AsRawFd for LibinputInputBackend { } } -/// calloop source associated with the libinput backend -pub type LibinputSource = Generic; +impl EventSource for LibinputInputBackend { + type Event = InputEvent; + type Metadata = LibinputConfig; + type Ret = (); -/// Binds a [`LibinputInputBackend`] to a given [`LoopHandle`]. -/// -/// Automatically feeds the backend with incoming events without any manual calls to -/// [`dispatch_new_events`](InputBackend::dispatch_new_events). Should be used to achieve the smallest possible latency. -pub fn libinput_bind( - backend: LibinputInputBackend, - handle: LoopHandle, -) -> Result, InsertError> { - let source = Generic::new(backend, calloop::Interest::Readable, calloop::Mode::Level); + fn process_events(&mut self, _: Readiness, _: Token, callback: F) -> std::io::Result<()> + where + F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + self.dispatch_new_events(callback) + } - handle.insert_source(source, move |_, backend, _| { - if let Err(error) = backend.dispatch_new_events() { - warn!(backend.logger, "Libinput errored: {}", error); - return Err(std::io::Error::new(std::io::ErrorKind::Other, Box::new(error))); - } - Ok(()) - }) + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + poll.register(self.as_raw_fd(), Interest::Readable, Mode::Level, token) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + poll.reregister(self.as_raw_fd(), Interest::Readable, Mode::Level, token) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + poll.unregister(self.as_raw_fd()) + } } diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 546f18f..239effd 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -6,7 +6,7 @@ use crate::backend::{ egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError, SurfaceCreationError}, graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError}, input::{ - Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, + Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent, @@ -94,13 +94,10 @@ pub struct WinitGraphicsBackend { /// periodically to receive any events. pub struct WinitInputBackend { events_loop: EventLoop<()>, - events_handler: Option>, window: Rc, time: Instant, key_counter: u32, seat: Seat, - input_config: (), - handler: Option + 'static>>, logger: ::slog::Logger, size: Rc>, } @@ -211,7 +208,6 @@ where }, WinitInputBackend { events_loop, - events_handler: None, window, time: Instant::now(), key_counter: 0, @@ -224,24 +220,25 @@ where touch: true, }, ), - input_config: (), - handler: None, logger: log.new(o!("smithay_winit_component" => "input")), size, }, )) } -/// Handler trait to receive window-related events to provide a better *nested* experience. -pub trait WinitEventsHandler { - /// The window was resized, can be used to adjust the associated [`Output`](::wayland::output::Output)s mode. - /// - /// Here are provided the new size (in physical pixels) and the new scale factor provided by `winit`. - fn resized(&mut self, size: (f64, f64), scale: f64); - /// The window gained or lost focus - fn focus_changed(&mut self, focused: bool); - /// The window needs to be redrawn - fn refresh(&mut self); +/// Specific events generated by Winit +pub enum WinitEvent { + /// The window has been resized + Resized { + /// The new physical size (in pixels) + size: (f64, f64), + /// The new scale factor + scale_factor: f64, + }, + /// The focus state of the window changed + Focus(bool), + /// A redraw was requested + Refresh, } impl WinitGraphicsBackend { @@ -611,29 +608,12 @@ impl TouchCancelEvent for WinitTouchCancelledEvent { } } -impl WinitInputBackend { - /// Set the events handler - pub fn set_events_handler(&mut self, handler: H) { - self.events_handler = Some(Box::new(handler)); - info!(self.logger, "New events handler set."); - } - - /// Get a reference to the set events handler, if any - pub fn get_events_handler(&mut self) -> Option<&mut dyn WinitEventsHandler> { - self.events_handler - .as_mut() - .map(|handler| &mut **handler as &mut dyn WinitEventsHandler) - } - - /// Clear out the currently set events handler - pub fn clear_events_handler(&mut self) { - self.events_handler = None; - info!(self.logger, "Events handler unset."); - } -} +/// Input config for Winit +/// +/// This backend does not allow any input configuration, so this type does nothing. +pub struct WinitInputConfig; impl InputBackend for WinitInputBackend { - type InputConfig = (); type EventError = WinitInputError; type KeyboardKeyEvent = WinitKeyboardInputEvent; @@ -647,32 +627,17 @@ impl InputBackend for WinitInputBackend { type TouchCancelEvent = WinitTouchCancelledEvent; type TouchFrameEvent = UnusedEvent; - fn set_handler + 'static>(&mut self, mut handler: H) { - if self.handler.is_some() { - self.clear_handler(); - } - info!(self.logger, "New input handler set."); - trace!(self.logger, "Calling on_seat_created with {:?}", self.seat); - handler.on_seat_created(&self.seat); - self.handler = Some(Box::new(handler)); - } + type SpecialEvent = WinitEvent; + type InputConfig = WinitInputConfig; - fn get_handler(&mut self) -> Option<&mut dyn InputHandler> { - self.handler - .as_mut() - .map(|handler| handler as &mut dyn InputHandler) - } - - fn clear_handler(&mut self) { - if let Some(mut handler) = self.handler.take() { - trace!(self.logger, "Calling on_seat_destroyed with {:?}", self.seat); - handler.on_seat_destroyed(&self.seat); - } - info!(self.logger, "Removing input handler"); + fn seats(&self) -> Vec { + vec![self.seat.clone()] } fn input_config(&mut self) -> &mut Self::InputConfig { - &mut self.input_config + /// So much effort to return a useless singleton! + static mut CONFIG: WinitInputConfig = WinitInputConfig; + unsafe { &mut CONFIG } } /// Processes new events of the underlying event loop to drive the set [`InputHandler`]. @@ -687,7 +652,10 @@ impl InputBackend for WinitInputBackend { /// /// The linked [`WinitGraphicsBackend`] will error with a lost context and should /// not be used anymore as well. - fn dispatch_new_events(&mut self) -> ::std::result::Result<(), WinitInputError> { + fn dispatch_new_events(&mut self, mut callback: F) -> ::std::result::Result<(), WinitInputError> + where + F: FnMut(InputEvent, &mut WinitInputConfig), + { let mut closed = false; { @@ -701,10 +669,9 @@ impl InputBackend for WinitInputBackend { let time = &self.time; let seat = &self.seat; let window = &self.window; - let mut handler = self.handler.as_mut(); - let mut events_handler = self.events_handler.as_mut(); let logger = &self.logger; let window_size = &self.size; + let mut callback = move |event| callback(event, &mut WinitInputConfig); self.events_loop .run_return(move |event, _target, control_flow| match event { @@ -712,16 +679,14 @@ impl InputBackend for WinitInputBackend { *control_flow = ControlFlow::Exit; } Event::RedrawRequested(_id) => { - if let Some(events_handler) = events_handler.as_mut() { - events_handler.refresh(); - } + callback(InputEvent::Special(WinitEvent::Refresh)); } Event::WindowEvent { event, .. } => { let duration = Instant::now().duration_since(*time); let nanos = duration.subsec_nanos() as u64; let time = ((1000 * duration.as_secs()) + (nanos / 1_000_000)) as u32; - match (event, handler.as_mut(), events_handler.as_mut()) { - (WindowEvent::Resized(psize), _, events_handler) => { + match event { + WindowEvent::Resized(psize) => { trace!(logger, "Resizing window to {:?}", psize); let scale_factor = window.window().scale_factor(); let mut wsize = window_size.borrow_mut(); @@ -730,156 +695,140 @@ impl InputBackend for WinitInputBackend { if let Window::Wayland { ref surface, .. } = **window { surface.resize(psize.width as i32, psize.height as i32, 0, 0); } - if let Some(events_handler) = events_handler { - events_handler.resized(psize.into(), scale_factor); - } - } - (WindowEvent::Focused(focus), _, Some(events_handler)) => { - events_handler.focus_changed(focus) - } - ( - WindowEvent::ScaleFactorChanged { + callback(InputEvent::Special(WinitEvent::Resized { + size: psize.into(), scale_factor, - new_inner_size: new_psize, - }, - _, - events_handler, - ) => { + })); + } + WindowEvent::Focused(focus) => { + callback(InputEvent::Special(WinitEvent::Focus(focus))); + } + + WindowEvent::ScaleFactorChanged { + scale_factor, + new_inner_size: new_psize, + } => { let mut wsize = window_size.borrow_mut(); wsize.scale_factor = scale_factor; if let Window::Wayland { ref surface, .. } = **window { surface.resize(new_psize.width as i32, new_psize.height as i32, 0, 0); } - if let Some(events_handler) = events_handler { - let psize_f64: (f64, f64) = - (new_psize.width.into(), new_psize.height.into()); - events_handler.resized(psize_f64, wsize.scale_factor); - } + let psize_f64: (f64, f64) = (new_psize.width.into(), new_psize.height.into()); + callback(InputEvent::Special(WinitEvent::Resized { + size: psize_f64, + scale_factor: wsize.scale_factor, + })); } - ( - WindowEvent::KeyboardInput { - input: KeyboardInput { scancode, state, .. }, - .. - }, - Some(handler), - _, - ) => { + WindowEvent::KeyboardInput { + input: KeyboardInput { scancode, state, .. }, + .. + } => { match state { ElementState::Pressed => *key_counter += 1, ElementState::Released => { *key_counter = key_counter.checked_sub(1).unwrap_or(0) } }; - trace!(logger, "Calling on_keyboard_key with {:?}", (scancode, state)); - handler.on_keyboard_key( - seat, - WinitKeyboardInputEvent { + callback(InputEvent::Keyboard { + seat: seat.clone(), + event: WinitKeyboardInputEvent { time, key: scancode, count: *key_counter, state, }, - ) + }); } - (WindowEvent::CursorMoved { position, .. }, Some(handler), _) => { - trace!(logger, "Calling on_pointer_move_absolute with {:?}", position); + WindowEvent::CursorMoved { position, .. } => { let lpos = position.to_logical(window_size.borrow().scale_factor); - handler.on_pointer_move_absolute( - seat, - WinitMouseMovedEvent { + callback(InputEvent::PointerMotionAbsolute { + seat: seat.clone(), + event: WinitMouseMovedEvent { size: window_size.clone(), time, logical_position: lpos, }, - ) + }); } - (WindowEvent::MouseWheel { delta, .. }, Some(handler), _) => { + WindowEvent::MouseWheel { delta, .. } => { let event = WinitMouseWheelEvent { time, delta }; - trace!(logger, "Calling on_pointer_axis with {:?}", delta); - handler.on_pointer_axis(seat, event); + callback(InputEvent::PointerAxis { + seat: seat.clone(), + event, + }); } - (WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => { - trace!(logger, "Calling on_pointer_button with {:?}", (button, state)); - handler.on_pointer_button(seat, WinitMouseInputEvent { time, button, state }) + WindowEvent::MouseInput { state, button, .. } => { + callback(InputEvent::PointerButton { + seat: seat.clone(), + event: WinitMouseInputEvent { time, button, state }, + }); } - ( - WindowEvent::Touch(Touch { - phase: TouchPhase::Started, - location, - id, - .. - }), - Some(handler), - _, - ) => { - trace!(logger, "Calling on_touch_down at {:?}", location); - handler.on_touch_down( - seat, - WinitTouchStartedEvent { + + WindowEvent::Touch(Touch { + phase: TouchPhase::Started, + location, + id, + .. + }) => { + callback(InputEvent::TouchDown { + seat: seat.clone(), + event: WinitTouchStartedEvent { size: window_size.clone(), time, location: location.into(), id, }, - ) + }); } - ( - WindowEvent::Touch(Touch { - phase: TouchPhase::Moved, - location, - id, - .. - }), - Some(handler), - _, - ) => { - trace!(logger, "Calling on_touch_motion at {:?}", location); - handler.on_touch_motion( - seat, - WinitTouchMovedEvent { + WindowEvent::Touch(Touch { + phase: TouchPhase::Moved, + location, + id, + .. + }) => { + callback(InputEvent::TouchMotion { + seat: seat.clone(), + event: WinitTouchMovedEvent { size: window_size.clone(), time, location: location.into(), id, }, - ) + }); } - ( - WindowEvent::Touch(Touch { - phase: TouchPhase::Ended, - location, - id, - .. - }), - Some(handler), - _, - ) => { - trace!(logger, "Calling on_touch_motion at {:?}", location); - handler.on_touch_motion( - seat, - WinitTouchMovedEvent { + + WindowEvent::Touch(Touch { + phase: TouchPhase::Ended, + location, + id, + .. + }) => { + callback(InputEvent::TouchMotion { + seat: seat.clone(), + event: WinitTouchMovedEvent { size: window_size.clone(), time, location: location.into(), id, }, - ); - trace!(logger, "Calling on_touch_up"); - handler.on_touch_up(seat, WinitTouchEndedEvent { time, id }); + }); + callback(InputEvent::TouchUp { + seat: seat.clone(), + event: WinitTouchEndedEvent { time, id }, + }) } - ( - WindowEvent::Touch(Touch { - phase: TouchPhase::Cancelled, - id, - .. - }), - Some(handler), - _, - ) => { - trace!(logger, "Calling on_touch_cancel"); - handler.on_touch_cancel(seat, WinitTouchCancelledEvent { time, id }) + + WindowEvent::Touch(Touch { + phase: TouchPhase::Cancelled, + id, + .. + }) => { + callback(InputEvent::TouchCancel { + seat: seat.clone(), + event: WinitTouchCancelledEvent { time, id }, + }); } - (WindowEvent::CloseRequested, _, _) | (WindowEvent::Destroyed, _, _) => { + WindowEvent::CloseRequested | WindowEvent::Destroyed => { warn!(logger, "Window closed"); *closed_ptr = true; }