Detectar el cierre / cierre de sesión del usuario en Python / GTK en Linux – SIGTERM / HUP no recibido

OK, esta es probablemente una difícil, tengo una aplicación pyGTK que tiene lockings aleatorios debido a errores de X Window que no puedo detectar / controlar.

Así que creé una envoltura que reinicia la aplicación tan pronto como detecta una falla, ahora surge el problema, cuando el usuario cierra la sesión o apaga el sistema, la aplicación sale con el estado 1. Pero en algunos errores de X, también lo hace.

Así que intenté literalmente cualquier cosa para detectar el apagado / cierre de sesión, sin éxito, esto es lo que he intentado:

import pygtk import gtk import sys class Test(gtk.Window): def delete_event(self, widget, event, data=None): open("delete_event", "wb") def destroy_event(self, widget, data=None): open("destroy_event", "wb") def destroy_event2(self, widget, event, data=None): open("destroy_event2", "wb") def __init__(self): gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) self.show() self.connect("delete_event", self.delete_event) self.connect("destroy", self.destroy_event) self.connect("destroy-event", self.destroy_event2) def foo(): open("add_event", "wb") def ex(): open("sys_event", "wb") from signal import * def clean(sig): f = open("sig_event", "wb") f.write(str(sig)) f.close() exit(0) for sig in (SIGABRT, SIGILL, SIGINT, SIGSEGV, SIGTERM): signal(sig, lambda *args: clean(sig)) def at(): open("at_event", "wb") import atexit atexit.register(at) f = Test() sys.exitfunc = ex gtk.quit_add(gtk.main_level(), foo) gtk.main() open("exit_event", "wb") 

Ninguno de estos tiene éxito, ¿hay alguna forma de bajo nivel para detectar el apagado del sistema? Google no encontró nada relacionado con eso.

Supongo que debe haber una manera, ¿verdad? : /

    EDITAR: OK, más cosas.

    He creado este script de shell:

     #!/bin/bash trap test_term TERM trap test_hup HUP test_term(){ echo "teeeeeeeeeerm" >~/Desktop/term.info exit 0 } test_hup(){ echo "huuuuuuuuuuup" >~/Desktop/hup.info exit 1 } while [ true ] do echo "idle..." sleep 2 done 

    Y también creó un archivo .desktop para ejecutarlo:

     [Desktop Entry] Name=Kittens GenericName=Kittens Comment=Kitten Script Exec=kittens StartupNotify=true Terminal=false Encoding=UTF-8 Type=Application Categories=Network;GTK; Name[de_DE]=Kittens 

    Normalmente, esto debería crear el archivo de término en el cierre de sesión y el archivo hup cuando se inició con &. Pero no en mi sistema. A GDM no le importa el script en absoluto, cuando vuelvo a iniciar sesión, todavía se está ejecutando.

    También he intentado usar shopt -s huponexit , sin éxito.

    EDIT2:
    También aquí hay más información sobre el código real, todo se ve así:

     Wrapper Script, that catches errors and restarts the programm -> Main Programm with GTK Mainloop -> Background Updater Thread 

    El flujo es así:

     Start Wrapper -> enter restart loop while restarts  start program -> check return code -> write error to file or exit the wrapper on 0 

    Ahora, al apagar, start program retorno 1. Eso significa que se terminó o que el proceso principal terminó, el problema principal es averiguar cuál de estos dos acaba de suceder. X errores resultan en un 1 también. Atrapar en el shellscript no funciona.

    Si quieres echar un vistazo al código real, échale un vistazo en GitHub:
    http://github.com/BonsaiDen/Atarashii

    OK, finalmente encontré la solución 🙂

    Simplemente no puedes confiar en las señales en este caso. Debe conectarse a la sesión de escritorio para recibir una notificación de que se va a cerrar la sesión.

     import gnome.ui gnome.program_init('Program', self.version) # This is going to trigger a warning that program name has been set twice, you can ignore this, it seems to be a problem with a recent version of glib, the warning is all over the place out there client = gnome.ui.master_client() # connect us to gnome session manager, we need to init the program before this client.connect('save-yourself', self.on_logout) # This gets called when the user confirms the logout/shutdown client.connect('shutdown-cancelled', self.on_logout_cancel) # This gets called when the logout/shutdown is canceled client.connect('die', self.on_logout) # Don't know when this gets called it never got in my tests def on_logout(self, *args): # save settings an create a file that tells the wrapper that we have exited correctly! # we'll still return with status code 1, but that's just gtk crashing somehow def on_logout_cancel(self, *args): # simply delete the logout file if it exists 

    Una nota importante aquí: no intente salir de su progtwig en on_logout , si lo hace, GNOME no reconocerá que su progtwig ha sido cancelado y le dará el diálogo de que algunos progtwigs aún se están ejecutando.

    Se te olvidó cerrar el bucle de eventos de gtk.

    Este código sale con el código 0 cuando cierra la ventana:

     import gtk class Test(gtk.Window): def destroy_event(self, widget, data=None): gtk.main_quit() def __init__(self): gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) self.connect("destroy", self.destroy_event) self.show() f = Test() gtk.main() 

    EDITAR: Aquí está el código para capturar la señal SIGTERM:

     import signal def handler(signum, frame): print 'Signal handler called with signal', signum print 'Finalizing main loop' gtk.main_quit() signal.signal(signal.SIGTERM, handler) 

    El rest del código es exactamente como el de arriba, sin cambios. Funciona aquí cuando envío SIGTERM al proceso de python: gtk main loop termina y el progtwig sale con el código de salida 0 .