From abb21d99243ccd8ea39a0d2b9f1bf54cba3b0358 Mon Sep 17 00:00:00 2001 From: Leon Vack Date: Wed, 17 Apr 2024 20:59:19 +0200 Subject: [PATCH] Perform wlcs interactions using an InputBackend --- src/backend.rs | 4 +- src/config.rs | 4 +- wlcs_pinnacle/src/input_backend.rs | 332 +++++++++++++++++++++++++++++ wlcs_pinnacle/src/lib.rs | 48 +++-- wlcs_pinnacle/src/main_loop.rs | 163 +++++++------- 5 files changed, 449 insertions(+), 102 deletions(-) create mode 100644 wlcs_pinnacle/src/input_backend.rs diff --git a/src/backend.rs b/src/backend.rs index 0d2d23e..659e546 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -43,10 +43,10 @@ use self::{udev::Udev, winit::Winit}; #[cfg(feature = "testing")] pub mod dummy; -#[cfg(feature = "wlcs")] -pub mod wlcs; pub mod udev; pub mod winit; +#[cfg(feature = "wlcs")] +pub mod wlcs; pub enum Backend { /// The compositor is running in a Winit window diff --git a/src/config.rs b/src/config.rs index db6ebdf..7a56042 100644 --- a/src/config.rs +++ b/src/config.rs @@ -563,14 +563,14 @@ impl State { error!("gRPC server error: {err}"); } })); - }, + } None => { self.grpc_server_join_handle = Some(tokio::spawn(async move { if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await { error!("gRPC server error: {err}"); } })); - }, + } // FIXME: Not really high priority but if you somehow reload the config really, REALLY // | fast at startup then I think there's a chance that the gRPC server // | could get started twice. diff --git a/wlcs_pinnacle/src/input_backend.rs b/wlcs_pinnacle/src/input_backend.rs new file mode 100644 index 0000000..cf916a9 --- /dev/null +++ b/wlcs_pinnacle/src/input_backend.rs @@ -0,0 +1,332 @@ +use core::hash::Hash; + +use smithay::{ + backend::input::{ + AbsolutePositionEvent, ButtonState, Device, DeviceCapability, Event, InputBackend, + InputEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent, + TouchDownEvent, TouchEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent, + }, + utils::{Logical, Point}, +}; + +pub struct WlcsInputBackend {} + +impl InputBackend for WlcsInputBackend { + type Device = WlcsDevice; + type KeyboardKeyEvent = UnusedEvent; + type PointerAxisEvent = UnusedEvent; + type PointerButtonEvent = WlcsPointerButtonEvent; + type PointerMotionEvent = WlcsPointerMotionEvent; + type PointerMotionAbsoluteEvent = WlcsPointerMotionAbsoluteEvent; + type GestureSwipeBeginEvent = UnusedEvent; + type GestureSwipeUpdateEvent = UnusedEvent; + type GestureSwipeEndEvent = UnusedEvent; + type GesturePinchBeginEvent = UnusedEvent; + type GesturePinchUpdateEvent = UnusedEvent; + type GesturePinchEndEvent = UnusedEvent; + type GestureHoldBeginEvent = UnusedEvent; + type GestureHoldEndEvent = UnusedEvent; + type TouchDownEvent = WlcsTouchDownEvent; + type TouchUpEvent = WlcsTouchUpEvent; + type TouchMotionEvent = WlcsTouchMotionEvent; + type TouchCancelEvent = UnusedEvent; + type TouchFrameEvent = UnusedEvent; + type TabletToolAxisEvent = UnusedEvent; + type TabletToolProximityEvent = UnusedEvent; + type TabletToolTipEvent = UnusedEvent; + type TabletToolButtonEvent = UnusedEvent; + type SwitchToggleEvent = UnusedEvent; + type SpecialEvent = (); +} + +#[derive(PartialEq, Eq)] +pub struct WlcsDevice { + pub device_id: u32, + pub capability: DeviceCapability, +} + +impl Hash for WlcsDevice { + fn hash(&self, state: &mut H) { + self.device_id.hash(state); + } +} + +impl Device for WlcsDevice { + fn id(&self) -> String { + format!("{}", self.device_id).into() + } + + fn name(&self) -> String { + format!("wlcs-device-{}", self.device_id).into() + } + + fn has_capability(&self, capability: DeviceCapability) -> bool { + self.capability == capability + } + + fn usb_id(&self) -> Option<(u32, u32)> { + None + } + + fn syspath(&self) -> Option { + None + } +} + +pub struct WlcsPointerButtonEvent { + pub device_id: u32, + pub time: u64, + pub button_code: u32, + pub state: ButtonState, +} + +impl Into> for WlcsPointerButtonEvent { + fn into(self) -> InputEvent { + InputEvent::::PointerButton { event: self } + } +} + +impl Event for WlcsPointerButtonEvent { + fn time(&self) -> u64 { + self.time + } + + fn device(&self) -> ::Device { + WlcsDevice { + device_id: self.device_id, + capability: DeviceCapability::Pointer, + } + } +} + +impl PointerButtonEvent for WlcsPointerButtonEvent { + fn button_code(&self) -> u32 { + self.button_code + } + + fn state(&self) -> ButtonState { + self.state + } +} + +pub struct WlcsPointerMotionEvent { + pub device_id: u32, + pub time: u64, + pub delta: Point, +} + +impl Into> for WlcsPointerMotionEvent { + fn into(self) -> InputEvent { + InputEvent::::PointerMotion { event: self } + } +} + +impl Event for WlcsPointerMotionEvent { + fn time(&self) -> u64 { + self.time + } + + fn device(&self) -> ::Device { + WlcsDevice { + device_id: self.device_id, + capability: DeviceCapability::Pointer, + } + } +} + +impl PointerMotionEvent for WlcsPointerMotionEvent { + fn delta_x(&self) -> f64 { + self.delta.x + } + + fn delta_y(&self) -> f64 { + self.delta.y + } + + fn delta_x_unaccel(&self) -> f64 { + self.delta_x() + } + + fn delta_y_unaccel(&self) -> f64 { + self.delta_y() + } +} + +pub struct WlcsPointerMotionAbsoluteEvent { + pub device_id: u32, + pub time: u64, + pub position: Point, +} + +impl Into> for WlcsPointerMotionAbsoluteEvent { + fn into(self) -> InputEvent { + InputEvent::::PointerMotionAbsolute { event: self } + } +} + +impl Event for WlcsPointerMotionAbsoluteEvent { + fn time(&self) -> u64 { + self.time + } + + fn device(&self) -> ::Device { + WlcsDevice { + device_id: self.device_id, + capability: DeviceCapability::Pointer, + } + } +} + +impl AbsolutePositionEvent for WlcsPointerMotionAbsoluteEvent { + fn x(&self) -> f64 { + self.position.x + } + + fn y(&self) -> f64 { + self.position.y + } + + fn x_transformed(&self, _width: i32) -> f64 { + self.x() + } + + fn y_transformed(&self, _height: i32) -> f64 { + self.y() + } +} + +impl PointerMotionAbsoluteEvent for WlcsPointerMotionAbsoluteEvent {} + +pub struct WlcsTouchDownEvent { + pub device_id: u32, + pub time: u64, + pub position: Point, +} + +impl Into> for WlcsTouchDownEvent { + fn into(self) -> InputEvent { + InputEvent::::TouchDown { event: self } + } +} + +impl Event for WlcsTouchDownEvent { + fn time(&self) -> u64 { + self.time + } + + fn device(&self) -> ::Device { + WlcsDevice { + device_id: self.device_id, + capability: DeviceCapability::Touch, + } + } +} + +impl TouchEvent for WlcsTouchDownEvent { + fn slot(&self) -> TouchSlot { + None.into() + } +} + +impl AbsolutePositionEvent for WlcsTouchDownEvent { + fn x(&self) -> f64 { + self.position.x + } + + fn y(&self) -> f64 { + self.position.y + } + + fn x_transformed(&self, _width: i32) -> f64 { + self.x() + } + + fn y_transformed(&self, _height: i32) -> f64 { + self.y() + } +} + +impl TouchDownEvent for WlcsTouchDownEvent {} + +pub struct WlcsTouchUpEvent { + pub device_id: u32, + pub time: u64, +} + +impl Into> for WlcsTouchUpEvent { + fn into(self) -> InputEvent { + InputEvent::::TouchUp { event: self } + } +} + +impl Event for WlcsTouchUpEvent { + fn time(&self) -> u64 { + self.time + } + + fn device(&self) -> ::Device { + WlcsDevice { + device_id: self.device_id, + capability: DeviceCapability::Touch, + } + } +} + +impl TouchEvent for WlcsTouchUpEvent { + fn slot(&self) -> TouchSlot { + None.into() + } +} + +impl TouchUpEvent for WlcsTouchUpEvent {} + +pub struct WlcsTouchMotionEvent { + pub device_id: u32, + pub time: u64, + pub position: Point, +} + +impl Into> for WlcsTouchMotionEvent { + fn into(self) -> InputEvent { + InputEvent::::TouchMotion { event: self } + } +} + +impl Event for WlcsTouchMotionEvent { + fn time(&self) -> u64 { + self.time + } + + fn device(&self) -> ::Device { + WlcsDevice { + device_id: self.device_id, + capability: DeviceCapability::Touch, + } + } +} + +impl TouchEvent for WlcsTouchMotionEvent { + fn slot(&self) -> TouchSlot { + None.into() + } +} + +impl AbsolutePositionEvent for WlcsTouchMotionEvent { + fn x(&self) -> f64 { + self.position.x + } + + fn y(&self) -> f64 { + self.position.y + } + + fn x_transformed(&self, _width: i32) -> f64 { + self.x() + } + + fn y_transformed(&self, _height: i32) -> f64 { + self.y() + } +} + +impl TouchMotionEvent for WlcsTouchMotionEvent {} diff --git a/wlcs_pinnacle/src/lib.rs b/wlcs_pinnacle/src/lib.rs index a4cb482..1e7e608 100644 --- a/wlcs_pinnacle/src/lib.rs +++ b/wlcs_pinnacle/src/lib.rs @@ -1,3 +1,4 @@ +mod input_backend; mod main_loop; use std::{ @@ -47,23 +48,32 @@ pub enum WlcsEvent { surface_id: u32, location: Point, }, - PointerMove { + NewPointer { + device_id: u32, + }, + PointerMoveRelative { + device_id: u32, + delta: Point, + }, + PointerMoveAbsolute { device_id: u32, position: Point, - absolute: bool, }, PointerButton { device_id: u32, button_id: i32, pressed: bool, }, + NewTouch { + device_id: u32, + }, TouchDown { device_id: u32, - location: Point, + position: Point, }, TouchMove { device_id: u32, - location: Point, + position: Point, }, TouchUp { device_id: u32, @@ -88,12 +98,18 @@ struct PinnacleHandle { } static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!( - // ("wl_compositor", 4), - // ("wl_subcompositor", 1), - // ("wl_data_device_manager", 3), - // ("wl_seat", 7), - // ("wl_output", 4), - // ("xdg_wm_base", 3), + // Skip reasons: + // 5 Missing extension: gtk_primary_selection_device_manager>= 1 + // 1 Missing extension: wlcs_non_existent_extension>= 1 + // 89 Missing extension: wl_shell>= 2 + // 1 Missing extension: xdg_not_really_an_extension>= 1 + // 30 Missing extension: zwlr_foreign_toplevel_manager_v1>= 1 + // 12 Missing extension: zwlr_virtual_pointer_manager_v1>= 1 + // 15 Missing extension: zwp_pointer_constraints_v1>= 1 + // 3 Missing extension: zwp_relative_pointer_manager_v1>= 1 + // 12 Missing extension: zwp_text_input_manager_v2>= 1 + // 11 Missing extension: zwp_text_input_manager_v3>= 1 + // 180 Missing extension: zxdg_shell_v6>= 1 ); static DESCRIPTOR: WlcsIntegrationDescriptor = WlcsIntegrationDescriptor { @@ -218,20 +234,18 @@ struct PointerHandle { impl Pointer for PointerHandle { fn move_absolute(&mut self, x: wl_fixed_t, y: wl_fixed_t) { self.sender - .send(WlcsEvent::PointerMove { + .send(WlcsEvent::PointerMoveAbsolute { device_id: self.device_id, position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), - absolute: true, }) .expect("failed to send move_absolute"); } fn move_relative(&mut self, dx: wl_fixed_t, dy: wl_fixed_t) { self.sender - .send(WlcsEvent::PointerMove { + .send(WlcsEvent::PointerMoveRelative { device_id: self.device_id, - position: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(), - absolute: false, + delta: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(), }) .expect("failed to send move_relative"); } @@ -267,7 +281,7 @@ impl Touch for TouchHandle { self.sender .send(WlcsEvent::TouchDown { device_id: self.device_id, - location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), + position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), }) .expect("failed to send touch_down"); } @@ -276,7 +290,7 @@ impl Touch for TouchHandle { self.sender .send(WlcsEvent::TouchMove { device_id: self.device_id, - location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), + position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), }) .expect("failed to send touch_move"); } diff --git a/wlcs_pinnacle/src/main_loop.rs b/wlcs_pinnacle/src/main_loop.rs index 02a5b90..e6a602e 100644 --- a/wlcs_pinnacle/src/main_loop.rs +++ b/wlcs_pinnacle/src/main_loop.rs @@ -2,22 +2,24 @@ use std::{sync::Arc, time::Duration}; use pinnacle::{ backend::dummy::setup_dummy, - focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget}, state::{ClientState, State}, }; use smithay::{ - backend::input::ButtonState, - input::pointer::{ButtonEvent, MotionEvent, RelativeMotionEvent}, + backend::input::{ButtonState, DeviceCapability, InputEvent}, reexports::{ calloop::channel::{Channel, Event}, wayland_server::Resource, }, - utils::SERIAL_COUNTER, wayland::seat::WaylandFocus, }; -use tracing::warn; -use crate::WlcsEvent; +use crate::{ + input_backend::{ + WlcsDevice, WlcsInputBackend, WlcsPointerButtonEvent, WlcsPointerMotionAbsoluteEvent, + WlcsPointerMotionEvent, WlcsTouchDownEvent, WlcsTouchUpEvent, + }, + WlcsEvent, +}; pub(crate) fn run(channel: Channel) { let config_path = @@ -95,88 +97,87 @@ fn handle_event(event: WlcsEvent, state: &mut State) { state.space.map_element(toplevel.clone(), location, false); } } - WlcsEvent::PointerMove { - device_id: _, - position, - absolute, - } => { - let serial = SERIAL_COUNTER.next_serial(); - let ptr = state.seat.get_pointer().unwrap(); - let ptr_location = ptr.current_location(); - let location = if absolute { position } else { ptr_location + position }; - - let under = state - .space - .element_under(location) - .and_then(|(w, _)| w.wl_surface()) - .map(|surf| (PointerFocusTarget::WlSurface(surf), location.to_i32_round())); - - let time = Duration::from(state.clock.now()).as_millis() as u32; - ptr.motion( - state, - under.clone(), - &MotionEvent { - location, - serial, - time, + WlcsEvent::NewPointer { device_id } => { + state.process_input_event(InputEvent::::DeviceAdded { + device: WlcsDevice { + device_id, + capability: DeviceCapability::Pointer, }, - ); - - if !absolute { - let utime = Duration::from(state.clock.now()).as_micros() as u64; - ptr.relative_motion( - state, - under, - &RelativeMotionEvent { - delta: position, - delta_unaccel: position, - utime, - }, - ) - } - ptr.frame(state); + }) } + WlcsEvent::PointerMoveAbsolute { + device_id, + position, + } => state.process_input_event( + WlcsPointerMotionAbsoluteEvent { + device_id, + time: Duration::from(state.clock.now()).as_millis() as u64, + position, + } + .into(), + ), + WlcsEvent::PointerMoveRelative { device_id, delta } => state.process_input_event( + WlcsPointerMotionEvent { + device_id, + time: Duration::from(state.clock.now()).as_millis() as u64, + delta, + } + .into(), + ), WlcsEvent::PointerButton { - device_id: _, + device_id, button_id, pressed, - } => { - let serial = SERIAL_COUNTER.next_serial(); - let ptr = state.seat.get_pointer().unwrap(); - if !ptr.is_grabbed() { - let ptr_location = ptr.current_location(); - let under = state - .space - .element_under(ptr_location) - .map(|(w, _)| w.clone()); - if let Some(win) = &under { - state.space.raise_element(win, true); - } - state.seat.get_keyboard().unwrap().set_focus( - state, - under.map(|w| KeyboardFocusTarget::Window(w)), - serial, - ); - } - let time = Duration::from(state.clock.now()).as_millis() as u32; - ptr.button( - state, - &ButtonEvent { - serial, - time, - button: button_id as u32, - state: if pressed { - ButtonState::Pressed - } else { - ButtonState::Released - }, + } => state.process_input_event( + WlcsPointerButtonEvent { + device_id, + time: Duration::from(state.clock.now()).as_millis() as u64, + button_code: button_id as u32, + state: if pressed { + ButtonState::Pressed + } else { + ButtonState::Released }, - ); - ptr.frame(state); + } + .into(), + ), + WlcsEvent::NewTouch { device_id } => { + state.process_input_event(InputEvent::::DeviceAdded { + device: WlcsDevice { + device_id, + capability: DeviceCapability::Pointer, + }, + }) } - WlcsEvent::TouchDown { .. } => warn!("TouchDown"), - WlcsEvent::TouchMove { .. } => warn!("TouchMove"), - WlcsEvent::TouchUp { .. } => warn!("TouchUp"), + WlcsEvent::TouchDown { + device_id, + position, + } => state.process_input_event( + WlcsTouchDownEvent { + device_id, + time: Duration::from(state.clock.now()).as_millis() as u64, + position, + } + .into(), + ), + WlcsEvent::TouchMove { + device_id, + position, + } => state.process_input_event( + WlcsTouchDownEvent { + device_id, + time: Duration::from(state.clock.now()).as_millis() as u64, + position, + } + .into(), + ), + WlcsEvent::TouchUp { device_id } => state.process_input_event( + WlcsTouchUpEvent { + device_id, + time: Duration::from(state.clock.now()).as_millis() as u64, + } + .into(), + ), } }