fix(station-bar): make SNI watcher D-Bus calls async (self-deadlock)

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 <noreply@anthropic.com>
main
Amir Alexander Abdelbaki 2026-07-21 20:52:32 +02:00
parent 4da704cb5d
commit 057a5a44d8
1 changed files with 19 additions and 11 deletions

View File

@ -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