I am writing a Python application using GTK for the GUI. I noticed that closing it with Ctrl-C from the terminal isn't working and I discovered this is because of a bug, so I tried to manually handle the signal. The problem is that if I set the default behaviour to the default one, the signal is caught and the application is closed correctly, but if I use a custom handler it doesn't work. Here is my (simplified) code:
from gi.repository import Gtk
import signal
class MainWindow(Gtk.Window):
def __init__(self):
...
signal.signal(signal.SIGINT, self.__signal_handler)
def __signal_handler(self, signal, frame):
print "Caught!"
...
if __name__ == "__main__":
win = MainWindow()
win.show_all()
Gtk.main()
If, instead, I set the default behaviour, the signal is caught correctly:
from gi.repository import Gtk
import signal
class MainWindow(Gtk.Window):
def __init__(self):
...
signal.signal(signal.SIGINT, signal.SIG_DFL)
...
if __name__ == "__main__":
win = MainWindow()
win.show_all()
Gtk.main()
Am I missing something?
EDIT:
I tried some more and I noticed that the signal is actually captured, but the window is not shutdown immediately, but only when the focus has been acquired again. If, instead, I run a
kill -9 pid
from another terminal window, the application is closed immediately.
I also remember having lots of trouble regarding signal handling while learning appindicators with pygtk3. Here a working example demonstrating how it can be done for SIGHUP, SIGINT and SIGTERM:
#!/usr/bin/python
from gi.repository import Gtk, GLib, GObject
from gi.repository import AppIndicator3 as appindicator
import os
import signal
class Gui():
def __init__(self):
self.window = Gtk.Window(title="Signal example")
self.window.set_size_request(250,150)
self.window.connect("delete-event", Gtk.main_quit)
self.window.show_all()
def cleanup(self):
print("... Cleaning up variables, etc.")
def quit(self, widget):
print("... Exiting main gtk loop")
Gtk.main_quit()
def InitSignal(gui):
def signal_action(signal):
if signal is 1:
print("Caught signal SIGHUP(1)")
elif signal is 2:
print("Caught signal SIGINT(2)")
elif signal is 15:
print("Caught signal SIGTERM(15)")
gui.cleanup()
gui.quit(None)
def idle_handler(*args):
print("Python signal handler activated.")
GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH)
def handler(*args):
print("GLib signal handler activated.")
signal_action(args[0])
def install_glib_handler(sig):
unix_signal_add = None
if hasattr(GLib, "unix_signal_add"):
unix_signal_add = GLib.unix_signal_add
elif hasattr(GLib, "unix_signal_add_full"):
unix_signal_add = GLib.unix_signal_add_full
if unix_signal_add:
print("Register GLib signal handler: %r" % sig)
unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig)
else:
print("Can't install GLib signal handler, too old gi.")
SIGS = [getattr(signal, s, None) for s in "SIGINT SIGTERM SIGHUP".split()]
for sig in filter(None, SIGS):
print("Register Python signal handler: %r" % sig)
signal.signal(sig, idle_handler)
GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH)
if __name__ == "__main__":
gui = Gui()
InitSignal(gui)
Gtk.main()
Note that when recieving a signal, if you don't exit gtk loop (Gtk.main_quit()) then when it recieves a signal for the second time it will close itself, probably because of the bug you mentioned. Nontheless for cleaning up variables right before exiting (including with CTRL + C) still works perfect.
If I recall correctly I got the solution from a person in pygtk irc channel, so I cannot give the right credit to the person that provided me with the solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With