From aa65f3608d53eb88707d9c5687d40785c8bee60a Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 22 Jan 2020 07:00:37 +0300 Subject: [PATCH] anvil: add a contains_point fn for Window.matching Currently implemented to be equivalent to the previous size-based check. This will allow implementing an input-region-aware check. --- anvil/src/shell.rs | 25 +++++++++++++++++++-- anvil/src/window_map.rs | 49 ++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 8e26fd9..6b75b5b 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -11,6 +11,7 @@ use smithay::{ protocol::{wl_buffer, wl_shell_surface, wl_surface}, Display, }, + utils::Rectangle, wayland::{ compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent}, data_device::DnDIconRole, @@ -36,7 +37,11 @@ define_roles!(Roles => [ CursorImage, CursorImageRole ] ); -pub type MyWindowMap = WindowMap Option<(i32, i32)>>; +pub type MyWindowMap = WindowMap< + Roles, + fn(&SurfaceAttributes) -> Option<(i32, i32)>, + fn(&SurfaceAttributes, (f64, f64)) -> bool, +>; pub type MyCompositorToken = CompositorToken; @@ -62,9 +67,10 @@ pub fn init_shell( ); // Init a window map, to track the location of our windows - let window_map = Rc::new(RefCell::new(WindowMap::<_, _>::new( + let window_map = Rc::new(RefCell::new(WindowMap::new( compositor_token, get_size as _, + contains_point as _, ))); // init the xdg_shell @@ -169,3 +175,18 @@ fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> { .map(|(x, y)| (x as i32, y as i32)) }) } + +fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool { + let (w, h) = match get_size(attrs) { + None => return false, // If the surface has no size, it can't have an input region. + Some(wh) => wh, + }; + + let rect = Rectangle { + x: 0, + y: 0, + width: w, + height: h, + }; + rect.contains((point.0 as i32, point.1 as i32)) +} diff --git a/anvil/src/window_map.rs b/anvil/src/window_map.rs index 3f7dbe3..2278d0a 100644 --- a/anvil/src/window_map.rs +++ b/anvil/src/window_map.rs @@ -50,14 +50,17 @@ where { /// Finds the topmost surface under this point if any and returns it together with the location of this /// surface. + /// + /// You need to provide a `contains_point` function which checks if the point (in surface-local + /// coordinates) is within the input region of the given `SurfaceAttributes`. fn matching( &self, point: (f64, f64), ctoken: CompositorToken, - get_size: F, + contains_point: F, ) -> Option<(wl_surface::WlSurface, (f64, f64))> where - F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>, + F: Fn(&SurfaceAttributes, (f64, f64)) -> bool, { if !self.input_bbox.contains((point.0 as i32, point.1 as i32)) { return None; @@ -69,25 +72,17 @@ where wl_surface, self.location, |wl_surface, attributes, role, &(mut x, mut y)| { - if let Some((w, h)) = get_size(attributes) { - if let Ok(subdata) = Role::::data(role) { - x += subdata.location.0; - y += subdata.location.1; - } - let my_rect = Rectangle { - x, - y, - width: w, - height: h, - }; - if my_rect.contains((point.0 as i32, point.1 as i32)) { - *found.borrow_mut() = - Some((wl_surface.clone(), (my_rect.x as f64, my_rect.y as f64))); - } - TraversalAction::DoChildren((x, y)) - } else { - TraversalAction::SkipChildren + if let Ok(subdata) = Role::::data(role) { + x += subdata.location.0; + y += subdata.location.1; } + + let surface_local_point = (point.0 - x as f64, point.1 - y as f64); + if contains_point(attributes, surface_local_point) { + *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64))); + } + + TraversalAction::DoChildren((x, y)) }, |_, _, _, _| {}, |_, _, _, _| { @@ -148,23 +143,27 @@ where } } -pub struct WindowMap { +pub struct WindowMap { ctoken: CompositorToken, windows: Vec>, /// A function returning the surface size. get_size: F, + /// A function that checks if the point is in the surface's input region. + contains_point: G, } -impl WindowMap +impl WindowMap where F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>, + G: Fn(&SurfaceAttributes, (f64, f64)) -> bool, R: Role + Role + Role + 'static, { - pub fn new(ctoken: CompositorToken, get_size: F) -> WindowMap { + pub fn new(ctoken: CompositorToken, get_size: F, contains_point: G) -> Self { WindowMap { ctoken, windows: Vec::new(), get_size, + contains_point, } } @@ -185,7 +184,7 @@ where pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> { for w in &self.windows { - if let Some(surface) = w.matching(point, self.ctoken, &self.get_size) { + if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) { return Some(surface); } } @@ -198,7 +197,7 @@ where ) -> Option<(wl_surface::WlSurface, (f64, f64))> { let mut found = None; for (i, w) in self.windows.iter().enumerate() { - if let Some(surface) = w.matching(point, self.ctoken, &self.get_size) { + if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) { found = Some((i, surface)); break; }