git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit56cd6e4720e6c61e480ed8acd2f664ab9bac4706
parent289d1d1b10
authorLucas Galante <[email protected]>
date2026-08-04 14:54
fix: absorb size-only configure echoes instead of sending them

XdgToplevel::configure had an "already at this size" check, but it ran
AFTER wlr_xdg_toplevel_set_size had scheduled the configure — the stale
size still reached the client. For self-sizing clients (status bar
segments) whose content width flaps, that echo re-triggered a resize on
both sides and the pair ping-ponged at frame rate: ~3300 alternating
95/104 configures in five minutes while the cpu reading hovered around
10%, jittering the module and its neighbors.

The echo is now detected BEFORE any wlr set_* call: when the scheduled
size merely restates the client's current committed geometry and every
non-size field matches what was last sent, agree with reality (update
configure_sent, consume the scheduled size) and send nothing. A configure
whose size differs from the committed geometry — a real compositor-driven
resize — always goes through.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/server/xdg_toplevel.rs | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index e981c5b..395df6a 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -207,6 +207,43 @@ impl XdgToplevel {
             }
         }
 
+        // Absorb a size-only ECHO: the scheduled size merely restates what the
+        // client has already committed (its current geometry) and nothing else
+        // changed. Sending it anyway hands a self-sizing client a stale size
+        // one commit later — and when the client's content width flaps (the
+        // cpu module's text crossing 10%), that stale echo re-triggers a
+        // resize on both sides and the pair ping-pongs at frame rate (the
+        // status-bar jitter: ~3300 alternating 95/104 configures in 5min).
+        // Agree with reality instead and send nothing. A configure whose size
+        // DIFFERS from the committed geometry — a real compositor-driven
+        // resize — always goes through.
+        {
+            let echo_w = scheduled.width.or(sent.width);
+            let echo_h = scheduled.height.or(sent.height);
+            let non_size_equal = scheduled.bounds.width == sent.bounds.width
+                && scheduled.bounds.height == sent.bounds.height
+                && scheduled.activated == sent.activated
+                && scheduled.ssd == sent.ssd
+                && scheduled.tiled == sent.tiled
+                && scheduled.capabilities == sent.capabilities
+                && scheduled.maximized == sent.maximized
+                && scheduled.inform_fullscreen == sent.inform_fullscreen
+                && scheduled.resizing == sent.resizing;
+            if non_size_equal
+                && matches!(self.configure_state, ConfigureState::Idle)
+                && self.geometry.width > 0
+                && self.geometry.height > 0
+                && echo_w == Some(self.geometry.width as u32)
+                && echo_h == Some(self.geometry.height as u32)
+            {
+                (*self.window).configure_sent.width = echo_w;
+                (*self.window).configure_sent.height = echo_h;
+                (*self.window).configure_scheduled.width = None;
+                (*self.window).configure_scheduled.height = None;
+                return false;
+            }
+        }
+
         ffi::wlr_xdg_toplevel_set_activated(self.wlr_toplevel, scheduled.activated);
         ffi::wlr_xdg_toplevel_set_tiled(
             self.wlr_toplevel,