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.
This commit is contained in:
Ivan Molodetskikh 2020-02-03 15:55:48 +03:00
parent 533a006bd1
commit ebb3a05502
No known key found for this signature in database
GPG Key ID: 02CE38DA47E9D691
2 changed files with 62 additions and 82 deletions

View File

@ -41,11 +41,7 @@ define_roles!(Roles =>
[ CursorImage, CursorImageRole ] [ CursorImage, CursorImageRole ]
); );
pub type MyWindowMap = WindowMap< pub type MyWindowMap = WindowMap<Roles>;
Roles,
fn(&SurfaceAttributes) -> Option<(i32, i32)>,
fn(&SurfaceAttributes, (f64, f64)) -> bool,
>;
pub type MyCompositorToken = CompositorToken<Roles>; pub type MyCompositorToken = CompositorToken<Roles>;
@ -122,11 +118,7 @@ pub fn init_shell(
); );
// Init a window map, to track the location of our windows // 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)));
compositor_token,
get_size as _,
contains_point as _,
)));
// init the xdg_shell // init the xdg_shell
let xdg_window_map = window_map.clone(); let xdg_window_map = window_map.clone();
@ -281,6 +273,43 @@ pub struct SurfaceData {
pub input_region: Option<RegionAttributes>, pub input_region: Option<RegionAttributes>,
} }
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( fn surface_commit(
surface: &wl_surface::WlSurface, surface: &wl_surface::WlSurface,
token: CompositorToken<Roles>, token: CompositorToken<Roles>,
@ -316,41 +345,3 @@ fn surface_commit(
} }
}); });
} }
fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> {
attrs
.user_data
.get::<SurfaceData>()
.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::<SurfaceData>().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)
}

View File

@ -4,7 +4,7 @@ use smithay::{
reexports::wayland_server::protocol::wl_surface, reexports::wayland_server::protocol::wl_surface,
utils::Rectangle, utils::Rectangle,
wayland::{ wayland::{
compositor::{roles::Role, CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction}, compositor::{roles::Role, CompositorToken, SubsurfaceRole, TraversalAction},
shell::{ shell::{
legacy::{ShellSurface, ShellSurfaceRole}, legacy::{ShellSurface, ShellSurfaceRole},
xdg::{ToplevelSurface, XdgSurfaceRole}, xdg::{ToplevelSurface, XdgSurfaceRole},
@ -12,6 +12,8 @@ use smithay::{
}, },
}; };
use crate::shell::SurfaceData;
pub enum Kind<R> { pub enum Kind<R> {
Xdg(ToplevelSurface<R>), Xdg(ToplevelSurface<R>),
Wl(ShellSurface<R>), Wl(ShellSurface<R>),
@ -60,18 +62,11 @@ where
{ {
/// Finds the topmost surface under this point if any and returns it together with the location of this /// Finds the topmost surface under this point if any and returns it together with the location of this
/// surface. /// surface.
/// fn matching(
/// 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<F>(
&self, &self,
point: (f64, f64), point: (f64, f64),
ctoken: CompositorToken<R>, ctoken: CompositorToken<R>,
contains_point: F, ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
) -> Option<(wl_surface::WlSurface, (f64, f64))>
where
F: Fn(&SurfaceAttributes, (f64, f64)) -> bool,
{
if !self.bbox.contains((point.0 as i32, point.1 as i32)) { if !self.bbox.contains((point.0 as i32, point.1 as i32)) {
return None; return None;
} }
@ -82,13 +77,18 @@ where
wl_surface, wl_surface,
self.location, self.location,
|wl_surface, attributes, role, &(mut x, mut y)| { |wl_surface, attributes, role, &(mut x, mut y)| {
let data = attributes.user_data.get::<SurfaceData>();
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) { if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
x += subdata.location.0; x += subdata.location.0;
y += subdata.location.1; y += subdata.location.1;
} }
let surface_local_point = (point.0 - x as f64, point.1 - y as f64); 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))); *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
} }
@ -104,10 +104,7 @@ where
found.into_inner() found.into_inner()
} }
fn self_update<F>(&mut self, ctoken: CompositorToken<R>, get_size: F) fn self_update(&mut self, ctoken: CompositorToken<R>) {
where
F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>,
{
let (base_x, base_y) = self.location; 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); 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() { if let Some(wl_surface) = self.toplevel.get_surface() {
@ -115,9 +112,9 @@ where
wl_surface, wl_surface,
(base_x, base_y), (base_x, base_y),
|_, attributes, role, &(mut x, mut y)| { |_, attributes, role, &(mut x, mut y)| {
// The input region is intersected with the surface size, so the surface size let data = attributes.user_data.get::<SurfaceData>();
// can serve as an approximation for the input bounding box.
if let Some((w, h)) = get_size(attributes) { if let Some((w, h)) = data.and_then(SurfaceData::size) {
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) { if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
x += subdata.location.0; x += subdata.location.0;
y += subdata.location.1; y += subdata.location.1;
@ -149,27 +146,19 @@ where
} }
} }
pub struct WindowMap<R, F, G> { pub struct WindowMap<R> {
ctoken: CompositorToken<R>, ctoken: CompositorToken<R>,
windows: Vec<Window<R>>, windows: Vec<Window<R>>,
/// 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<R, F, G> WindowMap<R, F, G> impl<R> WindowMap<R>
where where
F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>,
G: Fn(&SurfaceAttributes, (f64, f64)) -> bool,
R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static, R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{ {
pub fn new(ctoken: CompositorToken<R>, get_size: F, contains_point: G) -> Self { pub fn new(ctoken: CompositorToken<R>) -> Self {
WindowMap { WindowMap {
ctoken, ctoken,
windows: Vec::new(), windows: Vec::new(),
get_size,
contains_point,
} }
} }
@ -179,13 +168,13 @@ where
bbox: Rectangle::default(), bbox: Rectangle::default(),
toplevel, toplevel,
}; };
window.self_update(self.ctoken, &self.get_size); window.self_update(self.ctoken);
self.windows.insert(0, window); self.windows.insert(0, window);
} }
pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> { pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
for w in &self.windows { 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); return Some(surface);
} }
} }
@ -198,7 +187,7 @@ where
) -> Option<(wl_surface::WlSurface, (f64, f64))> { ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
let mut found = None; let mut found = None;
for (i, w) in self.windows.iter().enumerate() { 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)); found = Some((i, surface));
break; break;
} }
@ -224,7 +213,7 @@ where
pub fn refresh(&mut self) { pub fn refresh(&mut self) {
self.windows.retain(|w| w.toplevel.alive()); self.windows.retain(|w| w.toplevel.alive());
for w in &mut self.windows { 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<R>, location: (i32, i32)) { pub fn set_location(&mut self, toplevel: &Kind<R>, location: (i32, i32)) {
if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) { if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
w.location = location; w.location = location;
w.self_update(self.ctoken, &self.get_size); w.self_update(self.ctoken);
} }
} }
} }