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:
parent
533a006bd1
commit
ebb3a05502
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue