shin / src /free_claude_code /cli /desktop_tray.py
LastNoob's picture
Add a native Free Claude Code app icon (#1252)
1bfa806 unverified
Raw
History Blame Contribute Delete
1.88 kB
"""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)