fix(tray): replace tkinter messagebox with Win32 MessageBoxW
Lint & Test / test (push) Successful in 2m3s
Lint & Test / test (push) Successful in 2m3s
The packaged embedded Python distribution does not ship the tcl/tk runtime, so tkinter.messagebox.askyesno crashed with 'Can't find a usable init.tcl' when the user clicked Shutdown or Restart in the tray menu. Use ctypes + user32.MessageBoxW instead — no tcl/tk, no extra dependencies.
This commit is contained in:
@@ -4,9 +4,32 @@ import os
|
||||
import sys
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
from tkinter import messagebox
|
||||
from typing import Callable
|
||||
|
||||
|
||||
def _confirm(message: str, title: str = "LED Grab") -> bool:
|
||||
"""Show a Yes/No confirmation dialog using the Win32 API.
|
||||
|
||||
Uses ``ctypes`` instead of ``tkinter.messagebox`` because the packaged
|
||||
embedded Python distribution does not include the tcl/tk runtime, which
|
||||
causes ``tkinter`` to fail with ``Can't find a usable init.tcl``.
|
||||
"""
|
||||
if sys.platform != "win32":
|
||||
# Non-Windows: no tray in practice, but fall back to auto-confirm.
|
||||
return True
|
||||
try:
|
||||
import ctypes
|
||||
|
||||
# MB_YESNO = 0x04, MB_ICONQUESTION = 0x20, MB_SETFOREGROUND = 0x10000
|
||||
# IDYES = 6
|
||||
flags = 0x04 | 0x20 | 0x10000
|
||||
result = ctypes.windll.user32.MessageBoxW(0, message, title, flags)
|
||||
return result == 6
|
||||
except Exception:
|
||||
# If the dialog cannot be shown for any reason, proceed with the action.
|
||||
return True
|
||||
|
||||
|
||||
try:
|
||||
import pystray
|
||||
from PIL import Image
|
||||
@@ -60,9 +83,10 @@ class TrayManager:
|
||||
webbrowser.open(f"http://localhost:{self._port}")
|
||||
|
||||
def _restart(self, icon: "pystray.Icon", item: "pystray.MenuItem") -> None:
|
||||
if not messagebox.askyesno("LED Grab", "Restart the server?"):
|
||||
if not _confirm("Restart the server?"):
|
||||
return
|
||||
from wled_controller.server_ref import _broadcast_restarting
|
||||
|
||||
_broadcast_restarting()
|
||||
self._icon.stop()
|
||||
self._on_exit()
|
||||
@@ -70,7 +94,7 @@ class TrayManager:
|
||||
os.execv(sys.executable, [sys.executable, "-m", "wled_controller"])
|
||||
|
||||
def _shutdown(self, icon: "pystray.Icon", item: "pystray.MenuItem") -> None:
|
||||
if not messagebox.askyesno("LED Grab", "Shut down the server?"):
|
||||
if not _confirm("Shut down the server?"):
|
||||
return
|
||||
self._on_exit()
|
||||
self._icon.stop()
|
||||
|
||||
Reference in New Issue
Block a user