Add custom icon and tray-minimize behavior (like VersaGUI's TrayApp)
Minimizing or closing hides the window instead of leaving a taskbar entry; only "Beenden" in the tray right-click menu really exits. Tray callbacks route through a queue instead of touching Tk directly from pystray's thread (same pattern as the earlier serial-thread fix). Also fixes the build script: PyInstaller failed on the network share while copying Tcl/Tk tzdata (path-length issue), so building now happens in a local temp copy instead of directly on Z:. Adds an info button that explains the MCP server's available tools.
This commit is contained in:
parent
e456af7c19
commit
4ac29a3e5c
6 changed files with 208 additions and 25 deletions
61
AGENTS.md
61
AGENTS.md
|
|
@ -116,30 +116,63 @@ zuverlässig zur echten Python313-Installation auf.
|
|||
|
||||
## Gepackte .exe (PyInstaller) — kein Terminal-Flash, kein Python-Setup nötig
|
||||
|
||||
`build_and_deploy.ps1` baut `desktop_viewer.py` mit PyInstaller
|
||||
(`--windowed --onedir`) und kopiert das Ergebnis lokal nach
|
||||
`%LOCALAPPDATA%\VersaPadViewer\VersaPadViewer.exe`. Desktop-Verknüpfung
|
||||
"VersaPad Viewer (Fenster)" zeigt dorthin.
|
||||
`build_and_deploy.ps1` kopiert den Quellcode zuerst nach `%TEMP%`, baut dort
|
||||
mit PyInstaller (`--windowed --onedir --icon icon.ico`), und kopiert das
|
||||
Ergebnis nach `%LOCALAPPDATA%\VersaPadViewer\VersaPadViewer.exe`.
|
||||
Desktop-Verknüpfung "VersaPad Viewer (Fenster)" zeigt dorthin (inkl. eigenem
|
||||
Icon, `IconLocation` zeigt auf die `.exe` selbst statt auf `pythonw.exe`).
|
||||
|
||||
**`--onedir`, nicht `--onefile`** — Single-File-PyInstaller-Bundles lösen
|
||||
öfter AV-Fehlalarme aus (sehen strukturell wie ein Packer aus); `--onedir`
|
||||
(Ordner mit `.exe` + `_internal`) ist unauffälliger. Trotzdem unsigniert,
|
||||
also grundsätzlich nie über Smart App Control/AV in Stein gemeißelt sicher.
|
||||
|
||||
**Kritischer Stolperstein:** Die gebaute `.exe` läuft NICHT vom Netzlaufwerk
|
||||
aus (`Z:\Git\...`, SMB-Share auf cj-ki) — Windows blockiert das Nachladen
|
||||
der `_internal`-DLLs von einem Netzwerkpfad, der Prozess startet dann
|
||||
einfach nie, ganz ohne Fehlermeldung/Crash-Log/AV-Benachrichtigung (sah
|
||||
zuerst wie ein AV-Block aus, war aber keiner — sauber verifiziert indem
|
||||
dieselbe `.exe` 1:1 lokal kopiert sofort lief). Bauen darf auf Z: passieren,
|
||||
das fertige Bundle muss vor dem Start nach C: kopiert werden — genau das
|
||||
macht `build_and_deploy.ps1`.
|
||||
**Zwei Netzlaufwerk-Stolpersteine, deshalb baut UND deployt alles lokal:**
|
||||
1. Laufzeit: die gebaute `.exe` läuft NICHT vom Netzlaufwerk aus (`Z:\Git\...`,
|
||||
SMB-Share auf cj-ki) — Windows blockiert das Nachladen der
|
||||
`_internal`-DLLs von einem Netzwerkpfad, der Prozess startet dann einfach
|
||||
nie, ganz ohne Fehlermeldung/Crash-Log/AV-Benachrichtigung (sah zuerst wie
|
||||
ein AV-Block aus, war aber keiner — verifiziert indem dieselbe `.exe` 1:1
|
||||
lokal kopiert sofort lief).
|
||||
2. Buildzeit: PyInstaller scheitert beim Kopieren der Tcl/Tk-`tzdata`
|
||||
(viele tief verschachtelte, lang benannte Zeitzonen-Ordner) auf dem
|
||||
SMB-Share mit `FileNotFoundError: [WinError 3]` — Pfadlängen-Problem,
|
||||
kombiniert mit dem eh schon langen Projektpfad (`Z:\Git\Versa Board\
|
||||
versapad-viewer\dist\...`).
|
||||
|
||||
Deshalb kopiert `build_and_deploy.ps1` den Quellcode zuerst nach `%TEMP%`
|
||||
und baut NUR dort — Z: wird nur zum Lesen der `.py`-Dateien angefasst.
|
||||
|
||||
Bei erneutem Bauen: `.\build_and_deploy.ps1` in PowerShell ausführen
|
||||
(lokal, nicht über die sandboxed Bash-Tool-Umgebung — die hat eine eigene
|
||||
Dateisystem-Sicht, die nicht zuverlässig mit dem echten Windows-Dateisystem
|
||||
übereinstimmt; Kopieroperationen für Dinge, die der User/andere Prozesse
|
||||
sehen sollen, gehören in PowerShell, nicht in Bash).
|
||||
übereinstimmt; siehe Sessionlog: ein `cp -r` über Bash landete an einem Ort,
|
||||
den PowerShell/der reale Explorer nicht sah. Kopieroperationen für Dinge,
|
||||
die der User/andere Prozesse sehen sollen, gehören in PowerShell, nicht in
|
||||
Bash).
|
||||
|
||||
## Icon + Tray (kein Taskleisten-Eintrag beim Minimieren, wie VersaGUI)
|
||||
|
||||
- `icon.png`/`icon.ico` — generiert via Pillow (dunkles abgerundetes Quadrat,
|
||||
blauer Block, 2x2-Punktraster; flaches Design, keine Farbverläufe/
|
||||
Anti-Aliasing-Details, siehe Speicher-Notiz zu Tkinter-Flat-Design).
|
||||
`.ico` fürs Fenster-/Taskleisten-/Exe-Icon, `.png` fürs Tray-Icon (pystray
|
||||
braucht ein PIL-Image, kein Multi-Res-`.ico`).
|
||||
- `resource_path()` in `desktop_viewer.py` findet Assets sowohl im
|
||||
Quellordner als auch im PyInstaller-Bundle (`sys._MEIPASS`).
|
||||
- Minimieren (`<Unmap>` mit `state()=='iconic'`) ruft `withdraw()` statt
|
||||
normal zu minimieren → kein Taskleisten-Eintrag, nur noch Tray-Icon.
|
||||
Schließen (X) macht dasselbe (`_hide_to_tray`, nicht `_quit`) — echtes
|
||||
Beenden nur über "Beenden" im Tray-Rechtsklickmenü (mirrort VersaGUIs
|
||||
`TrayApp`-Menü: Öffnen/Beenden). Tray-Icon läuft über `pystray.Icon.
|
||||
run_detached()` in eigenem Thread — Klicks im Tray-Menü legen nur ein
|
||||
Ereignis in `self._tray_queue`, das der Main-Thread per `after()`-Polling
|
||||
abholt (dieselbe Queue-statt-Direktzugriff-Regel wie beim Serial-Thread,
|
||||
siehe oben — Tk-Aufrufe aus einem Fremdthread haben schon mal einen
|
||||
stillen Absturz verursacht).
|
||||
- Neue Abhängigkeiten: `pystray`, `pillow` (zusätzlich zu `pyserial`).
|
||||
- Info-Button (ⓘ oben rechts im Header) öffnet einen Dialog mit der
|
||||
MCP-Server-Doku (`MCP_INFO_TEXT`-Konstante) — rein informativ, keine Logik.
|
||||
|
||||
## Dateien/Pfade (hardcoded, hal9001-spezifisch)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue