Skip to content

power applet: debounce device menu rebuilds - #13949

Open
rumours86 wants to merge 1 commit into
linuxmint:masterfrom
rumours86:power-applet-debounce-rebuild
Open

power applet: debounce device menu rebuilds#13949
rumours86 wants to merge 1 commit into
linuxmint:masterfrom
rumours86:power-applet-debounce-rebuild

Conversation

@rumours86

Copy link
Copy Markdown

The bug. _devicesChanged() is connected to the csd-power proxy's g-properties-changed and rebuilds the whole device menu — destroying and recreating every DeviceItem — on each signal. With a flapping AC adapter (loose plug / failing cable) csd-power emits a storm of signals: measured 126 in 3 minutes against ~18 at idle. The flood of destroyed/recreated actors drives GJS into high-frequency incremental GC; while it runs, GJS blocks JS callbacks from C — including the shell's own paint vfunc (UiActor.vfunc_paint in layout.js, which paints everything). Result: every time the charger blinks, the entire screen freezes or goes black for seconds (Attempting to run a JS callback during garbage collection ... The offending callback was paint(), a vfunc at exactly the frame rate in .xsession-errors), and blocked destroy callbacks leave zombie notification banners floating over all windows.

Measurements (Cinnamon 6.6.9, 3000x2000 eDP): deliberately flapping the charger produced 200 unpainted frames over 9s with the stock applet; removing the applet from the panel dropped it to 29; with this debounce the blackouts are gone entirely (user-confirmed over many plug/unplug cycles).

The fix. Coalesce bursts into one rebuild per 500ms: the first signal is handled immediately (icon still reacts instantly), the rest of a burst is folded into a single trailing rebuild.

🤖 Generated with Claude Code

_devicesChanged() is connected to the csd-power proxy's
g-properties-changed and rebuilt the whole device menu (destroying and
recreating every DeviceItem) on each signal.  With a flapping AC adapter
(loose plug or failing cable) csd-power emits a storm of signals - 126 in
3 minutes measured against ~18 at idle - and the flood of destroyed and
recreated actors drives GJS into high-frequency incremental GC.  While
that GC runs, GJS blocks JS callbacks from C, including the shell's paint
vfunc, so the entire screen freezes or goes black for seconds every time
the charger blinks; destroy callbacks of notification banners get blocked
too, leaving stuck banners floating over all windows.

Debounce the rebuild: handle the first signal immediately and fold the
rest of a burst into a single trailing rebuild 500ms later.  An A/B test
with a deliberately flapped charger went from 200 unpainted frames over
9s to under 30, and with this fix applied the blackouts are gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant