wayland.compositor: rework the subsurface tree
Rework the subsurface tree by: - forbidding subsurface loops - storing the relative depth of a parent to its children, finally respecting the wl_subsurface specification. closes #23
This commit is contained in:
parent
5768e1fd87
commit
9f9e6d4329
|
@ -294,9 +294,11 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
compositor_token: MyCompositorToken,
|
compositor_token: MyCompositorToken,
|
||||||
screen_dimensions: (u32, u32),
|
screen_dimensions: (u32, u32),
|
||||||
) {
|
) {
|
||||||
compositor_token
|
compositor_token.with_surface_tree_upward(
|
||||||
.with_surface_tree_upward(root, location, |_surface, attributes, role, &(mut x, mut y)| {
|
root,
|
||||||
// there is actually something to draw !
|
location,
|
||||||
|
|_surface, attributes, role, &(mut x, mut y)| {
|
||||||
|
// Pull a new buffer if available
|
||||||
if attributes.user_data.texture.is_none() {
|
if attributes.user_data.texture.is_none() {
|
||||||
if let Some(buffer) = attributes.user_data.buffer.take() {
|
if let Some(buffer) = attributes.user_data.buffer.take() {
|
||||||
if let Ok(m) = self.texture_from_buffer(buffer.clone()) {
|
if let Ok(m) = self.texture_from_buffer(buffer.clone()) {
|
||||||
|
@ -307,7 +309,23 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
buffer.release();
|
buffer.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Now, should we be drawn ?
|
||||||
|
if attributes.user_data.texture.is_some() {
|
||||||
|
// if yes, also process the children
|
||||||
|
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
|
||||||
|
x += subdata.location.0;
|
||||||
|
y += subdata.location.1;
|
||||||
|
}
|
||||||
|
TraversalAction::DoChildren((x, y))
|
||||||
|
} else {
|
||||||
|
// we are not display, so our children are neither
|
||||||
|
TraversalAction::SkipChildren
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_surface, attributes, role, &(mut x, mut y)| {
|
||||||
if let Some(ref metadata) = attributes.user_data.texture {
|
if let Some(ref metadata) = attributes.user_data.texture {
|
||||||
|
// we need to re-extract the subsurface offset, as the previous closure
|
||||||
|
// only passes it to our children
|
||||||
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
|
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
|
||||||
x += subdata.location.0;
|
x += subdata.location.0;
|
||||||
y += subdata.location.1;
|
y += subdata.location.1;
|
||||||
|
@ -332,13 +350,10 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
TraversalAction::DoChildren((x, y))
|
|
||||||
} else {
|
|
||||||
// we are not display, so our children are neither
|
|
||||||
TraversalAction::SkipChildren
|
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.unwrap();
|
|_, _, _, _| true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_windows(
|
pub fn draw_windows(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
reexports::wayland_server::protocol::wl_surface,
|
reexports::wayland_server::protocol::wl_surface,
|
||||||
utils::Rectangle,
|
utils::Rectangle,
|
||||||
|
@ -63,7 +65,7 @@ where
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// need to check more carefully
|
// need to check more carefully
|
||||||
let mut found = None;
|
let found = RefCell::new(None);
|
||||||
if let Some(wl_surface) = self.toplevel.get_surface() {
|
if let Some(wl_surface) = self.toplevel.get_surface() {
|
||||||
let _ = ctoken.with_surface_tree_downward(
|
let _ = ctoken.with_surface_tree_downward(
|
||||||
wl_surface,
|
wl_surface,
|
||||||
|
@ -81,18 +83,22 @@ where
|
||||||
height: h,
|
height: h,
|
||||||
};
|
};
|
||||||
if my_rect.contains((point.0 as i32, point.1 as i32)) {
|
if my_rect.contains((point.0 as i32, point.1 as i32)) {
|
||||||
found = Some((wl_surface.clone(), (my_rect.x as f64, my_rect.y as f64)));
|
*found.borrow_mut() =
|
||||||
TraversalAction::Break
|
Some((wl_surface.clone(), (my_rect.x as f64, my_rect.y as f64)));
|
||||||
} else {
|
|
||||||
TraversalAction::DoChildren((x, y))
|
|
||||||
}
|
}
|
||||||
|
TraversalAction::DoChildren((x, y))
|
||||||
} else {
|
} else {
|
||||||
TraversalAction::SkipChildren
|
TraversalAction::SkipChildren
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|_, _, _, _| {},
|
||||||
|
|_, _, _, _| {
|
||||||
|
// only continue if the point is not found
|
||||||
|
found.borrow().is_none()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
found
|
found.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_update<F>(&mut self, ctoken: CompositorToken<U, R>, get_size: F)
|
fn self_update<F>(&mut self, ctoken: CompositorToken<U, R>, get_size: F)
|
||||||
|
@ -129,6 +135,8 @@ where
|
||||||
TraversalAction::SkipChildren
|
TraversalAction::SkipChildren
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|_, _, _, _| {},
|
||||||
|
|_, _, _, _| true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.surface = Rectangle {
|
self.surface = Rectangle {
|
||||||
|
|
|
@ -300,6 +300,7 @@ impl Drop for EGLImages {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println!("RELEASING EGL BUFFER");
|
||||||
self.buffer.release();
|
self.buffer.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,7 @@ where
|
||||||
Some(|surface| SurfaceData::<U, R>::cleanup(&surface)),
|
Some(|surface| SurfaceData::<U, R>::cleanup(&surface)),
|
||||||
SurfaceData::<U, R>::new(),
|
SurfaceData::<U, R>::new(),
|
||||||
);
|
);
|
||||||
|
SurfaceData::<U, R>::init(&surface);
|
||||||
surface
|
surface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,11 +287,21 @@ where
|
||||||
{
|
{
|
||||||
/// Access the data of a surface tree from bottom to top
|
/// Access the data of a surface tree from bottom to top
|
||||||
///
|
///
|
||||||
/// The provided closure is called successively on the surface and all its child subsurfaces,
|
/// You provide three closures, a "filter", a "processor" and a "post filter".
|
||||||
/// in a depth-first order. This matches the order in which the surfaces are supposed to be
|
|
||||||
/// drawn: top-most last.
|
|
||||||
///
|
///
|
||||||
/// The arguments provided to the closure are, in this order:
|
/// The first closure is initially called on a surface to determine if its children
|
||||||
|
/// should be processed as well. It returns a `TraversalAction<T>` reflecting that.
|
||||||
|
///
|
||||||
|
/// The second closure is supposed to do the actual processing. The processing closure for
|
||||||
|
/// a surface may be called after the processing closure of some of its children, depending
|
||||||
|
/// on the stack ordering the client requested. Here the surfaces are processed in the same
|
||||||
|
/// order as they are supposed to be drawn: from the farthest of the screen to the nearest.
|
||||||
|
///
|
||||||
|
/// The third closure is called once all the subtree of a node has been processed, and gives
|
||||||
|
/// an opportunity for early-stopping. If it returns `true` the processing will continue,
|
||||||
|
/// while if it returns `false` it'll stop.
|
||||||
|
///
|
||||||
|
/// The arguments provided to the closures are, in this order:
|
||||||
///
|
///
|
||||||
/// - The surface object itself
|
/// - The surface object itself
|
||||||
/// - a mutable reference to its surface attribute data
|
/// - a mutable reference to its surface attribute data
|
||||||
|
@ -301,27 +311,40 @@ where
|
||||||
///
|
///
|
||||||
/// If the surface not managed by the `CompositorGlobal` that provided this token, this
|
/// If the surface 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_upward<F, T>(&self, surface: &WlSurface, initial: T, f: F) -> Result<(), ()>
|
pub fn with_surface_tree_upward<F1, F2, F3, T>(
|
||||||
where
|
&self,
|
||||||
F: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
surface: &WlSurface,
|
||||||
|
initial: T,
|
||||||
|
filter: F1,
|
||||||
|
processor: F2,
|
||||||
|
post_filter: F3,
|
||||||
|
) where
|
||||||
|
F1: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
|
F2: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T),
|
||||||
|
F3: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> bool,
|
||||||
{
|
{
|
||||||
SurfaceData::<U, R>::map_tree(surface, initial, f, false);
|
SurfaceData::<U, R>::map_tree(surface, &initial, filter, processor, post_filter, false);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the data of a surface tree from top to bottom
|
/// Access the data of a surface tree from top to bottom
|
||||||
///
|
///
|
||||||
/// The provided closure is called successively on the surface and all its child subsurfaces,
|
/// Behavior is the same as [`with_surface_tree_upward`](CompositorToken::with_surface_tree_upward), but
|
||||||
/// in a depth-first order. This matches the reverse of the order in which the surfaces are
|
/// the processing is done in the reverse order, from the nearest of the screen to the deepest.
|
||||||
/// supposed to be drawn: top-most first.
|
|
||||||
///
|
///
|
||||||
/// Behavior is the same as [`with_surface_tree_upward`](CompositorToken::with_surface_tree_upward).
|
/// This would typically be used to find out which surface of a subsurface tree has been clicked for example.
|
||||||
pub fn with_surface_tree_downward<F, T>(&self, surface: &WlSurface, initial: T, f: F) -> Result<(), ()>
|
pub fn with_surface_tree_downward<F1, F2, F3, T>(
|
||||||
where
|
&self,
|
||||||
F: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
surface: &WlSurface,
|
||||||
|
initial: T,
|
||||||
|
filter: F1,
|
||||||
|
processor: F2,
|
||||||
|
post_filter: F3,
|
||||||
|
) where
|
||||||
|
F1: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
|
F2: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T),
|
||||||
|
F3: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> bool,
|
||||||
{
|
{
|
||||||
SurfaceData::<U, R>::map_tree(surface, initial, f, true);
|
SurfaceData::<U, R>::map_tree(surface, &initial, filter, processor, post_filter, true);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the parent of this surface
|
/// Retrieve the parent of this surface
|
||||||
|
|
|
@ -13,11 +13,8 @@ use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
/// fact that lifetime of objects are decided by Wayland-server to ensure
|
/// fact that lifetime of objects are decided by Wayland-server to ensure
|
||||||
/// the cleanup will be done properly, and we won't leak anything.
|
/// the cleanup will be done properly, and we won't leak anything.
|
||||||
///
|
///
|
||||||
/// This implementation is not strictly a tree, but rather a directed graph
|
/// Each node also appears within its children list, to allow relative placement
|
||||||
/// with the constraint that node can have at most one incoming edge. Aka like
|
/// between them.
|
||||||
/// a tree, but with loops allowed. This is because the Wayland protocol does not
|
|
||||||
/// have a failure case to forbid this. Note that if any node in such a graph does not
|
|
||||||
/// have a parent, then the graph is a tree and this node is its root.
|
|
||||||
pub struct SurfaceData<U, R> {
|
pub struct SurfaceData<U, R> {
|
||||||
parent: Option<WlSurface>,
|
parent: Option<WlSurface>,
|
||||||
children: Vec<WlSurface>,
|
children: Vec<WlSurface>,
|
||||||
|
@ -44,7 +41,7 @@ impl<U: Default, R: Default> SurfaceData<U, R> {
|
||||||
pub fn new() -> Mutex<SurfaceData<U, R>> {
|
pub fn new() -> Mutex<SurfaceData<U, R>> {
|
||||||
Mutex::new(SurfaceData {
|
Mutex::new(SurfaceData {
|
||||||
parent: None,
|
parent: None,
|
||||||
children: Vec::new(),
|
children: vec![],
|
||||||
role: Default::default(),
|
role: Default::default(),
|
||||||
attributes: Default::default(),
|
attributes: Default::default(),
|
||||||
})
|
})
|
||||||
|
@ -56,13 +53,20 @@ where
|
||||||
U: 'static,
|
U: 'static,
|
||||||
R: 'static,
|
R: 'static,
|
||||||
{
|
{
|
||||||
|
/// Initializes the surface, must be called at creation for state coherence
|
||||||
|
pub fn init(surface: &WlSurface) {
|
||||||
|
let my_data_mutex = surface.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
|
let mut my_data = my_data_mutex.lock().unwrap();
|
||||||
|
debug_assert!(my_data.children.len() == 0);
|
||||||
|
my_data.children.push(surface.clone());
|
||||||
|
}
|
||||||
|
|
||||||
/// Cleans the `as_ref().user_data` of that surface, must be called when it is destroyed
|
/// Cleans the `as_ref().user_data` of that surface, must be called when it is destroyed
|
||||||
pub fn cleanup(surface: &WlSurface) {
|
pub fn cleanup(surface: &WlSurface) {
|
||||||
let my_data_mutex = surface.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
let my_data_mutex = surface.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut my_data = my_data_mutex.lock().unwrap();
|
let mut my_data = my_data_mutex.lock().unwrap();
|
||||||
if let Some(old_parent) = my_data.parent.take() {
|
if let Some(old_parent) = my_data.parent.take() {
|
||||||
if !old_parent.as_ref().equals(surface.as_ref()) {
|
// We had a parent, lets unregister ourselves from it
|
||||||
// We had a parent that is not ourselves, lets unregister ourselves from it
|
|
||||||
let old_parent_mutex = old_parent
|
let old_parent_mutex = old_parent
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.user_data::<Mutex<SurfaceData<U, R>>>()
|
.user_data::<Mutex<SurfaceData<U, R>>>()
|
||||||
|
@ -72,7 +76,6 @@ where
|
||||||
.children
|
.children
|
||||||
.retain(|c| !c.as_ref().equals(surface.as_ref()));
|
.retain(|c| !c.as_ref().equals(surface.as_ref()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// orphan all our children
|
// orphan all our children
|
||||||
for child in &my_data.children {
|
for child in &my_data.children {
|
||||||
// don't do anything if this child is ourselves
|
// don't do anything if this child is ourselves
|
||||||
|
@ -159,6 +162,21 @@ impl<U: 'static, R: RoleType + 'static> SurfaceData<U, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R> {
|
impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R> {
|
||||||
|
/// Checks if the first surface is an ancestor of the second
|
||||||
|
pub fn is_ancestor(a: &WlSurface, b: &WlSurface) -> bool {
|
||||||
|
let b_mutex = b.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
|
let b_guard = b_mutex.lock().unwrap();
|
||||||
|
if let Some(ref parent) = b_guard.parent {
|
||||||
|
if parent.as_ref().equals(a.as_ref()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return Self::is_ancestor(a, parent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the parent of a surface
|
/// Sets the parent of a surface
|
||||||
///
|
///
|
||||||
/// if this surface already has a role, does nothing and fails, otherwise
|
/// if this surface already has a role, does nothing and fails, otherwise
|
||||||
|
@ -166,6 +184,10 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
pub fn set_parent(child: &WlSurface, parent: &WlSurface) -> Result<(), ()> {
|
pub fn set_parent(child: &WlSurface, parent: &WlSurface) -> Result<(), ()> {
|
||||||
debug_assert!(child.as_ref().is_alive());
|
debug_assert!(child.as_ref().is_alive());
|
||||||
debug_assert!(parent.as_ref().is_alive());
|
debug_assert!(parent.as_ref().is_alive());
|
||||||
|
// ensure the child is not already a parent of the parent
|
||||||
|
if Self::is_ancestor(child, parent) {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
// change child's parent
|
// change child's parent
|
||||||
{
|
{
|
||||||
|
@ -177,7 +199,6 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
child_guard.parent = Some(parent.clone());
|
child_guard.parent = Some(parent.clone());
|
||||||
}
|
}
|
||||||
// register child to new parent
|
// register child to new parent
|
||||||
// double scoping is to be robust to have a child be its own parent
|
|
||||||
{
|
{
|
||||||
let parent_mutex = parent.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
let parent_mutex = parent.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut parent_guard = parent_mutex.lock().unwrap();
|
let mut parent_guard = parent_mutex.lock().unwrap();
|
||||||
|
@ -222,11 +243,16 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
child_guard.parent.as_ref().cloned()
|
child_guard.parent.as_ref().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the parent surface (if any) of this surface
|
/// Retrieve the children surface (if any) of this surface
|
||||||
pub fn get_children(child: &WlSurface) -> Vec<WlSurface> {
|
pub fn get_children(parent: &WlSurface) -> Vec<WlSurface> {
|
||||||
let child_mutex = child.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
let parent_mutex = parent.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let child_guard = child_mutex.lock().unwrap();
|
let parent_guard = parent_mutex.lock().unwrap();
|
||||||
child_guard.children.to_vec()
|
parent_guard
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.filter(|s| !s.as_ref().equals(parent.as_ref()))
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reorders a surface relative to one of its sibling
|
/// Reorders a surface relative to one of its sibling
|
||||||
|
@ -238,10 +264,6 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
let data_guard = data_mutex.lock().unwrap();
|
let data_guard = data_mutex.lock().unwrap();
|
||||||
data_guard.parent.as_ref().cloned().unwrap()
|
data_guard.parent.as_ref().cloned().unwrap()
|
||||||
};
|
};
|
||||||
if parent.as_ref().equals(relative_to.as_ref()) {
|
|
||||||
// TODO: handle positioning relative to parent
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index_of(surface: &WlSurface, slice: &[WlSurface]) -> Option<usize> {
|
fn index_of(surface: &WlSurface, slice: &[WlSurface]) -> Option<usize> {
|
||||||
for (i, s) in slice.iter().enumerate() {
|
for (i, s) in slice.iter().enumerate() {
|
||||||
|
@ -255,7 +277,7 @@ impl<U: 'static, R: RoleType + Role<SubsurfaceRole> + 'static> SurfaceData<U, R>
|
||||||
let parent_mutex = parent.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
let parent_mutex = parent.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut parent_guard = parent_mutex.lock().unwrap();
|
let mut parent_guard = parent_mutex.lock().unwrap();
|
||||||
let my_index = index_of(surface, &parent_guard.children).unwrap();
|
let my_index = index_of(surface, &parent_guard.children).unwrap();
|
||||||
let mut other_index = match index_of(surface, &parent_guard.children) {
|
let mut other_index = match index_of(relative_to, &parent_guard.children) {
|
||||||
Some(idx) => idx,
|
Some(idx) => idx,
|
||||||
None => return Err(()),
|
None => return Err(()),
|
||||||
};
|
};
|
||||||
|
@ -295,76 +317,81 @@ impl<U: 'static, R: 'static> SurfaceData<U, R> {
|
||||||
/// Note that an internal lock is taken during access of this data,
|
/// Note that an internal lock is taken during access of this data,
|
||||||
/// so the tree cannot be manipulated at the same time.
|
/// so the tree cannot be manipulated at the same time.
|
||||||
///
|
///
|
||||||
/// The callback returns whether the traversal should continue or not. Returning
|
/// The first callback determines if this node children should be processed or not.
|
||||||
/// false will cause an early-stopping.
|
///
|
||||||
pub fn map_tree<F, T>(root: &WlSurface, initial: T, mut f: F, reverse: bool)
|
/// The second actually does the processing, being called on children in display depth
|
||||||
where
|
/// order.
|
||||||
F: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
///
|
||||||
{
|
/// The third is called once all the children of a node has been processed (including itself), only if the first
|
||||||
// helper function for recursion
|
/// returned `DoChildren`, and gives an opportunity to early stop
|
||||||
fn map<U: 'static, R: 'static, F, T>(
|
pub fn map_tree<F1, F2, F3, T>(
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
root: &WlSurface,
|
|
||||||
initial: &T,
|
initial: &T,
|
||||||
f: &mut F,
|
mut filter: F1,
|
||||||
|
mut processor: F2,
|
||||||
|
mut post_filter: F3,
|
||||||
|
reverse: bool,
|
||||||
|
) where
|
||||||
|
F1: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
|
F2: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T),
|
||||||
|
F3: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> bool,
|
||||||
|
{
|
||||||
|
Self::map(
|
||||||
|
surface,
|
||||||
|
initial,
|
||||||
|
&mut filter,
|
||||||
|
&mut processor,
|
||||||
|
&mut post_filter,
|
||||||
|
reverse,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function for map_tree
|
||||||
|
fn map<F1, F2, F3, T>(
|
||||||
|
surface: &WlSurface,
|
||||||
|
initial: &T,
|
||||||
|
filter: &mut F1,
|
||||||
|
processor: &mut F2,
|
||||||
|
post_filter: &mut F3,
|
||||||
reverse: bool,
|
reverse: bool,
|
||||||
) -> bool
|
) -> bool
|
||||||
where
|
where
|
||||||
F: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
F1: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> TraversalAction<T>,
|
||||||
|
F2: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T),
|
||||||
|
F3: FnMut(&WlSurface, &mut SurfaceAttributes<U>, &mut R, &T) -> bool,
|
||||||
{
|
{
|
||||||
// stop if we met the root, so to not deadlock/inifinte loop
|
|
||||||
if surface.as_ref().equals(root.as_ref()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let data_mutex = surface.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
let data_mutex = surface.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
let mut data_guard = data_mutex.lock().unwrap();
|
||||||
let data_guard = &mut *data_guard;
|
let data_guard = &mut *data_guard;
|
||||||
// call the callback on ourselves
|
// call the filter on ourselves
|
||||||
match f(surface, &mut data_guard.attributes, &mut data_guard.role, initial) {
|
match filter(surface, &mut data_guard.attributes, &mut data_guard.role, initial) {
|
||||||
TraversalAction::DoChildren(t) => {
|
TraversalAction::DoChildren(t) => {
|
||||||
// loop over children
|
// loop over children
|
||||||
if reverse {
|
if reverse {
|
||||||
for c in data_guard.children.iter().rev() {
|
for c in data_guard.children.iter().rev() {
|
||||||
if !map::<U, R, _, _>(c, root, &t, f, true) {
|
if c.as_ref().equals(surface.as_ref()) {
|
||||||
|
processor(surface, &mut data_guard.attributes, &mut data_guard.role, initial);
|
||||||
|
} else if !Self::map(c, &t, filter, processor, post_filter, true) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for c in &data_guard.children {
|
for c in &data_guard.children {
|
||||||
if !map::<U, R, _, _>(c, root, &t, f, false) {
|
if c.as_ref().equals(surface.as_ref()) {
|
||||||
|
processor(surface, &mut data_guard.attributes, &mut data_guard.role, initial);
|
||||||
|
} else if !Self::map(c, &t, filter, processor, post_filter, false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
post_filter(surface, &mut data_guard.attributes, &mut data_guard.role, initial)
|
||||||
|
}
|
||||||
|
TraversalAction::SkipChildren => {
|
||||||
|
// still process ourselves
|
||||||
|
processor(surface, &mut data_guard.attributes, &mut data_guard.role, initial);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
TraversalAction::SkipChildren => true,
|
|
||||||
TraversalAction::Break => false,
|
TraversalAction::Break => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_mutex = root.as_ref().user_data::<Mutex<SurfaceData<U, R>>>().unwrap();
|
|
||||||
let mut data_guard = data_mutex.lock().unwrap();
|
|
||||||
let data_guard = &mut *data_guard;
|
|
||||||
// call the callback on ourselves
|
|
||||||
if let TraversalAction::DoChildren(t) =
|
|
||||||
f(root, &mut data_guard.attributes, &mut data_guard.role, &initial)
|
|
||||||
{
|
|
||||||
// loop over children
|
|
||||||
if reverse {
|
|
||||||
for c in data_guard.children.iter().rev() {
|
|
||||||
if !map::<U, R, _, _>(c, root, &t, &mut f, true) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for c in &data_guard.children {
|
|
||||||
if !map::<U, R, _, _>(c, root, &t, &mut f, false) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue