如何读取dbus-monitor输出?

我正在玩dbus-monitor来试图理解dbus在Ubuntu环境中是如何工作的。 我在这方面有几个问题:

  1. 能告诉我如何正确阅读以下内容吗? 我理解这个大创意,但不了解细节。

    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 

    我知道第一个是信号而第二个是方法。 目的地是否意味着信号可以有特定的接收器/插槽? 什么是会员 ? 列表中的项目是否跟随信号中传递的参数? 什么是发件人连续剧

  2. 我注意到了音量控制和通知之间的关系。 从我从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 

    似乎通知是由其方法触发的。 我只是不明白为什么它这样工作。 在我看来,如果有一个信号发出“notification-audio-volume-medium”,而通知会听取这个信号并做出相应的反应,那就更有意义了。 如果发送/接收是公开的而不是私有的,它是否会提供更大的灵活性和效率? 例如,如果有“通知 – 音频 – 音量 – 媒体”的公共信号,那么几个应用程序可以监听此信号(这将允许竞争通知应用程序出现),开发人员只需要关注发送信号虽然接收和处理信号将是通知应用程序的业务(或任何其他需要这些信号的程序)。

  3. 我刚接触Dbus,想要了解更多,因为我在Python上使用Dbus,主要是为了开发一些applet。 我已经看过dbus-python教程了 ,它教会了如何监听所有信号(既不指定接口也不指定路径等)。但是如何跟踪调用方法,如dbus-monitor呢?

如果你有耐心教它是如何工作的,那么欢迎你。

D-Bus介绍

  • D-Bus提供了服务之间通信的方法。 服务可以是匿名的 (仅通过总线地址识别,如:1.6),服务可以获取众所周知的名称 ,例如org.freedesktop.Notificationsorg.freedesktop.NetworkManager 。 您可以在日志中看到的发件人和目标是服务。 “空目的地”表示广播:向所有服务提供。

  • 服务可以将一个或多个对象导出到总线。 对象被赋予对象路径 ,例如/org/freedesktop/NetworkManager/ActiveConnection/1/org/ayatana/menu/DA00003 。 对象路径使用斜杠作为分隔符,如文件系统路径。

  • 每个对象可以支持一个或多个接口 。 接口只不过是一组方法和信号,通常称为成员 (非常类似于OOP接口)。 方法和信号具有固定的签名。 成员始终在众所周知的接口名称中命名。

  • 一旦发布,众所周知的名称永远不会改变

  • 任何服务都可以连接到另一个服务的信号,并异步调用其方法。 任何服务都可以发出信号。

信号

现在来看你的具体问题。

  signal sender =:1.1948  - > dest =(null destination)serial = 1829990 path = / org / ayatana / menu / DA00003; 接口= org.ayatana.dbusmenu; 构件= ItemPropertyUpdated
 int32 23
字符串“已启用”
变体布尔值true

是的,你是对的,这是一个信号。 它由服务广播:1.1948 ,“self”对象是/org/ayatana/menu/DA00003 。 该信号的名称为ItemPropertyUpdated ,它在org.ayatana.dbusmenu接口中org.ayatana.dbusmenu (类似于C ++中的org.ayatana.dbusmenu::ItemPropertyUpdated )。 我想,串口是总线上事件的一种唯一标识符。

然后我们看到信号参数。 根据接口文档 ,第一个int32参数是项的id,第二个字符串是其属性名,第三个变量是属性值。 因此, /org/ayatana/menu/DA00003对象通知我们项目标识#23将其enabled属性更改为true。


信号的另一个例子:

  signal sender =:1.1602  - > dest =(null destination)serial = 20408 path = / im / pidgin / purple / PurpleObject; 接口= im.pidgin.purple.PurpleInterface; 构件= SendingChatMsg
    int32 47893
   字符串“test”
    uint32 1
 signal sender =:1.1602  - > dest =(null destination)serial = 20409 path = / im / pidgin / purple / PurpleObject; 接口= im.pidgin.purple.PurpleInterface; 构件= IrcSendingText
    int32 64170
   字符串“PRIVMSG #chat:test

我使用Pidgin向IRC频道发送短信“test”, /im/pidgin/purple/PurpleObjectim.pidgin.purple.PurpleInterface接口下发出两个信号:首先是一般的SendingChatMsg ,然后是更具体的IrcSendingText

方法

现在的方法。 方法是一种让D-Bus对象执行某些操作,或执行某些查询和返回数据的方法。 它们与传统的OOP方法非常相似,只是异步调用D-Bus方法。

我们以编程方式调用D-Bus方法。

 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 

请注意参数,尤其是图标名称。 在您的示例中, "notification-audio-volume-medium"是中等音量扬声器的图标。

定制服务

绝对可以运行您自己的D-Bus服务,导出您自己的D-Bus对象,并使用您自己的方法和信号定义您自己的D-Bus接口。 一旦掌握了整体概念并阅读dbus模块文档,这一切都可以通过Python轻松完成。 :)

我也在寻找通过dbus脚本收集桌面通知的解决方案。 这个问题是我用谷歌搜索最接近的问题,但是为notify-osd写一个替代品似乎有点矫枉过正:)

查看最近通知的 applet源代码,我得到了一些提示,如何监控dbus消息,这是我提出的python实现:

 import gtk import dbus from dbus.mainloop.glib import DBusGMainLoop def filter_cb(bus, message): # the NameAcquired message comes through before match string gets applied if message.get_member() != "Notify": return args = message.get_args_list() # args are # (app_name, notification_id, icon, summary, body, actions, hints, timeout) print("Notification from app '%s'" % args[0]) print("Summary: %s" % args[3]) print("Body: %s", args[4]) DBusGMainLoop(set_as_default=True) bus = dbus.SessionBus() bus.add_match_string( "type='method_call',interface='org.freedesktop.Notifications',member='Notify'") bus.add_message_filter(filter_cb) gtk.main() 

希望这有助于某人,因为似乎没有很多与监视dbus消息相关的简单python示例。