Repository navigation
Conversation
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 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Affected plugin:
hancore.shibumi.statusIn the Notch shell at 1.25x scale, the whole bar shakes horizontally by 1–3 px every frame. The bell shakes the most. Quickshell sits at ~100% CPU, and restarting the shell doesn't help. At 1.6x the same layout settles and looks fine.
Cause
spacingSavings(G3's interior ink contraction) feeds back into its own input:updateShiftandbellShiftcome frominkEdge(), which usesstatusPlacement.origin.x, the widget's absolute window position. The glyph ink they measure is also snapped to absolute device pixels (BarGlyph.symbolCanvasusessnapX).spacingSavingsis subtracted fromcontentWidth, so it changes G3'simplicitWidth. It also reaches the bar'sspacingRecovery.shellXand every widget in it, G3 included.Qt.callLateronly defers each flip by one frame, so the cycle never ends.Observed with
shell debugBarGeometry: G3's width alternated 89 ↔ 86 and the left budget alternated 530.36 ↔ 527.96, which shifted every group after it. With temporary logging,spacingSavingsstepped through 2.4 → 5.6 → 3.2 → 4.8 → … before the fix.Fix
syncSpacingSavings()now remembers the value it last left and when it left it. If the new value is a return to that value within 500 ms, the sync is skipped, so the reservation settles on its current value. A change to a different value still applies immediately, as does a return after 500 ms. This uses no Timer, so the "exactly one lifecycle timer" contract still holds. The worst case is a reservation one snapped device pixel off from the painted shifts until the next real layout change.This breaks the cycle without changing the device-pixel snapping. A deeper fix would make the reservation independent of absolute position. I left that out because it touches the shared BarInk/BarGlyph placement model.
Also adds a source guard to
tests/status-plugin-regression.sh.Checks
debugBarGeometrysamples, and Quickshell ran at ~100% CPU.omarchy restart shell): savings settle after a few adjustments. 20/20debugBarGeometrysamples were identical, frames only differ where telemetry values update, and Quickshell is at ~1% CPU.OMARCHY_PATH=/usr/share/omarchy ./tests/status-plugin-regression.sh: passed, including the new guard. The guard fails against the original file.OMARCHY_PATH=/usr/share/omarchy ./tests/contract-regression.sh: ended withShibumi complete contract regression passed (Omarchy baseline installed-package-v4.0.6). Three steps were made non-fatal in a local, uncommitted run so the rest could execute:test_package_release.py›test_lifecycle_contract_pins_exact_release_identities, andtest_shibumi_suite.py›test_current_package_rejects_byte_and_mode_drift/test_exact_current_package_identity_is_admitted. These fail by design for any unreleased plugin change: the only difference is thehancore.shibumi.statuspayload digest against the pinnedpublic-beta.16.5.1identity. They pass on cleanmain. I didn't touch the release pins, since a new identity is a maintainer release step.network-plugin-regression.sh›network-qr-encoder-regression.py. This is environmental: the test hard-codes/usr/bin/node, and Node on this machine is installed via mise. The rest ofnetwork-plugin-regression.shpassed with that step made non-fatal.Remaining gate
Repeat on the isolated validation system at 1.25x with Fit, Dock and Notch. Check that G3 settles with tray and drawer items present and absent, and that the update→bell gap still meets the 14 px ink target to within one device pixel.
🤖 Generated with Claude Code