Je m'amuse avec dbus-monitor pour essayer de comprendre le fonctionnement de dbus dans un environnement Ubuntu. J'ai plusieurs questions à cet égard:
Pourriez-vous s'il vous plaît laissez-moi savoir comment lire ce qui suit correctement? Je comprends la grande idée, mais pas les détails.
signal sender=:1.1948 -> dest=(null destination) serial=1829990 path=/org/ayatana/menu/DA00003; interface=org.ayatana.dbusmenu; member=ItemPropertyUpdated
int32 23
string "enabled"
variant boolean true
method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1399 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications;
member=GetCapabilities
Je comprends que le premier est un signal alors que le second est une méthode. Est-ce que destination signifie qu'il peut y avoir un récepteur/créneau spécifique pour un signal? Qu'est-ce qu'un membre ? Et les éléments de la liste suivant le signal sont-ils les arguments passés dans le signal? Quels sont expéditeurs et séries ?
J'ai remarqué quelque chose à propos de la relation entre le contrôle du volume et les notifications. D'après ce que j'ai lu de la sortie dbus-monitor
method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1400 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
string "gnome-settings-daemon"
uint32 0
string "notification-audio-volume-medium"
string " "
string ""
array [
]
array [
dict entry(
string "value"
variant int32 38
)
dict entry(
string "x-canonical-private-synchronous"
variant string "volume"
)
]
int32 -1
Il semble que la notification est déclenchée par sa méthode. Je ne comprends tout simplement pas pourquoi cela fonctionne de cette façon. À mon avis, il serait plus logique qu'un signal soit émis "notification-audio-volume-medium" pendant que la notification écoute ce signal et réagir en conséquence. Si l'envoi/la réception était public plutôt que privé, cela ne permettrait-il pas plus de flexibilité et d'efficacité? Par exemple, s'il existe un signal public pour "notification-audio-volume-medium" , plusieurs applications peuvent écouter ce signal (ce qui permettrait de les applications de notification à venir) et les développeurs devraient simplement se préoccuper d'envoyer des signaux, tandis que capturer et traiter un signal serait l'activité de l'application notifiante (ou tout autre programme ayant besoin de ces signaux).
Je viens juste de découvrir Dbus et je souhaite en apprendre davantage, car je travaille avec Dbus sur Python, principalement pour développer des applets. J'ai vu le tutoriel dbus-python et il enseigne comment écouter tous les signaux (en ne spécifiant ni interface, ni chemin, etc.) Mais comment suivre les méthodes lorsqu'elles sont appelées, comme le fait dbus-monitor ?
Si vous avez la patience d'enseigner comment cela fonctionne, vous êtes le bienvenu.
D-Bus fournit un moyen de communication entre services. Les services peuvent être anonymous (identifiés uniquement par l’adresse de bus, telle que: 1.6), et les services peuvent acquérir noms bien connus, comme org.freedesktop.Notifications
ou org.freedesktop.NetworkManager
. L'expéditeur et la destination que vous pouvez voir dans les journaux sont des services. "Destination nulle" signifie diffusion: livraison à tous les services.
Un service peut exporter un ou plusieurs objets vers le bus. Les objets sont donnés chemins d'objet, comme /org/freedesktop/NetworkManager/ActiveConnection/1
ou /org/ayatana/menu/DA00003
. Les chemins des objets utilisent une barre oblique comme séparateur, comme les chemins du système de fichiers.
Chaque objet peut supporter un ou plusieurs interfaces. Une interface n’est rien de plus qu’un ensemble de méthodes et de signaux, plus communément appelé membres (très similaire à OOP interface). Les méthodes et les signaux ont des signatures fixes. Les membres sont toujours nommés au sein de noms connus noms d'interface.
Une fois publiés, les noms connus ne changent jamais .
Tout service peut se connecter aux signaux d'un autre service et appeler ses méthodes de manière asynchrone. Tout service peut émettre des signaux.
Passons maintenant à vos questions spécifiques.
émetteur du signal =: 1.1948 -> dest = (destination nulle) serial = 1829990 chemin =/org/ayatana/menu/DA00003; interface = org.ayatana.dbusmenu; member = ItemPropertyUpdated int32 23 chaîne de caractères "enabled" variante boolean true
Oui, vous avez raison, c'est un signal. Il est diffusé par le service :1.1948
et l'objet "self" est /org/ayatana/menu/DA00003
. Le signal a pour nom ItemPropertyUpdated
qui est défini dans l'interface org.ayatana.dbusmenu
(comme org.ayatana.dbusmenu::ItemPropertyUpdated
en C++). Le numéro de série, je suppose, est une sorte d’identificateur unique de l’événement sur le bus.
Ensuite, nous voyons les arguments du signal. Selon la documentation de l'interface , le premier argument int32 est l'identifiant d'un élément, la deuxième chaîne est le nom de sa propriété et la troisième variante est sa valeur. Ainsi, l'objet /org/ayatana/menu/DA00003
nous notifie que l'ID d'élément n ° 23 a changé sa propriété enabled
en true.
Un autre exemple sur les signaux:
émetteur du signal =: 1.1602 -> dest = (destination nulle) serial = 20408 chemin =/im/Pidgin/purple/PurpleObject; interface = im.Pidgin.purple.PurpleInterface; member = SendingChatMsg int32 47893 string "test" uint32 1 émetteur du signal =: 1.1602 -> dest = (destination nulle) serial = 20409 chemin =/im/Pidgin/purple/PurpleObject; interface = im.Pidgin.purple.PurpleInterface; membre = IrcSendingText int32 64170 string "PRIVMSG #chat: test
J'ai envoyé un message texte "test" à l'aide de Pidgin à un canal IRC, et /im/Pidgin/purple/PurpleObject
a émis deux signaux sous l'interface im.Pidgin.purple.PurpleInterface
: d'abord un SendingChatMsg
général, puis un _IrcSendingText
plus spécifique.
Maintenant les méthodes. Les méthodes sont un moyen de demander aux objets D-Bus de faire quelque chose, ou d'effectuer une requête et de renvoyer des données. Elles ressemblent beaucoup aux méthodes classiques OOP, à la différence que les méthodes D-Bus sont appelées de manière asynchrone.
Appelons une méthode D-Bus par programme.
import dbus, dbus.proxies
#-- connect to the session bus (as opposed to the system bus)
session = dbus.SessionBus()
#-- create proxy object of D-Bus object
obj_proxy = dbus.proxies.ProxyObject(conn=session,
bus_name="org.freedesktop.Notifications", #-- name of the service we are retrieving object from
object_path="/org/freedesktop/Notifications") #-- the object path
#-- create proxy object of the D-Bus object wrapped into specific interface
intf_proxy = dbus.proxies.Interface(obj_proxy, "org.freedesktop.Notifications")
#-- lastly, create proxy object of the D-Bus method
method_proxy = intf_proxy.get_dbus_method("Notify")
#-- ... and call the method
method_proxy("test from python",
dbus.UInt32(0),
"bluetooth", #-- icon name
"Notification summary",
"Here goes notification body",
[], {},
5) #-- timeout
Notez les arguments, en particulier le nom de l'icône. Dans votre exemple, "notification-audio-volume-medium"
était l'icône du haut-parleur de volume moyen.
Il est tout à fait possible d’exécuter vos propres services D-Bus, d’exporter vos propres objets D-Bus et de définir vos propres interfaces D-Bus avec vos propres méthodes et signaux. Tout cela peut être fait facilement dans Python une fois que vous avez compris le concept global et lu la documentation du module dbus
. :)