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.
This commit is contained in:
Ivan Molodetskikh 2020-01-22 07:00:37 +03:00
parent 9bfa85efc9
commit aa65f3608d
No known key found for this signature in database
GPG Key ID: 02CE38DA47E9D691
2 changed files with 47 additions and 27 deletions

View File

@ -11,6 +11,7 @@ use smithay::{
protocol::{wl_buffer, wl_shell_surface, wl_surface}, protocol::{wl_buffer, wl_shell_surface, wl_surface},
Display, Display,
}, },
utils::Rectangle,
wayland::{ wayland::{
compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent}, compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent},
data_device::DnDIconRole, data_device::DnDIconRole,
@ -36,7 +37,11 @@ define_roles!(Roles =>
[ CursorImage, CursorImageRole ] [ CursorImage, CursorImageRole ]
); );
pub type MyWindowMap = WindowMap<Roles, fn(&SurfaceAttributes) -> Option<(i32, i32)>>; pub type MyWindowMap = WindowMap<
Roles,
fn(&SurfaceAttributes) -> Option<(i32, i32)>,
fn(&SurfaceAttributes, (f64, f64)) -> bool,
>;
pub type MyCompositorToken = CompositorToken<Roles>; pub type MyCompositorToken = CompositorToken<Roles>;
@ -62,9 +67,10 @@ 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 _, get_size as _,
contains_point as _,
))); )));
// init the xdg_shell // 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)) .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))
}

View File

@ -50,14 +50,17 @@ 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.
///
/// 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>( fn matching<F>(
&self, &self,
point: (f64, f64), point: (f64, f64),
ctoken: CompositorToken<R>, ctoken: CompositorToken<R>,
get_size: F, contains_point: F,
) -> Option<(wl_surface::WlSurface, (f64, f64))> ) -> Option<(wl_surface::WlSurface, (f64, f64))>
where 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)) { if !self.input_bbox.contains((point.0 as i32, point.1 as i32)) {
return None; return None;
@ -69,25 +72,17 @@ 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)| {
if let Some((w, h)) = get_size(attributes) {
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 my_rect = Rectangle {
x, let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
y, if contains_point(attributes, surface_local_point) {
width: w, *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
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)) TraversalAction::DoChildren((x, y))
} else {
TraversalAction::SkipChildren
}
}, },
|_, _, _, _| {}, |_, _, _, _| {},
|_, _, _, _| { |_, _, _, _| {
@ -148,23 +143,27 @@ where
} }
} }
pub struct WindowMap<R, F> { pub struct WindowMap<R, F, G> {
ctoken: CompositorToken<R>, ctoken: CompositorToken<R>,
windows: Vec<Window<R>>, windows: Vec<Window<R>>,
/// A function returning the surface size. /// A function returning the surface size.
get_size: F, get_size: F,
/// A function that checks if the point is in the surface's input region.
contains_point: G,
} }
impl<R, F> WindowMap<R, F> impl<R, F, G> WindowMap<R, F, G>
where where
F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>, 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) -> WindowMap<R, F> { pub fn new(ctoken: CompositorToken<R>, get_size: F, contains_point: G) -> Self {
WindowMap { WindowMap {
ctoken, ctoken,
windows: Vec::new(), windows: Vec::new(),
get_size, get_size,
contains_point,
} }
} }
@ -185,7 +184,7 @@ where
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.get_size) { if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) {
return Some(surface); return Some(surface);
} }
} }
@ -198,7 +197,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.get_size) { if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) {
found = Some((i, surface)); found = Some((i, surface));
break; break;
} }