From 934183ef003714f4d8dedeba55396c76ec8d5e4c Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Tue, 5 Sep 2023 18:02:05 +0400 Subject: input: Clip pointer movement smarter --- src/input.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/src/input.rs b/src/input.rs index 3dc589c0..ec3f9afd 100644 --- a/src/input.rs +++ b/src/input.rs @@ -294,36 +294,73 @@ impl State { } } InputEvent::PointerMotion { event, .. } => { + // We need an output to be able to move the pointer. + if self.niri.global_space.outputs().next().is_none() { + return; + } + let serial = SERIAL_COUNTER.next_serial(); let pointer = self.niri.seat.get_pointer().unwrap(); - let mut pos = pointer.current_location(); - - pos += event.delta(); - - let mut min_x = i32::MAX; - let mut min_y = i32::MAX; - let mut max_x = 0; - let mut max_y = 0; - for output in self.niri.global_space.outputs() { - // FIXME: smarter clamping. - let geom = self.niri.global_space.output_geometry(output).unwrap(); - min_x = min_x.min(geom.loc.x); - min_y = min_y.min(geom.loc.y); - max_x = max_x.max(geom.loc.x + geom.size.w); - max_y = max_y.max(geom.loc.y + geom.size.h); - } - pos.x = pos.x.clamp(min_x as f64, max_x as f64); - pos.y = pos.y.clamp(min_y as f64, max_y as f64); + let pos = pointer.current_location(); + + // We have an output, so we can compute the new location and focus. + let mut new_pos = pos + event.delta(); + + if self + .niri + .global_space + .output_under(new_pos) + .next() + .is_none() + { + // We ended up outside the outputs and need to clip the movement. + if let Some(output) = self.niri.global_space.output_under(pos).next() { + // The pointer was previously on some output. Clip the movement against its + // boundaries. + let geom = self.niri.global_space.output_geometry(output).unwrap(); + new_pos.x = new_pos + .x + .clamp(geom.loc.x as f64, (geom.loc.x + geom.size.w - 1) as f64); + new_pos.y = new_pos + .y + .clamp(geom.loc.y as f64, (geom.loc.y + geom.size.h - 1) as f64); + } else { + // The pointer was not on any output in the first place. Find one for it. + // Start by clamping the X coordinate. + let mut min_x = i32::MAX; + let mut max_x = 0; + for output in self.niri.global_space.outputs() { + let geom = self.niri.global_space.output_geometry(output).unwrap(); + min_x = min_x.min(geom.loc.x); + max_x = max_x.max(geom.loc.x + geom.size.w); + } + + new_pos.x = new_pos.x.clamp(min_x as f64, (max_x - 1) as f64); + + // Now clamp the Y coordinate. Assume every X from min to max has some + // output. + let geom = self + .niri + .global_space + .outputs() + .map(|output| self.niri.global_space.output_geometry(output).unwrap()) + .find(|geom| geom.contains((new_pos.x as i32, geom.loc.y))) + .unwrap(); + new_pos.y = new_pos + .y + .clamp(geom.loc.y as f64, (geom.loc.y + geom.size.h - 1) as f64); + } + } - let under = self.niri.surface_under_and_global_space(pos); + let under = self.niri.surface_under_and_global_space(new_pos); pointer.motion( self, under.clone(), &MotionEvent { - location: pos, + location: new_pos, serial, time: event.time_msec(), }, -- cgit