compositor: TraversalAction for tree traversal

This commit is contained in:
Victor Berger 2017-06-13 17:38:25 +02:00
parent 19634f30ed
commit a487c5963a
3 changed files with 45 additions and 23 deletions

View File

@ -147,18 +147,21 @@ fn main() {
continue;
}
// this surface is a root of a subsurface tree that needs to be drawn
compositor_token.with_surface_tree(surface, |surface, attributes| {
compositor_token.with_surface_tree(surface, (100, 100), |surface,
attributes,
&(mut x, mut y)| {
if let Some((ref contents, (w, h))) = attributes.user_data.buffer {
// there is actually something to draw !
let mut x = 100;
let mut y = 100;
if let Some(ref subdata) = attributes.subsurface_attributes {
x += subdata.x;
y += subdata.y;
}
drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions);
TraversalAction::DoChildren((x, y))
} else {
// we are not display, so our children are neither
TraversalAction::SkipChildren
}
true
});
}
}

View File

@ -97,7 +97,7 @@ mod tree;
mod region;
use self::region::RegionData;
pub use self::tree::RoleStatus;
pub use self::tree::{RoleStatus, TraversalAction};
use self::tree::SurfaceData;
use wayland_server::{Client, EventLoopHandle, Init, resource_is_registered};
@ -302,13 +302,13 @@ impl<U: Send + 'static, H: Handler<U> + Send + 'static> CompositorToken<U, H> {
///
/// If the surface is not managed by the CompositorGlobal that provided this token, this
/// will panic (having more than one compositor is not supported).
pub fn with_surface_tree<F>(&self, surface: &wl_surface::WlSurface, f: F) -> Result<(), ()>
where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>) -> bool
pub fn with_surface_tree<F, T>(&self, surface: &wl_surface::WlSurface, initial: T, f: F) -> Result<(), ()>
where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>, &T) -> TraversalAction<T>
{
assert!(resource_is_registered::<_, CompositorHandler<U, H>>(surface, self.hid),
"Accessing the data of foreign surfaces is not supported.");
unsafe {
SurfaceData::<U>::map_tree(surface, f);
SurfaceData::<U>::map_tree(surface, initial, f);
}
Ok(())
}

View File

@ -48,6 +48,16 @@ pub enum Location {
After,
}
/// Possible actions to do after handling a node diring tree traversal
pub enum TraversalAction<T> {
/// Traverse its children as well, providing them the data T
DoChildren(T),
/// Skip its children
SkipChildren,
/// Stop traversal completely
Break,
}
impl<U: Default> SurfaceData<U> {
fn new() -> SurfaceData<U> {
SurfaceData {
@ -275,12 +285,14 @@ impl<U> SurfaceData<U> {
///
/// The callback returns wether the traversal should continue or not. Returning
/// false will cause an early-stopping.
pub unsafe fn map_tree<F>(root: &wl_surface::WlSurface, mut f: F)
where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>) -> bool
pub unsafe fn map_tree<F, T>(root: &wl_surface::WlSurface, initial: T, mut f: F)
where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>, &T) -> TraversalAction<T>
{
// helper function for recursion
unsafe fn map<U, F>(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, f: &mut F) -> bool
where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>) -> bool
unsafe fn map<U, F, T>(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, initial: &T,
f: &mut F)
-> bool
where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>, &T) -> TraversalAction<T>
{
// stop if we met the root, so to not deadlock/inifinte loop
if surface.equals(root) {
@ -290,27 +302,34 @@ impl<U> SurfaceData<U> {
let data_mutex = SurfaceData::<U>::get_data(surface);
let mut data_guard = data_mutex.lock().unwrap();
// call the callback on ourselves
if f(surface, &mut data_guard.attributes) {
// loop over children
for c in &data_guard.children {
if !map(c, root, f) {
return false;
match f(surface, &mut data_guard.attributes, initial) {
TraversalAction::DoChildren(t) => {
// loop over children
for c in &data_guard.children {
if !map(c, root, &t, f) {
return false;
}
}
true
}
TraversalAction::SkipChildren => true,
TraversalAction::Break => false,
}
true
}
let data_mutex = Self::get_data(root);
let mut data_guard = data_mutex.lock().unwrap();
// call the callback on ourselves
if f(root, &mut data_guard.attributes) {
// loop over children
for c in &data_guard.children {
if !map::<U, _>(c, root, &mut f) {
break;
match f(root, &mut data_guard.attributes, &initial) {
TraversalAction::DoChildren(t) => {
// loop over children
for c in &data_guard.children {
if !map::<U, _, _>(c, root, &t, &mut f) {
break;
}
}
}
_ => {}
}
}
}