From 057a5a44d88066d5f0be518e40c2bba7db2e16c4 Mon Sep 17 00:00:00 2001 From: The_miro Date: Tue, 21 Jul 2026 20:52:32 +0200 Subject: [PATCH] fix(station-bar): make SNI watcher D-Bus calls async (self-deadlock) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bar hosts the StatusNotifierWatcher in-process (sni_watcher.py), so the *_sync proxy creation and RegisterStatusNotifierHost call blocked the main loop waiting on a reply only that same loop could produce — a self-deadlock freezing the whole bar (clock, holo intro) until the 25s D-Bus timeout. Switch to new_for_bus + call (async, fire-and-forget). Co-Authored-By: Claude Opus 4.8 --- desktopenvs/hyprdrive/station-bar/tray.py | 30 ++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/desktopenvs/hyprdrive/station-bar/tray.py b/desktopenvs/hyprdrive/station-bar/tray.py index c6d3b1f..a14dcd4 100644 --- a/desktopenvs/hyprdrive/station-bar/tray.py +++ b/desktopenvs/hyprdrive/station-bar/tray.py @@ -35,11 +35,20 @@ class TrayHost: self._on_watcher_appeared, self._on_watcher_vanished) def _on_watcher_appeared(self, _conn, _name, _owner) -> None: + # MUST be async: this bar hosts the StatusNotifierWatcher itself (see + # sni_watcher.py), so a *_sync proxy here would block the main loop + # waiting on a reply only that same loop can produce — a self-deadlock + # that freezes the whole bar (its clock, its holo intro — everything) + # until the 25s D-Bus timeout finally lets it go. + Gio.DBusProxy.new_for_bus( + Gio.BusType.SESSION, Gio.DBusProxyFlags.NONE, None, + _WATCHER_BUS, _WATCHER_PATH, _WATCHER_IFACE, None, + self._on_watcher_ready, None, + ) + + def _on_watcher_ready(self, _source, result, _user_data) -> None: try: - self._watcher = Gio.DBusProxy.new_for_bus_sync( - Gio.BusType.SESSION, Gio.DBusProxyFlags.NONE, None, - _WATCHER_BUS, _WATCHER_PATH, _WATCHER_IFACE, None, - ) + self._watcher = Gio.DBusProxy.new_for_bus_finish(result) except GLib.Error: self._watcher = None return @@ -56,14 +65,13 @@ class TrayHost: def _ensure_host_registered(self) -> None: if self._registered_host or self._watcher is None: return - try: - self._watcher.call_sync( - "RegisterStatusNotifierHost", GLib.Variant("(s)", (_HOST_NAME,)), - Gio.DBusCallFlags.NONE, 500, None, - ) - except GLib.Error: - pass + # Async for the same self-deadlock reason as _on_watcher_appeared: this + # call targets our own in-process watcher. Fire-and-forget. self._registered_host = True + self._watcher.call( + "RegisterStatusNotifierHost", GLib.Variant("(s)", (_HOST_NAME,)), + Gio.DBusCallFlags.NONE, 2000, None, None, + ) def available(self) -> bool: return self._watcher is not None