diff --git a/src/ifs/wl_surface/wl_subsurface.rs b/src/ifs/wl_surface/wl_subsurface.rs index 0a2fef38..a6cc1619 100644 --- a/src/ifs/wl_surface/wl_subsurface.rs +++ b/src/ifs/wl_surface/wl_subsurface.rs @@ -45,6 +45,7 @@ pub struct WlSubsurface { pub tracker: Tracker, had_buffer: Cell, version: Version, + initial_commit: Cell, } #[derive(Default)] @@ -111,6 +112,7 @@ impl WlSubsurface { tracker: Default::default(), had_buffer: Cell::new(false), version, + initial_commit: Cell::new(true), } } @@ -128,6 +130,9 @@ impl WlSubsurface { } pub fn apply_state(&self, pending: &mut PendingSubsurfaceData) -> Result<(), WlSurfaceError> { + if self.initial_commit.take() { + self.update_has_buffer(); + } if let Some(state) = &mut pending.state.take() { self.surface.apply_state(state)?; } @@ -283,6 +288,23 @@ impl WlSubsurface { } self.surface.client.state.damage(rect); } + + fn update_has_buffer(&self) { + let has_buffer = self.surface.buffer.is_some(); + if self.had_buffer.replace(has_buffer) != has_buffer { + if has_buffer { + if self.parent.visible.get() { + self.surface.set_visible(true); + self.damage(); + } + } else { + if self.surface.toplevel.is_some() { + self.damage(); + } + self.surface.destroy_node(); + } + } + } } impl WlSubsurfaceRequestHandler for WlSubsurface { @@ -381,20 +403,7 @@ impl SurfaceExt for WlSubsurface { } fn after_apply_commit(self: Rc) { - let has_buffer = self.surface.buffer.is_some(); - if self.had_buffer.replace(has_buffer) != has_buffer { - if has_buffer { - if self.parent.visible.get() { - self.surface.set_visible(true); - self.damage(); - } - } else { - if self.surface.toplevel.is_some() { - self.damage(); - } - self.surface.destroy_node(); - } - } + self.update_has_buffer(); } fn subsurface_parent(&self) -> Option> { diff --git a/src/it/tests.rs b/src/it/tests.rs index 543b84bb..dc28888c 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -84,6 +84,7 @@ mod t0050_fifo; mod t0051_pointer_warp; mod t0052_bar; mod t0053_theme; +mod t0054_subsurface_already_attached; pub trait TestCase: Sync { fn name(&self) -> &'static str; @@ -156,5 +157,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> { t0051_pointer_warp, t0052_bar, t0053_theme, + t0054_subsurface_already_attached, } } diff --git a/src/it/tests/t0054_subsurface_already_attached.rs b/src/it/tests/t0054_subsurface_already_attached.rs new file mode 100644 index 00000000..a60cde94 --- /dev/null +++ b/src/it/tests/t0054_subsurface_already_attached.rs @@ -0,0 +1,47 @@ +use { + crate::{ + it::{test_error::TestError, testrun::TestRun}, + theme::Color, + tree::Node, + }, + std::rc::Rc, +}; + +testcase!(); + +/// Test subsurface with already attached buffer +async fn test(run: Rc) -> Result<(), TestError> { + run.backend.install_default()?; + + let seat = run.get_seat("default")?; + + run.state.eng.yield_now().await; + + run.cfg.show_workspace(seat.id(), "")?; + + let client = run.create_client().await?; + + let parent = client.create_window().await?; + parent.map().await?; + parent.set_color(0, 0, 0, 255); + + let child = client.comp.create_surface().await?; + let buffer = client + .spbm + .create_buffer(Color::from_srgba_straight(255, 255, 255, 255))?; + child.attach(buffer.id)?; + let child_viewport = client.viewporter.get_viewport(&child)?; + child_viewport.set_source(0, 0, 1, 1)?; + child_viewport.set_destination(100, 100)?; + child.commit()?; + + let _sub = client + .sub + .get_subsurface(child.id, parent.surface.id) + .await?; + parent.map().await?; + + tassert!(child.server.node_visible()); + + Ok(()) +}