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
+38 -7
View File
@@ -292,6 +292,29 @@ Panel {
readonly property color hoverFill: bar ? Style.hoverFillFor(bar.foreground, Color.accent) : "transparent"
readonly property color selectedFill: bar ? Style.selectedFillFor(bar.foreground, Color.accent) : "transparent"
// scannerEnabled lives on the shared WifiDevice, which has no reference
// counting, and a bar widget is instantiated once per monitor. Tracking the
// device this instance turned scanning on for keeps the release correct when
// the panel closes, the device is replaced, or the widget is destroyed —
// without a closed instance ever claiming the scanner.
property var scannerDevice: null
function setScannerEnabled(enabled) {
var nextDevice = opened ? wifiDevice : null
if (scannerDevice && scannerDevice !== nextDevice)
scannerDevice.scannerEnabled = false
scannerDevice = nextDevice
if (scannerDevice)
scannerDevice.scannerEnabled = enabled
}
Component.onDestruction: {
if (scannerDevice) scannerDevice.scannerEnabled = false
}
// KeyboardPanel primes layer-shell focus whenever the panel opens. That's
// what makes the SUPER+CTRL+W keybind land here with navigation ready.
onOpenedChanged: {
@@ -305,6 +328,10 @@ Panel {
syncBandIndex()
cursorActive = false
} else {
// Drop a restart armed by this open: without it a close/reopen inside
// the 100ms window reuses the running timer and re-enables the scanner
// almost immediately, undoing the deferral #6605 restored.
scanRestart.stop()
// Reset throughput tracking so the next open doesn't compute a fake
// rate from a sample taken minutes ago.
prevSampleTime = 0
@@ -316,7 +343,7 @@ Panel {
routerPingLatency = -1
internetPingLatency = -1
internetPingPacketLoss = 0
if (wifiDevice) wifiDevice.scannerEnabled = false
setScannerEnabled(false)
}
}
@@ -357,7 +384,7 @@ Panel {
}
onWifiDeviceChanged: {
if (wifiDevice) wifiDevice.scannerEnabled = opened
setScannerEnabled(true)
syncWifiNetworks()
}
@@ -452,13 +479,15 @@ Panel {
bandProc.command = ["omarchy-network-band"]
bandProc.running = true
}
if (wifiDevice) {
// A closed panel has no nearby-network list to fill, and bare refresh()
// reaches here from action completion, timeouts and construction.
if (opened && wifiDevice) {
if (scanWifi) {
scanning = true
wifiDevice.scannerEnabled = false
setScannerEnabled(false)
scanRestart.start()
} else {
wifiDevice.scannerEnabled = true
setScannerEnabled(true)
}
}
syncWifiNetworks()
@@ -792,8 +821,10 @@ Panel {
interval: 100
repeat: false
onTriggered: {
if (root.wifiDevice) root.wifiDevice.scannerEnabled = true
scanDone.start()
if (root.opened && root.wifiDevice) {
root.setScannerEnabled(true)
scanDone.start()
}
}
}