##// END OF EJS Templates
Download as always starts downloads in new window/tab...
Download as always starts downloads in new window/tab This is a slightly worse user experience if it succeeds, because the new tab flashes up before closing again, but it will let us display an informative error page if it fails, without navigating the user away from the interactive notebook view.

File last commit:

r11126:b337c5c3
r13838:19c6ee99
Show More
inputhookqt4.py
180 lines | 6.6 KiB | text/x-python | PythonLexer
Christian Boos
inputhook: move inputhook_qt4 related code in own file
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
#-----------------------------------------------------------------------------
Siyu Zhang
Changed sleep in signal thread to .01 sec. Moved imports to top.
r10352 import os
import signal
import threading
Christian Boos
inputhookqt4: use InteractiveShell.instance instead of get_ipython...
r5132 from IPython.core.interactiveshell import InteractiveShell
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 from IPython.external.qt_for_kernel import QtCore, QtGui
Christian Boos
inputhook: disable CTRL+C when a hook is active....
r4944 from IPython.lib.inputhook import allow_CTRL_C, ignore_CTRL_C, stdin_ready
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931
#-----------------------------------------------------------------------------
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 # Module Globals
#-----------------------------------------------------------------------------
got_kbdint = False
sigint_timer = None
#-----------------------------------------------------------------------------
Christian Boos
inputhook: move inputhook_qt4 related code in own file
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
-----
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936 We use a custom input hook instead of PyQt4's default one, as it
interacts better with the readline packages (issue #481).
Christian Boos
inputhook: move inputhook_qt4 related code in own file
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.
"""
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 if app is None:
app = QtCore.QCoreApplication.instance()
if app is None:
app = QtGui.QApplication([" "])
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936 # Re-use previously created inputhook if any
Christian Boos
inputhookqt4: use InteractiveShell.instance instead of get_ipython...
r5132 ip = InteractiveShell.instance()
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936 if hasattr(ip, '_inputhook_qt4'):
return app, ip._inputhook_qt4
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936 # Otherwise create the inputhook_qt4/preprompthook_qt4 pair of
# hooks (they both share the got_kbdint flag)
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931
def inputhook_qt4():
Christian Boos
inputhookqt4: polish the qt4 related hooks...
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.
"""
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 try:
Christian Boos
inputhook: disable CTRL+C when a hook is active....
r4944 allow_CTRL_C()
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936 app = QtCore.QCoreApplication.instance()
Christian Boos
inputhookqt4: make hook more robust in case of unexpected conditions...
r5180 if not app: # shouldn't happen, but safer if it happens anyway...
return 0
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
if not stdin_ready():
Bradley M. Froehle
inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication....
r8402 # Generally a program would run QCoreApplication::exec()
# from main() to enter and process the Qt event loop until
# quit() or exit() is called and the program terminates.
#
# For our input hook integration, we need to repeatedly
# enter and process the Qt event loop for only a short
# amount of time (say 50ms) to ensure that Python stays
# responsive to other user inputs.
#
# A naive approach would be to repeatedly call
# QCoreApplication::exec(), using a timer to quit after a
# short amount of time. Unfortunately, QCoreApplication
# emits an aboutToQuit signal before stopping, which has
# the undesirable effect of closing all modal windows.
#
# To work around this problem, we instead create a
# QEventLoop and call QEventLoop::exec(). Other than
# setting some state variables which do not seem to be
# used anywhere, the only thing QCoreApplication adds is
# the aboutToQuit signal which is precisely what we are
# trying to avoid.
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 timer = QtCore.QTimer()
Bradley M. Froehle
inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication....
r8402 event_loop = QtCore.QEventLoop()
timer.timeout.connect(event_loop.quit)
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 while not stdin_ready():
timer.start(50)
Bradley M. Froehle
inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication....
r8402 event_loop.exec_()
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 timer.stop()
except KeyboardInterrupt:
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 global got_kbdint, sigint_timer
Christian Boos
inputhook: disable CTRL+C when a hook is active....
r4944 ignore_CTRL_C()
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 got_kbdint = True
Christian Boos
inputhook: disable CTRL+C when a hook is active....
r4944 mgr.clear_inputhook()
Siyu Zhang
Added comments explaining the SIGINT timer
r10387
# 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).
Siyu Zhang
Workaround so only one CTRL-C is required for a new prompt in --gui=qt...
r10350 if(os.name == 'posix'):
pid = os.getpid()
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 if(not sigint_timer):
sigint_timer = threading.Timer(.01, os.kill,
Siyu Zhang
Added comments explaining the SIGINT timer
r10387 args=[pid, signal.SIGINT] )
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 sigint_timer.start()
Siyu Zhang
Workaround so only one CTRL-C is required for a new prompt in --gui=qt...
r10350 else:
print("\nKeyboardInterrupt - Ctrl-C again for new prompt")
Christian Boos
inputhookqt4: make hook more robust in case of unexpected conditions...
r5180 except: # NO exceptions are allowed to escape from a ctypes callback
MinRK
Don't ignore ctrl-C during normal execution in inputhook_qt4
r5741 ignore_CTRL_C()
Christian Boos
inputhookqt4: make hook more robust in case of unexpected conditions...
r5180 from traceback import print_exc
print_exc()
print("Got exception from inputhook_qt4, unregistering.")
Fernando Perez
Clear inputhook after printing exception information....
r5761 mgr.clear_inputhook()
MinRK
Don't ignore ctrl-C during normal execution in inputhook_qt4
r5741 finally:
allow_CTRL_C()
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 return 0
def preprompthook_qt4(ishell):
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936 """'pre_prompt_hook' used to restore the Qt4 input hook
(in case the latter was temporarily deactivated after a
CTRL+C)
"""
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 global got_kbdint, sigint_timer
if(sigint_timer):
sigint_timer.cancel()
sigint_timer = None
Siyu Zhang
keep track of the sigint timer, and cancel it on a new prompt
r10383
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 if got_kbdint:
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931 mgr.set_inputhook(inputhook_qt4)
Siyu Zhang
Made sigint_timer and got_kbdint module globals
r10405 got_kbdint = False
Christian Boos
inputhookqt4: polish the qt4 related hooks...
r4936
ip._inputhook_qt4 = inputhook_qt4
ip.set_hook('pre_prompt_hook', preprompthook_qt4)
Christian Boos
inputhook: move inputhook_qt4 related code in own file
r4931
return app, inputhook_qt4