Fix UI freeze during maintenance reloads on Wayland/Linux (#1114)

This commit is contained in:
EvilGrinUK authored and GitHub committed 2026-07-21 08:14:46 +02:00
1 parent 866663c0b1
commit 3aec843bbb
2 files changed
+19 -3

No files matched your search

+13 -3
View File
@@ -2407,15 +2407,25 @@ class GUIManager:
0.05s gives similar performance and CPU usage. 0.05s gives similar performance and CPU usage.
Not ideal, but the simplest way to avoid threads, thread safety, Not ideal, but the simplest way to avoid threads, thread safety,
loop.call_soon_threadsafe, futures and all of that. 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: while True:
try: try:
update() # Drain pending Tk events non-blockingly
while do_one_event(DONT_WAIT):
pass
except tk.TclError: except tk.TclError:
# root has been destroyed # Root window was destroyed
break break
await asyncio.sleep(0.05) await asyncio.sleep(0.05)
self._poll_task = None self._poll_task = None
def close(self, *args) -> int: def close(self, *args) -> int:
+6
View File
@@ -7,6 +7,7 @@ from multiprocessing import freeze_support
if __name__ == "__main__": if __name__ == "__main__":
freeze_support() freeze_support()
import io import io
import os
import sys import sys
import signal import signal
import asyncio import asyncio
@@ -40,6 +41,11 @@ if __name__ == "__main__":
if sys.version_info < (3, 10): if sys.version_info < (3, 10):
raise RuntimeError("Python 3.10 or higher is required") 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): class Parser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs) -> None: def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)