inputhookqt4.py
122 lines
| 4.2 KiB
| text/x-python
|
PythonLexer
|
r4931 | # -*- coding: utf-8 -*- | ||
""" | ||||
Qt4's inputhook support function | ||||
Author: Christian Boos | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
# Copyright (C) 2011 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
|
r5132 | from IPython.core.interactiveshell import InteractiveShell | ||
|
r4931 | from IPython.external.qt_for_kernel import QtCore, QtGui | ||
|
r4944 | from IPython.lib.inputhook import allow_CTRL_C, ignore_CTRL_C, stdin_ready | ||
|
r4931 | |||
#----------------------------------------------------------------------------- | ||||
# Code | ||||
#----------------------------------------------------------------------------- | ||||
def create_inputhook_qt4(mgr, app=None): | ||||
"""Create an input hook for running the Qt4 application event loop. | ||||
Parameters | ||||
---------- | ||||
mgr : an InputHookManager | ||||
app : Qt Application, optional. | ||||
Running application to use. If not given, we probe Qt for an | ||||
existing application object, and create a new one if none is found. | ||||
Returns | ||||
------- | ||||
A pair consisting of a Qt Application (either the one given or the | ||||
one found or created) and a inputhook. | ||||
Notes | ||||
----- | ||||
|
r4936 | We use a custom input hook instead of PyQt4's default one, as it | ||
interacts better with the readline packages (issue #481). | ||||
|
r4931 | The inputhook function works in tandem with a 'pre_prompt_hook' | ||
which automatically restores the hook as an inputhook in case the | ||||
latter has been temporarily disabled after having intercepted a | ||||
KeyboardInterrupt. | ||||
""" | ||||
|
r4936 | |||
|
r4931 | if app is None: | ||
app = QtCore.QCoreApplication.instance() | ||||
if app is None: | ||||
app = QtGui.QApplication([" "]) | ||||
|
r4936 | # Re-use previously created inputhook if any | ||
|
r5132 | ip = InteractiveShell.instance() | ||
|
r4936 | if hasattr(ip, '_inputhook_qt4'): | ||
return app, ip._inputhook_qt4 | ||||
|
r4931 | |||
|
r4936 | # Otherwise create the inputhook_qt4/preprompthook_qt4 pair of | ||
# hooks (they both share the got_kbdint flag) | ||||
|
r4931 | |||
got_kbdint = [False] | ||||
def inputhook_qt4(): | ||||
|
r4936 | """PyOS_InputHook python hook for Qt4. | ||
Process pending Qt events and if there's no pending keyboard | ||||
input, spend a short slice of time (50ms) running the Qt event | ||||
loop. | ||||
As a Python ctypes callback can't raise an exception, we catch | ||||
the KeyboardInterrupt and temporarily deactivate the hook, | ||||
which will let a *second* CTRL+C be processed normally and go | ||||
back to a clean prompt line. | ||||
""" | ||||
|
r4931 | try: | ||
|
r4944 | allow_CTRL_C() | ||
|
r4936 | app = QtCore.QCoreApplication.instance() | ||
|
r5180 | if not app: # shouldn't happen, but safer if it happens anyway... | ||
return 0 | ||||
|
r4931 | app.processEvents(QtCore.QEventLoop.AllEvents, 300) | ||
if not stdin_ready(): | ||||
timer = QtCore.QTimer() | ||||
timer.timeout.connect(app.quit) | ||||
while not stdin_ready(): | ||||
timer.start(50) | ||||
app.exec_() | ||||
timer.stop() | ||||
except KeyboardInterrupt: | ||||
|
r4944 | ignore_CTRL_C() | ||
|
r4931 | got_kbdint[0] = True | ||
|
r5743 | print("\nKeyboardInterrupt - Ctrl-C again for new prompt") | ||
|
r4944 | mgr.clear_inputhook() | ||
|
r5180 | except: # NO exceptions are allowed to escape from a ctypes callback | ||
|
r5741 | ignore_CTRL_C() | ||
|
r5180 | mgr.clear_inputhook() | ||
from traceback import print_exc | ||||
print_exc() | ||||
print("Got exception from inputhook_qt4, unregistering.") | ||||
|
r5741 | finally: | ||
allow_CTRL_C() | ||||
|
r4931 | return 0 | ||
def preprompthook_qt4(ishell): | ||||
|
r4936 | """'pre_prompt_hook' used to restore the Qt4 input hook | ||
(in case the latter was temporarily deactivated after a | ||||
CTRL+C) | ||||
""" | ||||
|
r4931 | if got_kbdint[0]: | ||
mgr.set_inputhook(inputhook_qt4) | ||||
|
r4932 | got_kbdint[0] = False | ||
|
r4936 | |||
ip._inputhook_qt4 = inputhook_qt4 | ||||
ip.set_hook('pre_prompt_hook', preprompthook_qt4) | ||||
|
r4931 | |||
return app, inputhook_qt4 | ||||