input: when updating pointer in the confined mode, recalibrate to the valid coordinates

This commit is contained in:
Skygrango 2026-05-13 20:05:39 +08:00 committed by Ian Douglas Scott
parent a533ac1ec3
commit 9702aae523

View file

@ -354,27 +354,6 @@ impl State {
_ => {} _ => {}
}); });
} }
let original_position = position;
position += event.delta().as_global();
let output = shell
.outputs()
.find(|output| output.geometry().to_f64().contains(position))
.cloned()
.unwrap_or(current_output.clone());
let output_geometry = output.geometry();
position.x = position.x.clamp(
output_geometry.loc.x as f64,
(output_geometry.loc.x + output_geometry.size.w - 1) as f64,
);
position.y = position.y.clamp(
output_geometry.loc.y as f64,
(output_geometry.loc.y + output_geometry.size.h - 1) as f64,
);
let new_under = State::surface_under(position, &output, &shell)
.map(|(target, pos)| (target, pos.as_logical()));
std::mem::drop(shell); std::mem::drop(shell);
ptr.relative_motion( ptr.relative_motion(
@ -392,6 +371,25 @@ impl State {
return; return;
} }
let original_position = position;
position += event.delta().as_global();
let shell = self.common.shell.read();
let output = shell
.outputs()
.find(|output| output.geometry().to_f64().contains(position))
.cloned()
.unwrap_or(current_output.clone());
drop(shell);
let output_geometry = output.geometry();
position.x = position.x.clamp(
output_geometry.loc.x as f64,
(output_geometry.loc.x + output_geometry.size.w - 1) as f64,
);
position.y = position.y.clamp(
output_geometry.loc.y as f64,
(output_geometry.loc.y + output_geometry.size.h - 1) as f64,
);
if ptr.is_grabbed() { if ptr.is_grabbed() {
if seat if seat
.user_data() .user_data()
@ -499,50 +497,90 @@ impl State {
} }
} }
// If confined, don't move pointer if it would go outside surface or region // If confined, help user to update valid coordinates can improve user experience
if pointer_confined && let Some((surface, surface_loc)) = &under { let shell = self.common.shell.read();
if new_under.as_ref().and_then(|(under, _)| under.wl_surface()) let new_under = if pointer_confined && let Some((surface, surface_loc)) = &under
!= surface.wl_surface() {
{ let is_legal = |pos: Point<f64, Global>, shell: &Shell| {
ptr.frame(self); let new_under = State::surface_under(pos, &output, shell)
return; .map(|(target, pos)| (target, pos.as_logical()));
}
match surface { //We should only check size, not the surface, so that we can move the mouse over the OSD in confined mode
PointerFocusTarget::WlSurface { surface, .. } => { // if new_under.as_ref().and_then(|(under, _)| under.wl_surface())
if under_from_surface_tree( // != surface.wl_surface()
surface, // {
position.as_logical() - surface_loc.to_f64(), // return (false, None);
(0, 0), // }
WindowSurfaceType::ALL,
) match surface {
.is_none() PointerFocusTarget::WlSurface { surface, .. } => {
{ if under_from_surface_tree(
ptr.frame(self); surface,
return;
}
}
PointerFocusTarget::X11Surface { surface, .. } => {
if surface
.surface_under(
position.as_logical() - surface_loc.to_f64(), position.as_logical() - surface_loc.to_f64(),
(0, 0), (0, 0),
WindowSurfaceType::ALL, WindowSurfaceType::ALL,
) )
.is_none() .is_none()
{ {
ptr.frame(self); return (false, None);
return; }
}
PointerFocusTarget::X11Surface { surface, .. } => {
if surface
.surface_under(
position.as_logical() - surface_loc.to_f64(),
(0, 0),
WindowSurfaceType::ALL,
)
.is_none()
{
return (false, None);
}
}
_ => {}
}
if let Some(region) = &confine_region
&& !region
.contains((pos.as_logical() - *surface_loc).to_i32_round())
{
return (false, None);
}
(true, new_under)
};
match is_legal(position, &shell) {
(true, under) => under,
_ => {
let y_only_pos = Point::new(original_position.x, position.y);
let x_only_pos = Point::new(position.x, original_position.y);
match is_legal(y_only_pos, &shell) {
(true, under) => {
position = y_only_pos;
under
}
_ => match is_legal(x_only_pos, &shell) {
(true, under) => {
position = x_only_pos;
under
}
_ => {
position = original_position;
None
}
},
} }
} }
_ => {}
}
if let Some(region) = confine_region
&& !region
.contains((position.as_logical() - *surface_loc).to_i32_round())
{
ptr.frame(self);
return;
} }
} else {
State::surface_under(position, &output, &shell)
.map(|(target, pos)| (target, pos.as_logical()))
};
drop(shell);
if pointer_confined && new_under.is_none() {
ptr.frame(self);
return;
} }
let serial = SERIAL_COUNTER.next_serial(); let serial = SERIAL_COUNTER.next_serial();
@ -557,24 +595,32 @@ impl State {
); );
ptr.frame(self); ptr.frame(self);
// If pointer is now in a constraint region, activate it // If pointer is now in a constraint region and window is in focused, activate it
if let Some((under, surface_location)) = new_under if let Some((under, surface_location)) = new_under
.and_then(|(target, loc)| Some((target.wl_surface()?.into_owned(), loc))) .and_then(|(target, loc)| Some((target.wl_surface()?.into_owned(), loc)))
{ {
with_pointer_constraint(&under, &ptr, |constraint| match constraint { let shell = self.common.shell.read();
Some(constraint) if !constraint.is_active() => { let is_focused = seat
let region = match &*constraint { .get_keyboard()
PointerConstraint::Locked(locked) => locked.region(), .and_then(|k| k.current_focus())
PointerConstraint::Confined(confined) => confined.region(), .is_some_and(|f| f.has_surface(&shell, &under));
};
let point = if is_focused {
(ptr.current_location() - surface_location).to_i32_round(); with_pointer_constraint(&under, &ptr, |constraint| match constraint {
if region.is_none_or(|region| region.contains(point)) { Some(constraint) if !constraint.is_active() => {
constraint.activate(); let region = match &*constraint {
PointerConstraint::Locked(locked) => locked.region(),
PointerConstraint::Confined(confined) => confined.region(),
};
let point =
(ptr.current_location() - surface_location).to_i32_round();
if region.is_none_or(|region| region.contains(point)) {
constraint.activate();
}
} }
} _ => {}
_ => {} });
}); }
} }
let mut shell = self.common.shell.write(); let mut shell = self.common.shell.write();