2010-03-22 28 views
5

OK esto es presumiblemente difícil, tengo una aplicación pyGTK que tiene bloqueos aleatorios debido a errores de X Window que no puedo detectar /controlar.Detectar cierre de sesión/apagado de usuario en Python/GTK bajo Linux - SIGTERM/HUP no recibido

Así que creé un contenedor que reinicia la aplicación tan pronto como detecta un bloqueo, ahora viene 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 X se lo hace también

así que he intentado literalmente cualquier cosa que coger el cierre/cierre de sesión, sin éxito, aquí 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 éstos tiene éxito, ¿hay alguna manera de bajo nivel para detectar el sistema ¿apagar? 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 se debe crear el archivo término al cerrar la sesión y el archivo Hup cuando se ha iniciado con &. Pero no en mi sistema. A GDM no le importa el script, cuando lo vuelvo a abrir, todavía se está ejecutando.

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

Edit2:
También aquí hay algo más de información aboute el código real, todo el asunto es así:

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

El flujo es la siguiente:

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

Ahora en el apagado , start program return 1. Eso significa que terminó o el proceso principal finalizó, el problema principal es averiguar cuál de estos dos acaba de suceder. X Los errores dan como resultado un 1 también. Atrapando en el shellscript no funciona.

Si quieres echar un vistazo al código real a echarle un vistazo encima en GitHub:
http://github.com/BonsaiDen/Atarashii

Respuesta

1

OK, finalmente encontró la solución :)

Usted simplemente no puede confiar en las señales en este caso. Debes conectarte 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: No trate de salir de su programa en on_logout, si lo hace, GNOME no reconocerá que su programa se ha salido y le dará el diálogo que algunos programas son todavía corriendo.

0

Usted se olvidó de cerrar bucle de eventos de GTK.

Este código finalice con el código 0 cuando se 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() 

EDIT: Aquí está el código para captar 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 resto de la el código es exactamente como el anterior, sin cambios. Funciona aquí cuando envío SIGTERM al proceso python: gtk main loop finaliza y el programa sale con el código de salida 0.

+0

Eso no resuelve el problema, destroy_event ni siquiera recibe una llamada cuando el usuario cierra la sesión o apaga el sistema, ninguno de los archivos anteriores se crea. El otro problema se debe al script de envoltura, primero se "mata", por lo que la aplicación saldrá con 1 porque su proceso principal desapareció. –

+0

Investigaciones adicionales indican que en realidad el proceso debería obtener un SIGTERM. Pero no lo consigue, parece que acaba de ser asesinado ... –

+0

Según la fuente de GDM, primero envía SIGTERM, parece que Python simplemente no le importa:/ –

Cuestiones relacionadas