diff --git a/src/desktop/space.rs b/src/desktop/space.rs index 7365cdf..70dcfc1 100644 --- a/src/desktop/space.rs +++ b/src/desktop/space.rs @@ -287,14 +287,15 @@ impl Space { if old_geo.map(|old_geo| old_geo != geo).unwrap_or(false) { // Add damage for the old position of the window damage.push(old_geo.unwrap()); - } /* else { - // window stayed at its place - // TODO: Only push surface damage - // But this would need to take subsurfaces into account and accumulate damage at least. - // Even better would be if damage would be ignored that is hidden by subsurfaces... - }*/ - // Add damage for the new position (see TODO above for a better approach) - damage.push(geo); + damage.push(geo); + } else { + // window stayed at its place + let loc = window_loc(window, &self.id); + damage.extend(window.accumulated_damage().into_iter().map(|mut rect| { + rect.loc += loc; + rect + })); + } } // That is all completely new damage, which we need to store for subsequent renders diff --git a/src/desktop/window.rs b/src/desktop/window.rs index f3292d0..9077983 100644 --- a/src/desktop/window.rs +++ b/src/desktop/window.rs @@ -374,6 +374,57 @@ impl Window { found.into_inner() } + /// Damage of all the surfaces of this window + pub(super) fn accumulated_damage(&self) -> Vec> { + let mut damage = Vec::new(); + let location = (0, 0).into(); + if let Some(surface) = self.0.toplevel.get_surface() { + with_surface_tree_upward( + surface, + location, + |_surface, states, location| { + let mut location = *location; + if let Some(data) = states.data_map.get::>() { + let data = data.borrow(); + if data.texture.is_none() { + if states.role == Some("subsurface") { + let current = states.cached_state.current::(); + location += current.location; + } + return TraversalAction::DoChildren(location); + } + } + TraversalAction::SkipChildren + }, + |_surface, states, location| { + let mut location = *location; + if let Some(data) = states.data_map.get::>() { + let data = data.borrow(); + let attributes = states.cached_state.current::(); + + if data.texture.is_none() { + if states.role == Some("subsurface") { + let current = states.cached_state.current::(); + location += current.location; + } + + damage.extend(attributes.damage.iter().map(|dmg| { + let mut rect = match dmg { + Damage::Buffer(rect) => rect.to_logical(attributes.buffer_scale), + Damage::Surface(rect) => *rect, + }; + rect.loc += location; + rect + })); + } + } + }, + |_, _, _| true, + ) + } + damage + } + pub fn toplevel(&self) -> &Kind { &self.0.toplevel }