From ebb3a055020066fb74389567b9ffcd1dd1166059 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Mon, 3 Feb 2020 15:55:48 +0300 Subject: [PATCH] anvil: make get_size and contains_point methods This removes the need to store them as generic members, and will ease the addition of new methods. --- anvil/src/shell.rs | 87 ++++++++++++++++++----------------------- anvil/src/window_map.rs | 57 +++++++++++---------------- 2 files changed, 62 insertions(+), 82 deletions(-) diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 26a7378..9737173 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -41,11 +41,7 @@ define_roles!(Roles => [ CursorImage, CursorImageRole ] ); -pub type MyWindowMap = WindowMap< - Roles, - fn(&SurfaceAttributes) -> Option<(i32, i32)>, - fn(&SurfaceAttributes, (f64, f64)) -> bool, ->; +pub type MyWindowMap = WindowMap; pub type MyCompositorToken = CompositorToken; @@ -122,11 +118,7 @@ pub fn init_shell( ); // Init a window map, to track the location of our windows - let window_map = Rc::new(RefCell::new(WindowMap::new( - compositor_token, - get_size as _, - contains_point as _, - ))); + let window_map = Rc::new(RefCell::new(WindowMap::new(compositor_token))); // init the xdg_shell let xdg_window_map = window_map.clone(); @@ -281,6 +273,43 @@ pub struct SurfaceData { pub input_region: Option, } +impl SurfaceData { + /// Returns the size of the surface. + pub fn size(&self) -> Option<(i32, i32)> { + self.dimensions + } + + /// Checks if the surface's input region contains the point. + pub fn contains_point(&self, point: (f64, f64)) -> bool { + let (w, h) = match self.size() { + 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, + }; + + let point = (point.0 as i32, point.1 as i32); + + // The input region is always within the surface itself, so if the surface itself doesn't contain the + // point we can return false. + if !rect.contains(point) { + return false; + } + + // If there's no input region, we're done. + if self.input_region.is_none() { + return true; + } + + self.input_region.as_ref().unwrap().contains(point) + } +} + fn surface_commit( surface: &wl_surface::WlSurface, token: CompositorToken, @@ -316,41 +345,3 @@ fn surface_commit( } }); } - -fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> { - attrs - .user_data - .get::() - .and_then(|data| data.dimensions) -} - -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, - }; - - let point = (point.0 as i32, point.1 as i32); - - // The input region is always within the surface itself, so if the surface itself doesn't contain the - // point we can return false. - if !rect.contains(point) { - return false; - } - - let input_region = &attrs.user_data.get::().unwrap().input_region; - - // If there's no input region, we're done. - if input_region.is_none() { - return true; - } - - input_region.as_ref().unwrap().contains(point) -} diff --git a/anvil/src/window_map.rs b/anvil/src/window_map.rs index 3498293..8fb1cdb 100644 --- a/anvil/src/window_map.rs +++ b/anvil/src/window_map.rs @@ -4,7 +4,7 @@ use smithay::{ reexports::wayland_server::protocol::wl_surface, utils::Rectangle, wayland::{ - compositor::{roles::Role, CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction}, + compositor::{roles::Role, CompositorToken, SubsurfaceRole, TraversalAction}, shell::{ legacy::{ShellSurface, ShellSurfaceRole}, xdg::{ToplevelSurface, XdgSurfaceRole}, @@ -12,6 +12,8 @@ use smithay::{ }, }; +use crate::shell::SurfaceData; + pub enum Kind { Xdg(ToplevelSurface), Wl(ShellSurface), @@ -60,18 +62,11 @@ 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( + fn matching( &self, point: (f64, f64), ctoken: CompositorToken, - contains_point: F, - ) -> Option<(wl_surface::WlSurface, (f64, f64))> - where - F: Fn(&SurfaceAttributes, (f64, f64)) -> bool, - { + ) -> Option<(wl_surface::WlSurface, (f64, f64))> { if !self.bbox.contains((point.0 as i32, point.1 as i32)) { return None; } @@ -82,13 +77,18 @@ where wl_surface, self.location, |wl_surface, attributes, role, &(mut x, mut y)| { + let data = attributes.user_data.get::(); + 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) { + if data + .map(|data| data.contains_point(surface_local_point)) + .unwrap_or(false) + { *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64))); } @@ -104,10 +104,7 @@ where found.into_inner() } - fn self_update(&mut self, ctoken: CompositorToken, get_size: F) - where - F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>, - { + fn self_update(&mut self, ctoken: CompositorToken) { let (base_x, base_y) = self.location; let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y); if let Some(wl_surface) = self.toplevel.get_surface() { @@ -115,9 +112,9 @@ where wl_surface, (base_x, base_y), |_, attributes, role, &(mut x, mut y)| { - // The input region is intersected with the surface size, so the surface size - // can serve as an approximation for the input bounding box. - if let Some((w, h)) = get_size(attributes) { + let data = attributes.user_data.get::(); + + if let Some((w, h)) = data.and_then(SurfaceData::size) { if let Ok(subdata) = Role::::data(role) { x += subdata.location.0; y += subdata.location.1; @@ -149,27 +146,19 @@ 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, contains_point: G) -> Self { + pub fn new(ctoken: CompositorToken) -> Self { WindowMap { ctoken, windows: Vec::new(), - get_size, - contains_point, } } @@ -179,13 +168,13 @@ where bbox: Rectangle::default(), toplevel, }; - window.self_update(self.ctoken, &self.get_size); + window.self_update(self.ctoken); self.windows.insert(0, window); } 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.contains_point) { + if let Some(surface) = w.matching(point, self.ctoken) { return Some(surface); } } @@ -198,7 +187,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.contains_point) { + if let Some(surface) = w.matching(point, self.ctoken) { found = Some((i, surface)); break; } @@ -224,7 +213,7 @@ where pub fn refresh(&mut self) { self.windows.retain(|w| w.toplevel.alive()); for w in &mut self.windows { - w.self_update(self.ctoken, &self.get_size); + w.self_update(self.ctoken); } } @@ -244,7 +233,7 @@ where pub fn set_location(&mut self, toplevel: &Kind, location: (i32, i32)) { if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) { w.location = location; - w.self_update(self.ctoken, &self.get_size); + w.self_update(self.ctoken); } } }