From 6c91db7162ccc1e79e0d6fb3c99b89d88ee896a2 Mon Sep 17 00:00:00 2001 From: Mistercarmi Date: Thu, 21 May 2026 21:33:53 +0200 Subject: [PATCH] =?UTF-8?q?v0.3.1=20=E2=80=94=20fix=20freeze=20UI=20d?= =?UTF-8?q?=C3=BB=20au=20polling=20PZ=20synchrone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le poll PZ (tasklist toutes les 15 s) tournait sur le main thread tkinter. Sur les PC où tasklist est lent (antivirus, beaucoup de process), l'UI freezait plusieurs secondes à chaque tick. is_pz_running() est maintenant exécuté dans un thread daemon ; le résultat est marshalé sur le main thread via self.after(0, ...). Co-Authored-By: Claude Opus 4.7 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- CHANGELOG.md | 10 +++++++++ docs/release_notes_v0.3.1.md | 28 ++++++++++++++++++++++++++ src/pzsavesync/gui.py | 29 ++++++++++++++++++--------- 4 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 docs/release_notes_v0.3.1.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e276b90..6ca1968 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -14,7 +14,7 @@ body: attributes: label: Version de PZ SaveSync description: Affichée en bas à gauche de la fenêtre - placeholder: "ex. v0.3.0" + placeholder: "ex. v0.3.1" validations: required: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 4294ed5..8a6792f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/), versioning sémantique ([SemVer](https://semver.org/lang/fr/)). +## [0.3.1] — 2026-05-21 + +### Fixed +- **Freeze UI à chaque clic sur certains PC** : le polling de Project Zomboid + (toutes les 15 s) appelait `tasklist` de manière synchrone sur le thread UI. + Sur les PC où `tasklist` est lent (antivirus actif, beaucoup de process), ça + bloquait l'interface plusieurs secondes à chaque tick. Le poll s'exécute + maintenant dans un thread daemon, et le résultat est marshalé sur le main + thread via `self.after(0, ...)`. + ## [0.3.0] — 2026-05-21 ### Added — Distribution & dev experience diff --git a/docs/release_notes_v0.3.1.md b/docs/release_notes_v0.3.1.md new file mode 100644 index 0000000..ff71255 --- /dev/null +++ b/docs/release_notes_v0.3.1.md @@ -0,0 +1,28 @@ +## 🩹 PZ SaveSync v0.3.1 — Hotfix anti-freeze + +Patch ciblé sur un bug remonté en early testing : sur certains PC, l'interface freezait plusieurs secondes à chaque interaction. + +### 📥 Installation rapide + +Télécharge **`PZSaveSync.exe`** ci-dessous, double-clique pour remplacer ton ancienne version. Ta config et tes profils sont conservés. + +> ℹ️ Windows SmartScreen affichera un avertissement « éditeur inconnu » au premier lancement (exe non signé). Clique sur **« Informations complémentaires » → « Exécuter quand même »**. + +### 🐛 Corrigé + +- **Freeze UI à chaque clic** sur certains setups. Le polling du process Project Zomboid (toutes les 15 s pour détecter quand tu fermes le jeu) appelait `tasklist` de manière synchrone sur le thread UI. Sur les PC où `tasklist` est lent à répondre (antivirus actif inspectant le call, beaucoup de process ouverts), ça bloquait l'interface plusieurs secondes à chaque tick — et la sensation était « ça freeze à chaque clic ». + + Le poll s'exécute maintenant dans un **thread daemon séparé**, et le résultat est marshalé sur le main thread via `self.after(0, ...)`. Plus aucun blocage UI dû au polling. + +### 🔧 Migration depuis v0.3.0 + +- **Aucune action requise.** Drop-in replacement du `.exe`. Config, profils et historique des versions préservés. + +### 🧪 Tests + +- Tous les tests existants (45 unitaires + 2 intégration) passent. +- Build PyInstaller : `.exe` final ~21 MB. + +### 📜 Licence + +Source Available — Tous droits réservés. Voir [LICENSE](https://github.com/Mistercarmi/PZSaveSync/blob/main/LICENSE). diff --git a/src/pzsavesync/gui.py b/src/pzsavesync/gui.py index 18f5459..efdbf83 100644 --- a/src/pzsavesync/gui.py +++ b/src/pzsavesync/gui.py @@ -4,6 +4,7 @@ import os import platform import subprocess +import threading from pathlib import Path from tkinter import filedialog, messagebox @@ -84,7 +85,7 @@ def _open_path(path: Path | str) -> None: ACTION_DANGER = "#b24545" # rouge, attention ACTION_RELEASE = "#7a5a3a" # brun chaud (libérer un verrou — sobre, pas dangereux) -APP_VERSION = "0.3.0" +APP_VERSION = "0.3.1" _AppBase = (ctk.CTk, TkinterDnD.DnDWrapper) if _DND_AVAILABLE else (ctk.CTk,) @@ -1996,21 +1997,32 @@ def _schedule_pz_poll(self): self.after(15000, self._poll_pz) def _poll_pz(self): - try: - running, _ = pz_detector.is_pz_running() - except Exception: - running = False + # On exécute is_pz_running() dans un thread daemon : sur certains PC + # (antivirus actif, beaucoup de process) tasklist peut prendre plusieurs + # secondes et bloquerait sinon le main thread → freeze UI à chaque poll. + def worker(): + try: + running, _ = pz_detector.is_pz_running() + except Exception: + running = False + try: + self.after(0, self._handle_pz_poll_result, running) + except Exception: + pass + + threading.Thread(target=worker, daemon=True).start() + # Re-scheduler indépendamment du résultat + self.after(15000, self._poll_pz) + def _handle_pz_poll_result(self, running: bool): if running: self._pz_was_running = True - # MAJ footer pour indiquer qu'on voit PZ if hasattr(self, "footer_pz_status"): self.footer_pz_status.configure( text="🎮 PZ détecté", text_color=COLOR_OK, ) else: if self._pz_was_running and self.cfg.save_name: - # Transition running → stopped : propose un push self._pz_was_running = False if hasattr(self, "footer_pz_status"): self.footer_pz_status.configure(text="", text_color=COLOR_TEXT_DIM) @@ -2018,9 +2030,6 @@ def _poll_pz(self): elif hasattr(self, "footer_pz_status"): self.footer_pz_status.configure(text="", text_color=COLOR_TEXT_DIM) - # Re-scheduler - self.after(15000, self._poll_pz) - def _prompt_push_after_pz_close(self): if not self.cfg.save_name: return