aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/handlers/mod.rs21
-rw-r--r--src/input.rs90
-rw-r--r--src/niri.rs34
3 files changed, 140 insertions, 5 deletions
diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs
index ebf53c62..d3393ccd 100644
--- a/src/handlers/mod.rs
+++ b/src/handlers/mod.rs
@@ -11,7 +11,7 @@ use std::thread;
use smithay::backend::allocator::dmabuf::Dmabuf;
use smithay::backend::renderer::ImportDma;
use smithay::desktop::{PopupKind, PopupManager};
-use smithay::input::pointer::{CursorIcon, CursorImageStatus};
+use smithay::input::pointer::{CursorIcon, CursorImageStatus, PointerHandle};
use smithay::input::{Seat, SeatHandler, SeatState};
use smithay::output::Output;
use smithay::reexports::wayland_server::protocol::wl_data_source::WlDataSource;
@@ -22,6 +22,7 @@ use smithay::utils::{Logical, Rectangle, Size};
use smithay::wayland::compositor::{send_surface_state, with_states};
use smithay::wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier};
use smithay::wayland::input_method::{InputMethodHandler, PopupSurface};
+use smithay::wayland::pointer_constraints::PointerConstraintsHandler;
use smithay::wayland::selection::data_device::{
set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState,
ServerDndGrabHandler,
@@ -36,10 +37,10 @@ use smithay::wayland::session_lock::{
};
use smithay::{
delegate_cursor_shape, delegate_data_control, delegate_data_device, delegate_dmabuf,
- delegate_input_method_manager, delegate_output, delegate_pointer_gestures,
- delegate_presentation, delegate_primary_selection, delegate_relative_pointer, delegate_seat,
- delegate_session_lock, delegate_tablet_manager, delegate_text_input_manager,
- delegate_virtual_keyboard_manager,
+ delegate_input_method_manager, delegate_output, delegate_pointer_constraints,
+ delegate_pointer_gestures, delegate_presentation, delegate_primary_selection,
+ delegate_relative_pointer, delegate_seat, delegate_session_lock, delegate_tablet_manager,
+ delegate_text_input_manager, delegate_virtual_keyboard_manager,
};
use crate::layout::output_size;
@@ -78,6 +79,16 @@ delegate_pointer_gestures!(State);
delegate_relative_pointer!(State);
delegate_text_input_manager!(State);
+impl PointerConstraintsHandler for State {
+ fn new_constraint(&mut self, _surface: &WlSurface, pointer: &PointerHandle<Self>) {
+ self.niri.maybe_activate_pointer_constraint(
+ pointer.current_location(),
+ &self.niri.pointer_focus,
+ );
+ }
+}
+delegate_pointer_constraints!(State);
+
impl InputMethodHandler for State {
fn new_popup(&mut self, surface: PopupSurface) {
let popup = PopupKind::from(surface.clone());
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);
diff --git a/src/niri.rs b/src/niri.rs
index 084d51e9..0a3c34c9 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -61,6 +61,7 @@ use smithay::wayland::cursor_shape::CursorShapeManagerState;
use smithay::wayland::dmabuf::DmabufFeedback;
use smithay::wayland::input_method::InputMethodManagerState;
use smithay::wayland::output::OutputManagerState;
+use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraintsState};
use smithay::wayland::pointer_gestures::PointerGesturesState;
use smithay::wayland::presentation::PresentationState;
use smithay::wayland::relative_pointer::RelativePointerManagerState;
@@ -142,6 +143,7 @@ pub struct Niri {
pub virtual_keyboard_state: VirtualKeyboardManagerState,
pub pointer_gestures_state: PointerGesturesState,
pub relative_pointer_state: RelativePointerManagerState,
+ pub pointer_constraints_state: PointerConstraintsState,
pub data_device_state: DataDeviceState,
pub primary_selection_state: PrimarySelectionState,
pub data_control_state: DataControlState,
@@ -299,6 +301,8 @@ impl State {
pub fn move_cursor(&mut self, location: Point<f64, Logical>) {
let under = self.niri.surface_under_and_global_space(location);
+ self.niri
+ .maybe_activate_pointer_constraint(location, &under);
self.niri.pointer_focus = under.clone();
let under = under.map(|u| u.surface);
@@ -355,6 +359,9 @@ impl State {
return false;
}
+ self.niri
+ .maybe_activate_pointer_constraint(location, &under);
+
self.niri.pointer_focus = under.clone();
let under = under.map(|u| u.surface);
@@ -642,6 +649,7 @@ impl Niri {
let tablet_state = TabletManagerState::new::<State>(&display_handle);
let pointer_gestures_state = PointerGesturesState::new::<State>(&display_handle);
let relative_pointer_state = RelativePointerManagerState::new::<State>(&display_handle);
+ let pointer_constraints_state = PointerConstraintsState::new::<State>(&display_handle);
let data_device_state = DataDeviceState::new::<State>(&display_handle);
let primary_selection_state = PrimarySelectionState::new::<State>(&display_handle);
let data_control_state = DataControlState::new::<State, _>(
@@ -754,6 +762,7 @@ impl Niri {
tablet_state,
pointer_gestures_state,
relative_pointer_state,
+ pointer_constraints_state,
data_device_state,
primary_selection_state,
data_control_state,
@@ -2352,6 +2361,31 @@ impl Niri {
output_state.lock_surface = Some(surface);
}
+
+ pub fn maybe_activate_pointer_constraint(
+ &self,
+ new_pos: Point<f64, Logical>,
+ new_under: &Option<PointerFocus>,
+ ) {
+ let Some(under) = new_under else { return };
+ let pointer = &self.seat.get_pointer().unwrap();
+ with_pointer_constraint(&under.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() {
+ let new_pos_within_surface = new_pos.to_i32_round() - under.surface.1;
+ if !region.contains(new_pos_within_surface) {
+ return;
+ }
+ }
+
+ constraint.activate();
+ });
+ }
}
render_elements! {