2017-09-30 09:43:14 +00:00
|
|
|
use smithay::utils::Rectangle;
|
2017-09-28 19:57:02 +00:00
|
|
|
use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction};
|
|
|
|
use smithay::wayland::compositor::roles::Role;
|
2018-04-22 17:58:10 +00:00
|
|
|
use smithay::wayland::shell::xdg::{ToplevelSurface, XdgSurfaceRole};
|
2018-04-23 09:40:41 +00:00
|
|
|
use smithay::wayland::shell::legacy::{ShellSurface, ShellSurfaceRole};
|
2017-09-22 12:56:59 +00:00
|
|
|
use wayland_server::Resource;
|
|
|
|
use wayland_server::protocol::wl_surface;
|
|
|
|
|
2018-04-23 09:40:41 +00:00
|
|
|
pub enum Kind<U, R, SD, D> {
|
|
|
|
Xdg(ToplevelSurface<U, R, SD>),
|
|
|
|
Wl(ShellSurface<U, R, D>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<U, R, SD, D> Kind<U, R, SD, D>
|
|
|
|
where
|
|
|
|
U: 'static,
|
|
|
|
R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole<D>> + 'static,
|
|
|
|
SD: 'static,
|
|
|
|
D: 'static,
|
|
|
|
{
|
|
|
|
pub fn alive(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
Kind::Xdg(ref t) => t.alive(),
|
|
|
|
Kind::Wl(ref t) => t.alive(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn get_surface(&self) -> Option<&Resource<wl_surface::WlSurface>> {
|
|
|
|
match *self {
|
|
|
|
Kind::Xdg(ref t) => t.get_surface(),
|
|
|
|
Kind::Wl(ref t) => t.get_surface(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Window<U, R, SD, D> {
|
2017-09-22 12:56:59 +00:00
|
|
|
location: (i32, i32),
|
|
|
|
surface: Rectangle,
|
2018-04-23 09:40:41 +00:00
|
|
|
toplevel: Kind<U, R, SD, D>,
|
2017-09-22 12:56:59 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 09:40:41 +00:00
|
|
|
impl<U, R, SD, D> Window<U, R, SD, D>
|
2017-09-22 12:56:59 +00:00
|
|
|
where
|
|
|
|
U: 'static,
|
2018-04-23 09:40:41 +00:00
|
|
|
R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole<D>> + 'static,
|
2017-09-22 12:56:59 +00:00
|
|
|
SD: 'static,
|
2018-04-23 09:40:41 +00:00
|
|
|
D: 'static,
|
2017-09-22 12:56:59 +00:00
|
|
|
{
|
|
|
|
// 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-23 09:40:41 +00:00
|
|
|
pub struct WindowMap<U, R, SD, D, F> {
|
2018-04-22 09:58:39 +00:00
|
|
|
ctoken: CompositorToken<U, R>,
|
2018-04-23 09:40:41 +00:00
|
|
|
windows: Vec<Window<U, R, SD, D>>,
|
2017-09-22 12:56:59 +00:00
|
|
|
get_size: F,
|
|
|
|
}
|
|
|
|
|
2018-04-23 09:40:41 +00:00
|
|
|
impl<U, R, SD, D, F> WindowMap<U, R, SD, D, F>
|
2017-09-22 12:56:59 +00:00
|
|
|
where
|
|
|
|
F: Fn(&SurfaceAttributes<U>) -> Option<(i32, i32)>,
|
|
|
|
U: 'static,
|
2018-04-23 09:40:41 +00:00
|
|
|
R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole<D>> + 'static,
|
2017-09-22 12:56:59 +00:00
|
|
|
SD: 'static,
|
2018-04-23 09:40:41 +00:00
|
|
|
D: 'static,
|
2017-09-22 12:56:59 +00:00
|
|
|
{
|
2018-04-23 09:40:41 +00:00
|
|
|
pub fn new(ctoken: CompositorToken<U, R>, get_size: F) -> WindowMap<U, R, D, SD, F> {
|
2017-09-22 12:56:59 +00:00
|
|
|
WindowMap {
|
|
|
|
ctoken: ctoken,
|
|
|
|
windows: Vec::new(),
|
|
|
|
get_size: get_size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-23 09:40:41 +00:00
|
|
|
pub fn insert(&mut self, toplevel: Kind<U, R, SD, D>, 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-23 09:40:41 +00:00
|
|
|
Func: FnMut(&Kind<U, R, SD, D>, (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();
|
|
|
|
}
|
|
|
|
}
|