feat: enforce pointer constraints
This commit is contained in:
1 parent
8fea6f85ee
commit
4f5f88b06f
2 files changed
+102
-17
No files matched your search
@@ -12,7 +12,9 @@ use smithay::{
|
|||||||
compositor::with_states,
|
compositor::with_states,
|
||||||
fractional_scale::{FractionalScaleHandler, with_fractional_scale},
|
fractional_scale::{FractionalScaleHandler, with_fractional_scale},
|
||||||
output::OutputHandler,
|
output::OutputHandler,
|
||||||
pointer_constraints::{PointerConstraintsHandler, with_pointer_constraint},
|
pointer_constraints::{
|
||||||
|
PointerConstraint, PointerConstraintsHandler, with_pointer_constraint,
|
||||||
|
},
|
||||||
selection::{
|
selection::{
|
||||||
SelectionHandler,
|
SelectionHandler,
|
||||||
data_device::{
|
data_device::{
|
||||||
@@ -57,25 +59,31 @@ impl FractionalScaleHandler for Ferese {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PointerConstraintsHandler for Ferese {
|
impl PointerConstraintsHandler for Ferese {
|
||||||
fn new_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>) {
|
fn new_constraint(&mut self, _surface: &WlSurface, pointer: &PointerHandle<Self>) {
|
||||||
let focused = pointer
|
self.activate_focused_pointer_constraint(pointer);
|
||||||
.current_focus()
|
|
||||||
.is_some_and(|focused| focused == *surface);
|
|
||||||
if focused {
|
|
||||||
with_pointer_constraint(surface, pointer, |constraint| {
|
|
||||||
if let Some(constraint) = constraint {
|
|
||||||
constraint.activate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_position_hint(
|
fn cursor_position_hint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
_pointer: &PointerHandle<Self>,
|
pointer: &PointerHandle<Self>,
|
||||||
_location: smithay::utils::Point<f64, smithay::utils::Logical>,
|
location: smithay::utils::Point<f64, smithay::utils::Logical>,
|
||||||
) {
|
) {
|
||||||
|
let locked = with_pointer_constraint(surface, pointer, |constraint| {
|
||||||
|
constraint.is_some_and(|constraint| {
|
||||||
|
constraint.is_active() && matches!(&*constraint, PointerConstraint::Locked(_))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if !locked || pointer.current_focus().as_ref() != Some(surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some((focused_surface, origin)) = self.surface_under(pointer.current_location()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if focused_surface == *surface {
|
||||||
|
pointer.set_location(origin + location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+79
-2
@@ -5,10 +5,11 @@ use smithay::{
|
|||||||
},
|
},
|
||||||
input::{
|
input::{
|
||||||
keyboard::FilterResult,
|
keyboard::FilterResult,
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerHandle, RelativeMotionEvent},
|
||||||
},
|
},
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
utils::{SERIAL_COUNTER, Serial},
|
utils::{Logical, Point, SERIAL_COUNTER, Serial},
|
||||||
|
wayland::pointer_constraints::{PointerConstraint, with_pointer_constraint},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Ferese;
|
use crate::Ferese;
|
||||||
@@ -36,6 +37,8 @@ impl Ferese {
|
|||||||
};
|
};
|
||||||
let position = event.position_transformed(geometry.size) + geometry.loc.to_f64();
|
let position = event.position_transformed(geometry.size) + geometry.loc.to_f64();
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
|
let position = self.constrain_pointer_position(&pointer, position);
|
||||||
|
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
self,
|
self,
|
||||||
self.surface_under(position),
|
self.surface_under(position),
|
||||||
@@ -46,10 +49,12 @@ impl Ferese {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
|
self.activate_focused_pointer_constraint(&pointer);
|
||||||
}
|
}
|
||||||
InputEvent::PointerMotion { event, .. } => {
|
InputEvent::PointerMotion { event, .. } => {
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
let focus = self.surface_under(pointer.current_location());
|
let focus = self.surface_under(pointer.current_location());
|
||||||
|
|
||||||
pointer.relative_motion(
|
pointer.relative_motion(
|
||||||
self,
|
self,
|
||||||
focus,
|
focus,
|
||||||
@@ -64,9 +69,11 @@ impl Ferese {
|
|||||||
InputEvent::PointerButton { event, .. } => {
|
InputEvent::PointerButton { event, .. } => {
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
|
||||||
if event.state() == ButtonState::Pressed && !pointer.is_grabbed() {
|
if event.state() == ButtonState::Pressed && !pointer.is_grabbed() {
|
||||||
self.focus_window_under_pointer(serial);
|
self.focus_window_under_pointer(serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer.button(
|
pointer.button(
|
||||||
self,
|
self,
|
||||||
&ButtonEvent {
|
&ButtonEvent {
|
||||||
@@ -93,12 +100,14 @@ impl Ferese {
|
|||||||
frame = frame.v120(Axis::Horizontal, value as i32);
|
frame = frame.v120(Axis::Horizontal, value as i32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if vertical != 0.0 {
|
if vertical != 0.0 {
|
||||||
frame = frame.value(Axis::Vertical, vertical);
|
frame = frame.value(Axis::Vertical, vertical);
|
||||||
if let Some(value) = event.amount_v120(Axis::Vertical) {
|
if let Some(value) = event.amount_v120(Axis::Vertical) {
|
||||||
frame = frame.v120(Axis::Vertical, value as i32);
|
frame = frame.v120(Axis::Vertical, value as i32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if source == AxisSource::Finger {
|
if source == AxisSource::Finger {
|
||||||
if event.amount(Axis::Horizontal) == Some(0.0) {
|
if event.amount(Axis::Horizontal) == Some(0.0) {
|
||||||
frame = frame.stop(Axis::Horizontal);
|
frame = frame.stop(Axis::Horizontal);
|
||||||
@@ -107,7 +116,9 @@ impl Ferese {
|
|||||||
frame = frame.stop(Axis::Vertical);
|
frame = frame.stop(Axis::Vertical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
|
|
||||||
pointer.axis(self, frame);
|
pointer.axis(self, frame);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
}
|
}
|
||||||
@@ -118,6 +129,7 @@ impl Ferese {
|
|||||||
fn focus_window_under_pointer(&mut self, serial: Serial) {
|
fn focus_window_under_pointer(&mut self, serial: Serial) {
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
let keyboard = self.seat.get_keyboard().expect("seat has a keyboard");
|
let keyboard = self.seat.get_keyboard().expect("seat has a keyboard");
|
||||||
|
|
||||||
if let Some((window, _)) = self.space.element_under(pointer.current_location()) {
|
if let Some((window, _)) = self.space.element_under(pointer.current_location()) {
|
||||||
let window = window.clone();
|
let window = window.clone();
|
||||||
self.space.raise_element(&window, true);
|
self.space.raise_element(&window, true);
|
||||||
@@ -130,10 +142,75 @@ impl Ferese {
|
|||||||
} else {
|
} else {
|
||||||
keyboard.set_focus(self, Option::<WlSurface>::None, serial);
|
keyboard.set_focus(self, Option::<WlSurface>::None, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.space.elements().for_each(|window| {
|
self.space.elements().for_each(|window| {
|
||||||
if let Some(toplevel) = window.toplevel() {
|
if let Some(toplevel) = window.toplevel() {
|
||||||
toplevel.send_pending_configure();
|
toplevel.send_pending_configure();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constrain_pointer_position(
|
||||||
|
&self,
|
||||||
|
pointer: &PointerHandle<Self>,
|
||||||
|
requested: Point<f64, Logical>,
|
||||||
|
) -> Point<f64, Logical> {
|
||||||
|
let current = pointer.current_location();
|
||||||
|
let Some(focused_surface) = pointer.current_focus() else {
|
||||||
|
return requested;
|
||||||
|
};
|
||||||
|
let Some((surface, origin)) = self.surface_under(current) else {
|
||||||
|
return requested;
|
||||||
|
};
|
||||||
|
if surface != focused_surface {
|
||||||
|
return requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_pointer_constraint(&surface, pointer, |constraint| {
|
||||||
|
let Some(constraint) = constraint.filter(|constraint| constraint.is_active()) else {
|
||||||
|
return requested;
|
||||||
|
};
|
||||||
|
|
||||||
|
match &*constraint {
|
||||||
|
PointerConstraint::Locked(_) => current,
|
||||||
|
PointerConstraint::Confined(_) => {
|
||||||
|
let remains_on_surface = self
|
||||||
|
.surface_under(requested)
|
||||||
|
.is_some_and(|(candidate, _)| candidate == surface);
|
||||||
|
let inside_region = constraint
|
||||||
|
.region()
|
||||||
|
.is_none_or(|region| region.contains((requested - origin).to_i32_round()));
|
||||||
|
|
||||||
|
if remains_on_surface && inside_region {
|
||||||
|
requested
|
||||||
|
} else {
|
||||||
|
current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn activate_focused_pointer_constraint(&self, pointer: &PointerHandle<Self>) {
|
||||||
|
let position = pointer.current_location();
|
||||||
|
let Some((surface, origin)) = self.surface_under(position) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if pointer.current_focus().as_ref() != Some(&surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_pointer_constraint(&surface, pointer, |constraint| {
|
||||||
|
let Some(constraint) = constraint else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let inside_region = constraint
|
||||||
|
.region()
|
||||||
|
.is_none_or(|region| region.contains((position - origin).to_i32_round()));
|
||||||
|
|
||||||
|
if !constraint.is_active() && inside_region {
|
||||||
|
constraint.activate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user