Track the power profile through Quickshell instead of polling busctl (#15027)
* Track the power profile through Quickshell instead of polling busctl Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Recover the power profile when the daemon was down at shell start Addresses Codex review: Quickshell never attaches its PowerProfiles listener if the daemon failed at startup. One-off reads on startup, power source changes and an IPC refresh from omarchy-powerprofiles-set cover that, still with no timer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Don't let a stale power profile read win over a change signal or drop a refresh Addresses Codex re-review: a busctl read in flight could overwrite a newer PowerProfiles signal, and refreshes requested while a read ran were dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test power profile transitions and stale reads as behavior, not source text Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3c1f7b780f
commit
1b1cc5ecb5
5 files changed
+101
-25
No files matched your search
@@ -28,4 +28,30 @@ assertDeepEqual(
|
||||
{ level: 40, notify: false, notifiedLowBattery: false },
|
||||
'battery clears notified state after recovery'
|
||||
)
|
||||
|
||||
const reply = profile => JSON.stringify({ type: 's', data: profile })
|
||||
assertEqual(battery.parseActiveProfile(reply('power-saver')), 'power-saver', 'battery parses the busctl profile reply')
|
||||
assertEqual(battery.parseActiveProfile(''), '', 'battery reads a missing daemon as no profile')
|
||||
|
||||
// Walk the profile through a session on battery: a startup read, then change
|
||||
// signals, with the lock video gated on power-saver.
|
||||
let profile = battery.profileAfterRead('', reply('balanced'), 0, 0)
|
||||
assert(!battery.isPowerSaverOnBattery(true, profile), 'battery keeps the video on balanced')
|
||||
profile = 'power-saver'
|
||||
assert(battery.isPowerSaverOnBattery(true, profile), 'battery stops the video when power-saver arrives on battery')
|
||||
assert(!battery.isPowerSaverOnBattery(false, profile), 'battery ignores power-saver on AC')
|
||||
profile = 'balanced'
|
||||
assert(!battery.isPowerSaverOnBattery(true, profile), 'battery resumes the video when power-saver ends')
|
||||
|
||||
// A read that sampled balanced before a power-saver signal must not undo it.
|
||||
const signalsAtStart = 3
|
||||
profile = 'power-saver'
|
||||
profile = battery.profileAfterRead(profile, reply('balanced'), signalsAtStart, signalsAtStart + 1)
|
||||
assertEqual(profile, 'power-saver', 'battery drops a read made stale by a change signal')
|
||||
assert(battery.isPowerSaverOnBattery(true, profile), 'battery keeps the video stopped after a stale read')
|
||||
assertEqual(
|
||||
battery.profileAfterRead('balanced', reply('power-saver'), signalsAtStart, signalsAtStart),
|
||||
'power-saver',
|
||||
'battery takes a read no signal overtook'
|
||||
)
|
||||
JS
|
||||
@@ -147,10 +147,17 @@ assert(
|
||||
)
|
||||
assert(
|
||||
batteryService.includes('property string activePowerProfile') &&
|
||||
batteryService.includes('UPower.onBattery && activePowerProfile === "power-saver"') &&
|
||||
batteryService.includes('powerSaverOnBattery: BatteryModel.isPowerSaverOnBattery(UPower.onBattery, activePowerProfile)') &&
|
||||
/function onProfileChanged\(\) \{\s*root\.powerProfileSignals\+\+\s*root\.activePowerProfile = root\.profileName\(PowerProfiles\.profile\)/.test(batteryService) &&
|
||||
batteryService.includes('root.activePowerProfile = BatteryModel.profileAfterRead(root.activePowerProfile, text, root.powerProfileReadSignals, root.powerProfileSignals)') &&
|
||||
/if \(powerProfileReadProcess\.running\) \{\s*powerProfileReadPending = true/.test(batteryService) &&
|
||||
batteryService.includes('if (root.powerProfileReadPending) Qt.callLater(root.refreshPowerProfile)') &&
|
||||
batteryService.includes('case PowerProfile.PowerSaver: return "power-saver"') &&
|
||||
batteryService.includes('"get-property", "net.hadess.PowerProfiles", "/net/hadess/PowerProfiles", "net.hadess.PowerProfiles", "ActiveProfile"') &&
|
||||
!batteryService.includes('["powerprofilesctl"') &&
|
||||
batteryService.includes('interval: 2000'),
|
||||
!/Timer \{[^}]*refreshPowerProfile/.test(batteryService) &&
|
||||
batteryService.includes('function refreshPowerProfile(): void { root.refreshPowerProfile() }') &&
|
||||
fs.readFileSync(path.join(root, 'bin/omarchy-powerprofiles-set'), 'utf8').includes('omarchy-shell -q battery refreshPowerProfile'),
|
||||
'the battery service tracks the active power-saver profile'
|
||||
)
|
||||
assert(
|
||||
|
||||
Reference in new issue
Block a user