From 243d302447dfc11850a0622303cdcc8bb35d3fe4 Mon Sep 17 00:00:00 2001 From: mikairyuu Date: Thu, 19 Mar 2026 22:53:31 +0300 Subject: [PATCH] fix(bluetooth): show connected devices without pairing bonds BlueZ exposes `Paired` and `Connected` as separate states, but the Bluetooth page currently conflates them in a few places. As a result, devices that connect successfully without creating a pairing bond can fail to appear as connected in COSMIC Settings. This patch separates those two concepts in the UI/state handling: - initialize a device as connected from `Connected`, not from `Connected && Paired`, - do not let `Paired` updates mutate connection state, - treat paired or currently connected devices as "known" devices in the main device list, - keep `Forget` available only for actually paired devices. ## User-visible effect This fixes cases such as the DualShock 3, where the controller is successfully connected but does not show up as connected in the Bluetooth settings page. ## Notes This also matches the behavior already used in `cosmic-applet-bluetooth`, which treats `Connected` and `Paired` as separate states and reports a device as connected based on `is_connected()`, not on pairing state. A follow-up could rename the section/title to better reflect that it now contains paired-or-connected devices rather than only paired ones. - [x] I have disclosed use of any AI generated code in my commit messages. - [x] I understand these changes in full and will be able to respond to review comments. - [x] My change is accurately described in the commit message. - [x] My contribution is tested and working as described. - [x] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions. --- cosmic-settings/src/pages/bluetooth/mod.rs | 18 ++++++++++-------- subscriptions/bluetooth/src/device.rs | 3 +-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cosmic-settings/src/pages/bluetooth/mod.rs b/cosmic-settings/src/pages/bluetooth/mod.rs index d2da586..830311e 100644 --- a/cosmic-settings/src/pages/bluetooth/mod.rs +++ b/cosmic-settings/src/pages/bluetooth/mod.rs @@ -811,7 +811,7 @@ fn connected_devices() -> Section { page.model.selected_adapter.as_ref().map(|adapter| { page.model .devices_for_adapter(adapter) - .any(|(_, device)| device.paired) + .any(|(_, device)| device.paired || device.is_connected()) }) == Some(true) && page.model.active != Active::Disabled }) @@ -822,7 +822,7 @@ fn connected_devices() -> Section { page.model .devices_for_adapter(page.model.selected_adapter.as_ref().unwrap()) .filter_map(|(path, device)| { - if !device.paired { + if !(device.paired || device.is_connected()) { return None; } @@ -846,10 +846,12 @@ fn connected_devices() -> Section { &descriptions[device_disconnect], ) })) - .push(popup_button( - Some(Message::ForgetDevice(path.clone())), - &descriptions[device_forget], - )) + .push_maybe(device.paired.then(|| { + popup_button( + Some(Message::ForgetDevice(path.clone())), + &descriptions[device_forget], + ) + })) .width(Length::Fixed(200.0)) .apply(widget::container) .padding(theme::spacing().space_xxs) @@ -914,7 +916,7 @@ fn available_devices() -> Section { page.model.selected_adapter.as_ref().map(|adapter| { page.model .devices_for_adapter(adapter) - .any(|(_, device)| !device.paired) + .any(|(_, device)| !device.paired || !device.is_connected()) }) == Some(true) && page.model.active != Active::Disabled }) @@ -925,7 +927,7 @@ fn available_devices() -> Section { page.model .devices_for_adapter(page.model.selected_adapter.as_ref().unwrap()) .filter_map(|(path, device)| { - if device.paired { + if device.paired || device.is_connected() { return None::>; } diff --git a/subscriptions/bluetooth/src/device.rs b/subscriptions/bluetooth/src/device.rs index 8f9f9eb..5374c5a 100644 --- a/subscriptions/bluetooth/src/device.rs +++ b/subscriptions/bluetooth/src/device.rs @@ -61,7 +61,7 @@ impl Device { let alias = alias.ok(); let device_type: String = proxy.icon().await; let paired = proxy.device.paired().await.unwrap_or(false); - let enabled = if proxy.device.connected().await.unwrap_or(false) && paired { + let enabled = if proxy.device.connected().await.unwrap_or(false) { Active::Enabled } else { Active::Disabled @@ -111,7 +111,6 @@ impl Device { } } DeviceUpdate::Paired(paired) => { - self.enabled = Active::Enabling; self.paired = paired; } DeviceUpdate::Icon(icon) => self.icon = icon,