inputhookwx.py
152 lines
| 5.0 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2066 | #!/usr/bin/env python | |
# encoding: utf-8 | |||
""" | |||
Enable wxPython to be used interacive by setting PyOS_InputHook. | |||
Authors: Robin Dunn, Brian Granger, Ondrej Certik | |||
""" | |||
#----------------------------------------------------------------------------- | |||
# Copyright (C) 2008-2009 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 | |||
#----------------------------------------------------------------------------- | |||
import os | |||
import sys | |||
import time | |||
from timeit import default_timer as clock | |||
import wx | |||
if os.name == 'posix': | |||
import select | |||
elif sys.platform == 'win32': | |||
import msvcrt | |||
#----------------------------------------------------------------------------- | |||
# Code | |||
#----------------------------------------------------------------------------- | |||
def stdin_ready(): | |||
if os.name == 'posix': | |||
infds, outfds, erfds = select.select([sys.stdin],[],[],0) | |||
if infds: | |||
return True | |||
else: | |||
return False | |||
elif sys.platform == 'win32': | |||
return msvcrt.kbhit() | |||
def inputhook_wx1(): | |||
"""Run the wx event loop by processing pending events only. | |||
This approach seems to work, but its performance is not great as it | |||
relies on having PyOS_InputHook called regularly. | |||
""" | |||
app = wx.GetApp() | |||
if app is not None: | |||
assert wx.Thread_IsMain() | |||
# Make a temporary event loop and process system events until | |||
# there are no more waiting, then allow idle events (which | |||
# will also deal with pending or posted wx events.) | |||
evtloop = wx.EventLoop() | |||
ea = wx.EventLoopActivator(evtloop) | |||
while evtloop.Pending(): | |||
evtloop.Dispatch() | |||
app.ProcessIdle() | |||
del ea | |||
return 0 | |||
class EventLoopTimer(wx.Timer): | |||
def __init__(self, func): | |||
self.func = func | |||
wx.Timer.__init__(self) | |||
def Notify(self): | |||
self.func() | |||
class EventLoopRunner(object): | |||
def Run(self, time): | |||
self.evtloop = wx.EventLoop() | |||
self.timer = EventLoopTimer(self.check_stdin) | |||
self.timer.Start(time) | |||
self.evtloop.Run() | |||
def check_stdin(self): | |||
if stdin_ready(): | |||
self.timer.Stop() | |||
self.evtloop.Exit() | |||
def inputhook_wx2(): | |||
"""Run the wx event loop, polling for stdin. | |||
This version runs the wx eventloop for an undetermined amount of time, | |||
during which it periodically checks to see if anything is ready on | |||
stdin. If anything is ready on stdin, the event loop exits. | |||
The argument to elr.Run controls how often the event loop looks at stdin. | |||
This determines the responsiveness at the keyboard. A setting of 1000 | |||
enables a user to type at most 1 char per second. I have found that a | |||
setting of 10 gives good keyboard response. We can shorten it further, | |||
but eventually performance would suffer from calling select/kbhit too | |||
often. | |||
""" | |||
app = wx.GetApp() | |||
if app is not None: | |||
assert wx.Thread_IsMain() | |||
elr = EventLoopRunner() | |||
# As this time is made shorter, keyboard response improves, but idle | |||
# CPU load goes up. 10 ms seems like a good compromise. | |||
elr.Run(time=10) # CHANGE time here to control polling interval | |||
return 0 | |||
def inputhook_wx3(): | |||
"""Run the wx event loop by processing pending events only. | |||
This is like inputhook_wx1, but it keeps processing pending events | |||
until stdin is ready. After processing all pending events, a call to | |||
time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%. | |||
This sleep time should be tuned though for best performance. | |||
""" | |||
app = wx.GetApp() | |||
if app is not None: | |||
assert wx.Thread_IsMain() | |||
evtloop = wx.EventLoop() | |||
ea = wx.EventLoopActivator(evtloop) | |||
t = clock() | |||
while not stdin_ready(): | |||
while evtloop.Pending(): | |||
t = clock() | |||
evtloop.Dispatch() | |||
app.ProcessIdle() | |||
# We need to sleep at this point to keep the idle CPU load | |||
# low. However, if sleep to long, GUI response is poor. As | |||
# a compromise, we watch how often GUI events are being processed | |||
# and switch between a short and long sleep time. Here are some | |||
# stats useful in helping to tune this. | |||
# time CPU load | |||
# 0.001 13% | |||
# 0.005 3% | |||
# 0.01 1.5% | |||
# 0.05 0.5% | |||
if clock()-t > 0.1: | |||
# Few GUI events coming in, so we can sleep longer | |||
time.sleep(0.05) | |||
else: | |||
# Many GUI events coming in, so sleep only very little | |||
time.sleep(0.001) | |||
del ea | |||
return 0 | |||
# This is our default implementation | |||
inputhook_wx = inputhook_wx3 |