diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 2657982..d00eff5 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -92,10 +92,14 @@ impl AnvilState { let mut location = self.pointer_location.borrow_mut(); location.0 += x as f64; location.1 += y as f64; - // clamp to screen limits - // this event is never generated by winit so self.screen_size is relevant - location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64); - location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64); + + #[cfg(feature = "udev")] + { + // clamp to screen limits + // this event is never generated by winit + *location = self.clamp_coords(*location); + } + let under = self .window_map .borrow() @@ -110,8 +114,11 @@ impl AnvilState { { if self.session.is_some() { // we are started on a tty - let (ux, uy) = evt.position_transformed(self.screen_size); - (ux as f64, uy as f64) + let x = self.pointer_location.borrow().0; + let screen_size = self.current_output_size(x); + // monitor coordinates + let (ux, uy) = evt.position_transformed(screen_size); + ((ux + self.current_output_offset(x)) as f64, uy as f64) } else { // we are started in winit evt.position() @@ -128,6 +135,67 @@ impl AnvilState { self.pointer.motion((x, y), under, serial, evt.time()); } + #[cfg(feature = "udev")] + fn clamp_coords(&self, pos: (f64, f64)) -> (f64, f64) { + let output_map = self.output_map + .as_ref().unwrap(); + let outputs = output_map.borrow(); + + if outputs.len() == 0 { + return pos; + } + + let (mut x, mut y) = pos; + // max_x is the sum of the width of all outputs + let max_x = outputs + .iter() + .fold(0u32, |acc, output| acc + output.size.0); + x = x.max(0.0).min(max_x as f64); + + // max y depends on the current output + let max_y = self.current_output_size(x).1; + y = y.max(0.0).min(max_y as f64); + + (x, y) + } + + #[cfg(feature = "udev")] + fn current_output_idx(&self, x: f64) -> usize { + let output_map = self.output_map.as_ref().unwrap(); + let outputs = output_map.borrow(); + + outputs + .iter() + // map each output to their x position + .scan(0u32, |acc, output| { + let curr_x = *acc; + *acc += output.size.0; + Some(curr_x) + }) + // get an index + .enumerate() + // find the first one with a greater x + .find(|(_idx, x_pos)| *x_pos as f64 > x) + // the previous output is the one we are on + .map(|(idx, _)| idx - 1) + .unwrap_or(outputs.len() - 1) + } + #[cfg(feature = "udev")] + fn current_output_size(&self, x: f64) -> (u32, u32) { + let output_map = self.output_map.as_ref().unwrap(); + let outputs = output_map.borrow(); + outputs[self.current_output_idx(x)].size + } + #[cfg(feature = "udev")] + fn current_output_offset(&self, x: f64) -> u32 { + let output_map = self.output_map.as_ref().unwrap(); + let outputs = output_map.borrow(); + outputs + .iter() + .take(self.current_output_idx(x)) + .fold(0u32, |acc, output| acc + output.size.0) + } + fn on_pointer_button(&mut self, evt: B::PointerButtonEvent) { let serial = SCOUNTER.next_serial(); let button = match evt.button() { diff --git a/anvil/src/state.rs b/anvil/src/state.rs index 671601b..37982d5 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -27,7 +27,7 @@ use smithay::{ #[cfg(feature = "udev")] use smithay::backend::session::Session; -use crate::{buffer_utils::BufferUtils, shell::init_shell}; +use crate::{buffer_utils::BufferUtils, shell::init_shell, udev::MyOutput}; pub struct AnvilState { pub socket_name: String, @@ -43,7 +43,8 @@ pub struct AnvilState { pub keyboard: KeyboardHandle, pub pointer_location: Rc>, pub cursor_status: Arc>, - pub screen_size: (u32, u32), + #[cfg(feature = "udev")] + pub output_map: Option>>>, pub seat_name: String, #[cfg(feature = "udev")] pub session: Option, @@ -58,6 +59,8 @@ impl AnvilState { buffer_utils: BufferUtils, #[cfg(feature = "udev")] session: Option, #[cfg(not(feature = "udev"))] _session: Option<()>, + #[cfg(feature = "udev")] output_map: Option>>>, + #[cfg(not(feature = "udev"))] _output_map: Option<()>, log: slog::Logger, ) -> AnvilState { // init the wayland connection @@ -162,7 +165,8 @@ impl AnvilState { keyboard, cursor_status, pointer_location: Rc::new(RefCell::new((0.0, 0.0))), - screen_size: (1920, 1080), + #[cfg(feature = "udev")] + output_map, seat_name, #[cfg(feature = "udev")] session, diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 78a79de..4a0dff1 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -112,6 +112,8 @@ pub fn run_udev( let buffer_utils = BufferUtils::new(egl_buffer_reader.clone(), log.clone()); #[cfg(not(feature = "egl"))] let buffer_utils = BufferUtils::new(log.clone()); + + let output_map = Rc::new(RefCell::new(Vec::new())); /* * Initialize session @@ -127,6 +129,7 @@ pub fn run_udev( event_loop.handle(), buffer_utils, Some(session), + Some(output_map.clone()), log.clone(), ); @@ -138,8 +141,6 @@ pub fn run_udev( let bytes = include_bytes!("../resources/cursor2.rgba"); let udev_backend = UdevBackend::new(state.seat_name.clone(), log.clone()).map_err(|_| ())?; - let output_map = Rc::new(RefCell::new(Vec::new())); - let mut udev_handler = UdevHandlerImpl { compositor_token: state.ctoken, #[cfg(feature = "egl")] @@ -227,10 +228,10 @@ pub fn run_udev( Ok(()) } -struct MyOutput { - device_id: dev_t, - crtc: crtc::Handle, - size: (u32, u32), +pub struct MyOutput { + pub device_id: dev_t, + pub crtc: crtc::Handle, + pub size: (u32, u32), _wl: Output, global: Option>, } diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 0e0f221..be16774 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -58,6 +58,7 @@ pub fn run_winit( event_loop.handle(), buffer_utils, None, + None, log.clone(), );