Stop closed network panels from leaving Wi-Fi scanning enabled (#6772)

* Stop closed network panels from leaving Wi-Fi scanning enabled

refresh() defaults scanWifi to false and its no-scan branch enabled the
scanner unconditionally. Five paths reach it with no panel on screen —
Component.onCompleted, clearNetworkAction(), failNetworkAction(), the
band-change actionProc exit, and the 30s actionTimeout — so the scanner
stayed on and Quickshell kept re-arming RequestScan behind a closed panel.
scanRestart had the mirror gap: it enabled the scanner 100ms after
refresh(true) without re-checking that the panel was still open.

Every sweep takes the radio off the operating channel, so this degraded
the link it was scanning from: one sweep every 17s, gateway RTT rising
from ~2ms to repeated 150ms+ spikes on an otherwise idle connection.

Gate the scanner block on the panel being open, cancel a pending restart
on close and re-check the panel when it fires, and track the WifiDevice
this instance enabled so close, device replacement and destruction
release the right object. Destruction matters on its own: a bar reload
with the panel open would otherwise die with opened still true and never
write scannerEnabled = false.

* Cover the scanner ownership helper's own invariants

The previous assertion only pinned that no write bypasses
setScannerEnabled(); it said nothing about what the helper does. Dropping
either the opened gate or the release-before-adopt from the helper still
passed, while a closed instance could reclaim scanning and a device swap
could leave the previous interface scanning.

Run the helper's actual JavaScript against stand-in devices instead,
following the extract-and-eval pattern the agents panel tests already use.
Removing either invariant now fails its own assertion.
This commit is contained in:
Francisco Cabral
2026-08-13 11:46:16 +02:00
committed by GitHub
parent 8ca61d6b8b
commit 5f74a996c7
2 changed files with 92 additions and 7 deletions
+54
View File
@@ -21,6 +21,60 @@ assert(barPress, 'network bar button has an onPressed handler')
const barPressCode = barPress[0].replace(/\/\/.*$/gm, '')
assert(!/refresh\(/.test(barPressCode), 'network bar click opens the panel without a second refresh that would undo the deferred scan')
// A closed panel has no nearby-network list to fill. Quickshell's scanner
// re-arms RequestScan on its own timer, and every sweep takes the radio off
// the operating channel, so a scanner left enabled behind a closed panel keeps
// degrading the connection it is scanning from.
const refreshFn = panelSource.match(/function refresh\(scanWifi\)[\s\S]*?\n {2}\}/)
assert(refreshFn, 'network has a refresh() function')
assert(/if \(opened && wifiDevice\)/.test(refreshFn[0]), 'network only touches the scanner from refresh() while its panel is open')
// The 100ms deferral can outlive the panel: closing inside the window would
// otherwise re-enable scanning from a timer nobody is watching.
const scanRestart = panelSource.match(/id: scanRestart[\s\S]*?onTriggered: \{[\s\S]*?\n {4}\}/)
assert(scanRestart, 'network has the deferred scan restart timer')
assert(/root\.opened/.test(scanRestart[0]), 'network re-checks the panel before the deferred restart re-enables scanning')
assert(/scanRestart\.stop\(\)/.test(panelSource), 'network cancels a pending scan restart when the panel closes')
// scannerEnabled lives on a shared WifiDevice with no reference counting, so
// the panel has to own what it enabled. Run the helper's own JavaScript against
// stand-in devices: the two invariants it carries are that a closed panel never
// takes a device, and that adopting a new one releases the previous.
const scannerHelper = panelSource.match(/function setScannerEnabled\(enabled\) \{[\s\S]*?\n {2}\}/)
assert(scannerHelper, 'network has a scanner ownership helper')
var opened = false
var wifiDevice = { scannerEnabled: false }
var scannerDevice = null
eval(scannerHelper[0])
setScannerEnabled(true)
assert(
scannerDevice === null && wifiDevice.scannerEnabled === false,
'network does not let a closed panel claim or enable a scanner device'
)
var previousScannerDevice = { scannerEnabled: true }
var replacementScannerDevice = { scannerEnabled: false }
opened = true
scannerDevice = previousScannerDevice
wifiDevice = replacementScannerDevice
setScannerEnabled(true)
assert(
previousScannerDevice.scannerEnabled === false &&
scannerDevice === replacementScannerDevice &&
replacementScannerDevice.scannerEnabled === true,
'network releases the previous scanner device before enabling its replacement'
)
// Destruction is the case a guard-only fix misses: the widget dies with the
// panel still open, as a bar reload does, and nothing else would release it.
assert(
/Component\.onDestruction[\s\S]{0,140}scannerDevice\.scannerEnabled = false/.test(panelSource),
'network releases the scanner it owns when the widget is destroyed'
)
assert(!/wifiDevice\.scannerEnabled\s*=/.test(panelSource), 'network writes scanner state through its owned device reference rather than the moving wifiDevice reference')
// A row is a primitive snapshot that can outlive its WifiNetwork, and
// disconnect() falls back to the live connection when handed null, so row
// activation must go through the guarded disconnectRow().