You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 03:58:17