From 1a0e7dc79360e2aeb25ecac8418d23f54b3afc9b Mon Sep 17 00:00:00 2001 From: Martin Dybdal Date: Mon, 22 Feb 2021 16:13:35 +0100 Subject: [PATCH] Handle CTRL-C interrupts from terminal, to shutdown Mu gracefully --- mu/app.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/mu/app.py b/mu/app.py index cf9d02859..70baa4b35 100644 --- a/mu/app.py +++ b/mu/app.py @@ -24,6 +24,7 @@ import os import platform import sys +import signal from PyQt5.QtCore import ( Qt, @@ -31,6 +32,7 @@ QThread, QObject, pyqtSignal, + QTimer, ) from PyQt5.QtWidgets import QApplication, QSplashScreen @@ -108,6 +110,41 @@ def excepthook(*exc_args): sys.exit(1) +# The following function handles a problem with using CTRL+C +# in terminal to terminate Qt applications. +# From: +# https://coldfix.eu/2016/11/08/pyqt-boilerplate/#keyboardinterrupt-ctrl-c +def setup_interrupt_handling(editor_quit): + """Setup handling of KeyboardInterrupt (Ctrl-C) for PyQt.""" + + # Define this as a global function to make sure it is not garbage + # collected when going out of scope: + global _interrupt_handler + + def _interrupt_handler(signum, frame): + """Handle KeyboardInterrupt: quit application.""" + editor_quit() + + def safe_timer(timeout, func, *args, **kwargs): + """ + Create a timer that is safe against garbage collection and overlapping + calls. See: http://ralsina.me/weblog/posts/BB974.html + """ + + def timer_event(): + try: + func(*args, **kwargs) + finally: + QTimer.singleShot(timeout, timer_event) + + QTimer.singleShot(timeout, timer_event) + + signal.signal(signal.SIGINT, _interrupt_handler) + # Regularly run some (any) python code, so the signal handler gets a + # chance to be executed: + safe_timer(50, lambda: None) + + def setup_logging(): """ Configure logging. @@ -253,6 +290,9 @@ def load_theme(theme): editor_window.connect_toggle_comments(editor.toggle_comments, "Ctrl+K") editor.connect_to_status_bar(editor_window.status_bar) + # Make CTRL-C quit Mu + setup_interrupt_handling(editor.quit) + # Restore the previous session along with files passed by the os editor.restore_session(sys.argv[1:])