3

I have a wxPython app. I want it to respond to SIGTERM and SIGINT just like as if the "close" button had been clicked. However, when I bind the signals using signal.signal(signal.SIGTERM, exit_handler), they only get executed after an event is sent to the main app graphically (clicking on a button, opening menu, etc.). How can I avoid this and execute the handles as soon as the event is caught?

Relevant parts of code:

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        # ...
        self.Bind(wx.EVT_CLOSE, self.signal_handler)
        signal.signal(signal.SIGTERM, self.signal_handler)
        signal.signal(signal.SIGINT, self.signal_handler)

# ...

app = wx.App(redirect=False, clearSigInt=False)
frame = MyFrame(None, "Hello World")
app.MainLoop()

This happens even if the signal calls are moved outside any function and executed before any wx calls.

randomdude999
  • 701
  • 7
  • 20

1 Answers1

3

One way of doing it, is to add a 'timer' to fake an event.

import wx
import signal, os

def signalUSR1_handler(sig,frame):
    print ("Signal Caught")

class ExampleFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        pid_no = str(os.getpid())
        panel = wx.Panel(self)
        self.quote1 = wx.StaticText(panel, label="Test signal with timer", pos=(20, 30))
        self.quote2 = wx.StaticText(panel, label="Send this process a USR1 signal", pos=(20, 50))
        self.quote3 = wx.StaticText(panel, label="kill -s USR1 "+pid_no, pos=(20, 70))
        self.button = wx.Button(panel, -1, "Click", pos=(20,90))
        self.button.Bind(wx.EVT_BUTTON, self.OnPress)
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
        self.timer.Start(1000)
        self.Show()
    def OnPress(self, event):
        print ("Button Pressed")
    def OnTimer(self, event):
        return
app = wx.App()
ExampleFrame(None)
signal.signal(signal.SIGUSR1,signalUSR1_handler)
app.MainLoop()
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • 4
    To help you understand why it works this way: IIRC, signals in Python are caught when they happen, but only processed when executing Python code. So if the signal happens while the program is in the MainLoop waiting for an event then nothing will be done about it until something causes control to return to Python code (such as dispatching an event to a handler in Python code.) So using a timer as above is one way to ensure that control leaves the MainLoop and goes into Python code periodically so the signal handlers can be called. – RobinDunn Jul 11 '16 at 23:17
  • @RobinDunn I really should have explained that in my answer, thanks! – Rolf of Saxony Jul 12 '16 at 07:10