From 64512e81710717447f59498de6e306c3d72d470f 2019-10-30 01:21:02 From: Paul McCarthy Date: 2019-10-30 01:21:02 Subject: [PATCH] RF: Clean up wxphoenix input hook. --- diff --git a/IPython/terminal/pt_inputhooks/wx.py b/IPython/terminal/pt_inputhooks/wx.py index df41e7e..ebe3b1c 100644 --- a/IPython/terminal/pt_inputhooks/wx.py +++ b/IPython/terminal/pt_inputhooks/wx.py @@ -9,8 +9,12 @@ import wx def ignore_keyboardinterrupts(func): - """Decorator which causes KeyboardInterrupt exceptions to be - ignored during execution of the decorated function. + """Decorator which causes KeyboardInterrupt exceptions to be ignored during + execution of the decorated function. + + This is used by the inputhook functions to handle the event where the user + presses CTRL+C while IPython is idle, and the inputhook loop is running. In + this case, we want to ignore interrupts. """ def wrapper(*args, **kwargs): try: @@ -159,34 +163,34 @@ def inputhook_wxphoenix(context): if app is None: return - # Wx uses milliseconds + if context.input_is_ready(): + return + + assert wx.IsMainThread() + + # Wx uses milliseconds poll_interval = 100 - # This function gets polled periodically; when - # input is ready, the wx main loop is stopped. - def wake(): + # We have to create a dummy wx.Frame, otherwise wx.App.MainLoop will know + # that it has nothing to do, and will return immediately. + frame = getattr(inputhook_wxphoenix, '_frame', None) + if frame is None: + inputhook_wxphoenix._frame = frame = wx.Frame(None) + frame.Show(False) + + # Use a wx.Timer to periodically check whether input is ready - as soon as + # it is, we exit the main loop + def poll(ev): if context.input_is_ready(): app.ExitMainLoop() - # We have to put the wx.Timer in a wx.Frame for it to fire properly. - # We make the Frame hidden when we create it in the main app below. - class TimerFrame(wx.Frame): - def __init__(self, func): - wx.Frame.__init__(self, None, -1) - self.timer = wx.Timer(self) - self.timer.Start(poll_interval) - self.Bind(wx.EVT_TIMER, self.on_timer) - self.func = func - - def on_timer(self, event): - self.func() - - frame = TimerFrame(wake) - frame.Show(False) - - # The import of wx on Linux sets the handler for signal.SIGINT - # to 0. This is a bug in wx or gtk. We fix by just setting it - # back to the Python default. + timer = wx.Timer() + timer.Start(poll_interval) + timer.Bind(wx.EVT_TIMER, poll) + + # The import of wx on Linux sets the handler for signal.SIGINT to 0. This + # is a bug in wx or gtk. We fix by just setting it back to the Python + # default. if not callable(signal.getsignal(signal.SIGINT)): signal.signal(signal.SIGINT, signal.default_int_handler) @@ -195,6 +199,7 @@ def inputhook_wxphoenix(context): # Get the major wx version number to figure out what input hook we should use. major_version = 3 + try: major_version = int(wx.__version__[0]) except Exception: