2010-03-22 19 views
5

OK đây có lẽ là một khó khăn, tôi đã có ứng dụng pyGTK có sự cố ngẫu nhiên do lỗi X Window mà tôi không thể bắt /điều khiển. Vì vậy, tôi đã tạo một trình bao bọc khởi động lại ứng dụng ngay sau khi phát hiện sự cố, hiện tại xảy ra sự cố, khi người dùng đăng xuất hoặc tắt hệ thống, ứng dụng sẽ thoát với trạng thái 1. Nhưng trên một số lỗi X thì ứng dụng đó cũng vậy.Phát hiện đăng xuất/tắt máy của người dùng bằng Python/GTK trong Linux - SIGTERM/HUP không nhận được

Vì vậy, tôi đã cố gắng theo nghĩa đen bất cứ điều gì để bắt shutdown/logout, không có thành công, đây là những gì tôi đã cố gắng:

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

Không một trong những thành công, là có bất kỳ cấp độ đường thấp để phát hiện hệ thống tắt? Google không tìm thấy bất cứ điều gì liên quan đến điều đó.

Tôi đoán phải có một cách, tôi có đúng không? :/

EDIT: OK, nhiều nội dung khác.

Tôi đã tạo shell script này:

#!/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 

Và cũng tạo ra một file .desktop để chạy nó:

[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 

Thông thường điều này sẽ tạo ra các tập tin dài trên logout và file húp khi nó đã được bắt đầu với &. Nhưng không phải trên hệ thống của tôi. GDM không quan tâm đến kịch bản chút nào, khi tôi nói lại, nó vẫn đang chạy.

Tôi cũng đã thử sử dụng shopt -s huponexit, không thành công.

EDIT2:
Ngoài ra đây là một số thông tin aboute mã thật, toàn bộ sự việc như sau:

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

Dòng chảy là như thế này:

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

Bây giờ trên shutdown , start program trả lại 1. Điều đó có nghĩa là hoặc là nó đã làm hanup hoặc quá trình cha mẹ chấm dứt, vấn đề chính là để tìm ra cái nào trong hai điều này vừa xảy ra. X Lỗi dẫn đến 1 lỗi. Bẫy trong shellscript không hoạt động.

Nếu bạn muốn có một cái nhìn vào mã thực tế kiểm tra xem nó ra qua tại GitHub:
http://github.com/BonsaiDen/Atarashii

Trả lời

1

OK, cuối cùng tôi đã tìm thấy giải pháp :)

Bạn chỉ đơn giản là không thể dựa vào tín hiệu trong trường hợp này. Bạn phải kết nối với Phiên làm việc để được thông báo rằng việc đăng xuất sẽ xảy ra.

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 

Một lưu ý quan trọng ở đây: Đừng cố gắng để thoát khỏi chương trình của bạn trong on_logout, nếu bạn làm như vậy, GNOME sẽ không nhận ra rằng chương trình của bạn đã được thoát và sẽ cung cấp cho bạn hộp thoại rằng một số chương trình vẫn còn đang chạy.

0

Bạn quên đóng vòng lặp sự kiện gtk của.

Mã này thoát với mã 0 khi bạn đóng cửa sổ:

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: Dưới đây là đoạn mã để bắt tín hiệu 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) 

Phần còn lại của mã chính xác như trên, không có thay đổi. Nó hoạt động ở đây khi tôi gửi SIGTERM đến quá trình python: gtk vòng lặp chính kết thúc và thoát chương trình với mã thoát 0.

+0

Điều đó không giải quyết được vấn đề, destroy_event thậm chí không được gọi khi người dùng đăng xuất hoặc tắt hệ thống, không có tệp nào ở trên được tạo. Các vấn đề khác là do kịch bản wrapper, nó được "giết" đầu tiên, do đó, các ứng dụng sẽ thoát với 1 vì quá trình cha mẹ của nó đã biến mất. –

+0

Nghiên cứu thêm chỉ ra rằng thực sự quá trình sẽ nhận được SIGTERM. Nhưng nó không nhận được một, có vẻ như nó chỉ bị giết ... –

+0

Theo nguồn của GDM nó lần đầu tiên gửi SIGTERM, có vẻ như python chỉ không quan tâm:/ –

Các vấn đề liên quan