##// END OF EJS Templates
Merge pull request #11911 from pauldmccarthy/enh/wxphoenix_eventloop...
Matthias Bussonnier -
r25233:e06b5919 merge
parent child Browse files
Show More
@@ -8,13 +8,29 b' from timeit import default_timer as clock'
8 import wx
8 import wx
9
9
10
10
11 def ignore_keyboardinterrupts(func):
12 """Decorator which causes KeyboardInterrupt exceptions to be ignored during
13 execution of the decorated function.
14
15 This is used by the inputhook functions to handle the event where the user
16 presses CTRL+C while IPython is idle, and the inputhook loop is running. In
17 this case, we want to ignore interrupts.
18 """
19 def wrapper(*args, **kwargs):
20 try:
21 func(*args, **kwargs)
22 except KeyboardInterrupt:
23 pass
24 return wrapper
25
26
27 @ignore_keyboardinterrupts
11 def inputhook_wx1(context):
28 def inputhook_wx1(context):
12 """Run the wx event loop by processing pending events only.
29 """Run the wx event loop by processing pending events only.
13
30
14 This approach seems to work, but its performance is not great as it
31 This approach seems to work, but its performance is not great as it
15 relies on having PyOS_InputHook called regularly.
32 relies on having PyOS_InputHook called regularly.
16 """
33 """
17 try:
18 app = wx.GetApp()
34 app = wx.GetApp()
19 if app is not None:
35 if app is not None:
20 assert wx.Thread_IsMain()
36 assert wx.Thread_IsMain()
@@ -28,10 +44,9 b' def inputhook_wx1(context):'
28 evtloop.Dispatch()
44 evtloop.Dispatch()
29 app.ProcessIdle()
45 app.ProcessIdle()
30 del ea
46 del ea
31 except KeyboardInterrupt:
32 pass
33 return 0
47 return 0
34
48
49
35 class EventLoopTimer(wx.Timer):
50 class EventLoopTimer(wx.Timer):
36
51
37 def __init__(self, func):
52 def __init__(self, func):
@@ -41,6 +56,7 b' class EventLoopTimer(wx.Timer):'
41 def Notify(self):
56 def Notify(self):
42 self.func()
57 self.func()
43
58
59
44 class EventLoopRunner(object):
60 class EventLoopRunner(object):
45
61
46 def Run(self, time, input_is_ready):
62 def Run(self, time, input_is_ready):
@@ -55,6 +71,8 b' class EventLoopRunner(object):'
55 self.timer.Stop()
71 self.timer.Stop()
56 self.evtloop.Exit()
72 self.evtloop.Exit()
57
73
74
75 @ignore_keyboardinterrupts
58 def inputhook_wx2(context):
76 def inputhook_wx2(context):
59 """Run the wx event loop, polling for stdin.
77 """Run the wx event loop, polling for stdin.
60
78
@@ -69,7 +87,6 b' def inputhook_wx2(context):'
69 but eventually performance would suffer from calling select/kbhit too
87 but eventually performance would suffer from calling select/kbhit too
70 often.
88 often.
71 """
89 """
72 try:
73 app = wx.GetApp()
90 app = wx.GetApp()
74 if app is not None:
91 if app is not None:
75 assert wx.Thread_IsMain()
92 assert wx.Thread_IsMain()
@@ -78,10 +95,10 b' def inputhook_wx2(context):'
78 # CPU load goes up. 10 ms seems like a good compromise.
95 # CPU load goes up. 10 ms seems like a good compromise.
79 elr.Run(time=10, # CHANGE time here to control polling interval
96 elr.Run(time=10, # CHANGE time here to control polling interval
80 input_is_ready=context.input_is_ready)
97 input_is_ready=context.input_is_ready)
81 except KeyboardInterrupt:
82 pass
83 return 0
98 return 0
84
99
100
101 @ignore_keyboardinterrupts
85 def inputhook_wx3(context):
102 def inputhook_wx3(context):
86 """Run the wx event loop by processing pending events only.
103 """Run the wx event loop by processing pending events only.
87
104
@@ -90,9 +107,6 b' def inputhook_wx3(context):'
90 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
107 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
91 This sleep time should be tuned though for best performance.
108 This sleep time should be tuned though for best performance.
92 """
109 """
93 # We need to protect against a user pressing Control-C when IPython is
94 # idle and this is running. We trap KeyboardInterrupt and pass.
95 try:
96 app = wx.GetApp()
110 app = wx.GetApp()
97 if app is not None:
111 if app is not None:
98 assert wx.Thread_IsMain()
112 assert wx.Thread_IsMain()
@@ -133,15 +147,71 b' def inputhook_wx3(context):'
133 # Many GUI events coming in, so sleep only very little
147 # Many GUI events coming in, so sleep only very little
134 time.sleep(0.001)
148 time.sleep(0.001)
135 del ea
149 del ea
136 except KeyboardInterrupt:
137 pass
138 return 0
150 return 0
139
151
140 if sys.platform == 'darwin':
152
153 @ignore_keyboardinterrupts
154 def inputhook_wxphoenix(context):
155 """Run the wx event loop until the user provides more input.
156
157 This input hook is suitable for use with wxPython >= 4 (a.k.a. Phoenix).
158
159 It uses the same approach to that used in
160 ipykernel.eventloops.loop_wx. The wx.MainLoop is executed, and a wx.Timer
161 is used to periodically poll the context for input. As soon as input is
162 ready, the wx.MainLoop is stopped.
163 """
164
165 app = wx.GetApp()
166
167 if app is None:
168 return
169
170 if context.input_is_ready():
171 return
172
173 assert wx.IsMainThread()
174
175 # Wx uses milliseconds
176 poll_interval = 100
177
178 # Use a wx.Timer to periodically check whether input is ready - as soon as
179 # it is, we exit the main loop
180 def poll(ev):
181 if context.input_is_ready():
182 app.ExitMainLoop()
183
184 timer = wx.Timer()
185 timer.Start(poll_interval)
186 timer.Bind(wx.EVT_TIMER, poll)
187
188 # The import of wx on Linux sets the handler for signal.SIGINT to 0. This
189 # is a bug in wx or gtk. We fix by just setting it back to the Python
190 # default.
191 if not callable(signal.getsignal(signal.SIGINT)):
192 signal.signal(signal.SIGINT, signal.default_int_handler)
193
194 # The SetExitOnFrameDelete call allows us to run the wx mainloop without
195 # having a frame open.
196 app.SetExitOnFrameDelete(False)
197 app.MainLoop()
198
199
200 # Get the major wx version number to figure out what input hook we should use.
201 major_version = 3
202
203 try:
204 major_version = int(wx.__version__[0])
205 except Exception:
206 pass
207
208 # Use the phoenix hook on all platforms for wxpython >= 4
209 if major_version >= 4:
210 inputhook = inputhook_wxphoenix
141 # On OSX, evtloop.Pending() always returns True, regardless of there being
211 # On OSX, evtloop.Pending() always returns True, regardless of there being
142 # any events pending. As such we can't use implementations 1 or 3 of the
212 # any events pending. As such we can't use implementations 1 or 3 of the
143 # inputhook as those depend on a pending/dispatch loop.
213 # inputhook as those depend on a pending/dispatch loop.
214 elif sys.platform == 'darwin':
144 inputhook = inputhook_wx2
215 inputhook = inputhook_wx2
145 else:
216 else:
146 # This is our default implementation
147 inputhook = inputhook_wx3
217 inputhook = inputhook_wx3
General Comments 0
You need to be logged in to leave comments. Login now