From 3aec843bbb91a7d00f7bd7784e92bd97e3ee8a5f Mon Sep 17 00:00:00 2001 From: EvilGrinUK Date: Tue, 21 Jul 2026 07:14:46 +0100 Subject: [PATCH] Fix UI freeze during maintenance reloads on Wayland/Linux (#1114) --- gui.py | 16 +++++++++++++--- main.py | 6 ++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/gui.py b/gui.py index 8834068..b95ac61 100644 --- a/gui.py +++ b/gui.py @@ -2407,15 +2407,25 @@ class GUIManager: 0.05s gives similar performance and CPU usage. Not ideal, but the simplest way to avoid threads, thread safety, loop.call_soon_threadsafe, futures and all of that. + + Uses TKINTER_DONT_WAIT to prevent Tcl/Tk from hanging inside native + system calls (e.g. X11/Wayland input contexts) during heavy UI redraws. """ - update = self._root.update + do_one_event = self._root.dooneevent + # TKINTER_DONT_WAIT (1 << 1) tells Tcl to return immediately + # if no events are ready in the queue. + DONT_WAIT = 1 << 1 + while True: try: - update() + # Drain pending Tk events non-blockingly + while do_one_event(DONT_WAIT): + pass except tk.TclError: - # root has been destroyed + # Root window was destroyed break await asyncio.sleep(0.05) + self._poll_task = None def close(self, *args) -> int: diff --git a/main.py b/main.py index d924f34..dc62829 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ from multiprocessing import freeze_support if __name__ == "__main__": freeze_support() import io + import os import sys import signal import asyncio @@ -40,6 +41,11 @@ if __name__ == "__main__": if sys.version_info < (3, 10): raise RuntimeError("Python 3.10 or higher is required") + # Suppress X11 Input Method registration on Linux to prevent + # XWayland/Mutter lockups during heavy Tkinter layout updates. + if sys.platform.startswith("linux") and "XMODIFIERS" not in os.environ: + os.environ["XMODIFIERS"] = "@im=none" + class Parser(argparse.ArgumentParser): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs)