diff --git a/examples/simple.rs b/examples/simple.rs index 1cdbb86..412e2e3 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -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 }); } } diff --git a/src/compositor/mod.rs b/src/compositor/mod.rs index 5d6539f..94dc023 100644 --- a/src/compositor/mod.rs +++ b/src/compositor/mod.rs @@ -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 + Send + 'static> CompositorToken { /// /// 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(&self, surface: &wl_surface::WlSurface, f: F) -> Result<(), ()> - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + pub fn with_surface_tree(&self, surface: &wl_surface::WlSurface, initial: T, f: F) -> Result<(), ()> + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction { assert!(resource_is_registered::<_, CompositorHandler>(surface, self.hid), "Accessing the data of foreign surfaces is not supported."); unsafe { - SurfaceData::::map_tree(surface, f); + SurfaceData::::map_tree(surface, initial, f); } Ok(()) } diff --git a/src/compositor/tree.rs b/src/compositor/tree.rs index 8a77bd3..71d7786 100644 --- a/src/compositor/tree.rs +++ b/src/compositor/tree.rs @@ -48,6 +48,16 @@ pub enum Location { After, } +/// Possible actions to do after handling a node diring tree traversal +pub enum TraversalAction { + /// Traverse its children as well, providing them the data T + DoChildren(T), + /// Skip its children + SkipChildren, + /// Stop traversal completely + Break, +} + impl SurfaceData { fn new() -> SurfaceData { SurfaceData { @@ -275,12 +285,14 @@ impl SurfaceData { /// /// The callback returns wether the traversal should continue or not. Returning /// false will cause an early-stopping. - pub unsafe fn map_tree(root: &wl_surface::WlSurface, mut f: F) - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + pub unsafe fn map_tree(root: &wl_surface::WlSurface, initial: T, mut f: F) + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction { // helper function for recursion - unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, f: &mut F) -> bool - where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes) -> bool + unsafe fn map(surface: &wl_surface::WlSurface, root: &wl_surface::WlSurface, initial: &T, + f: &mut F) + -> bool + where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes, &T) -> TraversalAction { // stop if we met the root, so to not deadlock/inifinte loop if surface.equals(root) { @@ -290,27 +302,34 @@ impl SurfaceData { let data_mutex = SurfaceData::::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::(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::(c, root, &t, &mut f) { + break; + } } } + _ => {} } } }