From d19f77f5a59b3fc633792554f8e98f39cbf8a054 Mon Sep 17 00:00:00 2001 From: sodiboo Date: Sat, 23 Nov 2024 20:10:31 +0100 Subject: [PATCH] add InputBackend extensions; hook up Device::output() to motion_absolute --- src/input/backend_ext.rs | 44 ++++++++++++++++++++++++++++++++ src/input/mod.rs | 39 ++++++++++++++++++++-------- src/protocols/virtual_pointer.rs | 8 +++--- 3 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 src/input/backend_ext.rs diff --git a/src/input/backend_ext.rs b/src/input/backend_ext.rs new file mode 100644 index 000000000..91a2aad45 --- /dev/null +++ b/src/input/backend_ext.rs @@ -0,0 +1,44 @@ +use ::input as libinput; +use smithay::backend::input; +use smithay::backend::winit::WinitVirtualDevice; +use smithay::output::Output; + +use crate::protocols::virtual_pointer::VirtualPointer; + +pub trait NiriInputBackend: input::InputBackend { + type NiriDevice: NiriInputDevice; +} +impl NiriInputBackend for T +where + Self::Device: NiriInputDevice, +{ + type NiriDevice = Self::Device; +} + +pub trait NiriInputDevice: input::Device { + // FIXME: should this be per-event? logically yes, + // but right now we only use it for virtual pointers, which have static outputs. + fn output(&self) -> Option; +} + +impl NiriInputDevice for libinput::Device { + fn output(&self) -> Option { + // FIXME: Allow specifying the output per-device? + // In that case, change the method to take a reference to our state or config or something + // (because we can't easily change the libinput Device struct) + None + } +} + +impl NiriInputDevice for WinitVirtualDevice { + fn output(&self) -> Option { + // here it's actually *correct* to return None, because there is only one output. + None + } +} + +impl NiriInputDevice for VirtualPointer { + fn output(&self) -> Option { + self.output().cloned() + } +} diff --git a/src/input/mod.rs b/src/input/mod.rs index 8b53237e1..dff60886a 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -11,7 +11,7 @@ use niri_ipc::LayoutSwitchTarget; use smithay::backend::input::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, - InputBackend, InputEvent, KeyState, KeyboardKeyEvent, Keycode, MouseButton, PointerAxisEvent, + InputEvent, KeyState, KeyboardKeyEvent, Keycode, MouseButton, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent, ProximityState, Switch, SwitchState, SwitchToggleEvent, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, @@ -28,6 +28,7 @@ use smithay::input::touch::{ DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, UpEvent, }; use smithay::input::SeatHandler; +use smithay::output::Output; use smithay::utils::{Logical, Point, Rectangle, Transform, SERIAL_COUNTER}; use smithay::wayland::keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitor; use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint}; @@ -42,6 +43,7 @@ use crate::ui::screenshot_ui::ScreenshotUi; use crate::utils::spawning::spawn; use crate::utils::{center, get_monotonic_time, ResizeEdge}; +pub mod backend_ext; pub mod move_grab; pub mod resize_grab; pub mod scroll_tracker; @@ -50,6 +52,8 @@ pub mod swipe_tracker; pub mod touch_move_grab; pub mod touch_resize_grab; +use backend_ext::{NiriInputBackend as InputBackend, NiriInputDevice as _}; + pub const DOUBLE_CLICK_TIME: Duration = Duration::from_millis(400); #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -267,8 +271,10 @@ impl State { where I::Device: 'static, { + let device_output = event.device().output(); + let device_output = device_output.as_ref(); let (target_geo, keep_ratio, px, transform) = - if let Some(output) = self.niri.output_for_tablet() { + if let Some(output) = device_output.or_else(|| self.niri.output_for_tablet()) { ( self.niri.global_space.output_geometry(output).unwrap(), true, @@ -1517,12 +1523,14 @@ impl State { &mut self, event: I::PointerMotionAbsoluteEvent, ) { - let Some(output_geo) = self.global_bounding_rectangle() else { + let Some(pos) = self.compute_absolute_location(&event, None).or_else(|| { + self.global_bounding_rectangle().map(|output_geo| { + event.position_transformed(output_geo.size) + output_geo.loc.to_f64() + }) + }) else { return; }; - let pos = event.position_transformed(output_geo.size) + output_geo.loc.to_f64(); - let serial = SERIAL_COUNTER.next_serial(); let pointer = self.niri.seat.get_pointer().unwrap(); @@ -2362,14 +2370,13 @@ impl State { ); } - /// Computes the cursor position for the touch event. - /// - /// This function handles the touch output mapping, as well as coordinate transform - fn compute_touch_location>( + fn compute_absolute_location( &self, - evt: &E, + evt: &impl AbsolutePositionEvent, + fallback_output: Option<&Output>, ) -> Option> { - let output = self.niri.output_for_touch()?; + let output = evt.device().output(); + let output = output.as_ref().or(fallback_output)?; let output_geo = self.niri.global_space.output_geometry(output).unwrap(); let transform = output.current_transform(); let size = transform.invert().transform_size(output_geo.size); @@ -2379,6 +2386,16 @@ impl State { ) } + /// Computes the cursor position for the touch event. + /// + /// This function handles the touch output mapping, as well as coordinate transform + fn compute_touch_location( + &self, + evt: &impl AbsolutePositionEvent, + ) -> Option> { + self.compute_absolute_location(evt, self.niri.output_for_touch()) + } + fn on_touch_down(&mut self, evt: I::TouchDownEvent) { let Some(handle) = self.niri.seat.get_touch() else { return; diff --git a/src/protocols/virtual_pointer.rs b/src/protocols/virtual_pointer.rs index cad029343..3d8d5126e 100644 --- a/src/protocols/virtual_pointer.rs +++ b/src/protocols/virtual_pointer.rs @@ -7,8 +7,8 @@ use smithay::backend::input::{ PointerMotionAbsoluteEvent, PointerMotionEvent, UnusedEvent, }; use smithay::input::pointer::AxisFrame; +use smithay::output::Output; use smithay::reexports::wayland_protocols_wlr; -use smithay::reexports::wayland_server::protocol::wl_output::WlOutput; use smithay::reexports::wayland_server::protocol::wl_pointer; use smithay::reexports::wayland_server::protocol::wl_seat::WlSeat; use smithay::reexports::wayland_server::{ @@ -41,7 +41,7 @@ pub struct VirtualPointer { #[derive(Debug)] pub struct VirtualPointerUserData { seat: Option, - output: Option, + output: Option, axis_frame: Mutex>, } @@ -55,7 +55,7 @@ impl VirtualPointer { self.data().seat.as_ref() } - pub fn output(&self) -> Option<&WlOutput> { + pub fn output(&self) -> Option<&Output> { self.data().output.as_ref() } @@ -355,7 +355,7 @@ where seat, output, id, - } => (id, seat, output), + } => (id, seat, output.as_ref().and_then(Output::from_resource)), zwlr_virtual_pointer_manager_v1::Request::Destroy => return, _ => unreachable!(), };