Tier 0: render what the services already decided, honestly
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -21,9 +21,65 @@ import QtQuick
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Set by the page while it is visible; drives both scanners.
|
||||
// Set by the settings page while it is visible. One of several holds on
|
||||
// the radios rather than the only one -- see the scan holds below.
|
||||
property bool active: false
|
||||
|
||||
// ── Scan holds ───────────────────────────────────────────────────────────
|
||||
//
|
||||
// Two surfaces list the same radios: this page and the quick-settings
|
||||
// panel. Both used to write scannerEnabled and adapter.discovering from
|
||||
// their own visibility flag, and the last writer won -- so closing the
|
||||
// settings page turned scanning off underneath an open quick-settings
|
||||
// panel, which then sat on "Searching…" forever with nothing searching.
|
||||
//
|
||||
// So the radios are held rather than switched. Each surface acquires a
|
||||
// named hold while it is on screen and releases it when it goes away, and
|
||||
// scanning runs while ANY hold is outstanding. Names rather than a counter:
|
||||
// these holders are QML items that can be destroyed with a release already
|
||||
// in flight, and a counter that drifts either leaves the radio on forever
|
||||
// or turns it off under somebody. Acquiring a name twice is acquiring it
|
||||
// once.
|
||||
property var wifiScanHolders: []
|
||||
property var discoveryHolders: []
|
||||
|
||||
readonly property bool wifiScanWanted: root.wifiScanHolders.length > 0
|
||||
readonly property bool discoveryWanted: root.discoveryHolders.length > 0
|
||||
|
||||
// Whether it was this service that started BlueZ discovering. Something
|
||||
// else on the machine may already have been -- bluetoothctl, another
|
||||
// desktop component -- and stopping a scan we did not start is not ours to
|
||||
// do.
|
||||
property bool discoveryOwned: false
|
||||
|
||||
function acquireWifiScan(holder: string): void {
|
||||
if (holder === "" || root.wifiScanHolders.indexOf(holder) >= 0)
|
||||
return;
|
||||
root.wifiScanHolders = root.wifiScanHolders.concat([holder]);
|
||||
root.syncScanners();
|
||||
}
|
||||
|
||||
function releaseWifiScan(holder: string): void {
|
||||
if (root.wifiScanHolders.indexOf(holder) < 0)
|
||||
return;
|
||||
root.wifiScanHolders = root.wifiScanHolders.filter(name => name !== holder);
|
||||
root.syncScanners();
|
||||
}
|
||||
|
||||
function acquireDiscovery(holder: string): void {
|
||||
if (holder === "" || root.discoveryHolders.indexOf(holder) >= 0)
|
||||
return;
|
||||
root.discoveryHolders = root.discoveryHolders.concat([holder]);
|
||||
root.syncScanners();
|
||||
}
|
||||
|
||||
function releaseDiscovery(holder: string): void {
|
||||
if (root.discoveryHolders.indexOf(holder) < 0)
|
||||
return;
|
||||
root.discoveryHolders = root.discoveryHolders.filter(name => name !== holder);
|
||||
root.syncScanners();
|
||||
}
|
||||
|
||||
readonly property var wifiDevice: {
|
||||
for (const device of Networking.devices.values) {
|
||||
if (device.type === DeviceType.Wifi)
|
||||
@@ -213,20 +269,39 @@ Singleton {
|
||||
return "Could not connect";
|
||||
}
|
||||
|
||||
// Scanning follows visibility. NetworkManager keeps scanning as long as it
|
||||
// is asked to, and Bluetooth discovery is worse -- it holds the radio.
|
||||
// Scanning follows the outstanding holds, not any one surface's visibility.
|
||||
// NetworkManager keeps scanning as long as it is asked to, and Bluetooth
|
||||
// discovery is worse -- it holds the radio.
|
||||
//
|
||||
// Computed from state and applied idempotently, so calling this after every
|
||||
// acquire, release and device change is free: it writes only when the radio
|
||||
// is not already where the holds say it should be.
|
||||
function syncScanners(): void {
|
||||
if (root.wifiDevice)
|
||||
root.wifiDevice.scannerEnabled = root.active && root.wifiEnabled;
|
||||
root.wifiDevice.scannerEnabled = root.wifiScanWanted && root.wifiEnabled;
|
||||
|
||||
if (root.adapter && root.adapter.enabled) {
|
||||
const shouldDiscover = root.active;
|
||||
if (root.adapter.discovering !== shouldDiscover)
|
||||
root.adapter.discovering = shouldDiscover;
|
||||
if (!root.adapter || !root.adapter.enabled)
|
||||
return;
|
||||
const shouldDiscover = root.discoveryWanted;
|
||||
if (shouldDiscover && !root.adapter.discovering) {
|
||||
root.adapter.discovering = true;
|
||||
root.discoveryOwned = true;
|
||||
} else if (!shouldDiscover && root.discoveryOwned && root.adapter.discovering) {
|
||||
root.adapter.discovering = false;
|
||||
root.discoveryOwned = false;
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: root.syncScanners()
|
||||
// The settings page's own hold, expressed through the flag it already sets.
|
||||
onActiveChanged: {
|
||||
if (root.active) {
|
||||
root.acquireWifiScan("settings");
|
||||
root.acquireDiscovery("settings");
|
||||
} else {
|
||||
root.releaseWifiScan("settings");
|
||||
root.releaseDiscovery("settings");
|
||||
}
|
||||
}
|
||||
onWifiDeviceChanged: root.syncScanners()
|
||||
onWifiEnabledChanged: root.syncScanners()
|
||||
onAdapterChanged: root.syncScanners()
|
||||
|
||||
Reference in New Issue
Block a user