##// END OF EJS Templates
Use inputhook_wx2 on osx...
Lessandro Mariano -
Show More
@@ -1,163 +1,170 b''
1 1 # encoding: utf-8
2 2
3 3 """
4 4 Enable wxPython to be used interacive by setting PyOS_InputHook.
5 5
6 6 Authors: Robin Dunn, Brian Granger, Ondrej Certik
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2008-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 import sys
20 21 import signal
21 22 import time
22 23 from timeit import default_timer as clock
23 24 import wx
24 25
25 26 from IPython.lib.inputhook import stdin_ready
26 27
27 28
28 29 #-----------------------------------------------------------------------------
29 30 # Code
30 31 #-----------------------------------------------------------------------------
31 32
32 33 def inputhook_wx1():
33 34 """Run the wx event loop by processing pending events only.
34 35
35 36 This approach seems to work, but its performance is not great as it
36 37 relies on having PyOS_InputHook called regularly.
37 38 """
38 39 try:
39 40 app = wx.GetApp()
40 41 if app is not None:
41 42 assert wx.Thread_IsMain()
42 43
43 44 # Make a temporary event loop and process system events until
44 45 # there are no more waiting, then allow idle events (which
45 46 # will also deal with pending or posted wx events.)
46 47 evtloop = wx.EventLoop()
47 48 ea = wx.EventLoopActivator(evtloop)
48 49 while evtloop.Pending():
49 50 evtloop.Dispatch()
50 51 app.ProcessIdle()
51 52 del ea
52 53 except KeyboardInterrupt:
53 54 pass
54 55 return 0
55 56
56 57 class EventLoopTimer(wx.Timer):
57 58
58 59 def __init__(self, func):
59 60 self.func = func
60 61 wx.Timer.__init__(self)
61 62
62 63 def Notify(self):
63 64 self.func()
64 65
65 66 class EventLoopRunner(object):
66 67
67 68 def Run(self, time):
68 69 self.evtloop = wx.EventLoop()
69 70 self.timer = EventLoopTimer(self.check_stdin)
70 71 self.timer.Start(time)
71 72 self.evtloop.Run()
72 73
73 74 def check_stdin(self):
74 75 if stdin_ready():
75 76 self.timer.Stop()
76 77 self.evtloop.Exit()
77 78
78 79 def inputhook_wx2():
79 80 """Run the wx event loop, polling for stdin.
80 81
81 82 This version runs the wx eventloop for an undetermined amount of time,
82 83 during which it periodically checks to see if anything is ready on
83 84 stdin. If anything is ready on stdin, the event loop exits.
84 85
85 86 The argument to elr.Run controls how often the event loop looks at stdin.
86 87 This determines the responsiveness at the keyboard. A setting of 1000
87 88 enables a user to type at most 1 char per second. I have found that a
88 89 setting of 10 gives good keyboard response. We can shorten it further,
89 90 but eventually performance would suffer from calling select/kbhit too
90 91 often.
91 92 """
92 93 try:
93 94 app = wx.GetApp()
94 95 if app is not None:
95 96 assert wx.Thread_IsMain()
96 97 elr = EventLoopRunner()
97 98 # As this time is made shorter, keyboard response improves, but idle
98 99 # CPU load goes up. 10 ms seems like a good compromise.
99 100 elr.Run(time=10) # CHANGE time here to control polling interval
100 101 except KeyboardInterrupt:
101 102 pass
102 103 return 0
103 104
104 105 def inputhook_wx3():
105 106 """Run the wx event loop by processing pending events only.
106 107
107 108 This is like inputhook_wx1, but it keeps processing pending events
108 109 until stdin is ready. After processing all pending events, a call to
109 110 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
110 111 This sleep time should be tuned though for best performance.
111 112 """
112 113 # We need to protect against a user pressing Control-C when IPython is
113 114 # idle and this is running. We trap KeyboardInterrupt and pass.
114 115 try:
115 116 app = wx.GetApp()
116 117 if app is not None:
117 118 assert wx.Thread_IsMain()
118 119
119 120 # The import of wx on Linux sets the handler for signal.SIGINT
120 121 # to 0. This is a bug in wx or gtk. We fix by just setting it
121 122 # back to the Python default.
122 123 if not callable(signal.getsignal(signal.SIGINT)):
123 124 signal.signal(signal.SIGINT, signal.default_int_handler)
124 125
125 126 evtloop = wx.EventLoop()
126 127 ea = wx.EventLoopActivator(evtloop)
127 128 t = clock()
128 129 while not stdin_ready():
129 130 while evtloop.Pending():
130 131 t = clock()
131 132 evtloop.Dispatch()
132 133 app.ProcessIdle()
133 134 # We need to sleep at this point to keep the idle CPU load
134 135 # low. However, if sleep to long, GUI response is poor. As
135 136 # a compromise, we watch how often GUI events are being processed
136 137 # and switch between a short and long sleep time. Here are some
137 138 # stats useful in helping to tune this.
138 139 # time CPU load
139 140 # 0.001 13%
140 141 # 0.005 3%
141 142 # 0.01 1.5%
142 143 # 0.05 0.5%
143 144 used_time = clock() - t
144 145 if used_time > 5*60.0:
145 146 # print 'Sleep for 5 s' # dbg
146 147 time.sleep(5.0)
147 148 elif used_time > 10.0:
148 149 # print 'Sleep for 1 s' # dbg
149 150 time.sleep(1.0)
150 151 elif used_time > 0.1:
151 152 # Few GUI events coming in, so we can sleep longer
152 153 # print 'Sleep for 0.05 s' # dbg
153 154 time.sleep(0.05)
154 155 else:
155 156 # Many GUI events coming in, so sleep only very little
156 157 time.sleep(0.001)
157 158 del ea
158 159 except KeyboardInterrupt:
159 160 pass
160 161 return 0
161 162
162 # This is our default implementation
163 inputhook_wx = inputhook_wx3
163 if sys.platform == 'darwin':
164 # On OSX, evtloop.Pending() always returns True, regardless of there being
165 # any events pending. As such we can't use implementations 1 or 3 of the
166 # inputhook as those depend on a pending/dispatch loop.
167 inputhook_wx = inputhook_wx2
168 else:
169 # This is our default implementation
170 inputhook_wx = inputhook_wx3
General Comments 0
You need to be logged in to leave comments. Login now