From e79d427c2aacc01221abe84f3538085383c16c98 Mon Sep 17 00:00:00 2001 From: The_miro Date: Mon, 6 Jul 2026 00:17:35 +0200 Subject: [PATCH] fix(astal-menu): refresh Bluetooth list on device connection changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device rows already render a "Disconnect" button when a device is connected, but the list only rebuilt on adapter-level notify::devices / notify::is-powered — not on per-device state changes. So a device connected (via the menu or elsewhere) while the menu was open kept its "Connect" button and offered no way to disconnect. Hook each device's notify::connected/connecting/paired (once each) to refresh the list, so a connected device flips to "Disconnect". Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP --- desktopenvs/hyprlua/astal-menu/modules/bluetooth.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/desktopenvs/hyprlua/astal-menu/modules/bluetooth.py b/desktopenvs/hyprlua/astal-menu/modules/bluetooth.py index b834ebd..4519c72 100644 --- a/desktopenvs/hyprlua/astal-menu/modules/bluetooth.py +++ b/desktopenvs/hyprlua/astal-menu/modules/bluetooth.py @@ -44,6 +44,7 @@ class _BluetoothView(Gtk.Box): self.full = full self.bt = ctx.services.bluetooth self._recorded: set[str] = set() + self._hooked: set[str] = set() # devices whose state signals we've wired self.append(self._build_header()) @@ -121,11 +122,23 @@ class _BluetoothView(Gtk.Box): if not self.full: devices = [d for d in devices if d.get_connected() or d.get_paired()][:4] for dev in devices: + self._hook_device(dev) self._list.append(self._device_row(dev)) if self.full and self.ctx.feature("history", True): self._list.append(self._history_section()) + def _hook_device(self, dev) -> None: + # Rebuild the list when a device's connection state changes, so a freshly + # connected device flips its button to "Disconnect" (adapter-level + # notify::devices doesn't fire for per-device state changes). Hook once each. + key = dev.get_address() or "" + if key in self._hooked: + return + self._hooked.add(key) + for sig in ("notify::connected", "notify::connecting", "notify::paired"): + dev.connect(sig, lambda *_a: self._refresh()) + def _device_row(self, dev) -> Gtk.Widget: row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) row.add_css_class("bt-row")