aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input.rs100
-rw-r--r--src/niri.rs6
2 files changed, 86 insertions, 20 deletions
diff --git a/src/input.rs b/src/input.rs
index 063d321c..a86045bd 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1,3 +1,4 @@
+use std::any::Any;
use std::collections::HashSet;
use smithay::backend::input::{
@@ -14,7 +15,8 @@ use smithay::input::pointer::{
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, RelativeMotionEvent,
};
-use smithay::utils::SERIAL_COUNTER;
+use smithay::reexports::input;
+use smithay::utils::{Logical, Point, SERIAL_COUNTER};
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
use crate::config::{Action, Binds, LayoutAction, Modifiers};
@@ -28,8 +30,16 @@ pub enum CompositorMod {
Alt,
}
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct TabletData {
+ pub aspect_ratio: f64,
+}
+
impl State {
- pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>) {
+ pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>)
+ where
+ I::Device: 'static, // Needed for downcasting.
+ {
let _span = tracy_client::span!("process_input_event");
// A bit of a hack, but animation end runs some logic (i.e. workspace clean-up) and it
@@ -582,14 +592,10 @@ impl State {
pointer.frame(self);
}
InputEvent::TabletToolAxis { event, .. } => {
- let Some(output) = self.niri.output_for_tablet() else {
+ let Some(pos) = self.compute_tablet_position(&event) else {
return;
};
- let output_geo = self.niri.global_space.output_geometry(output).unwrap();
-
- 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();
@@ -671,14 +677,10 @@ impl State {
}
}
InputEvent::TabletToolProximity { event, .. } => {
- let Some(output) = self.niri.output_for_tablet() else {
+ let Some(pos) = self.compute_tablet_position(&event) else {
return;
};
- let output_geo = self.niri.global_space.output_geometry(output).unwrap();
-
- 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();
@@ -927,17 +929,75 @@ impl State {
}
pub fn process_libinput_event(&mut self, event: &mut InputEvent<LibinputInputBackend>) {
- if let InputEvent::DeviceAdded { device } = event {
- // According to Mutter code, this setting is specific to touchpads.
- let is_touchpad = device.config_tap_finger_count() > 0;
- if is_touchpad {
- let c = &self.niri.config.borrow().input.touchpad;
- let _ = device.config_tap_set_enabled(c.tap);
- let _ = device.config_scroll_set_natural_scroll_enabled(c.natural_scroll);
- let _ = device.config_accel_set_speed(c.accel_speed);
+ match event {
+ InputEvent::DeviceAdded { device } => {
+ // According to Mutter code, this setting is specific to touchpads.
+ let is_touchpad = device.config_tap_finger_count() > 0;
+ if is_touchpad {
+ let c = &self.niri.config.borrow().input.touchpad;
+ let _ = device.config_tap_set_enabled(c.tap);
+ let _ = device.config_scroll_set_natural_scroll_enabled(c.natural_scroll);
+ let _ = device.config_accel_set_speed(c.accel_speed);
+ }
+
+ if device.has_capability(smithay::reexports::input::DeviceCapability::TabletTool) {
+ match device.size() {
+ Some((w, h)) => {
+ self.niri.tablets.insert(
+ device.clone(),
+ TabletData {
+ aspect_ratio: w / h,
+ },
+ );
+ }
+ None => {
+ warn!("tablet tool device has no size");
+ }
+ }
+ }
+ }
+ InputEvent::DeviceRemoved { device } => {
+ self.niri.tablets.remove(device);
}
+ _ => (),
}
}
+
+ fn compute_tablet_position<I: InputBackend>(
+ &mut self,
+ event: &(impl Event<I> + TabletToolEvent<I>),
+ ) -> Option<Point<f64, Logical>>
+ where
+ I::Device: 'static,
+ {
+ let output = self.niri.output_for_tablet()?;
+ let output_geo = self.niri.global_space.output_geometry(output).unwrap();
+
+ let mut pos = event.position_transformed(output_geo.size);
+ pos.x /= output_geo.size.w as f64;
+ pos.y /= output_geo.size.h as f64;
+
+ let device = event.device();
+ if let Some(device) = (&device as &dyn Any).downcast_ref::<input::Device>() {
+ if let Some(data) = self.niri.tablets.get(device) {
+ // This code does the same thing as mutter with "keep aspect ratio" enabled.
+ let output_aspect_ratio = output_geo.size.w as f64 / output_geo.size.h as f64;
+ let ratio = data.aspect_ratio / output_aspect_ratio;
+
+ if ratio > 1. {
+ pos.x *= ratio;
+ } else {
+ pos.y /= ratio;
+ }
+ }
+ };
+
+ pos.x *= output_geo.size.w as f64;
+ pos.y *= output_geo.size.h as f64;
+ pos.x = pos.x.clamp(0.0, output_geo.size.w as f64 - 1.);
+ pos.y = pos.y.clamp(0.0, output_geo.size.h as f64 - 1.);
+ Some(pos + output_geo.loc.to_f64())
+ }
}
/// Check whether the key should be intercepted and mark intercepted
diff --git a/src/niri.rs b/src/niri.rs
index c9f7487e..66863f15 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -41,6 +41,7 @@ use smithay::reexports::calloop::timer::{TimeoutAction, Timer};
use smithay::reexports::calloop::{
self, Idle, Interest, LoopHandle, LoopSignal, Mode, PostAction, RegistrationToken,
};
+use smithay::reexports::input;
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::WmCapabilities;
use smithay::reexports::wayland_protocols_misc::server_decoration as _server_decoration;
use smithay::reexports::wayland_server::backend::{
@@ -86,6 +87,7 @@ use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
use crate::dbus::mutter_screen_cast::{self, ScreenCastToNiri};
use crate::frame_clock::FrameClock;
use crate::handlers::configure_lock_surface;
+use crate::input::TabletData;
use crate::layout::{output_size, Layout, MonitorRenderElement};
use crate::pw_utils::{Cast, PipeWire};
use crate::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
@@ -121,6 +123,8 @@ pub struct Niri {
// When false, we're idling with monitors powered off.
pub monitors_active: bool,
+ pub tablets: HashMap<input::Device, TabletData>,
+
// Smithay state.
pub compositor_state: CompositorState,
pub xdg_shell_state: XdgShellState,
@@ -694,6 +698,8 @@ impl Niri {
unmapped_windows: HashMap::new(),
monitors_active: true,
+ tablets: HashMap::new(),
+
compositor_state,
xdg_shell_state,
xdg_decoration_state,