##// END OF EJS Templates
Work on inputhook....
Brian Granger -
Show More
@@ -1,233 +1,286 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Inputhook management for GUI event loop integration.
4 Inputhook management for GUI event loop integration.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import ctypes
18 import ctypes
19 import sys
19 import sys
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Code
22 # Code
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 def _dummy_mainloop(*args, **kw):
26 pass
27
25
28
26 class InputHookManager(object):
29 class InputHookManager(object):
27 """Manage PyOS_InputHook for different GUI toolkits.
30 """Manage PyOS_InputHook for different GUI toolkits.
28
31
29 This class installs various hooks under ``PyOSInputHook`` to handle
32 This class installs various hooks under ``PyOSInputHook`` to handle
30 GUI event loop integration.
33 GUI event loop integration.
31 """
34 """
32
35
33 def __init__(self):
36 def __init__(self):
34 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
37 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
38 self._apps = {}
35 self._reset()
39 self._reset()
36
40
37 def _reset(self):
41 def _reset(self):
38 self._callback_pyfunctype = None
42 self._callback_pyfunctype = None
39 self._callback = None
43 self._callback = None
40 self._installed = False
44 self._installed = False
41 self._current_gui = None
45 self._current_gui = None
42
46
47 def _hijack_wx(self):
48 import wx
49 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
50 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
51 else: raise AttributeError('Could not find wx core module')
52 orig_mainloop = core.PyApp_MainLoop
53 core.PyApp_MainLoop = _dummy_mainloop
54 return orig_mainloop
55
56 def _hijack_qt4(self):
57 from PyQt4 import QtGui, QtCore
58 orig_mainloop = QtGui.qApp.exec_
59 QtGui.qApp.exec_ = _dummy_mainloop
60 QtGui.QApplication.exec_ = _dummy_mainloop
61 QtCore.QCoreApplication.exec_ = _dummy_mainloop
62 return orig_mainloop
63
64 def _hijack_gtk(self):
65 import gtk
66 orig_mainloop = gtk.main
67 gtk.mainloop = _dummy_mainloop
68 gtk.main = _dummy_mainloop
69 return orig_mainloop
70
71 def _hijack_tk(self):
72 import Tkinter
73 Tkinter.Misc.mainloop = _dummy_mainloop
74 Tkinter.mainloop = _dummy_mainloop
75
43 def get_pyos_inputhook(self):
76 def get_pyos_inputhook(self):
44 """Return the current PyOS_InputHook as a ctypes.c_void_p.
77 """Return the current PyOS_InputHook as a ctypes.c_void_p.
45 """
78 """
46 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
79 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
47
80
48 def get_pyos_inputhook_as_func(self):
81 def get_pyos_inputhook_as_func(self):
49 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE.
82 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE.
50 """
83 """
51 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
84 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
52
85
53 def set_inputhook(self, callback):
86 def set_inputhook(self, callback):
54 """Set PyOS_InputHook to callback and return the previous one.
87 """Set PyOS_InputHook to callback and return the previous one.
55 """
88 """
56 self._callback = callback
89 self._callback = callback
57 self._callback_pyfunctype = self.PYFUNC(callback)
90 self._callback_pyfunctype = self.PYFUNC(callback)
58 pyos_inputhook_ptr = self.get_pyos_inputhook()
91 pyos_inputhook_ptr = self.get_pyos_inputhook()
59 original = self.get_pyos_inputhook_as_func()
92 original = self.get_pyos_inputhook_as_func()
60 pyos_inputhook_ptr.value = \
93 pyos_inputhook_ptr.value = \
61 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
94 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
62 self._installed = True
95 self._installed = True
63 return original
96 return original
64
97
65 def clear_inputhook(self):
98 def clear_inputhook(self):
66 """Set PyOS_InputHook to NULL and return the previous one.
99 """Set PyOS_InputHook to NULL and return the previous one.
67 """
100 """
68 pyos_inputhook_ptr = self.get_pyos_inputhook()
101 pyos_inputhook_ptr = self.get_pyos_inputhook()
69 original = self.get_pyos_inputhook_as_func()
102 original = self.get_pyos_inputhook_as_func()
70 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
103 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
71 self._reset()
104 self._reset()
72 return original
105 return original
73
106
107 def clear_app_refs(self, gui=None):
108 """Clear IPython's internal reference to an application instance.
109
110 Parameters
111 ----------
112 gui : None or str
113 If None, clear all app references. If ('wx', 'qt4') clear
114 the app for that toolkit. References are not held for gtk or tk
115 as those toolkits don't have the notion of an app.
116 """
117 if gui is None:
118 self._apps = {}
119 elif self._apps.has_key(gui):
120 del self._apps[gui]
121
74 def enable_wx(self, app=False):
122 def enable_wx(self, app=False):
75 """Enable event loop integration with wxPython.
123 """Enable event loop integration with wxPython.
76
124
77 Parameters
125 Parameters
78 ----------
126 ----------
79 app : bool
127 app : bool
80 Create a running application object or not.
128 Create a running application object or not.
81
129
82 Notes
130 Notes
83 -----
131 -----
84 This methods sets the PyOS_InputHook for wxPython, which allows
132 This methods sets the PyOS_InputHook for wxPython, which allows
85 the wxPython to integrate with terminal based applications like
133 the wxPython to integrate with terminal based applications like
86 IPython.
134 IPython.
87
135
88 Once this has been called, you can use wx interactively by doing::
136 Once this has been called, you can use wx interactively by doing::
89
137
90 >>> import wx
138 >>> import wx
91 >>> app = wx.App(redirect=False, clearSigInt=False)
139 >>> app = wx.App(redirect=False, clearSigInt=False)
92
140
93 Both options this constructor are important for things to work
141 Both options this constructor are important for things to work
94 properly in an interactive context.
142 properly in an interactive context.
95
143
96 But, *don't start the event loop*. That is handled automatically by
144 But, *don't start the event loop*. That is handled automatically by
97 PyOS_InputHook.
145 PyOS_InputHook.
98 """
146 """
99 from IPython.lib.inputhookwx import inputhook_wx
147 from IPython.lib.inputhookwx import inputhook_wx
100 self.set_inputhook(inputhook_wx)
148 self.set_inputhook(inputhook_wx)
101 self._current_gui = 'wx'
149 self._current_gui = 'wx'
150 self._hijack_wx()
102 if app:
151 if app:
103 import wx
152 import wx
104 app = wx.App(redirect=False, clearSigInt=False)
153 app = wx.GetApp()
105 # The import of wx on Linux sets the handler for signal.SIGINT
154 if app is None:
106 # to 0. This is a bug in wx or gtk. We fix by just setting it
155 app = wx.App(redirect=False, clearSigInt=False)
107 # back to the Python default.
156 self._apps['wx'] = app
108 import signal
109 if not callable(signal.getsignal(signal.SIGINT)):
110 signal.signal(signal.SIGINT, signal.default_int_handler)
111 return app
157 return app
112
158
113 def disable_wx(self):
159 def disable_wx(self):
114 """Disable event loop integration with wxPython.
160 """Disable event loop integration with wxPython.
115
161
116 This merely sets PyOS_InputHook to NULL.
162 This merely sets PyOS_InputHook to NULL.
117 """
163 """
118 self.clear_inputhook()
164 self.clear_inputhook()
119
165
120 def enable_qt4(self, app=False):
166 def enable_qt4(self, app=False):
121 """Enable event loop integration with PyQt4.
167 """Enable event loop integration with PyQt4.
122
168
123 Parameters
169 Parameters
124 ----------
170 ----------
125 app : bool
171 app : bool
126 Create a running application object or not.
172 Create a running application object or not.
127
173
128 Notes
174 Notes
129 -----
175 -----
130 This methods sets the PyOS_InputHook for wxPython, which allows
176 This methods sets the PyOS_InputHook for wxPython, which allows
131 the PyQt4 to integrate with terminal based applications like
177 the PyQt4 to integrate with terminal based applications like
132 IPython.
178 IPython.
133
179
134 Once this has been called, you can simply create a QApplication and
180 Once this has been called, you can simply create a QApplication and
135 use it. But, *don't start the event loop*. That is handled
181 use it. But, *don't start the event loop*. That is handled
136 automatically by PyOS_InputHook.
182 automatically by PyOS_InputHook.
137 """
183 """
138 from PyQt4 import QtCore
184 from PyQt4 import QtCore
139 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
185 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
140 # was set when QtCore was imported, but if it ever got removed,
186 # was set when QtCore was imported, but if it ever got removed,
141 # you couldn't reset it. For earlier versions we can
187 # you couldn't reset it. For earlier versions we can
142 # probably implement a ctypes version.
188 # probably implement a ctypes version.
143 try:
189 try:
144 QtCore.pyqtRestoreInputHook()
190 QtCore.pyqtRestoreInputHook()
145 except AttributeError:
191 except AttributeError:
146 pass
192 pass
147 self._current_gui = 'qt4'
193 self._current_gui = 'qt4'
194 self._hijack_qt4()
148 if app:
195 if app:
149 from PyQt4 import QtGui
196 from PyQt4 import QtGui
150 app = QtGui.QApplication(sys.argv)
197 app = QtGui.QApplication.instance()
198 if app is None:
199 app = QtGui.QApplication(sys.argv)
200 self._apps['qt4'] = app
151 return app
201 return app
152
202
153 def disable_qt4(self):
203 def disable_qt4(self):
154 """Disable event loop integration with PyQt4.
204 """Disable event loop integration with PyQt4.
155
205
156 This merely sets PyOS_InputHook to NULL.
206 This merely sets PyOS_InputHook to NULL.
157 """
207 """
158 self.clear_inputhook()
208 self.clear_inputhook()
159
209
160 def enable_gtk(self, app=False):
210 def enable_gtk(self, app=False):
161 """Enable event loop integration with PyGTK.
211 """Enable event loop integration with PyGTK.
162
212
163 Parameters
213 Parameters
164 ----------
214 ----------
165 app : bool
215 app : bool
166 Create a running application object or not.
216 Create a running application object or not.
167
217
168 Notes
218 Notes
169 -----
219 -----
170 This methods sets the PyOS_InputHook for PyGTK, which allows
220 This methods sets the PyOS_InputHook for PyGTK, which allows
171 the PyGTK to integrate with terminal based applications like
221 the PyGTK to integrate with terminal based applications like
172 IPython.
222 IPython.
173
223
174 Once this has been called, you can simple create PyGTK objects and
224 Once this has been called, you can simple create PyGTK objects and
175 use them. But, *don't start the event loop*. That is handled
225 use them. But, *don't start the event loop*. That is handled
176 automatically by PyOS_InputHook.
226 automatically by PyOS_InputHook.
177 """
227 """
178 import gtk
228 import gtk
179 try:
229 try:
180 gtk.set_interactive(True)
230 gtk.set_interactive(True)
181 self._current_gui = 'gtk'
231 self._current_gui = 'gtk'
182 except AttributeError:
232 except AttributeError:
183 # For older versions of gtk, use our own ctypes version
233 # For older versions of gtk, use our own ctypes version
184 from IPython.lib.inputhookgtk import inputhook_gtk
234 from IPython.lib.inputhookgtk import inputhook_gtk
185 self.set_inputhook(inputhook_gtk)
235 self.set_inputhook(inputhook_gtk)
186 self._current_gui = 'gtk'
236 self._current_gui = 'gtk'
237 self._hijack_gtk()
187
238
188 def disable_gtk(self):
239 def disable_gtk(self):
189 """Disable event loop integration with PyGTK.
240 """Disable event loop integration with PyGTK.
190
241
191 This merely sets PyOS_InputHook to NULL.
242 This merely sets PyOS_InputHook to NULL.
192 """
243 """
193 self.clear_inputhook()
244 self.clear_inputhook()
194
245
195 def enable_tk(self, app=False):
246 def enable_tk(self, app=False):
196 """Enable event loop integration with Tk.
247 """Enable event loop integration with Tk.
197
248
198 Parameters
249 Parameters
199 ----------
250 ----------
200 app : bool
251 app : bool
201 Create a running application object or not.
252 Create a running application object or not.
202
253
203 Notes
254 Notes
204 -----
255 -----
205 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
256 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
206 sets ``PyOS_InputHook``.
257 sets ``PyOS_InputHook``.
207 """
258 """
208 self._current_gui = 'tk'
259 self._current_gui = 'tk'
260 self._hijack_tk()
209
261
210 def disable_tk(self):
262 def disable_tk(self):
211 """Disable event loop integration with Tkinter.
263 """Disable event loop integration with Tkinter.
212
264
213 This merely sets PyOS_InputHook to NULL.
265 This merely sets PyOS_InputHook to NULL.
214 """
266 """
215 self.clear_inputhook()
267 self.clear_inputhook()
216
268
217 def current_gui(self):
269 def current_gui(self):
218 """Return a string indicating the currently active GUI or None."""
270 """Return a string indicating the currently active GUI or None."""
219 return self._current_gui
271 return self._current_gui
220
272
221 inputhook_manager = InputHookManager()
273 inputhook_manager = InputHookManager()
222
274
223 enable_wx = inputhook_manager.enable_wx
275 enable_wx = inputhook_manager.enable_wx
224 disable_wx = inputhook_manager.disable_wx
276 disable_wx = inputhook_manager.disable_wx
225 enable_qt4 = inputhook_manager.enable_qt4
277 enable_qt4 = inputhook_manager.enable_qt4
226 disable_qt4 = inputhook_manager.disable_qt4
278 disable_qt4 = inputhook_manager.disable_qt4
227 enable_gtk = inputhook_manager.enable_gtk
279 enable_gtk = inputhook_manager.enable_gtk
228 disable_gtk = inputhook_manager.disable_gtk
280 disable_gtk = inputhook_manager.disable_gtk
229 enable_tk = inputhook_manager.enable_tk
281 enable_tk = inputhook_manager.enable_tk
230 disable_tk = inputhook_manager.disable_tk
282 disable_tk = inputhook_manager.disable_tk
231 clear_inputhook = inputhook_manager.clear_inputhook
283 clear_inputhook = inputhook_manager.clear_inputhook
232 set_inputhook = inputhook_manager.set_inputhook
284 set_inputhook = inputhook_manager.set_inputhook
233 current_gui = inputhook_manager.current_gui No newline at end of file
285 current_gui = inputhook_manager.current_gui
286 clear_app_refs = inputhook_manager.clear_app_refs
@@ -1,153 +1,162 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """
4 """
5 Enable wxPython to be used interacive by setting PyOS_InputHook.
5 Enable wxPython to be used interacive by setting PyOS_InputHook.
6
6
7 Authors: Robin Dunn, Brian Granger, Ondrej Certik
7 Authors: Robin Dunn, Brian Granger, Ondrej Certik
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2009 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import os
21 import os
22 import signal
22 import sys
23 import sys
23 import time
24 import time
24 from timeit import default_timer as clock
25 from timeit import default_timer as clock
25 import wx
26 import wx
26
27
27 if os.name == 'posix':
28 if os.name == 'posix':
28 import select
29 import select
29 elif sys.platform == 'win32':
30 elif sys.platform == 'win32':
30 import msvcrt
31 import msvcrt
31
32
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33 # Code
34 # Code
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35
36
36 def stdin_ready():
37 def stdin_ready():
37 if os.name == 'posix':
38 if os.name == 'posix':
38 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
39 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
39 if infds:
40 if infds:
40 return True
41 return True
41 else:
42 else:
42 return False
43 return False
43 elif sys.platform == 'win32':
44 elif sys.platform == 'win32':
44 return msvcrt.kbhit()
45 return msvcrt.kbhit()
45
46
46
47
47 def inputhook_wx1():
48 def inputhook_wx1():
48 """Run the wx event loop by processing pending events only.
49 """Run the wx event loop by processing pending events only.
49
50
50 This approach seems to work, but its performance is not great as it
51 This approach seems to work, but its performance is not great as it
51 relies on having PyOS_InputHook called regularly.
52 relies on having PyOS_InputHook called regularly.
52 """
53 """
53 app = wx.GetApp()
54 app = wx.GetApp()
54 if app is not None:
55 if app is not None:
55 assert wx.Thread_IsMain()
56 assert wx.Thread_IsMain()
56
57
57 # Make a temporary event loop and process system events until
58 # Make a temporary event loop and process system events until
58 # there are no more waiting, then allow idle events (which
59 # there are no more waiting, then allow idle events (which
59 # will also deal with pending or posted wx events.)
60 # will also deal with pending or posted wx events.)
60 evtloop = wx.EventLoop()
61 evtloop = wx.EventLoop()
61 ea = wx.EventLoopActivator(evtloop)
62 ea = wx.EventLoopActivator(evtloop)
62 while evtloop.Pending():
63 while evtloop.Pending():
63 evtloop.Dispatch()
64 evtloop.Dispatch()
64 app.ProcessIdle()
65 app.ProcessIdle()
65 del ea
66 del ea
66 return 0
67 return 0
67
68
68 class EventLoopTimer(wx.Timer):
69 class EventLoopTimer(wx.Timer):
69
70
70 def __init__(self, func):
71 def __init__(self, func):
71 self.func = func
72 self.func = func
72 wx.Timer.__init__(self)
73 wx.Timer.__init__(self)
73
74
74 def Notify(self):
75 def Notify(self):
75 self.func()
76 self.func()
76
77
77 class EventLoopRunner(object):
78 class EventLoopRunner(object):
78
79
79 def Run(self, time):
80 def Run(self, time):
80 self.evtloop = wx.EventLoop()
81 self.evtloop = wx.EventLoop()
81 self.timer = EventLoopTimer(self.check_stdin)
82 self.timer = EventLoopTimer(self.check_stdin)
82 self.timer.Start(time)
83 self.timer.Start(time)
83 self.evtloop.Run()
84 self.evtloop.Run()
84
85
85 def check_stdin(self):
86 def check_stdin(self):
86 if stdin_ready():
87 if stdin_ready():
87 self.timer.Stop()
88 self.timer.Stop()
88 self.evtloop.Exit()
89 self.evtloop.Exit()
89
90
90 def inputhook_wx2():
91 def inputhook_wx2():
91 """Run the wx event loop, polling for stdin.
92 """Run the wx event loop, polling for stdin.
92
93
93 This version runs the wx eventloop for an undetermined amount of time,
94 This version runs the wx eventloop for an undetermined amount of time,
94 during which it periodically checks to see if anything is ready on
95 during which it periodically checks to see if anything is ready on
95 stdin. If anything is ready on stdin, the event loop exits.
96 stdin. If anything is ready on stdin, the event loop exits.
96
97
97 The argument to elr.Run controls how often the event loop looks at stdin.
98 The argument to elr.Run controls how often the event loop looks at stdin.
98 This determines the responsiveness at the keyboard. A setting of 1000
99 This determines the responsiveness at the keyboard. A setting of 1000
99 enables a user to type at most 1 char per second. I have found that a
100 enables a user to type at most 1 char per second. I have found that a
100 setting of 10 gives good keyboard response. We can shorten it further,
101 setting of 10 gives good keyboard response. We can shorten it further,
101 but eventually performance would suffer from calling select/kbhit too
102 but eventually performance would suffer from calling select/kbhit too
102 often.
103 often.
103 """
104 """
104 app = wx.GetApp()
105 app = wx.GetApp()
105 if app is not None:
106 if app is not None:
106 assert wx.Thread_IsMain()
107 assert wx.Thread_IsMain()
107 elr = EventLoopRunner()
108 elr = EventLoopRunner()
108 # As this time is made shorter, keyboard response improves, but idle
109 # As this time is made shorter, keyboard response improves, but idle
109 # CPU load goes up. 10 ms seems like a good compromise.
110 # CPU load goes up. 10 ms seems like a good compromise.
110 elr.Run(time=10) # CHANGE time here to control polling interval
111 elr.Run(time=10) # CHANGE time here to control polling interval
111 return 0
112 return 0
112
113
113 def inputhook_wx3():
114 def inputhook_wx3():
114 """Run the wx event loop by processing pending events only.
115 """Run the wx event loop by processing pending events only.
115
116
116 This is like inputhook_wx1, but it keeps processing pending events
117 This is like inputhook_wx1, but it keeps processing pending events
117 until stdin is ready. After processing all pending events, a call to
118 until stdin is ready. After processing all pending events, a call to
118 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
119 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
119 This sleep time should be tuned though for best performance.
120 This sleep time should be tuned though for best performance.
120 """
121 """
121 app = wx.GetApp()
122 app = wx.GetApp()
122 if app is not None:
123 if app is not None:
123 assert wx.Thread_IsMain()
124 assert wx.Thread_IsMain()
124
125
126 # The import of wx on Linux sets the handler for signal.SIGINT
127 # to 0. This is a bug in wx or gtk. We fix by just setting it
128 # back to the Python default.
129 if not callable(signal.getsignal(signal.SIGINT)):
130 signal.signal(signal.SIGINT, signal.default_int_handler)
131
125 evtloop = wx.EventLoop()
132 evtloop = wx.EventLoop()
126 ea = wx.EventLoopActivator(evtloop)
133 ea = wx.EventLoopActivator(evtloop)
127 t = clock()
134 t = clock()
128 while not stdin_ready():
135 while not stdin_ready():
129 while evtloop.Pending():
136 while evtloop.Pending():
130 t = clock()
137 t = clock()
131 evtloop.Dispatch()
138 evtloop.Dispatch()
132 app.ProcessIdle()
139 app.ProcessIdle()
133 # We need to sleep at this point to keep the idle CPU load
140 # We need to sleep at this point to keep the idle CPU load
134 # low. However, if sleep to long, GUI response is poor. As
141 # low. However, if sleep to long, GUI response is poor. As
135 # a compromise, we watch how often GUI events are being processed
142 # a compromise, we watch how often GUI events are being processed
136 # and switch between a short and long sleep time. Here are some
143 # and switch between a short and long sleep time. Here are some
137 # stats useful in helping to tune this.
144 # stats useful in helping to tune this.
138 # time CPU load
145 # time CPU load
139 # 0.001 13%
146 # 0.001 13%
140 # 0.005 3%
147 # 0.005 3%
141 # 0.01 1.5%
148 # 0.01 1.5%
142 # 0.05 0.5%
149 # 0.05 0.5%
150 if clock()-t > 1.0:
151 time.sleep(1.0)
143 if clock()-t > 0.1:
152 if clock()-t > 0.1:
144 # Few GUI events coming in, so we can sleep longer
153 # Few GUI events coming in, so we can sleep longer
145 time.sleep(0.05)
154 time.sleep(0.05)
146 else:
155 else:
147 # Many GUI events coming in, so sleep only very little
156 # Many GUI events coming in, so sleep only very little
148 time.sleep(0.001)
157 time.sleep(0.001)
149 del ea
158 del ea
150 return 0
159 return 0
151
160
152 # This is our default implementation
161 # This is our default implementation
153 inputhook_wx = inputhook_wx3 No newline at end of file
162 inputhook_wx = inputhook_wx3
General Comments 0
You need to be logged in to leave comments. Login now