aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input.rs58
-rw-r--r--src/lib.rs1
-rw-r--r--src/niri.rs5
-rw-r--r--src/wheel_tracker.rs36
4 files changed, 100 insertions, 0 deletions
diff --git a/src/input.rs b/src/input.rs
index 0c106e20..dca07316 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1081,6 +1081,64 @@ impl State {
let horizontal_amount_v120 = event.amount_v120(Axis::Horizontal);
let vertical_amount_v120 = event.amount_v120(Axis::Vertical);
+ // Handle wheel bindings.
+ if source == AxisSource::Wheel {
+ let comp_mod = self.backend.mod_key();
+ let mods = self.niri.seat.get_keyboard().unwrap().modifier_state();
+
+ if let Some(v120) = horizontal_amount_v120 {
+ let config = self.niri.config.borrow();
+ let bindings = &config.binds;
+ let action_left = bound_action(bindings, comp_mod, Trigger::WheelLeft, mods);
+ let action_right = bound_action(bindings, comp_mod, Trigger::WheelRight, mods);
+ drop(config);
+
+ // If we have a bind with current modifiers along the scroll direction, then
+ // accumulate and don't pass to Wayland. If there's no bind, reset the accumulator.
+ if action_left.is_some() || action_right.is_some() {
+ let ticks = self.niri.horizontal_wheel_tracker.accumulate(v120);
+ if let Some(right) = action_right {
+ for _ in 0..ticks {
+ self.do_action(right.clone());
+ }
+ }
+ if let Some(left) = action_left {
+ for _ in ticks..0 {
+ self.do_action(left.clone());
+ }
+ }
+ return;
+ } else {
+ self.niri.horizontal_wheel_tracker.reset();
+ }
+ }
+
+ if let Some(v120) = vertical_amount_v120 {
+ let config = self.niri.config.borrow();
+ let bindings = &config.binds;
+ let action_up = bound_action(bindings, comp_mod, Trigger::WheelUp, mods);
+ let action_down = bound_action(bindings, comp_mod, Trigger::WheelDown, mods);
+ drop(config);
+
+ if action_up.is_some() || action_down.is_some() {
+ let ticks = self.niri.vertical_wheel_tracker.accumulate(v120);
+ if let Some(down) = action_down {
+ for _ in 0..ticks {
+ self.do_action(down.clone());
+ }
+ }
+ if let Some(up) = action_up {
+ for _ in ticks..0 {
+ self.do_action(up.clone());
+ }
+ }
+ return;
+ } else {
+ self.niri.vertical_wheel_tracker.reset();
+ }
+ }
+ }
+
let horizontal_amount = event.amount(Axis::Horizontal).unwrap_or_else(|| {
// Winit backend, discrete scrolling.
horizontal_amount_v120.unwrap_or(0.0) / 120. * 15.
diff --git a/src/lib.rs b/src/lib.rs
index 08be5398..0ad55d9c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,7 @@ pub mod rubber_band;
pub mod swipe_tracker;
pub mod ui;
pub mod utils;
+pub mod wheel_tracker;
pub mod window;
#[cfg(not(feature = "xdp-gnome-screencast"))]
diff --git a/src/niri.rs b/src/niri.rs
index 08f195fc..babd961c 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -114,6 +114,7 @@ use crate::utils::spawning::CHILD_ENV;
use crate::utils::{
center, center_f64, get_monotonic_time, make_screenshot_path, output_size, write_png_rgba8,
};
+use crate::wheel_tracker::WheelTracker;
use crate::window::{InitialConfigureState, Mapped, ResolvedWindowRules, Unmapped};
use crate::{animation, niri_render_elements};
@@ -204,6 +205,8 @@ pub struct Niri {
pub pointer_focus: PointerFocus,
pub tablet_cursor_location: Option<Point<f64, Logical>>,
pub gesture_swipe_3f_cumulative: Option<(f64, f64)>,
+ pub vertical_wheel_tracker: WheelTracker,
+ pub horizontal_wheel_tracker: WheelTracker,
pub lock_state: LockState,
@@ -1263,6 +1266,8 @@ impl Niri {
pointer_focus: PointerFocus::default(),
tablet_cursor_location: None,
gesture_swipe_3f_cumulative: None,
+ vertical_wheel_tracker: WheelTracker::new(),
+ horizontal_wheel_tracker: WheelTracker::new(),
lock_state: LockState::Unlocked,
diff --git a/src/wheel_tracker.rs b/src/wheel_tracker.rs
new file mode 100644
index 00000000..0163548a
--- /dev/null
+++ b/src/wheel_tracker.rs
@@ -0,0 +1,36 @@
+pub struct WheelTracker {
+ last: f64,
+ acc: f64,
+}
+
+impl WheelTracker {
+ #[allow(clippy::new_without_default)]
+ pub fn new() -> Self {
+ Self { last: 0., acc: 0. }
+ }
+
+ pub fn accumulate(&mut self, amount_v120: f64) -> i8 {
+ let changed_direction =
+ (self.last > 0. && amount_v120 < 0.) || (self.last < 0. && amount_v120 > 0.);
+ if changed_direction {
+ self.acc = 0.
+ }
+
+ self.last = amount_v120;
+ self.acc += amount_v120;
+
+ let mut ticks = 0;
+ if self.acc.abs() >= 120. {
+ let clamped = self.acc.clamp(-127. * 120., 127. * 120.);
+ ticks = (clamped as i16 / 120) as i8;
+ self.acc %= 120.;
+ }
+
+ ticks
+ }
+
+ pub fn reset(&mut self) {
+ self.last = 0.;
+ self.acc = 0.;
+ }
+}