Ouvindo notificações recebidas da libnotify usando DBus

9

Estou tentando filtrar todas as notificações através do speak. No entanto, parece que não consigo encontrar uma maneira de obter o corpo da notificação de um script python, ou mesmo o nome do sinal para ouvir.

bus.add_signal_receiver(espeak,
                    dbus_interface="org.freedesktop.Notifications",
                    signal_name="??")

Tentar pesquisar no Google apenas parece produzir resultados que envolvem a criação de novas notificações, por isso estou completamente perdido agora.

Alguém pode me ajudar com isso?

Em resumo, o que eu quero é ouvir as notificações recebidas usando python e obter o atributo "body" da notificação.

manmachine
fonte
1
Parece que uma notificação não produz um sinal, ou seja, dbus-monitor "type='signal',interface='org.freedesktop.Notifications'"não mostra nada, mas dbus-monitor "interface='org.freedesktop.Notifications'"mostra notificações (o tipo é 'method_call' e não 'signal').
jfs

Respostas:

11

Para manter isso atualizado: do dbus 1.5.something é necessário um parâmetro extra ao adicionar uma string de correspondência bus.add_match_string_non_blockingpara garantir que recebamos tudo.

O código resultante seria o seguinte:

import glib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def notifications(bus, message):
    print [arg for arg in message.get_args_list()]

DBusGMainLoop(set_as_default=True)

bus = dbus.SessionBus()
bus.add_match_string_non_blocking("eavesdrop=true, interface='org.freedesktop.Notifications', member='Notify'")
bus.add_message_filter(notifications)

mainloop = glib.MainLoop()
mainloop.run()
joost
fonte
Se eu quiser chamar outro método dbus diferente dentro do filtro de notificação, ele não funcionará. Tudo o que eu recebo unable to connect to session bus: Operation was cancelled. Estamos passando buspara o filtro.
Khurshid Alam
1
Na minha instalação do Python (Python 3, Ubuntu) eu precisava from gi.repository import GLib as glibfazer isso funcionar.
Owen
6

Com notificações, você quer dizer os "balões OSD" que algum software envia, como alteração de volume, bate-papo por mensagem instantânea, etc.? Você deseja criar um programa python para capturá-los?

Bem, o Ask Ubuntu não é o controle de qualidade de um programador, e o desenvolvimento de software está um pouco além do escopo, mas aqui está um pequeno código que eu capturei bolhas de notificação:

import glib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def notifications(bus, message):
    if message.get_member() == "Notify":
        print [arg for arg in message.get_args_list()]

DBusGMainLoop(set_as_default=True)

bus = dbus.SessionBus()
bus.add_match_string_non_blocking("interface='org.freedesktop.Notifications'")
bus.add_message_filter(notifications)

mainloop = glib.MainLoop()
mainloop.run()

Deixe isso em execução em um terminal, abra outra janela do terminal e teste-a:

notify-send --icon=/usr/share/pixmaps/debian-logo.png "My Title" "Some text body"

E o programa produzirá isso:

[dbus.String(u'notify-send'), dbus.UInt32(0L), dbus.String(u'/usr/share/pixmaps/debian-logo.png'), dbus.String(u'My Title'), dbus.String(u'Some text body'),...

Como você deve ter adivinhado, message.get_args_list()[0]é o remetente, [2] para o ícone, [3] para o resumo e [4] para o texto do corpo.

Para o significado dos outros campos, verifique os documentos oficiais de especificação

MestreLion
fonte
Parece que não funciona mais a partir de 16.04. A resposta de Joost abaixo corrige isso.
Catskul
3

Eu tive problemas para que qualquer um dos outros exemplos funcionasse, mas cheguei lá no final. Aqui está um exemplo de trabalho:

import glib
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def print_notification(bus, message):
  keys = ["app_name", "replaces_id", "app_icon", "summary",
          "body", "actions", "hints", "expire_timeout"]
  args = message.get_args_list()
  if len(args) == 8:
    notification = dict([(keys[i], args[i]) for i in range(8)])
    print notification["summary"], notification["body"]

loop = DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
session_bus.add_match_string("type='method_call',interface='org.freedesktop.Notifications',member='Notify',eavesdrop=true")
session_bus.add_message_filter(print_notification)

glib.MainLoop().run()

Se você quiser ver um exemplo de trabalho mais detalhado, recomendo examinar o arquivo Notifications.py no projeto recent_notifications .

kzar
fonte