features/adding_quickshell #6

Merged
thomas merged 48 commits from features/adding_quickshell into main 2026-08-27 14:55:30 +01:00
Showing only changes of commit c64cf5ff12 - Show all commits

View File

@@ -116,6 +116,68 @@ Item {
}
}
// device.timeToFull/timeToEmpty are computed by Quickshell from
// energy/energyCapacity/changeRate — when upowerd's EnergyFull glitches
// to 0 (the same daemon flake HEALTH routes around above), that formula
// divides by a bogus capacity and comes out negative rather than a
// real estimate (confirmed live: timeToFull sat at -3751 while `upower
// -i` itself still reported a normal 26.7 minutes). This recomputes
// the same estimate straight from sysfs as a fallback, only used when
// Quickshell's own value isn't positive. Unlike cycle_count/design
// capacity above, energy_now and power_now change continuously while
// (dis)charging, so this polls on a timer instead of reading once.
property real sysfsEnergyNowWh: -1
property real sysfsPowerNowW: -1
readonly property real fallbackTimeToFullSeconds: (root.sysfsPowerNowW > 0 && root.energyFullWh > 0 && root.sysfsEnergyNowWh >= 0)
? Math.max(0, (root.energyFullWh - root.sysfsEnergyNowWh) / root.sysfsPowerNowW * 3600) : -1
readonly property real fallbackTimeToEmptySeconds: (root.sysfsPowerNowW > 0 && root.sysfsEnergyNowWh > 0)
? (root.sysfsEnergyNowWh / root.sysfsPowerNowW * 3600) : -1
// Prefers upowerd's own live estimate when it's sane; only falls back
// to the sysfs-computed one when upowerd's has gone zero/negative.
readonly property real timeRemainingSeconds: {
const primary = root.onBattery ? root.device.timeToEmpty : root.device.timeToFull
if (primary > 0) return primary
return root.onBattery ? root.fallbackTimeToEmptySeconds : root.fallbackTimeToFullSeconds
}
Timer {
id: sysfsRateTimer
interval: 15000
repeat: true
running: root.batteryPresent
triggeredOnStart: true
onTriggered: {
if (!sysfsEnergyNowProc.running) sysfsEnergyNowProc.running = true
if (!sysfsPowerNowProc.running) sysfsPowerNowProc.running = true
}
}
Process {
id: sysfsEnergyNowProc
command: ["sh", "-c", "cat \"$(ls -d /sys/class/power_supply/BAT* 2>/dev/null | head -n1)/energy_now\" 2>/dev/null"]
stdout: StdioCollector {
id: sysfsEnergyNowCollector
onStreamFinished: {
const n = parseFloat(sysfsEnergyNowCollector.text.trim())
root.sysfsEnergyNowWh = (isNaN(n) || n < 0) ? -1 : (n / 1000000)
}
}
}
Process {
id: sysfsPowerNowProc
command: ["sh", "-c", "cat \"$(ls -d /sys/class/power_supply/BAT* 2>/dev/null | head -n1)/power_now\" 2>/dev/null"]
stdout: StdioCollector {
id: sysfsPowerNowCollector
onStreamFinished: {
const n = parseFloat(sysfsPowerNowCollector.text.trim())
root.sysfsPowerNowW = (isNaN(n) || n <= 0) ? -1 : (n / 1000000)
}
}
}
// Raw UPower state string (Charging/Discharging/PendingCharge/…) — more
// granular than modeLabel below, which collapses those down to the
// three phrases the hero text and STATE row show.
@@ -176,9 +238,7 @@ Item {
},
{
label: root.onBattery ? "TIME LEFT" : "TIME TO FULL",
value: root.batteryPresent
? root.formatDuration(root.onBattery ? root.device.timeToEmpty : root.device.timeToFull)
: "—"
value: root.batteryPresent ? root.formatDuration(root.timeRemainingSeconds) : "—"
},
{ label: "STATUS", value: root.rawStateLabel },
{ label: "CYCLES", value: root.cycleCount > 0 ? String(root.cycleCount) : "—" }