diff --git a/monitor/batteryIcon.py b/monitor/batteryIcon.py index 63d7f91..01b6a53 100755 --- a/monitor/batteryIcon.py +++ b/monitor/batteryIcon.py @@ -108,14 +108,48 @@ def make_battery_icon(percent, charging): return QIcon(pix) +def tray_host_ready(): + """True once a StatusNotifier tray host is registered on the session bus. + + Queried over D-Bus directly instead of via + QSystemTrayIcon.isSystemTrayAvailable(): Qt caches that result from the + moment QApplication is constructed. At login the icon's autostart usually + wins the race against wf-panel-pi, so Qt caches "no tray" forever and the + icon never appears even after the panel's tray comes up. Checking the bus + directly dodges that cache -- we build QApplication only once the host is + actually present. + """ + try: + result = subprocess.run( + ["dbus-send", "--session", "--print-reply", + "--dest=org.freedesktop.DBus", "/org/freedesktop/DBus", + "org.freedesktop.DBus.NameHasOwner", + "string:org.kde.StatusNotifierWatcher"], + capture_output=True, text=True, timeout=5) + except (subprocess.SubprocessError, OSError): + return False + return "boolean true" in result.stdout + + +def wait_for_tray(timeout=180): + """Block until a tray host appears, so autostart survives a cold boot.""" + deadline = time.monotonic() + timeout + while not tray_host_ready(): + if time.monotonic() > deadline: + print(f"Tray host not available after {timeout}s", file=sys.stderr) + sys.exit(1) + time.sleep(2) + + class BatteryTray: def __init__(self): self.app = QApplication(sys.argv) self.app.setQuitOnLastWindowClosed(False) - # At login the panel may not have started its system tray yet. - # Wait for it instead of giving up, so autostart works after a reboot. - deadline = time.monotonic() + 120 + # wait_for_tray() already confirmed a tray host on the bus, so Qt now + # reports the tray correctly. Keep a short re-check as a guard against + # the host still finishing its own registration. + deadline = time.monotonic() + 60 while not QSystemTrayIcon.isSystemTrayAvailable(): if time.monotonic() > deadline: print("System tray not available after 120s", file=sys.stderr) @@ -208,6 +242,7 @@ class BatteryTray: def main(): + wait_for_tray() bt = BatteryTray() sys.exit(bt.run())