From 55129be9697868c906130c945d2bd27087654f2b 2013-04-29 23:19:35 From: Fernando Perez Date: 2013-04-29 23:19:35 Subject: [PATCH] Merge pull request #3219 from siyuz/ctrl-c_clear_line Workaround so only one CTRL-C is required for a new prompt in --gui=qt. --- diff --git a/IPython/lib/inputhookqt4.py b/IPython/lib/inputhookqt4.py index eae4f44..4770e0a 100644 --- a/IPython/lib/inputhookqt4.py +++ b/IPython/lib/inputhookqt4.py @@ -16,11 +16,23 @@ Author: Christian Boos # Imports #----------------------------------------------------------------------------- +import os +import signal +import time +import threading + from IPython.core.interactiveshell import InteractiveShell from IPython.external.qt_for_kernel import QtCore, QtGui from IPython.lib.inputhook import allow_CTRL_C, ignore_CTRL_C, stdin_ready #----------------------------------------------------------------------------- +# Module Globals +#----------------------------------------------------------------------------- + +got_kbdint = False +sigint_timer = None + +#----------------------------------------------------------------------------- # Code #----------------------------------------------------------------------------- @@ -64,8 +76,6 @@ def create_inputhook_qt4(mgr, app=None): # Otherwise create the inputhook_qt4/preprompthook_qt4 pair of # hooks (they both share the got_kbdint flag) - got_kbdint = [False] - def inputhook_qt4(): """PyOS_InputHook python hook for Qt4. @@ -114,10 +124,31 @@ def create_inputhook_qt4(mgr, app=None): event_loop.exec_() timer.stop() except KeyboardInterrupt: + global got_kbdint, sigint_timer + ignore_CTRL_C() - got_kbdint[0] = True - print("\nKeyboardInterrupt - Ctrl-C again for new prompt") + got_kbdint = True mgr.clear_inputhook() + + # This generates a second SIGINT so the user doesn't have to + # press CTRL+C twice to get a clean prompt. + # + # Since we can't catch the resulting KeyboardInterrupt here + # (because this is a ctypes callback), we use a timer to + # generate the SIGINT after we leave this callback. + # + # Unfortunately this doesn't work on Windows (SIGINT kills + # Python and CTRL_C_EVENT doesn't work). + if(os.name == 'posix'): + pid = os.getpid() + if(not sigint_timer): + sigint_timer = threading.Timer(.01, os.kill, + args=[pid, signal.SIGINT] ) + sigint_timer.start() + else: + print("\nKeyboardInterrupt - Ctrl-C again for new prompt") + + except: # NO exceptions are allowed to escape from a ctypes callback ignore_CTRL_C() from traceback import print_exc @@ -134,9 +165,15 @@ def create_inputhook_qt4(mgr, app=None): (in case the latter was temporarily deactivated after a CTRL+C) """ - if got_kbdint[0]: + global got_kbdint, sigint_timer + + if(sigint_timer): + sigint_timer.cancel() + sigint_timer = None + + if got_kbdint: mgr.set_inputhook(inputhook_qt4) - got_kbdint[0] = False + got_kbdint = False ip._inputhook_qt4 = inputhook_qt4 ip.set_hook('pre_prompt_hook', preprompthook_qt4)