diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index b3115d0e..be07d0ca 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -301,6 +301,7 @@ pub struct WlSurface { pub extents: Cell, pub buffer_abs_pos: Cell, pub need_extents_update: Cell, + need_extents_propagation: Cell, pub buffer: CloneCell>>, pub shm_staging: CloneCell>>, pub shm_textures: DoubleBuffered, @@ -650,6 +651,7 @@ impl WlSurface { extents: Default::default(), buffer_abs_pos: Cell::new(Default::default()), need_extents_update: Default::default(), + need_extents_propagation: Default::default(), buffer: Default::default(), shm_staging: Default::default(), shm_textures: DoubleBuffered::new(DamageQueue::new().map(|damage| SurfaceShmTexture { @@ -904,7 +906,7 @@ impl WlSurface { self.ext.set(self.client.state.none_surface_ext.clone()); } - fn calculate_extents(&self) { + fn calculate_extents(&self, propagate: bool) { let old_extents = self.extents.get(); let mut extents = self.buffer_abs_pos.get().at_point(0, 0); let children = self.children.borrow(); @@ -925,7 +927,11 @@ impl WlSurface { self.extents.set(extents); self.need_extents_update.set(false); if old_extents != extents { - self.ext.get().extents_changed() + if propagate { + self.ext.get().extents_changed() + } else { + self.need_extents_propagation.set(true); + } } } @@ -1398,7 +1404,7 @@ impl WlSurface { .push(XWaylandEvent::SurfaceSerialAssigned(self.id)); } if self.need_extents_update.get() { - self.calculate_extents(); + self.calculate_extents(false); } if buffer_changed || transform_changed || alpha_changed { for (_, cursor) in &self.cursors { @@ -1461,6 +1467,9 @@ impl WlSurface { { self.output.get().update_presentation_type(); } + if self.need_extents_propagation.take() { + self.ext.get().extents_changed(); + } self.commit_version.fetch_add(1); Ok(()) } diff --git a/src/ifs/wl_surface/wl_subsurface.rs b/src/ifs/wl_surface/wl_subsurface.rs index 56d255b9..be00ab8d 100644 --- a/src/ifs/wl_surface/wl_subsurface.rs +++ b/src/ifs/wl_surface/wl_subsurface.rs @@ -308,7 +308,7 @@ impl WlSubsurfaceRequestHandler for WlSubsurface { if !parent.need_extents_update.get() { break; } - parent.calculate_extents(); + parent.calculate_extents(true); parent_opt = parent.ext.get().subsurface_parent(); } } diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index d28e298d..2c81c72c 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -24,6 +24,7 @@ use { WorkspaceNode, }, utils::{ + cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, @@ -90,6 +91,7 @@ pub struct XdgSurface { acked_serial: Cell>, geometry: Cell>, extents: Cell, + effective_geometry: Cell, pub absolute_desired_extents: Cell, ext: CloneCell>>, popup_display_stack: CloneCell>>>, @@ -231,6 +233,10 @@ pub trait XdgSurfaceExt: Debug { None } + fn effective_geometry(&self, geometry: Rect) -> Rect { + geometry + } + fn make_visible(self: Rc); fn node_layer(&self) -> NodeLayerLink; @@ -247,6 +253,7 @@ impl XdgSurface { acked_serial: Cell::new(None), geometry: Cell::new(None), extents: Cell::new(surface.extents.get()), + effective_geometry: Default::default(), absolute_desired_extents: Cell::new(Default::default()), ext: Default::default(), popup_display_stack: CloneCell::new(surface.client.state.root.stacked.clone()), @@ -262,10 +269,9 @@ impl XdgSurface { fn update_surface_position(&self) { let (mut x1, mut y1) = self.absolute_desired_extents.get().position(); - if let Some(geo) = self.geometry.get() { - x1 -= geo.x1(); - y1 -= geo.y1(); - } + let geo = self.effective_geometry.get(); + x1 -= geo.x1(); + y1 -= geo.y1(); self.surface.set_absolute_position(x1, y1); self.update_popup_positions(); } @@ -336,8 +342,8 @@ impl XdgSurface { self.surface.client.state.damage(extents.move_(x, y)); } - pub fn geometry(&self) -> Option { - self.geometry.get() + pub fn geometry(&self) -> Rect { + self.effective_geometry.get() } pub fn schedule_configure(self: &Rc) { @@ -512,6 +518,24 @@ impl XdgSurfaceRequestHandler for XdgSurface { } impl XdgSurface { + fn update_effective_geometry(&self) { + let geometry = self + .geometry + .get() + .unwrap_or_else(|| self.surface.extents.get()); + let mut effective_geometry = geometry; + let ext = self.ext.get(); + if let Some(ext) = &ext { + effective_geometry = ext.effective_geometry(geometry); + } + if self.effective_geometry.replace(effective_geometry) != effective_geometry { + self.update_surface_position(); + if let Some(ext) = &ext { + ext.geometry_changed(); + } + } + } + fn update_extents(&self) { let old_extents = self.extents.get(); let mut new_extents = self.surface.extents.get(); @@ -519,19 +543,19 @@ impl XdgSurface { new_extents = new_extents.intersect(geometry); } self.extents.set(new_extents); - if old_extents != new_extents - && let Some(ext) = self.ext.get() - { - ext.extents_changed(); + if old_extents != new_extents { + if self.geometry.is_none() { + self.update_effective_geometry(); + } + if let Some(ext) = self.ext.get() { + ext.extents_changed(); + } } } fn find_tree_at(&self, mut x: i32, mut y: i32, tree: &mut Vec) -> FindTreeResult { - if let Some(geo) = self.geometry.get() { - let (xt, yt) = geo.translate_inv(x, y); - x = xt; - y = yt; - } + let geo = self.effective_geometry.get(); + (x, y) = geo.translate_inv(x, y); self.surface.find_tree_at_(x, y, tree) } @@ -604,11 +628,8 @@ impl SurfaceExt for XdgSurface { { let prev = self.geometry.replace(Some(geometry)); if prev != Some(geometry) { + self.update_effective_geometry(); self.update_extents(); - self.update_surface_position(); - if let Some(ext) = self.ext.get() { - ext.geometry_changed(); - } } } Ok(()) diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index f1316bb6..424449d5 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -746,6 +746,10 @@ impl ToplevelNodeBase for XdgToplevel { ) -> Option { default_tile_drag_destination(self, source, split, abs_bounds, x, y) } + + fn tl_mark_fullscreen_ext(&self) { + self.xdg.update_effective_geometry(); + } } impl XdgSurfaceExt for XdgToplevel { @@ -776,6 +780,23 @@ impl XdgSurfaceExt for XdgToplevel { .damage(self.node_absolute_position()); } + fn effective_geometry(&self, geometry: Rect) -> Rect { + if !self.toplevel_data.is_fullscreen.get() { + return geometry; + } + let output = self + .toplevel_data + .output() + .node_absolute_position() + .at_point(0, 0); + let x_overflow = output.width() - geometry.width(); + let y_overflow = output.height() - geometry.height(); + output.at_point( + geometry.x1() - x_overflow / 2, + geometry.y1() - y_overflow / 2, + ) + } + fn make_visible(self: Rc) { self.node_make_visible(); } diff --git a/src/renderer.rs b/src/renderer.rs index a36f28c0..bce200f9 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -338,9 +338,8 @@ impl Renderer<'_> { bounds: Option<&Rect>, ) { let surface = &xdg.surface; - if let Some(geo) = xdg.geometry() { - (x, y) = geo.translate(x, y); - } + let geo = xdg.geometry(); + (x, y) = geo.translate(x, y); self.render_surface(surface, x, y, bounds); } diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 9e42820a..40e055a9 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -247,6 +247,7 @@ impl ToplevelNode for T { fn tl_mark_fullscreen(&self, fullscreen: bool) { self.tl_data().is_fullscreen.set(fullscreen); self.tl_mark_ancestor_fullscreen(fullscreen); + self.tl_mark_fullscreen_ext(); } } @@ -315,6 +316,10 @@ pub trait ToplevelNodeBase: Node { fn tl_mark_ancestor_fullscreen_ext(&self, fullscreen: bool) { let _ = fullscreen; } + + fn tl_mark_fullscreen_ext(&self) { + // nothing + } } pub struct FullscreenedData {