From ffb3030e36877aa346d476d717829e24bc7bfcc2 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Thu, 18 Sep 2025 07:59:22 +0300 Subject: Fix layer-shell initial commit logic I didn't properly update it for the Smithay refactor. It was reading initial_configure_sent too early. This worked before when niri had to reset it manually, but it no longer works now that it is automatically reset already before entering this function. --- src/tests/client.rs | 4 ++ src/tests/layer_shell.rs | 170 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 1 deletion(-) (limited to 'src/tests') diff --git a/src/tests/client.rs b/src/tests/client.rs index fc61c2ac..89fa15a3 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -438,6 +438,10 @@ impl LayerSurface { self.surface.attach(Some(&buffer), 0, 0); } + pub fn attach_null(&self) { + self.surface.attach(None, 0, 0); + } + pub fn set_size(&self, w: u16, h: u16) { self.viewport.set_destination(i32::from(w), i32::from(h)); } diff --git a/src/tests/layer_shell.rs b/src/tests/layer_shell.rs index 65014942..72caf724 100644 --- a/src/tests/layer_shell.rs +++ b/src/tests/layer_shell.rs @@ -1,6 +1,8 @@ use insta::assert_snapshot; use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::Layer; -use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::Anchor; +use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::{ + Anchor, KeyboardInteractivity, +}; use super::*; use crate::tests::client::{LayerConfigureProps, LayerMargin}; @@ -88,3 +90,169 @@ fn margin_overflow() { let layer = f.client(id).layer(&surface); assert_snapshot!(layer.format_recent_configures(), @"size: 0 × 0"); } + +#[test] +fn unmap_through_null_buffer() { + let mut f = Fixture::new(); + f.add_output(1, (1920, 1080)); + let id = f.add_client(); + + let layer = f.client(id).create_layer(None, Layer::Top, ""); + let surface = layer.surface.clone(); + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 50)), + ..Default::default() + }); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + assert_snapshot!(layer.format_recent_configures(), @"size: 1920 × 50"); + + layer.attach_new_buffer(); + layer.set_size(100, 100); + layer.ack_last_and_commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // No new configure since nothing changed. + assert_snapshot!(layer.format_recent_configures(), @""); + + // Unmap by attaching a null buffer. This moves the surface back to pre-initial-commit stage. + layer.attach_null(); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // Configures must be empty because we haven't done an initial commit yet. + assert_snapshot!(layer.format_recent_configures(), @""); + + // Do the initial commit again. + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 100)), + ..Default::default() + }); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // This is the new initial configure. + assert_snapshot!(layer.format_recent_configures(), @"size: 1920 × 100"); + + layer.attach_new_buffer(); + layer.set_size(100, 100); + layer.ack_last_and_commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + assert_snapshot!(layer.format_recent_configures(), @""); +} + +#[test] +fn multiple_commits_before_mapping() { + let mut f = Fixture::new(); + f.add_output(1, (1920, 1080)); + let id = f.add_client(); + + let layer = f.client(id).create_layer(None, Layer::Top, ""); + let surface = layer.surface.clone(); + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 50)), + ..Default::default() + }); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + assert_snapshot!(layer.format_recent_configures(), @"size: 1920 × 50"); + + // Change something that won't cause a configure. + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 50)), + kb_interactivity: Some(KeyboardInteractivity::OnDemand), + ..Default::default() + }); + layer.ack_last_and_commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // No new configure since the size hasn't changed. + assert_snapshot!(layer.format_recent_configures(), @""); + + // Change something that will cause a configure. + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 100)), + ..Default::default() + }); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // Configure with new size. + assert_snapshot!(layer.format_recent_configures(), @"size: 1920 × 100"); + + // Map. + layer.attach_new_buffer(); + layer.set_size(100, 100); + layer.ack_last_and_commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // No new configure since nothing changed. + assert_snapshot!(layer.format_recent_configures(), @""); + + // Unmap by attaching a null buffer. This moves the surface back to pre-initial-commit stage. + layer.attach_null(); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // Configures must be empty because we haven't done an initial commit yet. + assert_snapshot!(layer.format_recent_configures(), @""); + + // Same configure props as before, but since we unmapped, we should get a new initial + // configure (that will happen to match the previous configure we had got while mapped). + let surface = layer.surface.clone(); + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 100)), + ..Default::default() + }); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + assert_snapshot!(layer.format_recent_configures(), @"size: 1920 × 100"); + + // Change something that won't cause a configure. + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 100)), + kb_interactivity: Some(KeyboardInteractivity::OnDemand), + ..Default::default() + }); + layer.ack_last_and_commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // No new configure since the size hasn't changed. + assert_snapshot!(layer.format_recent_configures(), @""); + + // Change something that will cause a configure. + layer.set_configure_props(LayerConfigureProps { + anchor: Some(Anchor::Left | Anchor::Right | Anchor::Top), + size: Some((0, 50)), + ..Default::default() + }); + layer.commit(); + f.double_roundtrip(id); + + let layer = f.client(id).layer(&surface); + // Configure with new size. + assert_snapshot!(layer.format_recent_configures(), @"size: 1920 × 50"); +} -- cgit