Haskell中设置DBus接口属性失败,Dunst通知控制问题求助
解决Haskell中Dunst通知DBus属性设置失败的问题
问题背景
我尝试用Haskell复制两条可正常工作的dbus-send命令,用来控制Dunst通知的暂停状态:
获取属性的dbus-send命令
dbus-send --print-reply=literal \ --dest="org.freedesktop.Notifications" \ "/org/freedesktop/Notifications" \ "org.freedesktop.DBus.Properties.Get" \ "string:org.dunstproject.cmd0" \ "string:paused"
设置属性的dbus-send命令
dbus-send --print-reply=literal \ --dest="org.freedesktop.Notifications" \ "/org/freedesktop/Notifications" \ "org.freedesktop.DBus.Properties.Set" \ "string:org.dunstproject.cmd0" \ "string:paused" \ "variant:boolean:true"
我的Haskell代码
import DBus qualified as DBus import DBus.Client qualified as DBus getPaused = do let methodCall = (DBus.methodCall "/org/freedesktop/Notifications" "org.dunstproject.cmd0" "paused") { DBus.methodCallDestination = Just "org.freedesktop.Notifications" } client <- DBus.connectSession res <- DBus.getPropertyValue @Bool client methodCall print res setPaused = do let methodCall = (DBus.methodCall "/org/freedesktop/Notifications" "org.dunstproject.cmd0" "paused") { DBus.methodCallDestination = Just "org.freedesktop.Notifications" } client <- DBus.connectSession res <- DBus.setPropertyValue client methodCall True print res
getPaused能正常打印当前属性值,但setPaused执行时报错:
Just (MethodError { methodErrorName = ErrorName "org.freedesktop.DBus.Error.UnknownMethod" , methodErrorSerial = Serial 2 , methodErrorSender = Just (BusName ":1.11") , methodErrorDestination = Just (BusName ":1.475") , methodErrorBody = [Variant "No such interface “org.freedesktop.DBus.Properties” on object at path /org/freedesktop/Notifications" ] })
解决方案
问题出在setPropertyValue的参数构造逻辑上。虽然getPropertyValue能通过传入属性的接口和名称自动处理Properties.Get调用,但setPropertyValue的实现对参数格式要求更严格,直接模拟dbus-send的调用逻辑会更可靠。
方案一:手动构造Properties.Set方法调用
完全复刻dbus-send的行为,直接调用DBus标准的org.freedesktop.DBus.Properties.Set方法:
setPaused :: IO (Maybe DBus.MethodReturn) setPaused = do client <- DBus.connectSession let methodCall = DBus.methodCall "/org/freedesktop/Notifications" "org.freedesktop.DBus.Properties" "Set" { DBus.methodCallDestination = Just "org.freedesktop.Notifications" , DBus.methodCallBody = [ DBus.toVariant ("org.dunstproject.cmd0" :: String) , DBus.toVariant ("paused" :: String) , DBus.toVariant (DBus.toVariant True :: DBus.Variant) ] } res <- DBus.call client methodCall print res
方案二:使用propertyCall构造参数
如果想继续使用setPropertyValue函数,改用DBus.propertyCall构造符合要求的属性调用对象:
setPaused :: IO (Maybe ()) setPaused = do let propCall = DBus.propertyCall "/org/freedesktop/Notifications" "org.dunstproject.cmd0" "paused" client <- DBus.connectSession res <- DBus.setPropertyValue client propCall True print res
说明
- 方案一的参数和
dbus-send完全对应:依次传入属性所属接口名、属性名、包装为Variant类型的目标值 - 方案二利用库提供的
propertyCall辅助函数,自动适配setPropertyValue的参数格式,简化代码
内容的提问来源于stack exchange,提问作者carbolymer
相关产品推荐
相关产品推荐

