smithay/examples/helpers/window_map.rs

202 lines
6.5 KiB
Rust
Raw Normal View History

2017-09-30 09:43:14 +00:00
use smithay::utils::Rectangle;
use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction};
use smithay::wayland::compositor::roles::Role;
2018-04-22 09:58:39 +00:00
use smithay::wayland::shell::xdg::{ShellSurfaceRole, ToplevelSurface};
2017-09-22 12:56:59 +00:00
use wayland_server::Resource;
use wayland_server::protocol::wl_surface;
2018-04-22 09:58:39 +00:00
struct Window<U, R, SD> {
2017-09-22 12:56:59 +00:00
location: (i32, i32),
surface: Rectangle,
2018-04-22 09:58:39 +00:00
toplevel: ToplevelSurface<U, R, SD>,
2017-09-22 12:56:59 +00:00
}
2018-04-22 09:58:39 +00:00
impl<U, R, SD> Window<U, R, SD>
2017-09-22 12:56:59 +00:00
where
U: 'static,
R: Role<SubsurfaceRole> + Role<ShellSurfaceRole> + 'static,
SD: 'static,
{
// Find the topmost surface under this point if any and the location of this point in the surface
2018-01-07 21:30:38 +00:00
fn matching<F>(
2018-04-22 09:58:39 +00:00
&self,
point: (f64, f64),
ctoken: CompositorToken<U, R>,
get_size: F,
) -> Option<(Resource<wl_surface::WlSurface>, (f64, f64))>
2017-09-22 12:56:59 +00:00
where
F: Fn(&SurfaceAttributes<U>) -> Option<(i32, i32)>,
{
if !self.surface.contains((point.0 as i32, point.1 as i32)) {
return None;
}
// need to check more carefully
let mut found = None;
if let Some(wl_surface) = self.toplevel.get_surface() {
2017-09-22 13:00:29 +00:00
let _ = ctoken.with_surface_tree_downward(
2017-09-22 12:56:59 +00:00
wl_surface,
self.location,
2018-01-07 21:30:38 +00:00
|wl_surface, attributes, role, &(mut x, mut y)| {
if let Some((w, h)) = get_size(attributes) {
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
2018-04-22 09:58:39 +00:00
x += subdata.location.0;
y += subdata.location.1;
2018-01-07 21:30:38 +00:00
}
let my_rect = Rectangle {
x,
y,
width: w,
height: h,
};
if my_rect.contains((point.0 as i32, point.1 as i32)) {
2018-04-22 09:58:39 +00:00
found = Some((
wl_surface.clone(),
(point.0 - my_rect.x as f64, point.1 - my_rect.y as f64),
));
2018-01-07 21:30:38 +00:00
TraversalAction::Break
} else {
TraversalAction::DoChildren((x, y))
}
2017-09-22 12:56:59 +00:00
} else {
2018-01-07 21:30:38 +00:00
TraversalAction::SkipChildren
2017-09-22 12:56:59 +00:00
}
},
);
}
found
}
2018-04-22 09:58:39 +00:00
fn self_update<F>(&mut self, ctoken: CompositorToken<U, R>, get_size: F)
2017-09-22 12:56:59 +00:00
where
F: Fn(&SurfaceAttributes<U>) -> Option<(i32, i32)>,
{
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() {
2017-09-22 13:00:29 +00:00
let _ = ctoken.with_surface_tree_downward(
2017-09-22 12:56:59 +00:00
wl_surface,
(base_x, base_y),
|_, attributes, role, &(mut x, mut y)| {
if let Some((w, h)) = get_size(attributes) {
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
2018-04-22 09:58:39 +00:00
x += subdata.location.0;
y += subdata.location.1;
2017-09-22 12:56:59 +00:00
}
// update the bounding box
if x < min_x {
min_x = x;
}
if y < min_y {
min_y = y;
}
if x + w > max_x {
max_x = x + w;
}
if y + h > max_y {
max_y = y + w;
}
TraversalAction::DoChildren((x, y))
} else {
TraversalAction::SkipChildren
}
},
);
}
self.surface = Rectangle {
x: min_x,
y: min_y,
width: max_x - min_x,
height: max_y - min_y,
};
}
}
2018-04-22 09:58:39 +00:00
pub struct WindowMap<U, R, SD, F> {
ctoken: CompositorToken<U, R>,
windows: Vec<Window<U, R, SD>>,
2017-09-22 12:56:59 +00:00
get_size: F,
}
2018-04-22 09:58:39 +00:00
impl<U, R, SD, F> WindowMap<U, R, SD, F>
2017-09-22 12:56:59 +00:00
where
F: Fn(&SurfaceAttributes<U>) -> Option<(i32, i32)>,
U: 'static,
R: Role<SubsurfaceRole> + Role<ShellSurfaceRole> + 'static,
SD: 'static,
{
2018-04-22 09:58:39 +00:00
pub fn new(ctoken: CompositorToken<U, R>, get_size: F) -> WindowMap<U, R, SD, F> {
2017-09-22 12:56:59 +00:00
WindowMap {
ctoken: ctoken,
windows: Vec::new(),
get_size: get_size,
}
}
2018-04-22 09:58:39 +00:00
pub fn insert(&mut self, toplevel: ToplevelSurface<U, R, SD>, location: (i32, i32)) {
2017-09-22 12:56:59 +00:00
let mut window = Window {
location: location,
surface: Rectangle {
x: 0,
y: 0,
width: 0,
height: 0,
},
toplevel: toplevel,
};
window.self_update(self.ctoken, &self.get_size);
self.windows.insert(0, window);
}
2018-04-22 09:58:39 +00:00
pub fn get_surface_under(
&self,
point: (f64, f64),
) -> Option<(Resource<wl_surface::WlSurface>, (f64, f64))> {
2017-09-22 12:56:59 +00:00
for w in &self.windows {
if let Some(surface) = w.matching(point, self.ctoken, &self.get_size) {
return Some(surface);
}
}
None
}
2018-01-07 21:30:38 +00:00
pub fn get_surface_and_bring_to_top(
2018-04-22 09:58:39 +00:00
&mut self,
point: (f64, f64),
) -> Option<(Resource<wl_surface::WlSurface>, (f64, f64))> {
2017-09-22 12:56:59 +00:00
let mut found = None;
for (i, w) in self.windows.iter().enumerate() {
if let Some(surface) = w.matching(point, self.ctoken, &self.get_size) {
found = Some((i, surface));
break;
}
}
if let Some((i, surface)) = found {
let winner = self.windows.remove(i);
self.windows.insert(0, winner);
Some(surface)
} else {
None
}
}
pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
where
2018-04-22 09:58:39 +00:00
Func: FnMut(&ToplevelSurface<U, R, SD>, (i32, i32)),
2017-09-22 12:56:59 +00:00
{
for w in self.windows.iter().rev() {
f(&w.toplevel, w.location)
}
}
pub fn refresh(&mut self) {
self.windows.retain(|w| w.toplevel.alive());
for w in self.windows.iter_mut() {
w.self_update(self.ctoken, &self.get_size);
}
}
pub fn clear(&mut self) {
self.windows.clear();
}
}