From 7e9694c4dcc79414406529e0932eb425b0a23288 Mon Sep 17 00:00:00 2001 From: Lysec Date: Wed, 18 Feb 2026 14:24:29 +0100 Subject: [PATCH] ProgramCheckerService: move bluetoothctl check from BluetoothService here --- Services/Networking/BluetoothService.qml | 48 ++++++++--------------- Services/System/ProgramCheckerService.qml | 2 + 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/Services/Networking/BluetoothService.qml b/Services/Networking/BluetoothService.qml index dd879d9c9..275f09f05 100644 --- a/Services/Networking/BluetoothService.qml +++ b/Services/Networking/BluetoothService.qml @@ -6,6 +6,7 @@ import Quickshell.Bluetooth import Quickshell.Io import "../../Helpers/BluetoothUtils.js" as BluetoothUtils import qs.Commons +import qs.Services.System import qs.Services.UI Singleton { @@ -66,8 +67,6 @@ Singleton { // Internal: temporarily pause discovery during pair/connect to reduce HCI churn property bool _discoveryWasRunning: false property bool _ctlInit: false - // Track whether the bluetoothctl CLI is available on the system - property bool ctlBinaryAvailable: false Timer { id: initDelayTimer @@ -116,6 +115,16 @@ Singleton { } } + // Re-run polling once bluetoothctl availability is known + Connections { + target: ProgramCheckerService + function onBluetoothctlAvailableChanged() { + if (!adapter && ProgramCheckerService.bluetoothctlAvailable) { + requestCtlPoll(0); + } + } + } + function setAirplaneMode(state) { if (state) { Quickshell.execDetached(["rfkill", "block", "wifi"]); @@ -184,7 +193,7 @@ Singleton { id: ctlPollTimer interval: adapter ? ctlPollMs : 2000 repeat: true - running: adapter || root.ctlBinaryAvailable + running: adapter || ProgramCheckerService.bluetoothctlAvailable onTriggered: { pollCtlState(); var targetInterval = adapter ? ctlPollMs : 2000; @@ -195,7 +204,7 @@ Singleton { } function requestCtlPoll(delayMs) { - if (!adapter && !root.ctlBinaryAvailable) { + if (!adapter && !ProgramCheckerService.bluetoothctlAvailable) { return; } ctlPollTimer.interval = Math.max(50, delayMs || ctlPollSoonMs); @@ -203,7 +212,7 @@ Singleton { } function pollCtlState() { - if (!adapter && !root.ctlBinaryAvailable) { + if (!adapter && !ProgramCheckerService.bluetoothctlAvailable) { return; } if (ctlShowProcess.running) { @@ -214,29 +223,6 @@ Singleton { } catch (_) {} } - // One-time detection of bluetoothctl binary presence to avoid spamming logs on systems without Bluetooth - Process { - id: ctlBinaryCheck - running: true - command: ["sh", "-c", "command -v bluetoothctl >/dev/null 2>&1 && echo yes || echo no"] - stdout: StdioCollector { - onStreamFinished: { - var available = (text || "").trim() === "yes"; - root.ctlBinaryAvailable = available; - if (!available) { - Logger.i("Bluetooth", "bluetoothctl not found; disabling CLI fallback polling"); - } - } - } - stderr: StdioCollector { - onStreamFinished: { - if (text && text.trim()) { - Logger.d("Bluetooth", "bluetoothctl check stderr:", text.trim()); - } - } - } - } - // bluetoothctl state polling Process { id: ctlShowProcess @@ -311,7 +297,7 @@ Singleton { // Unify discovery controls function setScanActive(active) { - if (!adapter && !root.ctlBinaryAvailable) { + if (!adapter && !ProgramCheckerService.bluetoothctlAvailable) { Logger.d("Bluetooth", "Scan request ignored: bluetoothctl unavailable"); return; } @@ -344,7 +330,7 @@ Singleton { // Adapter power (enable/disable) via bluetoothctl function setBluetoothEnabled(state) { Logger.i("Bluetooth", "SetBluetoothEnabled", state); - if (!adapter && !root.ctlBinaryAvailable) { + if (!adapter && !ProgramCheckerService.bluetoothctlAvailable) { Logger.i("Bluetooth", "Enable/Disable skipped: no adapter or bluetoothctl"); return; } @@ -366,7 +352,7 @@ Singleton { // Toggle adapter discoverability (advertising visibility) via bluetoothctl function setDiscoverable(state) { - if (!adapter && !root.ctlBinaryAvailable) { + if (!adapter && !ProgramCheckerService.bluetoothctlAvailable) { Logger.d("Bluetooth", "Discoverable change skipped: no adapter or bluetoothctl"); return; } diff --git a/Services/System/ProgramCheckerService.qml b/Services/System/ProgramCheckerService.qml index d3bd6a59e..6487a526e 100644 --- a/Services/System/ProgramCheckerService.qml +++ b/Services/System/ProgramCheckerService.qml @@ -12,6 +12,7 @@ Singleton { // Program availability properties property bool nmcliAvailable: false + property bool bluetoothctlAvailable: false property bool wlsunsetAvailable: false property bool app2unitAvailable: false property bool gnomeCalendarAvailable: false @@ -20,6 +21,7 @@ Singleton { // Programs to check - maps property names to commands readonly property var programsToCheck: ({ + "bluetoothctlAvailable": ["sh", "-c", "command -v bluetoothctl"], "nmcliAvailable": ["sh", "-c", "command -v nmcli"], "wlsunsetAvailable": ["sh", "-c", "command -v wlsunset"], "app2unitAvailable": ["sh", "-c", "command -v app2unit"],