Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
fix: echo absorb must also fire in Committed state, not just Idle
Verification of the previous commit caught it inert: after any completed
configure round-trip the state machine rests in Committed (Acked →
Committed on commit; only the timeout path returns to Idle), so an
Idle-only gate never matched in steady state — the exact moment the echo
loop runs. A padding-change probe showed size-restating configures still
going out one per module resize.
The absorb now fires in Idle | Committed. Inflight/Acked stay excluded: a
real configure is mid-flight there and the scheduled size may need to
supersede it.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/server/xdg_toplevel.rs | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index 395df6a..99003b4 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -229,8 +229,15 @@ impl XdgToplevel {
&& scheduled.maximized == sent.maximized
&& scheduled.inform_fullscreen == sent.inform_fullscreen
&& scheduled.resizing == sent.resizing;
+ // Idle AND Committed: after any completed configure round-trip
+ // the state machine RESTS in Committed (Acked → Committed on
+ // commit; only the timeout path returns to Idle), so gating on
+ // Idle alone leaves this absorb dead in steady state — the exact
+ // moment the echo loop runs. Inflight/Acked stay excluded: a
+ // real configure is mid-flight and the scheduled size may need
+ // to supersede it.
if non_size_equal
- && matches!(self.configure_state, ConfigureState::Idle)
+ && matches!(self.configure_state, ConfigureState::Idle | ConfigureState::Committed)
&& self.geometry.width > 0
&& self.geometry.height > 0
&& echo_w == Some(self.geometry.width as u32)