fix(battery): report when no charge threshold exists instead of faking success (#3385)

* fix(battery): report when no charge threshold exists instead of faking success

* fix(battery): hide the charge limit controls when there is no battery

Follow-up to the review on #3385: the new explanation showed on
desktops and VMs with no battery at all, where it reads as a fault
report about hardware the machine was never going to have.

Both the explanation and the apply button now require
BatteryService.batteryAvailable. Hiding the button there is the same
point the pull request makes elsewhere: offering a control that cannot
work is what produced the false success in the first place. A machine
without a battery has no charge threshold to write to, so the limit was
never applicable.

BatteryService.batteryAvailable is already the gate used twice in this
file for the same reason.

(cherry picked from commit 6b50696b8a)
This commit is contained in:
Mario Mohar
2026-09-15 16:46:47 -04:00
committed by bbedward
parent 76ed5d68fa
commit 1b34aa0ce1
+46 -10
View File
@@ -16,22 +16,43 @@ Item {
return Theme.surfaceText;
}
// The sysfs names DMS can write, in the order they are tried. Hardware that
// exposes none of them, a Lenovo IdeaPad on ideapad_laptop for instance,
// used to run the apply script to completion without writing anything, and
// sh exiting 0 was indistinguishable from a successful write.
readonly property string thresholdFileList: "charge_control_limit_max charge_stop_threshold charge_control_end_threshold"
readonly property int noThresholdExitCode: 2
property bool chargeLimitSupported: true
Process {
id: thresholdProbe
running: Qt.platform.os === "linux"
command: ["sh", "-c", "for bat in /sys/class/power_supply/BAT*; do for file in " + root.thresholdFileList + "; do [ -f \"$bat/$file\" ] && exit 0; done; done; exit 1"]
onExited: exitCode => root.chargeLimitSupported = exitCode === 0
}
Process {
id: applyLimitProcess
command: ["pkexec", "sh", "-c", "
found=0
for bat in /sys/class/power_supply/BAT*; do
if [ -f \"$bat/charge_control_limit_max\" ]; then
echo " + SettingsData.batteryChargeLimit + " > \"$bat/charge_control_limit_max\"
elif [ -f \"$bat/charge_stop_threshold\" ]; then
echo " + SettingsData.batteryChargeLimit + " > \"$bat/charge_stop_threshold\"
elif [ -f \"$bat/charge_control_end_threshold\" ]; then
echo " + SettingsData.batteryChargeLimit + " > \"$bat/charge_control_end_threshold\"
fi
for file in " + root.thresholdFileList + "; do
if [ -f \"$bat/$file\" ]; then
found=1
echo " + SettingsData.batteryChargeLimit + " > \"$bat/$file\" || exit 1
break
fi
done
done
[ \"$found\" = 1 ] || exit " + root.noThresholdExitCode + "
"]
running: false
onExited: exitCode => {
if (exitCode !== 0) {
if (exitCode === root.noThresholdExitCode) {
root.chargeLimitSupported = false;
ToastService.showError(I18n.tr("Charge limit not supported on this hardware", "battery settings: toast title when sysfs has no charge threshold"), I18n.tr("No writable charge threshold file was found under /sys/class/power_supply.", "battery settings: why the charge limit could not be applied"));
} else if (exitCode !== 0) {
ToastService.showError(I18n.tr("Failed to apply charge limit to system"), I18n.tr("Process exited with code %1").arg(exitCode));
} else {
ToastService.showInfo(I18n.tr("Charge limit applied successfully"), I18n.tr("Limit set to %1%").arg(SettingsData.batteryChargeLimit));
@@ -214,9 +235,24 @@ done
onSliderValueChanged: newValue => SettingsData.set("batteryChargeLimit", newValue)
}
StyledText {
width: parent.width
// A machine without a battery has no charge threshold to
// write to either, but saying so there would be noise: the
// limit was never applicable in the first place.
visible: Qt.platform.os === "linux" && BatteryService.batteryAvailable && !root.chargeLimitSupported
text: I18n.tr("No writable charge threshold file was found under /sys/class/power_supply.", "battery settings: why the charge limit could not be applied")
wrapMode: Text.WordWrap
color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeMedium
}
Row {
// charge_control_* live in Linux sysfs; no BSD equivalent
visible: Qt.platform.os === "linux"
// charge_control_* live in Linux sysfs; no BSD equivalent.
// Without a battery the apply button cannot do anything,
// and offering it anyway is what produced the false
// success this change is about.
visible: Qt.platform.os === "linux" && BatteryService.batteryAvailable && root.chargeLimitSupported
width: parent.width
height: applyButton.height
layoutDirection: I18n.isRtl ? Qt.LeftToRight : Qt.RightToLeft