diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index f41f11b..ba63867 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -294,9 +294,11 @@ impl GliumDrawer { compositor_token: MyCompositorToken, screen_dimensions: (u32, u32), ) { - compositor_token - .with_surface_tree_upward(root, location, |_surface, attributes, role, &(mut x, mut y)| { - // there is actually something to draw ! + compositor_token.with_surface_tree_upward( + root, + location, + |_surface, attributes, role, &(mut x, mut y)| { + // Pull a new buffer if available if attributes.user_data.texture.is_none() { if let Some(buffer) = attributes.user_data.buffer.take() { if let Ok(m) = self.texture_from_buffer(buffer.clone()) { @@ -307,7 +309,23 @@ impl GliumDrawer { 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::::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 { + // we need to re-extract the subsurface offset, as the previous closure + // only passes it to our children if let Ok(subdata) = Role::::data(role) { x += subdata.location.0; y += subdata.location.1; @@ -332,13 +350,10 @@ impl GliumDrawer { ..Default::default() }, ); - TraversalAction::DoChildren((x, y)) - } else { - // we are not display, so our children are neither - TraversalAction::SkipChildren } - }) - .unwrap(); + }, + |_, _, _, _| true, + ); } pub fn draw_windows( diff --git a/anvil/src/window_map.rs b/anvil/src/window_map.rs index 2548a08..f7ff7af 100644 --- a/anvil/src/window_map.rs +++ b/anvil/src/window_map.rs @@ -1,3 +1,5 @@ +use std::cell::RefCell; + use smithay::{ reexports::wayland_server::protocol::wl_surface, utils::Rectangle, @@ -63,7 +65,7 @@ where return None; } // need to check more carefully - let mut found = None; + let found = RefCell::new(None); if let Some(wl_surface) = self.toplevel.get_surface() { let _ = ctoken.with_surface_tree_downward( wl_surface, @@ -81,18 +83,22 @@ where height: h, }; 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))); - TraversalAction::Break - } else { - TraversalAction::DoChildren((x, y)) + *found.borrow_mut() = + Some((wl_surface.clone(), (my_rect.x as f64, my_rect.y as f64))); } + TraversalAction::DoChildren((x, y)) } else { TraversalAction::SkipChildren } }, + |_, _, _, _| {}, + |_, _, _, _| { + // only continue if the point is not found + found.borrow().is_none() + }, ); } - found + found.into_inner() } fn self_update(&mut self, ctoken: CompositorToken, get_size: F) @@ -129,6 +135,8 @@ where TraversalAction::SkipChildren } }, + |_, _, _, _| {}, + |_, _, _, _| true, ); } self.surface = Rectangle { diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index 316df5d..38876c0 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -300,6 +300,7 @@ impl Drop for EGLImages { } } } + println!("RELEASING EGL BUFFER"); self.buffer.release(); } } diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index f3e51a1..c483dfd 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -139,6 +139,7 @@ where Some(|surface| SurfaceData::::cleanup(&surface)), SurfaceData::::new(), ); + SurfaceData::::init(&surface); surface } diff --git a/src/wayland/compositor/mod.rs b/src/wayland/compositor/mod.rs index e53d656..fd3ede5 100644 --- a/src/wayland/compositor/mod.rs +++ b/src/wayland/compositor/mod.rs @@ -287,11 +287,21 @@ where { /// 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, - /// in a depth-first order. This matches the order in which the surfaces are supposed to be - /// drawn: top-most last. + /// You provide three closures, a "filter", a "processor" and a "post filter". /// - /// 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` 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 /// - 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 /// will panic (having more than one compositor is not supported). - pub fn with_surface_tree_upward(&self, surface: &WlSurface, initial: T, f: F) -> Result<(), ()> - where - F: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + pub fn with_surface_tree_upward( + &self, + surface: &WlSurface, + initial: T, + filter: F1, + processor: F2, + post_filter: F3, + ) where + F1: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + F2: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T), + F3: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> bool, { - SurfaceData::::map_tree(surface, initial, f, false); - Ok(()) + SurfaceData::::map_tree(surface, &initial, filter, processor, post_filter, false); } /// 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, - /// in a depth-first order. This matches the reverse of the order in which the surfaces are - /// supposed to be drawn: top-most first. + /// Behavior is the same as [`with_surface_tree_upward`](CompositorToken::with_surface_tree_upward), but + /// the processing is done in the reverse order, from the nearest of the screen to the deepest. /// - /// Behavior is the same as [`with_surface_tree_upward`](CompositorToken::with_surface_tree_upward). - pub fn with_surface_tree_downward(&self, surface: &WlSurface, initial: T, f: F) -> Result<(), ()> - where - F: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + /// 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( + &self, + surface: &WlSurface, + initial: T, + filter: F1, + processor: F2, + post_filter: F3, + ) where + F1: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + F2: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T), + F3: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> bool, { - SurfaceData::::map_tree(surface, initial, f, true); - Ok(()) + SurfaceData::::map_tree(surface, &initial, filter, processor, post_filter, true); } /// Retrieve the parent of this surface diff --git a/src/wayland/compositor/tree.rs b/src/wayland/compositor/tree.rs index 5b1197e..45c69a3 100644 --- a/src/wayland/compositor/tree.rs +++ b/src/wayland/compositor/tree.rs @@ -13,11 +13,8 @@ use wayland_server::protocol::wl_surface::WlSurface; /// fact that lifetime of objects are decided by Wayland-server to ensure /// the cleanup will be done properly, and we won't leak anything. /// -/// This implementation is not strictly a tree, but rather a directed graph -/// with the constraint that node can have at most one incoming edge. Aka like -/// 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. +/// Each node also appears within its children list, to allow relative placement +/// between them. pub struct SurfaceData { parent: Option, children: Vec, @@ -44,7 +41,7 @@ impl SurfaceData { pub fn new() -> Mutex> { Mutex::new(SurfaceData { parent: None, - children: Vec::new(), + children: vec![], role: Default::default(), attributes: Default::default(), }) @@ -56,22 +53,28 @@ where U: '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::>>().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 pub fn cleanup(surface: &WlSurface) { let my_data_mutex = surface.as_ref().user_data::>>().unwrap(); let mut my_data = my_data_mutex.lock().unwrap(); if let Some(old_parent) = my_data.parent.take() { - if !old_parent.as_ref().equals(surface.as_ref()) { - // We had a parent that is not ourselves, lets unregister ourselves from it - let old_parent_mutex = old_parent - .as_ref() - .user_data::>>() - .unwrap(); - let mut old_parent_guard = old_parent_mutex.lock().unwrap(); - old_parent_guard - .children - .retain(|c| !c.as_ref().equals(surface.as_ref())); - } + // We had a parent, lets unregister ourselves from it + let old_parent_mutex = old_parent + .as_ref() + .user_data::>>() + .unwrap(); + let mut old_parent_guard = old_parent_mutex.lock().unwrap(); + old_parent_guard + .children + .retain(|c| !c.as_ref().equals(surface.as_ref())); } // orphan all our children for child in &my_data.children { @@ -159,6 +162,21 @@ impl SurfaceData { } impl + 'static> SurfaceData { + /// 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::>>().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 /// /// if this surface already has a role, does nothing and fails, otherwise @@ -166,6 +184,10 @@ impl + 'static> SurfaceData pub fn set_parent(child: &WlSurface, parent: &WlSurface) -> Result<(), ()> { debug_assert!(child.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 { @@ -177,7 +199,6 @@ impl + 'static> SurfaceData child_guard.parent = Some(parent.clone()); } // 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::>>().unwrap(); let mut parent_guard = parent_mutex.lock().unwrap(); @@ -222,11 +243,16 @@ impl + 'static> SurfaceData child_guard.parent.as_ref().cloned() } - /// Retrieve the parent surface (if any) of this surface - pub fn get_children(child: &WlSurface) -> Vec { - let child_mutex = child.as_ref().user_data::>>().unwrap(); - let child_guard = child_mutex.lock().unwrap(); - child_guard.children.to_vec() + /// Retrieve the children surface (if any) of this surface + pub fn get_children(parent: &WlSurface) -> Vec { + let parent_mutex = parent.as_ref().user_data::>>().unwrap(); + let parent_guard = parent_mutex.lock().unwrap(); + parent_guard + .children + .iter() + .filter(|s| !s.as_ref().equals(parent.as_ref())) + .cloned() + .collect() } /// Reorders a surface relative to one of its sibling @@ -238,10 +264,6 @@ impl + 'static> SurfaceData let data_guard = data_mutex.lock().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 { for (i, s) in slice.iter().enumerate() { @@ -255,7 +277,7 @@ impl + 'static> SurfaceData let parent_mutex = parent.as_ref().user_data::>>().unwrap(); let mut parent_guard = parent_mutex.lock().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, None => return Err(()), }; @@ -295,76 +317,81 @@ impl SurfaceData { /// Note that an internal lock is taken during access of this data, /// so the tree cannot be manipulated at the same time. /// - /// The callback returns whether the traversal should continue or not. Returning - /// false will cause an early-stopping. - pub fn map_tree(root: &WlSurface, initial: T, mut f: F, reverse: bool) - where - F: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + /// The first callback determines if this node children should be processed or not. + /// + /// The second actually does the processing, being called on children in display depth + /// order. + /// + /// The third is called once all the children of a node has been processed (including itself), only if the first + /// returned `DoChildren`, and gives an opportunity to early stop + pub fn map_tree( + surface: &WlSurface, + initial: &T, + mut filter: F1, + mut processor: F2, + mut post_filter: F3, + reverse: bool, + ) where + F1: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + F2: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T), + F3: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> bool, { - // helper function for recursion - fn map( - surface: &WlSurface, - root: &WlSurface, - initial: &T, - f: &mut F, - reverse: bool, - ) -> bool - where - F: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, - { - // stop if we met the root, so to not deadlock/inifinte loop - if surface.as_ref().equals(root.as_ref()) { - return true; - } + Self::map( + surface, + initial, + &mut filter, + &mut processor, + &mut post_filter, + reverse, + ); + } - let data_mutex = surface.as_ref().user_data::>>().unwrap(); - let mut data_guard = data_mutex.lock().unwrap(); - let data_guard = &mut *data_guard; - // call the callback on ourselves - match f(surface, &mut data_guard.attributes, &mut data_guard.role, initial) { - TraversalAction::DoChildren(t) => { - // loop over children - if reverse { - for c in data_guard.children.iter().rev() { - if !map::(c, root, &t, f, true) { - return false; - } - } - } else { - for c in &data_guard.children { - if !map::(c, root, &t, f, false) { - return false; - } - } - } - true - } - TraversalAction::SkipChildren => true, - TraversalAction::Break => false, - } - } - - let data_mutex = root.as_ref().user_data::>>().unwrap(); + // helper function for map_tree + fn map( + surface: &WlSurface, + initial: &T, + filter: &mut F1, + processor: &mut F2, + post_filter: &mut F3, + reverse: bool, + ) -> bool + where + F1: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, + F2: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T), + F3: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> bool, + { + let data_mutex = surface.as_ref().user_data::>>().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::(c, root, &t, &mut f, true) { - break; - } - } - } else { - for c in &data_guard.children { - if !map::(c, root, &t, &mut f, false) { - break; + // call the filter on ourselves + match filter(surface, &mut data_guard.attributes, &mut data_guard.role, initial) { + TraversalAction::DoChildren(t) => { + // loop over children + if reverse { + for c in data_guard.children.iter().rev() { + 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; + } + } + } else { + for c in &data_guard.children { + 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; + } } } + 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 + } + TraversalAction::Break => false, } } }