代码之家  ›  专栏  ›  技术社区  ›  Ivo Wetzel

在Linux下的Python/GTK中检测用户注销/关闭-未收到SIGTERM/HUP

  •  6
  • Ivo Wetzel  · 技术社区  · 16 年前

    好吧,这可能是一个困难的问题,我有一个pyGTK应用程序,它由于X窗口错误而随机崩溃,我无法捕获/控制。

    因此,我创建了一个包装器,它在检测到崩溃时立即重新启动应用程序,现在问题来了,当用户注销或关闭系统时,应用程序将以状态1退出。但是在某些X错误时,它也会这样做。

    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")
    

    没有一个成功,有没有低水平的方法来检测系统关闭?谷歌没有发现任何与此相关的信息。

    编辑:

    我创建了这个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
    

    并创建了一个.desktop文件来运行它:

    [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 
    

    通常,这应该在注销时创建术语文件,并在用&启动时创建hup文件;。但不是在我的系统里。GDM根本不关心脚本,当我重新登录时,它仍然在运行。

    我也试过用 shopt -s huponexit

    编辑2:
    这里还有一些关于真实代码的更多信息,整个过程如下:

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

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

    现在关机了, start program 返回1。这意味着要么它没有启动,要么父进程终止,主要问题是要找出这两个进程中哪一个刚刚发生。 X错误也会导致1。在shell脚本中陷进去不起作用。

    如果您想查看实际代码,请访问GitHub:
    http://github.com/BonsaiDen/Atarashii

    2 回复  |  直到 16 年前
        1
  •  2
  •   Ivo Wetzel    16 年前

    好吧,我终于找到了解决办法:)

    在这种情况下,你根本不能依赖信号。您必须连接到桌面会话才能得到注销即将发生的通知。

    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
    

    on_logout ,如果您这样做,GNOME将不会识别出您的程序已经退出,并将给您一些程序仍在运行的对话框。

        2
  •  0
  •   nosklo    16 年前

    你忘了关闭gtk的事件循环。

    0 关闭窗口时:

    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()
    

    编辑: 下面是捕获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)
    

    其余的代码与上面的完全一样,没有变化。我发邮件的时候它在这里工作 SIGTERM 0

    推荐文章