SerenaDashboardViewer: Attempt to fix tray on macOS (cannot run in background thread)

This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-03-28 11:37:54 +01:00
1 parent 971e2a5d28
commit 1a4e57eec7
1 file changed
+21 -7
+21 -7
View File
@@ -709,7 +709,7 @@ class SerenaDashboardViewer:
self._quitting = False
def run(self) -> None:
# Set app id (avoid app being lumped together with other Python-based apps in Windows taskbar)
# set app id (avoid app being lumped together with other Python-based apps in Windows taskbar)
if sys.platform == "win32":
import ctypes
@@ -732,6 +732,9 @@ class SerenaDashboardViewer:
if self.tray:
self.window.events.closing += self._on_closing
if self.tray:
self._start_tray()
def _start_callback():
if self.start_minimized:
self.window.minimize()
@@ -739,9 +742,6 @@ class SerenaDashboardViewer:
self.window.show()
self.window.restore()
if self.tray:
threading.Thread(target=self._run_tray, daemon=True).start()
webview.start(_start_callback, icon=icon_path)
def _on_closing(self) -> bool:
@@ -752,7 +752,7 @@ class SerenaDashboardViewer:
self.window.hide()
return False # Prevent the window from actually closing
def _run_tray(self) -> None:
def _start_tray(self) -> None:
dashboard_path = Path(SERENA_DASHBOARD_DIR)
icon_path = dashboard_path / "serena-icon-48.png"
@@ -781,5 +781,19 @@ class SerenaDashboardViewer:
Item("Quit", quit_app),
)
self._tray_icon = pystray.Icon("dashboard_viewer", icon_img, self.title, menu)
self._tray_icon.run()
kwargs = {}
if sys.platform == "darwin":
# Passing darwin_nsapplication integrates pystray with the NSApplication
# run loop that webview.start() is about to enter. sharedApplication()
# is idempotent; pywebview will reuse the same singleton.
from AppKit import NSApplication
kwargs["darwin_nsapplication"] = NSApplication.sharedApplication()
self._tray_icon = pystray.Icon("dashboard_viewer", icon_img, self.title, menu, **kwargs)
# On Windows/Linux, run_detached spawns pystray's own internal thread and
# returns immediately. On macOS it hooks into the NSApplication run loop
# that webview.start() is about to enter (run_detached is always called
# before webview.start() on macOS — see run()).
self._tray_icon.run_detached()