diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-12-21 16:19:16 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-12-21 16:19:16 +0400 |
| commit | 86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4 (patch) | |
| tree | c30a1b36c41acf31230cffc0c62190f133417bde /src | |
| parent | 17c23dc50fef82dd0edad376e3536b3f99d4329b (diff) | |
| download | niri-86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4.tar.gz niri-86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4.tar.bz2 niri-86c4c1368e3ca2e01d7179e5fb86f8c4bdbe2cc4.zip | |
Implement pointer-constraints
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/mod.rs | 21 | ||||
| -rw-r--r-- | src/input.rs | 90 | ||||
| -rw-r--r-- | src/niri.rs | 34 |
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! { |
