diff --git a/src/input/mod.rs b/src/input/mod.rs index 08bf703b..282daab7 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -703,11 +703,11 @@ impl State { position.x = position.x.clamp( output_geometry.loc.x as f64, - (output_geometry.loc.x + output_geometry.size.w) as f64, + ((output_geometry.loc.x + output_geometry.size.w) as f64).next_lower(), // FIXME: Replace with f64::next_down when stable ); position.y = position.y.clamp( output_geometry.loc.y as f64, - (output_geometry.loc.y + output_geometry.size.h) as f64, + ((output_geometry.loc.y + output_geometry.size.h) as f64).next_lower(), // FIXME: Replace with f64::next_down when stable ); // If confined, don't move pointer if it would go outside surface or region @@ -2337,3 +2337,32 @@ fn mapped_output_for_device<'a, D: Device + 'static>( }; map_to_output.or_else(|| state.shell.builtin_output()) } + +// FIXME: When f64::next_down reaches stable rust, use that instead +trait NextDown { + fn next_lower(self) -> Self; +} + +impl NextDown for f64 { + fn next_lower(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const NEG_TINY_BITS: u64 = 0x8000_0000_0000_0001; // Smallest (in magnitude) negative f64. + const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + NEG_TINY_BITS + } else if bits == abs { + bits - 1 + } else { + bits + 1 + }; + Self::from_bits(next_bits) + } +}