aboutsummaryrefslogtreecommitdiff
path: root/src/input.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-12-21 16:19:16 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-12-21 16:19:16 +0400
commit86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4 (patch)
treec30a1b36c41acf31230cffc0c62190f133417bde /src/input.rs
parent17c23dc50fef82dd0edad376e3536b3f99d4329b (diff)
downloadniri-86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4.tar.gz
niri-86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4.tar.bz2
niri-86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4.zip
Implement pointer-constraints
Diffstat (limited to 'src/input.rs')
-rw-r--r--src/input.rs90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/input.rs b/src/input.rs
index 3cdd09c2..90d7faff 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -17,6 +17,7 @@ use smithay::input::pointer::{
};
use smithay::reexports::input;
use smithay::utils::{Logical, Point, SERIAL_COUNTER};
+use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint};
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
use crate::config::{Action, Binds, LayoutAction, Modifiers};
@@ -509,6 +510,56 @@ impl State {
// We received an event for the regular pointer, so show it now.
self.niri.tablet_cursor_location = None;
+ // Check if we have an active pointer constraint.
+ let mut pointer_confined = None;
+ if let Some(focus) = self.niri.pointer_focus.as_ref() {
+ let focus_surface_loc = focus.surface.1;
+ let pos_within_surface = pos.to_i32_round() - focus_surface_loc;
+
+ let mut pointer_locked = false;
+ with_pointer_constraint(&focus.surface.0, &pointer, |constraint| {
+ let Some(constraint) = constraint else { return };
+ if !constraint.is_active() {
+ return;
+ }
+
+ // Constraint does not apply if not within region.
+ if let Some(region) = constraint.region() {
+ if !region.contains(pos_within_surface) {
+ return;
+ }
+ }
+
+ match &*constraint {
+ PointerConstraint::Locked(_locked) => {
+ pointer_locked = true;
+ }
+ PointerConstraint::Confined(confine) => {
+ pointer_confined = Some((focus.surface.clone(), confine.region().cloned()));
+ }
+ }
+ });
+
+ // If the pointer is locked, only send relative motion.
+ if pointer_locked {
+ pointer.relative_motion(
+ self,
+ Some(focus.surface.clone()),
+ &RelativeMotionEvent {
+ delta: event.delta(),
+ delta_unaccel: event.delta_unaccel(),
+ utime: event.time(),
+ },
+ );
+
+ pointer.frame(self);
+
+ // I guess a redraw to hide the tablet cursor could be nice? Doesn't matter too
+ // much here I think.
+ return;
+ }
+ }
+
if self
.niri
.global_space
@@ -552,6 +603,44 @@ impl State {
}
let under = self.niri.surface_under_and_global_space(new_pos);
+
+ // Handle confined pointer.
+ if let Some((focus_surface, region)) = pointer_confined {
+ let mut prevent = false;
+
+ // Prevent the pointer from leaving the focused surface.
+ if Some(&focus_surface.0) != under.as_ref().map(|x| &x.surface.0) {
+ prevent = true;
+ }
+
+ // Prevent the pointer from leaving the confine region, if any.
+ if let Some(region) = region {
+ let new_pos_within_surface = new_pos.to_i32_round() - focus_surface.1;
+ if !region.contains(new_pos_within_surface) {
+ prevent = true;
+ }
+ }
+
+ if prevent {
+ pointer.relative_motion(
+ self,
+ Some(focus_surface),
+ &RelativeMotionEvent {
+ delta: event.delta(),
+ delta_unaccel: event.delta_unaccel(),
+ utime: event.time(),
+ },
+ );
+
+ pointer.frame(self);
+
+ return;
+ }
+ }
+
+ // Activate a new confinement if necessary.
+ self.niri.maybe_activate_pointer_constraint(new_pos, &under);
+
self.niri.pointer_focus = under.clone();
let under = under.map(|u| u.surface);
@@ -614,6 +703,7 @@ impl State {
}
let under = self.niri.surface_under_and_global_space(pos);
+ self.niri.maybe_activate_pointer_constraint(pos, &under);
self.niri.pointer_focus = under.clone();
let under = under.map(|u| u.surface);