2011-12-23 2 views
1

Я пытаюсь написать программу с pynotify, связями Python для libnotify. В какой-то момент я хочу вызвать критическое уведомление и обновить его каждые несколько секунд, пока информация не изменится, пока пользователь не закроет ее. Все это работает, за исключением того, что происходит, когда пользователь отклоняет его.pynotify: «закрытый» обратный вызов сигнала никогда не запускался

Чтобы уточнить уведомление, необходимо позвонить Notification.show после Notification.update. Это нормально, но это означает, что мне нужно отслеживать, отклонил ли пользователь уведомление, иначе он снова появится.

Это должно быть возможно двумя способами я могу думать:

  1. Обнаружение виден ли или нет уведомления. Я не нашел способа найти это.
  2. Сохранение некоторой переменной при закрытии уведомления, а затем проверку ее перед обновлением и вызов Notification.show.

Этот второй метод должен быть возможен. Пример кода, который я нашел (там, кажется, нет надлежащей документации для pynotify), привел меня к вызову Notification.connect для подключения сигнала "closed" к обратному вызову. Я пытался это сделать, но обратный вызов никогда не запускался.

I Googled и отлаживается в течение длительного времени, но не смог добиться какого-либо прогресса. В конце концов я нашел несколько примеров скриптов, которые поставляются с 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.

ответ

0

попробуйте следующее:

добавить:

from time import sleep 

и в конце вашего emit_notification:

sleep(2) 
n.close() 

(Обновлено после обсуждения с ОП :) Это должно огонь ваш обратный вызов! Таким образом, вы можете протестировать вместе с dbus-монитором, если ваш DBus-Server делает то, что он должен делать. (Идея от ОП.)

Это все еще не то, что вы действительно ищете, но на какое-то время объясняет, по крайней мере, ваше недоумение по поводу неработающего сигнала.

Что вы, вероятно, должны изучить, являются свойствами действия. Я нашел что-то интересное here. Похоже, вы можете взаимодействовать с пользователем непосредственно в ваших уведомлениях.

Поскольку 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): 
+0

Нет, я до сих пор не понимаю «закрытие». сообщения на моем терминале, что и должен делать обратный вызов в этом тестовом сценарии. Вы получаете эти сообщения? И посмотрите [спецификацию «закрытого» сигнала] (http://www.galago-project.org/specs/notification/0.9/x408.html#signal-notification-closed), в котором говорится, что мы должны получить '' закрытый "сигнал, когда уведомление закрывается независимо от того, истекает ли уведомление, пользователь отклоняет его или мы называем' Notification.close'. – tremby

+0

Да, я получаю сообщение! Библиотека libnotify/pynotify является оберткой DBus-Communication. Таким образом, должен присутствовать соответствующий DBus-сервер, который правильно обрабатывает ваши запросы DBus-Clients. Просто чтобы быть на одной странице: на какой системе вы работаете? –

+0

Ubuntu 10.04 x86_64. В соответствии со спецификацией изменения, которые вы предложили (вызывая метод «Notification.close»), не должны были иметь значения - вы должны получить «закрытые» сигналы в любом случае. Можете ли вы дважды проверить? Интересно, почему это не будет работать для меня. – tremby

1

Я был ищет то же самое. Я нашел кого-то, использующего 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() 
+0

В моем случае проблема исчезла, и у меня есть идея, почему. Если у меня будет время, я буду исследовать - это, должно быть, был несвязанный патч, который сделал это в какой-то момент. Рад, что он работает на вас. – tremby