pynotify: "закрытый" сигнал обратного вызова никогда не срабатывает
Я пытаюсь написать программу с pynotify, привязки Python для libnotify. Я хочу вызвать критическое уведомление в какой-то момент и обновлять его каждые несколько секунд по мере изменения информации, пока пользователь не щелкнет его. Это все работает, за исключением обработки того, что происходит, когда пользователь отклоняет его.
Для того, чтобы обновить уведомление мне нужно позвонить Notification.show
после Notification.update
, Это нормально, но это означает, что мне нужно следить за тем, отклонил ли пользователь уведомление, в противном случае оно будет просто появляться снова.
Это должно быть возможно двумя способами, о которых я могу думать:
- Обнаружение, является ли уведомление видимым или нет. Я не нашел способа узнать это.
- Сохранение некоторой переменной при закрытии уведомления, затем проверка ее перед обновлением и вызов
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 где-то? Если сейчас это что-то непомощное, как насчет варианта 1 выше - есть ли способ сделать это?
Кажется, у меня есть libnotify 0.4.5 и pynotify 0.1.1.
2 ответа
Я искал то же самое. Я нашел кого-то, кто использовал 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()
Попробуйте следующее:
добавлять:
from time import sleep
и в конце вашего emit_notification:
sleep(2)
n.close()
(Обновлено после обсуждения с ОП:) Это должно запустить ваш обратный вызов! Таким образом, вы можете протестировать вместе с dbus-monitor, если ваш DBus-Server делает то, что должен делать. (Идея из ОП.)
Это все еще не то, что вы действительно ищете, но пока объясняет, по крайней мере, ваше недоумение по поводу пропущенного сигнала.
Что вы, вероятно, должны посмотреть, это свойства действия. Я нашел кое-что интересное здесь. Похоже, вы можете взаимодействовать с пользователем непосредственно в ваших уведомлениях.
Поскольку 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):