Fix: improve edge pointer accuracy

This commit is contained in:
RipleyTom 2026-07-21 10:32:09 +02:00 committed by Victoria Brekenfeld
parent 9789187416
commit 8955024bff
7 changed files with 43 additions and 32 deletions

View file

@ -337,7 +337,7 @@ impl State {
// Constraint does not apply if not within region // Constraint does not apply if not within region
if !constraint.region().is_none_or(|x| { if !constraint.region().is_none_or(|x| {
x.contains( x.contains(
(ptr.current_location() - *surface_loc).to_i32_round(), (ptr.current_location() - *surface_loc).to_i32_floor(),
) )
}) { }) {
return; return;
@ -382,14 +382,25 @@ impl State {
.unwrap_or(current_output.clone()); .unwrap_or(current_output.clone());
drop(shell); drop(shell);
let output_geometry = output.geometry(); let output_geometry = output.geometry();
position.x = position.x.clamp(
output_geometry.loc.x as f64, let scale = output.current_scale().fractional_scale();
(output_geometry.loc.x + output_geometry.size.w - 1) as f64, let physical = output
); .current_mode()
position.y = position.y.clamp( .map(|mode| output.current_transform().transform_size(mode.size))
output_geometry.loc.y as f64, .unwrap_or_default();
(output_geometry.loc.y + output_geometry.size.h - 1) as f64, let logical = physical.to_f64().to_logical(scale);
); let output_geometry_loc = output_geometry.loc.to_f64();
// output_geometry.size is a rounded value and may undershoot/overshoot the accurate logical size
// We constrain the position with:
// - output_geometry.size so that we don't send leave events to a fullscreen app
// - logical size so that the position doesn't end up outside the actual size of the output
// See https://github.com/pop-os/cosmic-comp/pull/2568
let max_x = output_geometry_loc.x
+ logical.w.min(output_geometry.size.w as f64).next_down();
let max_y = output_geometry_loc.y
+ logical.h.min(output_geometry.size.h as f64).next_down();
position.x = position.x.clamp(output_geometry_loc.x, max_x);
position.y = position.y.clamp(output_geometry_loc.y, max_y);
if ptr.is_grabbed() { if ptr.is_grabbed() {
if seat if seat
@ -543,7 +554,7 @@ impl State {
if let Some(region) = &confine_region if let Some(region) = &confine_region
&& !region && !region
.contains((pos.as_logical() - *surface_loc).to_i32_round()) .contains((pos.as_logical() - *surface_loc).to_i32_floor())
{ {
return (false, None); return (false, None);
} }
@ -614,7 +625,7 @@ impl State {
PointerConstraint::Confined(confined) => confined.region(), PointerConstraint::Confined(confined) => confined.region(),
}; };
let point = let point =
(ptr.current_location() - surface_location).to_i32_round(); (ptr.current_location() - surface_location).to_i32_floor();
if region.is_none_or(|region| region.contains(point)) { if region.is_none_or(|region| region.contains(point)) {
constraint.activate(); constraint.activate();
} }
@ -2210,7 +2221,7 @@ impl State {
if Rectangle::new(offset.as_local(), output_geo.size) if Rectangle::new(offset.as_local(), output_geo.size)
.intersection(output_geo) .intersection(output_geo)
.is_some_and(|geometry| { .is_some_and(|geometry| {
geometry.contains(global_pos.to_local(output).to_i32_round()) geometry.contains(global_pos.to_local(output).to_i32_floor())
}) })
&& let Some(element) = workspace.popup_element_under(location, seat) && let Some(element) = workspace.popup_element_under(location, seat)
{ {
@ -2224,7 +2235,7 @@ impl State {
if Rectangle::new(offset.as_local(), output_geo.size) if Rectangle::new(offset.as_local(), output_geo.size)
.intersection(output_geo) .intersection(output_geo)
.is_some_and(|geometry| { .is_some_and(|geometry| {
geometry.contains(global_pos.to_local(output).to_i32_round()) geometry.contains(global_pos.to_local(output).to_i32_floor())
}) })
&& let Some(element) = workspace.toplevel_element_under(location, seat) && let Some(element) = workspace.toplevel_element_under(location, seat)
{ {
@ -2427,7 +2438,7 @@ impl State {
if let Some(constraint) = constraint if let Some(constraint) = constraint
&& let Some(region) = constraint.region() && let Some(region) = constraint.region()
{ {
let point_in_surface = (p - surface_offset.to_f64()).to_i32_round(); let point_in_surface = (p - surface_offset.to_f64()).to_i32_floor();
return region.contains(point_in_surface); return region.contains(point_in_surface);
} }
true true

View file

@ -530,7 +530,7 @@ impl CosmicStack {
let geo = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry(); let geo = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry();
if surface_type.contains(WindowSurfaceType::TOPLEVEL) { if surface_type.contains(WindowSurfaceType::TOPLEVEL) {
let point_i32 = relative_pos.to_i32_round::<i32>(); let point_i32 = relative_pos.to_i32_floor::<i32>();
if (point_i32.x - geo.loc.x >= -RESIZE_BORDER && point_i32.x - geo.loc.x < 0) if (point_i32.x - geo.loc.x >= -RESIZE_BORDER && point_i32.x - geo.loc.x < 0)
|| (point_i32.y - geo.loc.y >= -RESIZE_BORDER && point_i32.y - geo.loc.y < 0) || (point_i32.y - geo.loc.y >= -RESIZE_BORDER && point_i32.y - geo.loc.y < 0)
|| (point_i32.x - geo.loc.x >= geo.size.w || (point_i32.x - geo.loc.x >= geo.size.w

View file

@ -113,7 +113,7 @@ impl Focus {
location: Point<f64, Logical>, location: Point<f64, Logical>,
) -> Option<Focus> { ) -> Option<Focus> {
let geo = surface.geometry(); let geo = surface.geometry();
let loc = location.to_i32_round::<i32>() - geo.loc; let loc = location.to_i32_floor::<i32>() - geo.loc;
if loc.y < 0 && loc.x < 0 { if loc.y < 0 && loc.x < 0 {
Some(Focus::ResizeTopLeft) Some(Focus::ResizeTopLeft)
} else if loc.y < 0 && loc.x >= geo.size.w { } else if loc.y < 0 && loc.x >= geo.size.w {
@ -292,7 +292,7 @@ impl CosmicWindow {
{ {
let geo = p.window.geometry(); let geo = p.window.geometry();
let point_i32 = relative_pos.to_i32_round::<i32>(); let point_i32 = relative_pos.to_i32_floor::<i32>();
let ssd_height = if has_ssd { SSD_HEIGHT } else { 0 }; let ssd_height = if has_ssd { SSD_HEIGHT } else { 0 };
if (point_i32.x - geo.loc.x >= -RESIZE_BORDER && point_i32.x - geo.loc.x < 0) if (point_i32.x - geo.loc.x >= -RESIZE_BORDER && point_i32.x - geo.loc.x < 0)

View file

@ -548,7 +548,7 @@ impl PointerGrab<State> for MenuGrab {
let mut bbox = elem.iced.bbox(); let mut bbox = elem.iced.bbox();
bbox.loc = elem.position.as_logical(); bbox.loc = elem.position.as_logical();
bbox.contains(event_location.to_i32_round()) bbox.contains(event_location.to_i32_floor())
}) { }) {
let element = &mut elements[i]; let element = &mut elements[i];
@ -753,7 +753,7 @@ impl TouchGrab<State> for MenuGrab {
let mut bbox = elem.iced.bbox(); let mut bbox = elem.iced.bbox();
bbox.loc = elem.position.as_logical(); bbox.loc = elem.position.as_logical();
bbox.contains(event_location.to_i32_round()) bbox.contains(event_location.to_i32_floor())
}) { }) {
let element = &mut elements[i]; let element = &mut elements[i];

View file

@ -3150,7 +3150,7 @@ impl TilingLayout {
location_f64: Point<f64, Local>, location_f64: Point<f64, Local>,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<KeyboardFocusTarget> { ) -> Option<KeyboardFocusTarget> {
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_floor();
for (mapped, geo) in self.mapped() { for (mapped, geo) in self.mapped() {
if !mapped.bbox().contains((location - geo.loc).as_logical()) { if !mapped.bbox().contains((location - geo.loc).as_logical()) {
@ -3177,7 +3177,7 @@ impl TilingLayout {
location_f64: Point<f64, Local>, location_f64: Point<f64, Local>,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<KeyboardFocusTarget> { ) -> Option<KeyboardFocusTarget> {
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_floor();
for (mapped, geo) in self.mapped() { for (mapped, geo) in self.mapped() {
// Tiled windows are rendered cropped to their tile (`geo`), so input must be bound to the tile as well // Tiled windows are rendered cropped to their tile (`geo`), so input must be bound to the tile as well
@ -3209,7 +3209,7 @@ impl TilingLayout {
overview: OverviewMode, overview: OverviewMode,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<(PointerFocusTarget, Point<f64, Local>)> { ) -> Option<(PointerFocusTarget, Point<f64, Local>)> {
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_floor();
if matches!(overview, OverviewMode::None) { if matches!(overview, OverviewMode::None) {
for (mapped, geo) in self.mapped() { for (mapped, geo) in self.mapped() {
@ -3244,7 +3244,7 @@ impl TilingLayout {
) -> Option<(PointerFocusTarget, Point<f64, Local>)> { ) -> Option<(PointerFocusTarget, Point<f64, Local>)> {
let tree = &self.queue.trees.back().unwrap().0; let tree = &self.queue.trees.back().unwrap().0;
let root = tree.root_node_id()?; let root = tree.root_node_id()?;
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_floor();
if matches!(overview, OverviewMode::None) { if matches!(overview, OverviewMode::None) {
for (mapped, geo) in self.mapped() { for (mapped, geo) in self.mapped() {
@ -3305,7 +3305,7 @@ impl TilingLayout {
.. ..
}, },
)) => { )) => {
let test_point = (location.to_f64() - last_geometry.loc.to_f64() let test_point = (location_f64 - last_geometry.loc.to_f64()
+ mapped.geometry().loc.to_f64().as_local()) + mapped.geometry().loc.to_f64().as_local())
.as_logical(); .as_logical();
mapped mapped
@ -3410,7 +3410,7 @@ impl TilingLayout {
} }
let location_f64 = location_f64.unwrap(); let location_f64 = location_f64.unwrap();
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_floor();
if matches!( if matches!(
overview.active_trigger(), overview.active_trigger(),
@ -3660,7 +3660,7 @@ impl TilingLayout {
TargetZone::WindowStack(id, last_geometry) TargetZone::WindowStack(id, last_geometry)
} else { } else {
let left_right = { let left_right = {
let relative_loc = (location.x - last_geometry.loc.x) as f64; let relative_loc = location_f64.x - last_geometry.loc.x as f64;
if relative_loc < last_geometry.size.w as f64 / 2.0 { if relative_loc < last_geometry.size.w as f64 / 2.0 {
(Direction::Left, relative_loc / last_geometry.size.w as f64) (Direction::Left, relative_loc / last_geometry.size.w as f64)
} else { } else {
@ -3671,7 +3671,7 @@ impl TilingLayout {
} }
}; };
let up_down = { let up_down = {
let relative_loc = (location.y - last_geometry.loc.y) as f64; let relative_loc = location_f64.y - last_geometry.loc.y as f64;
if relative_loc < last_geometry.size.h as f64 / 2.0 { if relative_loc < last_geometry.size.h as f64 / 2.0 {
(Direction::Up, relative_loc / last_geometry.size.h as f64) (Direction::Up, relative_loc / last_geometry.size.h as f64)
} else { } else {

View file

@ -785,7 +785,7 @@ impl Workspace {
location: Point<f64, Global>, location: Point<f64, Global>,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<KeyboardFocusTarget> { ) -> Option<KeyboardFocusTarget> {
if !self.output.geometry().contains(location.to_i32_round()) { if !self.output.geometry().contains(location.to_i32_floor()) {
return None; return None;
} }
let location = location.to_local(&self.output); let location = location.to_local(&self.output);
@ -834,7 +834,7 @@ impl Workspace {
location: Point<f64, Global>, location: Point<f64, Global>,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<KeyboardFocusTarget> { ) -> Option<KeyboardFocusTarget> {
if !self.output.geometry().contains(location.to_i32_round()) { if !self.output.geometry().contains(location.to_i32_floor()) {
return None; return None;
} }
let location = location.to_local(&self.output); let location = location.to_local(&self.output);
@ -884,7 +884,7 @@ impl Workspace {
overview: OverviewMode, overview: OverviewMode,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<(PointerFocusTarget, Point<f64, Global>)> { ) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
if !self.output.geometry().contains(location.to_i32_round()) { if !self.output.geometry().contains(location.to_i32_floor()) {
return None; return None;
} }
let location = location.to_local(&self.output); let location = location.to_local(&self.output);
@ -934,7 +934,7 @@ impl Workspace {
overview: OverviewMode, overview: OverviewMode,
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<(PointerFocusTarget, Point<f64, Global>)> { ) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
if !self.output.geometry().contains(location.to_i32_round()) { if !self.output.geometry().contains(location.to_i32_floor()) {
return None; return None;
} }
let location = location.to_local(&self.output); let location = location.to_local(&self.output);

View file

@ -63,7 +63,7 @@ impl PointerConstraintsHandler for State {
if let Some(region) = constraint.region() { if let Some(region) = constraint.region() {
if let Some(surface_location) = surface_location if let Some(surface_location) = surface_location
&& let position = pointer.current_location() && let position = pointer.current_location()
&& let point = (position - surface_location.as_logical()).to_i32_round() && let point = (position - surface_location.as_logical()).to_i32_floor()
&& region.contains(point) && region.contains(point)
{ {
constraint.activate(); constraint.activate();