pynotify: “关闭”信号回调从未触发
我正在尝试用pynotify写一个程序,pynotify是libnotify的Python绑定。我想在某个时刻显示一个重要的通知,并且希望它能随着信息的变化每隔几秒更新一次,直到用户点击关闭它。这个过程都能正常工作,除了处理用户关闭通知后的情况。
为了更新通知,我需要在调用Notification.update
之后再调用Notification.show
。这没问题,但这就意味着我需要记录用户是否关闭了通知,否则它会一直弹出来。
我想到有两种方法可以做到这一点:
- 检测通知是否可见。我还没找到任何方法来判断这一点。
- 在通知关闭时存储一个变量,然后在更新之前检查这个变量,再调用
Notification.show
。
第二种方法应该是可行的。我找到的示例代码(似乎没有pynotify的正式文档)让我调用Notification.connect
来把一个"closed"
信号连接到一个回调函数。我试着这么做了,但回调函数从来没有被触发。
我在网上搜索和调试了很长时间,但没有任何进展。最后我找到了一些随pynotify提供的示例脚本。其中一个脚本为"closed"
信号附加了一个处理程序:test-xy-stress.py
它的内容如下:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gobject
import gtk
import gtk.gdk
import pynotify
import sys
import random
exposed_signal_id = 0
count = 0
def handle_closed(n):
print "Closing."
def emit_notification(x, y):
n = pynotify.Notification("X, Y Test",
"This notification should point to %d, %d." % (x, y))
n.set_hint("x", x)
n.set_hint("y", y)
n.connect('closed', handle_closed)
n.show()
def popup_random_bubble():
display = gtk.gdk.display_get_default()
screen = display.get_default_screen()
screen_x2 = screen.get_width() - 1
screen_y2 = screen.get_height() - 1
x = random.randint(0, screen_x2)
y = random.randint(0, screen_y2)
emit_notification(x, y)
return True
if __name__ == '__main__':
if not pynotify.init("XY Stress"):
sys.exit(1)
gobject.timeout_add(1000, popup_random_bubble)
gtk.main()
我运行了这个脚本,发现这里的回调函数也从来没有被触发。
这可能只是我系统的问题,还是pynotify或libnotify中有bug呢?如果现在无法解决这个问题,那第一种方法有没有可能实现呢?
我似乎安装的是libnotify 0.4.5和pynotify 0.1.1。
2 个回答
试试下面的方法:
添加:
from time import sleep
然后在你的 emit_notification 的最后加上:
sleep(2)
n.close()
(在和提问者讨论后更新:) 这样应该能触发你的回调!这样你可以和 dbus-monitor 一起测试,看看你的 DBus 服务器是否正常工作。(这个想法来自提问者。)
这可能还不是你真正想要的,但至少可以解释你对未发出信号的困惑。
你可能应该关注一下动作属性。我在这里发现了一些有趣的东西 这里。看起来你可以直接在通知中与用户互动。
因为 pynotify 只是 DBus 通信的一个封装,你也可以尝试一个变通的方法:
from dbus import SessionBus, Interface
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
notify_busname = 'org.freedesktop.Notifications'
notify_obj_path ='/org/freedesktop/Notifications'
lbus = SessionBus()
notify_server = lbus.get_object(notify_busname, notify_obj_path)
然后在你的处理函数定义后:
notify_server.connect_to_signal(None, handle_closed)
我还为了测试目的,修改了你的函数签名,以适应 DBus 信号:
def handle_closed(*arg, **kwargs):
我也在找同样的东西。我发现有人用 gobject.MainLoop 来代替 gtk.main,这样可以解决问题:linuxquestions.org.
我发现这个方法对我有效:
#!/usr/bin/python
import pynotify
import gobject
def OnClicked(notification, signal_text):
print '1: ' + str(notification)
print '2: ' + str(signal_text)
notification.close()
global loop
loop.quit()
def OnClosed(notification):
print 'Ignoring fire'
notification.close()
global loop
loop.quit()
def Main():
pynotify.init('ProgramName')
global loop
loop = gobject.MainLoop()
notify = pynotify.Notification('Fire!', 'I\'m just kidding...')
# optionalm, just changes notification color
notify.set_urgency(pynotify.URGENCY_CRITICAL)
# optional, it will expire eventually
notify.set_timeout(pynotify.EXPIRES_NEVER)
notify.add_action('You Clicked The Button', 'Remove Fire', OnClicked)
notify.connect("closed",OnClosed)
notify.show()
loop.run()
if __name__ == '__main__':
Main()