wayland: implement new_constraint, remove_constraint and cursor_position_hint for PointerConstraintsHandler

new_constraint: check if the surface has pointer focus, keyboard focus, and if the pointer is within toplevel geometry or constraint region. If these conditions are met, then enable the constraint.

remove_constraint: apply last cursor position hint that saved in seat.

cursor_position_hint: save the cursor position hints provided by the client to the seat.
This commit is contained in:
Skygrango 2026-05-13 20:08:21 +08:00 committed by Ian Douglas Scott
parent 4fb7d49316
commit 208c2128cd
4 changed files with 156 additions and 42 deletions

View file

@ -1,35 +1,123 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::state::State;
use crate::{shell::CosmicSurface, state::State, utils::prelude::*};
use smithay::{
input::pointer::PointerHandle,
reexports::wayland_server::protocol::wl_surface::WlSurface,
utils::{Logical, Point},
wayland::{
pointer_constraints::{PointerConstraintsHandler, with_pointer_constraint},
seat::WaylandFocus,
},
wayland::{pointer_constraints::PointerConstraintsHandler, seat::WaylandFocus},
};
pub use smithay::wayland::pointer_constraints::{PointerConstraintRef, with_pointer_constraint};
impl PointerConstraintsHandler for State {
fn new_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>) {
// XXX region
if pointer
.current_focus()
.is_some_and(|x| x.wl_surface().as_deref() == Some(surface))
{
let seat = self
.common
.shell
.read()
.seats
.iter()
.find(|s| s.get_pointer().as_ref() == Some(pointer))
.cloned();
let (is_under, is_focused, surface_location) = if let Some(seat) = seat {
seat.set_pointer_constraint_hint(None);
let current_output = seat.active_output();
let position = seat.get_pointer().unwrap().current_location().as_global();
let shell = self.common.shell.read();
let under = State::surface_under(position, &current_output, &shell);
let mut surface_location = None;
let is_under = if let Some((target, target_loc)) = under
&& let Some(under_surface) = target.wl_surface()
{
if *under_surface == *surface {
surface_location = Some(target_loc);
true
} else {
CosmicSurface::surface_tree_offset(surface, &under_surface).is_some_and(
|offset| {
surface_location = Some(target_loc - offset.to_f64().as_global());
true
},
)
}
} else {
false
};
let is_focused = seat
.get_keyboard()
.and_then(|k| k.current_focus())
.is_some_and(|f| f.has_surface(&shell, surface));
(is_under, is_focused, surface_location)
} else {
(false, false, None)
};
if is_focused && is_under {
with_pointer_constraint(surface, pointer, |constraint| {
constraint.unwrap().activate();
if let Some(constraint) = constraint {
if let Some(region) = constraint.region() {
if let Some(surface_location) = surface_location
&& let position = pointer.current_location()
&& let point = (position - surface_location.as_logical()).to_i32_round()
&& region.contains(point)
{
constraint.activate();
}
} else {
constraint.activate();
}
}
});
}
}
fn remove_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>) {
if with_pointer_constraint(surface, pointer, |constraint| constraint.is_none()) {
let seat = self
.common
.shell
.read()
.seats
.iter()
.find(|s| s.get_pointer().as_ref() == Some(pointer))
.cloned();
if let Some(seat) = seat
&& let Some((hint_surface, hint_location)) = seat.pointer_constraint_hint()
&& hint_surface == *surface
{
self.apply_cursor_hint(surface, pointer, hint_location);
seat.set_pointer_constraint_hint(None);
}
}
}
fn cursor_position_hint(
&mut self,
_surface: &WlSurface,
_pointer: &PointerHandle<Self>,
_location: Point<f64, Logical>,
surface: &WlSurface,
pointer: &PointerHandle<Self>,
location: Point<f64, Logical>,
) {
// TODO
if with_pointer_constraint(surface, pointer, |constraint| {
constraint.is_some_and(|c| c.is_active())
}) {
let seat = self
.common
.shell
.read()
.seats
.iter()
.find(|s| s.get_pointer().as_ref() == Some(pointer))
.cloned();
if let Some(seat) = seat {
seat.set_pointer_constraint_hint(Some((surface.clone(), location)));
}
}
}
}