"""pystray adapter for the Windows tray and macOS menu bar.""" from io import BytesIO from PIL import Image from pystray import Icon, Menu, MenuItem from free_claude_code.cli.desktop import DesktopController, launch_desktop from free_claude_code.cli.desktop_assets import app_icon_bytes class PystrayDesktopTray: """Render desktop lifecycle actions through the native status area.""" def __init__(self, controller: DesktopController) -> None: self._controller = controller self._icon = Icon( "free-claude-code", _create_icon(), "Free Claude Code", Menu( MenuItem("Open Admin", self._open_admin, default=True), MenuItem("Check Server Status", self._check_status), MenuItem("Restart Server", self._restart_server), Menu.SEPARATOR, MenuItem("Quit", self._quit), ), ) def run(self) -> None: self._icon.run() def stop(self) -> None: self._icon.stop() def _open_admin(self, _icon: Icon, _item: MenuItem) -> None: self._controller.open_admin() def _check_status(self, _icon: Icon, _item: MenuItem) -> None: self._icon.notify( f"Server is {self._controller.status}.", "Free Claude Code", ) def _restart_server(self, _icon: Icon, _item: MenuItem) -> None: self._controller.restart_server() def _quit(self, _icon: Icon, _item: MenuItem) -> None: self._controller.quit() def _create_icon() -> Image.Image: """Load the same branded artwork used by native desktop launchers.""" with Image.open(BytesIO(app_icon_bytes(".png"))) as image: return image.convert("RGBA") def launch() -> None: """Launch the supported native tray adapter.""" launch_desktop(PystrayDesktopTray)