Fix battery tray icon vanishing after boot
The wait loop polled QSystemTrayIcon.isSystemTrayAvailable(), but Qt5 caches that value from the moment QApplication is constructed. At login the autostart wins the race against wf-panel-pi's tray, so Qt caches "no tray" permanently, the loop never escapes, and the process hangs until the 120s timeout and exits. Add wait_for_tray(), which polls the session bus directly (dbus-send NameHasOwner for org.kde.StatusNotifierWatcher) before QApplication is constructed, so Qt reports the tray correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -108,14 +108,48 @@ def make_battery_icon(percent, charging):
|
|||||||
return QIcon(pix)
|
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:
|
class BatteryTray:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.app = QApplication(sys.argv)
|
self.app = QApplication(sys.argv)
|
||||||
self.app.setQuitOnLastWindowClosed(False)
|
self.app.setQuitOnLastWindowClosed(False)
|
||||||
|
|
||||||
# At login the panel may not have started its system tray yet.
|
# wait_for_tray() already confirmed a tray host on the bus, so Qt now
|
||||||
# Wait for it instead of giving up, so autostart works after a reboot.
|
# reports the tray correctly. Keep a short re-check as a guard against
|
||||||
deadline = time.monotonic() + 120
|
# the host still finishing its own registration.
|
||||||
|
deadline = time.monotonic() + 60
|
||||||
while not QSystemTrayIcon.isSystemTrayAvailable():
|
while not QSystemTrayIcon.isSystemTrayAvailable():
|
||||||
if time.monotonic() > deadline:
|
if time.monotonic() > deadline:
|
||||||
print("System tray not available after 120s", file=sys.stderr)
|
print("System tray not available after 120s", file=sys.stderr)
|
||||||
@@ -208,6 +242,7 @@ class BatteryTray:
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
wait_for_tray()
|
||||||
bt = BatteryTray()
|
bt = BatteryTray()
|
||||||
sys.exit(bt.run())
|
sys.exit(bt.run())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user