Skip to content

fix(power-widget): Power widget charging icon/label stuck after unplugging AC - #6340

Closed
heyssh wants to merge 1 commit into
omacom:quattrofrom
heyssh:fix/power-widget-charging-state-detection
Closed

heyssh wants to merge 1 commit into
omacom:quattrofrom
heyssh:fix/power-widget-charging-state-detection

Conversation

@heyssh

@heyssh heyssh commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Fix: Power widget charging icon/label stuck after unplugging AC

Problem

In the Power bar-widget, when the charger cable was unplugged, the
battery icon and the status label (Charging) would not update —
they stayed stuck in the charging state indefinitely, even though the
system itself (upower --monitor) correctly reported the AC-unplug
event instantly.

Root cause

Two separate issues, found and fixed in sequence:

  1. Unreliable reactivity source. The icon/label were originally
    read via plain JS functions (batteryIcon(), modeLabel()) called
    directly inside QML Text bindings. This made their re-evaluation
    depend on QML's automatic dependency tracking working transitively
    across function calls into an imported .js module — a pattern
    that isn't guaranteed to be as reliable as a plain readonly property binding.

  2. Wrong UPower source property (the real cause). Charging state
    was derived from UPower.onBattery — a global, aggregate property
    on the UPower daemon. This property is known to lag or fail to
    notify promptly on some hardware. This is a well-documented pitfall
    in other UPower consumers (e.g. an equivalent bug was reported and
    fixed in cosmic-applets, where the fix was to switch from the
    global on_battery flag to the per-device state property).

    The correct, reliable source is the per-device state
    (UPowerDevice.state, e.g. UPowerDeviceState.Discharging /
    Charging / FullyCharged / PendingCharge), which is what
    upower --monitor itself reads and reports instantly.

Fix

  • Replaced the two JS functions with readonly property bindings
    (batteryIconText, modeLabelText) so the icon/label are
    guaranteed to re-evaluate on every relevant property change.
  • Changed discharging (and by extension charging) to be computed
    from UPowerDevice.state === UPowerDeviceState.Discharging instead
    of the global UPower.onBattery flag.

Known remaining behavior (not a bug)

There can still be a short delay (typically a couple of seconds)
between the physical plug/unplug event and the widget updating. This
comes from the underlying kernel → upowerd → DBus signal chain
(embedded-controller/ACPI reporting latency), which is outside the
widget's control and is consistent with the delay seen in
upower --monitor itself and in other desktop environments (GNOME,
KDE, etc.).

Testing

  • Verified with udevadm monitor --udev --subsystem-match=power_supply
    and upower -i <device> --monitor that the underlying system
    reports the state change, and confirmed the widget now reflects it
    (icon + label) without requiring the panel to be open.

Copilot AI review requested due to automatic review settings July 21, 2026 20:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the Power panel widget getting stuck showing the charging icon/label after AC unplug events by switching charge detection from the global UPower.onBattery flag to the per-device UPower.displayDevice.state, and by moving icon/label computation into readonly property bindings to improve QML reactivity.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Changes:

  • Replace batteryIcon() / modeLabel() QML functions with readonly property bindings (batteryIconText, modeLabelText).
  • Compute discharging from UPower.displayDevice.state instead of UPower.onBattery.
  • Update consumers to use the new bound properties for icon/label rendering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 53 to 56
readonly property bool discharging: {
var device = UPower.displayDevice
return !!(device && device.isPresent && UPower.onBattery)
return !!(device && device.isPresent && device.state === UPowerDeviceState.Discharging)
}
Comment on lines 70 to 73
readonly property bool charging: {
var d = UPower.displayDevice
return d && d.isPresent && !UPower.onBattery && !root.batteryFlowIdle
return d && d.isPresent && !root.discharging && !root.batteryFlowIdle
}
@heyssh heyssh changed the title fix(power-widget): use device.state instead of global onBattery for charge detection fix(power-widget): Power widget charging icon/label stuck after unplugging AC Jul 27, 2026
@heyssh heyssh closed this Jul 27, 2026
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.

2 participants