diff --git a/src/desktop/space.rs b/src/desktop/space.rs index d2fd8b2..a0836b9 100644 --- a/src/desktop/space.rs +++ b/src/desktop/space.rs @@ -4,7 +4,10 @@ use crate::{ desktop::{layer::*, output::*}, utils::{Logical, Point, Rectangle}, wayland::{ - compositor::{with_surface_tree_downward, SubsurfaceCachedState, TraversalAction}, + compositor::{ + get_parent, is_sync_subsurface, with_surface_tree_downward, SubsurfaceCachedState, + TraversalAction, + }, output::Output, shell::wlr_layer::Layer as WlrLayer, }, @@ -396,6 +399,21 @@ impl Space { } } + /// Automatically calls `Window::refresh` for the window that belongs to the given surface, + /// if managed by this space. + pub fn commit(&mut self, surface: &WlSurface) { + if is_sync_subsurface(surface) { + return; + } + let mut root = surface.clone(); + while let Some(parent) = get_parent(&root) { + root = parent; + } + if let Some(window) = self.windows().find(|w| w.toplevel().get_surface() == Some(&root)) { + window.refresh(); + } + } + pub fn render_output( &mut self, renderer: &mut R, diff --git a/src/desktop/window.rs b/src/desktop/window.rs index e8ced19..7b8b6a3 100644 --- a/src/desktop/window.rs +++ b/src/desktop/window.rs @@ -9,6 +9,7 @@ use crate::{ }, }; use std::{ + cell::Cell, collections::HashSet, hash::{Hash, Hasher}, rc::Rc, @@ -99,6 +100,7 @@ impl Kind { pub(super) struct WindowInner { pub(super) id: usize, toplevel: Kind, + bbox: Cell>, user_data: UserDataMap, } @@ -135,6 +137,7 @@ impl Window { Window(Rc::new(WindowInner { id, toplevel, + bbox: Cell::new(Rectangle::from_loc_and_size((0, 0), (0, 0))), user_data: UserDataMap::new(), })) } @@ -153,7 +156,7 @@ impl Window { // TODO: Cache and document when to trigger updates. If possible let space do it pub fn bbox(&self) -> Rectangle { if let Some(surface) = self.0.toplevel.get_surface() { - bbox_from_surface_tree(surface, (0, 0)) + self.0.bbox.get() } else { Rectangle::from_loc_and_size((0, 0), (0, 0)) } @@ -219,6 +222,16 @@ impl Window { } } + /// Updates internal values + /// + /// Needs to be called whenever the toplevel surface or any unsynchronized subsurfaces of this window are updated + /// to correctly update the bounding box of this window. + pub fn refresh(&self) { + if let Some(surface) = self.0.toplevel.get_surface() { + self.0.bbox.set(bbox_from_surface_tree(surface, (0, 0))); + } + } + /// Finds the topmost surface under this point if any and returns it together with the location of this /// surface. pub fn surface_under>>(