From 3f14512e5dbfdc1f14e1c110602fb095496d0593 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Tue, 24 Mar 2026 14:19:15 +0300 Subject: [PATCH] feat: add Restart and Shutdown tray actions with confirmation dialogs --- media_server/tray.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/media_server/tray.py b/media_server/tray.py index cb6ae7e..9cf6d08 100644 --- a/media_server/tray.py +++ b/media_server/tray.py @@ -4,6 +4,8 @@ import io import logging import os import signal +import subprocess +import sys import threading import webbrowser @@ -17,6 +19,26 @@ try: except ImportError: pystray = None +# tkinter is optional — used for confirmation dialogs +try: + import tkinter as tk + from tkinter import messagebox +except ImportError: + tk = None + messagebox = None + + +def _confirm(title: str, message: str) -> bool: + """Show a Yes/No confirmation dialog. Returns True if user clicks Yes.""" + if messagebox is None: + return True # No tkinter — skip confirmation + root = tk.Tk() + root.withdraw() + root.attributes("-topmost", True) + result = messagebox.askyesno(title, message, parent=root) + root.destroy() + return result + def _create_icon_image(size: int = 64) -> Image.Image: """Create a tray icon: green circle with white play triangle.""" @@ -75,16 +97,27 @@ def start_tray(host: str, port: int) -> "pystray.Icon | None": def on_show_ui(_icon, _item): webbrowser.open(url) + def on_restart(_icon, _item): + if not _confirm("Restart Media Server", "Are you sure you want to restart the server?"): + return + logger.info("Restart requested from tray") + _icon.stop() + # Re-launch the same process, then exit current + subprocess.Popen([sys.executable] + sys.argv) + os.kill(os.getpid(), signal.SIGINT) + def on_exit(_icon, _item): + if not _confirm("Exit Media Server", "Are you sure you want to shut down the server?"): + return logger.info("Exit requested from tray") _icon.stop() - # Signal the main process to shut down gracefully os.kill(os.getpid(), signal.SIGINT) menu = pystray.Menu( pystray.MenuItem("Show UI", on_show_ui, default=True), pystray.Menu.SEPARATOR, - pystray.MenuItem("Exit", on_exit), + pystray.MenuItem("Restart", on_restart), + pystray.MenuItem("Shutdown", on_exit), ) icon = pystray.Icon(