From d27cea5183e0268ce538b8d8e86240900555ff13 Mon Sep 17 00:00:00 2001 From: Matthew Guzzo Date: Thu, 29 Oct 2026 01:09:23 -0400 Subject: [PATCH] Fix status width oscillation at fractional scales In compact shells (Fit/Dock/Notch) the bar is centered and sized by its content, so the status widget moves whenever its own width changes. spacingSavings is derived from ink edges snapped to absolute device pixels, so at 1.25x that move flips the snapped value back, and Qt.callLater only defers each flip by one frame. The whole bar then resizes by 1-3 px every frame and Quickshell pins a CPU core. Ignore a return to the value just left within 500 ms so the reservation settles. Changes to new values still apply immediately. Co-Authored-By: Claude Opus 5.5 --- hancore.shibumi.status/BarWidget.qml | 14 +++++++++++++- tests/status-plugin-regression.sh | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/hancore.shibumi.status/BarWidget.qml b/hancore.shibumi.status/BarWidget.qml index 7c02acd..89bfb5d 100644 --- a/hancore.shibumi.status/BarWidget.qml +++ b/hancore.shibumi.status/BarWidget.qml @@ -122,13 +122,25 @@ Item { property real spacingSavings: 0 property bool savingsPending: false property bool spacingActive: false + property real spacingSavingsLeft: -1 + property double spacingSavingsChangedAt: 0 // Settle after layout: binding width directly to snapped ink feeds the // parent's new position back into its own reservation. function syncSpacingSavings() { if (!root || !spacingActive) return const saved = Math.max(0, updateShift - bellShift) savingsPending = false - if (Math.abs(spacingSavings - saved) > 1e-7) spacingSavings = saved + if (Math.abs(spacingSavings - saved) <= 1e-7) return + // Deferring alone does not settle it: a centered compact shell moves with + // its own width, and at fractional scales (1.25x) that move flips the + // snapped ink edges straight back, resizing the bar every frame. Ignore an + // immediate return to the value just left. + const now = Date.now() + if (Math.abs(saved - spacingSavingsLeft) <= 1e-7 + && now - spacingSavingsChangedAt < 500) return + spacingSavingsLeft = spacingSavings + spacingSavingsChangedAt = now + spacingSavings = saved } function scheduleSpacingSavings() { savingsPending = true diff --git a/tests/status-plugin-regression.sh b/tests/status-plugin-regression.sh index ebed578..7794cc9 100755 --- a/tests/status-plugin-regression.sh +++ b/tests/status-plugin-regression.sh @@ -111,6 +111,9 @@ if ('else if (lifecycleBar && "tearingDown" in lifecycleBar\n' raise SystemExit("Status no longer handles WidgetSlot's pre-destruction Bar revoke") PY printf 'status teardown ordering source guard passed\n' +rg -U -q 'Math\.abs\(saved - spacingSavingsLeft\) <= 1e-7\n[[:space:]]*&& now - spacingSavingsChangedAt < 500\) return' \ + "$status_widget" \ + || fail "status spacing savings no longer settle a self-induced width cycle" rg -Fq '["full", "icon", "text"]' "$status_widget" \ || fail "status widget does not expose Full/Icon/Text display modes" if rg -q 'SystemTray\.items|NotificationServer|makoctl|pgrep -x hypridle' \