##// END OF EJS Templates
Changed sleep in signal thread to .01 sec. Moved imports to top.
Siyu Zhang -
Show More
@@ -1,158 +1,162
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Qt4's inputhook support function
4 4
5 5 Author: Christian Boos
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 import os
20 import signal
21 import time
22 import threading
23
19 24 from IPython.core.interactiveshell import InteractiveShell
20 25 from IPython.external.qt_for_kernel import QtCore, QtGui
21 26 from IPython.lib.inputhook import allow_CTRL_C, ignore_CTRL_C, stdin_ready
22 27
23 28 #-----------------------------------------------------------------------------
24 29 # Code
25 30 #-----------------------------------------------------------------------------
26 31
27 32 def create_inputhook_qt4(mgr, app=None):
28 33 """Create an input hook for running the Qt4 application event loop.
29 34
30 35 Parameters
31 36 ----------
32 37 mgr : an InputHookManager
33 38
34 39 app : Qt Application, optional.
35 40 Running application to use. If not given, we probe Qt for an
36 41 existing application object, and create a new one if none is found.
37 42
38 43 Returns
39 44 -------
40 45 A pair consisting of a Qt Application (either the one given or the
41 46 one found or created) and a inputhook.
42 47
43 48 Notes
44 49 -----
45 50 We use a custom input hook instead of PyQt4's default one, as it
46 51 interacts better with the readline packages (issue #481).
47 52
48 53 The inputhook function works in tandem with a 'pre_prompt_hook'
49 54 which automatically restores the hook as an inputhook in case the
50 55 latter has been temporarily disabled after having intercepted a
51 56 KeyboardInterrupt.
52 57 """
53 58
54 59 if app is None:
55 60 app = QtCore.QCoreApplication.instance()
56 61 if app is None:
57 62 app = QtGui.QApplication([" "])
58 63
59 64 # Re-use previously created inputhook if any
60 65 ip = InteractiveShell.instance()
61 66 if hasattr(ip, '_inputhook_qt4'):
62 67 return app, ip._inputhook_qt4
63 68
64 69 # Otherwise create the inputhook_qt4/preprompthook_qt4 pair of
65 70 # hooks (they both share the got_kbdint flag)
66 71
67 72 got_kbdint = [False]
68 73
69 74 def inputhook_qt4():
70 75 """PyOS_InputHook python hook for Qt4.
71 76
72 77 Process pending Qt events and if there's no pending keyboard
73 78 input, spend a short slice of time (50ms) running the Qt event
74 79 loop.
75 80
76 81 As a Python ctypes callback can't raise an exception, we catch
77 82 the KeyboardInterrupt and temporarily deactivate the hook,
78 83 which will let a *second* CTRL+C be processed normally and go
79 84 back to a clean prompt line.
80 85 """
81 86 try:
82 87 allow_CTRL_C()
83 88 app = QtCore.QCoreApplication.instance()
84 89 if not app: # shouldn't happen, but safer if it happens anyway...
85 90 return 0
86 91 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
87 92 if not stdin_ready():
88 93 # Generally a program would run QCoreApplication::exec()
89 94 # from main() to enter and process the Qt event loop until
90 95 # quit() or exit() is called and the program terminates.
91 96 #
92 97 # For our input hook integration, we need to repeatedly
93 98 # enter and process the Qt event loop for only a short
94 99 # amount of time (say 50ms) to ensure that Python stays
95 100 # responsive to other user inputs.
96 101 #
97 102 # A naive approach would be to repeatedly call
98 103 # QCoreApplication::exec(), using a timer to quit after a
99 104 # short amount of time. Unfortunately, QCoreApplication
100 105 # emits an aboutToQuit signal before stopping, which has
101 106 # the undesirable effect of closing all modal windows.
102 107 #
103 108 # To work around this problem, we instead create a
104 109 # QEventLoop and call QEventLoop::exec(). Other than
105 110 # setting some state variables which do not seem to be
106 111 # used anywhere, the only thing QCoreApplication adds is
107 112 # the aboutToQuit signal which is precisely what we are
108 113 # trying to avoid.
109 114 timer = QtCore.QTimer()
110 115 event_loop = QtCore.QEventLoop()
111 116 timer.timeout.connect(event_loop.quit)
112 117 while not stdin_ready():
113 118 timer.start(50)
114 119 event_loop.exec_()
115 120 timer.stop()
116 121 except KeyboardInterrupt:
117 122 ignore_CTRL_C()
118 123 got_kbdint[0] = True
119 124 mgr.clear_inputhook()
120 import os, signal, time, threading
121 125 if(os.name == 'posix'):
122 126 pid = os.getpid()
123 127 print("^C")
124 128 thread = threading.Thread(
125 129 target = lambda:
126 ( time.sleep(.1),
130 ( time.sleep(.01),
127 131 os.kill(pid, signal.SIGINT) )
128 132 )
129 133
130 134 thread.start()
131 135 else:
132 136 print("\nKeyboardInterrupt - Ctrl-C again for new prompt")
133 137
134 138
135 139 except: # NO exceptions are allowed to escape from a ctypes callback
136 140 ignore_CTRL_C()
137 141 from traceback import print_exc
138 142 print_exc()
139 143 print("Got exception from inputhook_qt4, unregistering.")
140 144 mgr.clear_inputhook()
141 145 finally:
142 146 allow_CTRL_C()
143 147 return 0
144 148
145 149 def preprompthook_qt4(ishell):
146 150 """'pre_prompt_hook' used to restore the Qt4 input hook
147 151
148 152 (in case the latter was temporarily deactivated after a
149 153 CTRL+C)
150 154 """
151 155 if got_kbdint[0]:
152 156 mgr.set_inputhook(inputhook_qt4)
153 157 got_kbdint[0] = False
154 158
155 159 ip._inputhook_qt4 = inputhook_qt4
156 160 ip.set_hook('pre_prompt_hook', preprompthook_qt4)
157 161
158 162 return app, inputhook_qt4
General Comments 0
You need to be logged in to leave comments. Login now