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; continue;
} }
// this surface is a root of a subsurface tree that needs to be drawn // 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 { if let Some((ref contents, (w, h))) = attributes.user_data.buffer {
// there is actually something to draw ! // there is actually something to draw !
let mut x = 100;
let mut y = 100;
if let Some(ref subdata) = attributes.subsurface_attributes { if let Some(ref subdata) = attributes.subsurface_attributes {
x += subdata.x; x += subdata.x;
y += subdata.y; y += subdata.y;
} }
drawer.draw(&mut frame, contents, (w, h), (x, y), screen_dimensions); 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; mod region;
use self::region::RegionData; use self::region::RegionData;
pub use self::tree::RoleStatus; pub use self::tree::{RoleStatus, TraversalAction};
use self::tree::SurfaceData; use self::tree::SurfaceData;
use wayland_server::{Client, EventLoopHandle, Init, resource_is_registered}; 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 /// If the surface is not managed by the CompositorGlobal that provided this token, this
/// will panic (having more than one compositor is not supported). /// will panic (having more than one compositor is not supported).
pub fn with_surface_tree<F>(&self, surface: &wl_surface::WlSurface, f: F) -> Result<(), ()> 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>) -> bool where F: FnMut(&wl_surface::WlSurface, &mut SurfaceAttributes<U>, &T) -> TraversalAction<T>
{ {
assert!(resource_is_registered::<_, CompositorHandler<U, H>>(surface, self.hid), assert!(resource_is_registered::<_, CompositorHandler<U, H>>(surface, self.hid),
"Accessing the data of foreign surfaces is not supported."); "Accessing the data of foreign surfaces is not supported.");
unsafe { unsafe {
SurfaceData::<U>::map_tree(surface, f); SurfaceData::<U>::map_tree(surface, initial, f);
} }
Ok(()) Ok(())
} }

View File

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