回调和gtk主循环

时间:2012-01-04 13:46:09

标签: python gtk pynotify

我正在尝试创建一个简单的Unix桌面应用程序,该应用程序使用pynotify通知系统向用户显示一些警报,并允许他们通过警报上的按钮启动相关应用程序。

以下是相关的简化代码:

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

这很好用(它显示一个带有“Action”按钮的通知弹出窗口,触发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()

但当然这不是正确的解决方案,我很快得到“超出最大递归深度”Python RuntimeError。但是它表明更改gtk.main()调用的位置有一个发生率。

我试图查看有关主循环的Gtk和Pygtk文档,但最终没有找到解决方案。

所以我的问题是:做什么是正确的,背后的逻辑是什么?

TL; DR :如果我没有将gtk.main()放在显示通知的同一个函数中,则应该触发action_callback函数。由于这个函数需要放在gtk mainloop中,所以我不得不让gtk mainloop自己调用或者没有触发action_callback函数。

提前感谢您提供任何帮助;)

1 个答案:

答案 0 :(得分:3)

这里的问题是pynotify在未引用的对象上有回调错误。在您的第一个代码段中,当n函数退出时,main()会被取消引用(假设在cPython中引用计数)。 不幸的是,这意味着通知对象被销毁,并且未调用该操作(尽管您的通知守护程序仍将显示通知)。

解决这个问题的方法是保留对该通知的引用。 最简单的方法是抓住您的第一个代码段并将n = pynotify.Notification更改为self.last_notification = n = pynotify.Notication

如果您有多个通知,则需要将它们放入列表或集合中,但是在触发操作的情况下以及超时时,您需要确保它们被删除到期。