Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
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,