From d8abcc4ccae97b34536e6d14ca8fdac178046da8 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Thu, 9 Oct 2025 19:49:24 -0400 Subject: [PATCH] Fix the hang on exit for real this time. The other fix was just a practice run. --- Toby Doom Launcher.py | 58 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/Toby Doom Launcher.py b/Toby Doom Launcher.py index b3a97e0..3990d73 100755 --- a/Toby Doom Launcher.py +++ b/Toby Doom Launcher.py @@ -942,18 +942,32 @@ class DoomLauncher(QMainWindow): self.speechHandler = SpeechHandler(self.configFile) self.iwadSelector = IWADSelector() # Add IWAD selector self.gameProcess = None # Track running game process + self.isQuitting = False # Track if we're already quitting self.init_launcher_ui() def closeEvent(self, event): """Handle application close event""" + if self.isQuitting: + event.accept() + return + + self.isQuitting = True + # Terminate any running game process if self.gameProcess and self.gameProcess.poll() is None: try: self.gameProcess.terminate() self.gameProcess.wait(timeout=2) except: - self.gameProcess.kill() + try: + self.gameProcess.kill() + self.gameProcess.wait(timeout=1) + except: + pass + event.accept() + # Force quit after accepting the event + QApplication.instance().quit() def check_and_fix_controls(self): """Check and fix control bindings in GZDoom configuration for all game types.""" @@ -3145,8 +3159,25 @@ class DoomLauncher(QMainWindow): def monitor_game_process(self, process): """Monitor game process and exit when it's done""" - process.wait() # Wait for the game to finish - QApplication.instance().quit() # Quit the application + try: + # Poll instead of blocking to allow interruption + while process.poll() is None and not self.isQuitting: + import time + time.sleep(0.1) # Check every 100ms + except: + pass # If interrupted or error, just exit + finally: + # Game has finished, quit the application if not already quitting + if not self.isQuitting: + try: + self.isQuitting = True + print("Game finished, exiting launcher...") + sys.stdout.flush() + # Force exit immediately + import os + os._exit(0) + except: + pass # Application might already be quitting def get_flags_from_file(self) -> List[str]: """Read additional launch flags from doom_flags.txt""" @@ -3280,14 +3311,27 @@ if __name__ == "__main__": TOBY_VERSION: Final[str] = f"{int(TOBY_VERSION_NUMBER)}-{int(TOBY_VERSION_NUMBER * 10 % 10)}" setproctitle("Toby Doom Launcher") + app = QApplication(sys.argv) + # Set up signal handling for clean shutdown import signal + import os + def signal_handler(sig, frame): - QApplication.quit() - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) + print("\nReceived signal, exiting...") + sys.stdout.flush() + # Force exit immediately + os._exit(0) + + signal.signal(signal.SIGINT, signal_handler) # Ctrl+C + signal.signal(signal.SIGTERM, signal_handler) # Termination signal + signal.signal(signal.SIGQUIT, signal_handler) # Ctrl+\ - prevents core dump + + # Also use a timer as backup + timer = QTimer() + timer.timeout.connect(lambda: None) # Just wake up periodically + timer.start(100) # Every 100ms - app = QApplication(sys.argv) window = DoomLauncher() window.show() sys.exit(app.exec())