##// END OF EJS Templates
RF: Factor out keyboard interrupt catch
Paul McCarthy -
Show More
@@ -8,30 +8,41 b' from timeit import default_timer as clock'
8 8 import wx
9 9
10 10
11 def ignore_keyboardinterrupts(func):
12 """Decorator which causes KeyboardInterrupt exceptions to be
13 ignored during execution of the decorated function.
14 """
15 def wrapper(*args, **kwargs):
16 try:
17 func(*args, **kwargs)
18 except KeyboardInterrupt:
19 pass
20 return wrapper
21
22
23 @ignore_keyboardinterrupts
11 24 def inputhook_wx1(context):
12 25 """Run the wx event loop by processing pending events only.
13 26
14 27 This approach seems to work, but its performance is not great as it
15 28 relies on having PyOS_InputHook called regularly.
16 29 """
17 try:
18 app = wx.GetApp()
19 if app is not None:
20 assert wx.Thread_IsMain()
21
22 # Make a temporary event loop and process system events until
23 # there are no more waiting, then allow idle events (which
24 # will also deal with pending or posted wx events.)
25 evtloop = wx.EventLoop()
26 ea = wx.EventLoopActivator(evtloop)
27 while evtloop.Pending():
28 evtloop.Dispatch()
29 app.ProcessIdle()
30 del ea
31 except KeyboardInterrupt:
32 pass
30 app = wx.GetApp()
31 if app is not None:
32 assert wx.Thread_IsMain()
33
34 # Make a temporary event loop and process system events until
35 # there are no more waiting, then allow idle events (which
36 # will also deal with pending or posted wx events.)
37 evtloop = wx.EventLoop()
38 ea = wx.EventLoopActivator(evtloop)
39 while evtloop.Pending():
40 evtloop.Dispatch()
41 app.ProcessIdle()
42 del ea
33 43 return 0
34 44
45
35 46 class EventLoopTimer(wx.Timer):
36 47
37 48 def __init__(self, func):
@@ -41,6 +52,7 b' class EventLoopTimer(wx.Timer):'
41 52 def Notify(self):
42 53 self.func()
43 54
55
44 56 class EventLoopRunner(object):
45 57
46 58 def Run(self, time, input_is_ready):
@@ -55,6 +67,8 b' class EventLoopRunner(object):'
55 67 self.timer.Stop()
56 68 self.evtloop.Exit()
57 69
70
71 @ignore_keyboardinterrupts
58 72 def inputhook_wx2(context):
59 73 """Run the wx event loop, polling for stdin.
60 74
@@ -69,19 +83,18 b' def inputhook_wx2(context):'
69 83 but eventually performance would suffer from calling select/kbhit too
70 84 often.
71 85 """
72 try:
73 app = wx.GetApp()
74 if app is not None:
75 assert wx.Thread_IsMain()
76 elr = EventLoopRunner()
77 # As this time is made shorter, keyboard response improves, but idle
78 # CPU load goes up. 10 ms seems like a good compromise.
79 elr.Run(time=10, # CHANGE time here to control polling interval
80 input_is_ready=context.input_is_ready)
81 except KeyboardInterrupt:
82 pass
86 app = wx.GetApp()
87 if app is not None:
88 assert wx.Thread_IsMain()
89 elr = EventLoopRunner()
90 # As this time is made shorter, keyboard response improves, but idle
91 # CPU load goes up. 10 ms seems like a good compromise.
92 elr.Run(time=10, # CHANGE time here to control polling interval
93 input_is_ready=context.input_is_ready)
83 94 return 0
84 95
96
97 @ignore_keyboardinterrupts
85 98 def inputhook_wx3(context):
86 99 """Run the wx event loop by processing pending events only.
87 100
@@ -90,54 +103,50 b' def inputhook_wx3(context):'
90 103 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
91 104 This sleep time should be tuned though for best performance.
92 105 """
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()
97 if app is not None:
98 assert wx.Thread_IsMain()
99
100 # The import of wx on Linux sets the handler for signal.SIGINT
101 # to 0. This is a bug in wx or gtk. We fix by just setting it
102 # back to the Python default.
103 if not callable(signal.getsignal(signal.SIGINT)):
104 signal.signal(signal.SIGINT, signal.default_int_handler)
105
106 evtloop = wx.EventLoop()
107 ea = wx.EventLoopActivator(evtloop)
108 t = clock()
109 while not context.input_is_ready():
110 while evtloop.Pending():
111 t = clock()
112 evtloop.Dispatch()
113 app.ProcessIdle()
114 # We need to sleep at this point to keep the idle CPU load
115 # low. However, if sleep to long, GUI response is poor. As
116 # a compromise, we watch how often GUI events are being processed
117 # and switch between a short and long sleep time. Here are some
118 # stats useful in helping to tune this.
119 # time CPU load
120 # 0.001 13%
121 # 0.005 3%
122 # 0.01 1.5%
123 # 0.05 0.5%
124 used_time = clock() - t
125 if used_time > 10.0:
126 # print 'Sleep for 1 s' # dbg
127 time.sleep(1.0)
128 elif used_time > 0.1:
129 # Few GUI events coming in, so we can sleep longer
130 # print 'Sleep for 0.05 s' # dbg
131 time.sleep(0.05)
132 else:
133 # Many GUI events coming in, so sleep only very little
134 time.sleep(0.001)
135 del ea
136 except KeyboardInterrupt:
137 pass
106 app = wx.GetApp()
107 if app is not None:
108 assert wx.Thread_IsMain()
109
110 # The import of wx on Linux sets the handler for signal.SIGINT
111 # to 0. This is a bug in wx or gtk. We fix by just setting it
112 # back to the Python default.
113 if not callable(signal.getsignal(signal.SIGINT)):
114 signal.signal(signal.SIGINT, signal.default_int_handler)
115
116 evtloop = wx.EventLoop()
117 ea = wx.EventLoopActivator(evtloop)
118 t = clock()
119 while not context.input_is_ready():
120 while evtloop.Pending():
121 t = clock()
122 evtloop.Dispatch()
123 app.ProcessIdle()
124 # We need to sleep at this point to keep the idle CPU load
125 # low. However, if sleep to long, GUI response is poor. As
126 # a compromise, we watch how often GUI events are being processed
127 # and switch between a short and long sleep time. Here are some
128 # stats useful in helping to tune this.
129 # time CPU load
130 # 0.001 13%
131 # 0.005 3%
132 # 0.01 1.5%
133 # 0.05 0.5%
134 used_time = clock() - t
135 if used_time > 10.0:
136 # print 'Sleep for 1 s' # dbg
137 time.sleep(1.0)
138 elif used_time > 0.1:
139 # Few GUI events coming in, so we can sleep longer
140 # print 'Sleep for 0.05 s' # dbg
141 time.sleep(0.05)
142 else:
143 # Many GUI events coming in, so sleep only very little
144 time.sleep(0.001)
145 del ea
138 146 return 0
139 147
140 148
149 @ignore_keyboardinterrupts
141 150 def inputhook_wxphoenix(context):
142 151 """Run the wx event loop until the user provides more input.
143 152
@@ -183,6 +192,7 b' def inputhook_wxphoenix(context):'
183 192
184 193 app.MainLoop()
185 194
195
186 196 # Get the major wx version number to figure out what input hook we should use.
187 197 major_version = 3
188 198 try:
General Comments 0
You need to be logged in to leave comments. Login now