4

pynotify通知システムを使用してユーザーにアラートを表示し、アラートに配置されたボタンから関連するアプリケーションを起動できるようにする単純なUnixデスクトップアプリケーションを作成しようとしています。

関連する簡略化されたコードは次のとおりです。

import subprocess, pynotify, gobject, gtk

class Notifier():
    def __init__(self):
        pynotify.init('Notifications')
        n = pynotify.Notification("Some stuff")
        n.add_action("action", "Action", self.action_callback)
        n.show()
        gtk.main()

    def action_callback(self, n, action):
        subprocess.Popen(['ls', '/'])

if __name__ == '__main__':
    Notifier()

これは正常に機能します(アクティブ化されるとls /をトリガーする「アクション」ボタン付きの通知ポップアップが表示されます)実際に通知部分をループに入れようとするまで(通知を取得して表示するにはサーバーを定期的にポーリングする必要があります) 。

私はこれを試しました:

import subprocess, pynotify, gobject, gtk

class Notifier():
    def __init__(self):
        pynotify.init('Notifications')
        gobject.timeout_add(0, self.main)
        gtk.main()

    def action_callback(self, n, action):
        subprocess.Popen(['ls', '/'])

    def main(self):
        n = pynotify.Notification("Some stuff")
        n.add_action("action", "Action", self.action_callback)
        n.show()
        gobject.timeout_add(10000, self.main)

if __name__ == '__main__':
    Notifier()

しかし、何らかの理由で、「アクション」ボタンをクリックしても「action_callback」関数は呼び出されなくなりました。

これは私がGtkメインループを使用する方法の問題のようです。このようなことを行うと、関数が実際にトリガーされます:

import subprocess, pynotify, gobject, gtk

class Notifier():
    def __init__(self):
        pynotify.init('Notifications')
        self.main()

    def action_callback(self, n, action):
        subprocess.Popen(['ls', '/'])

    def main(self):
        n = pynotify.Notification("Some stuff")
        n.add_action("action", "Action", self.action_callback)
        n.show()
        gobject.timeout_add(10000, self.main)
        gtk.main()

if __name__ == '__main__':
    Notifier()

しかしもちろん、これは適切な解決策ではなく、「最大再帰深度を超えた」PythonRuntimeErrorがすぐに発生します。ただし、gtk.main()呼び出しの場所を変更することには問題があることを示しています。

メインループに関するGtkとPygtkのドキュメントを調べてみましたが、最終的には解決策が見つかりませんでした。

だから私の質問は:何をするのが適切で、その背後にある論理は何ですか?

TL; DR:通知を表示する同じ関数にgtk.main()を配置しないと、必要なときにaction_callback関数がトリガーされません。この関数はgtkmainloopに配置する必要があるため、gtk mainloopがそれ自体を呼び出すか、action_callback関数がトリガーされないままになります。

助けてくれてありがとう;)

4

1 に答える 1

3

ここでの問題は、pynotifyに参照されていないオブジェクトのコールバックに関するバグがあることです。最初のスニペットでnは、関数が終了すると、参照されなくなります(cPythonで参照カウントを想定)main()。残念ながら、これは通知オブジェクトが破棄され、アクションが呼び出されないことを意味します(ただし、通知デーモンは引き続き通知を表示します)。

これに対する回避策は、その通知への参照を保持することです。最も簡単な方法は、最初のスニペットを取得してに変更n = pynotify.Notificationすることself.last_notification = n = pynotify.Noticationです。

複数の通知がある場合は、それらをリストまたはセットにスローする必要がありますが、アクションがトリガーされた場合とタイムアウトの期限が切れた場合の両方で、通知が削除されることを確認する必要があります。

于 2012-09-09T02:21:32.663 に答える