我正在尝试使用 gdbus 更新以前的通知(使用进度条更改后显示屏幕亮度),因为 notify-send 不支持更新。
以前我使用了一种解决方法,即关闭前一个通知,但是这会导致通知消失然后重新出现,而不是平滑地更新进度条:
#!/bin/bash
for i in {0..100..10}
do
kill $(pgrep ^xfce4-notifyd$)
notify-send "Brightness" -h int:value:$(xbacklight -get) -h string:synchronous:volume -i weather-clear -t 1
done
我尝试了 dbus-send,但即使删除了提示部分,也没有出现任何通知。经过一番谷歌搜索,我找到了 gdbus 并让它工作了,但没有提示。
基本上,这是我目前使用 gdbus 所得到的结果:
#!/bin/bash
gdbus call --session --dest org.freedesktop.Notifications \
--object-path /org/freedesktop/Notifications \
--method org.freedesktop.Notifications.Notify \
brightness \
42 \
notification-display-brightness-full \
"Message" "Body" [] \
"{'value':i, 'name':'value', 'value':'$(xbacklight -get)'}" "{'type':'string', 'name':'synchronous', 'value':'volume'}" \
1
但是我被这个错误困住了:
Error parsing parameter 7 of type 'a{sv}': expected value:
{'value':i, 'name':'value', 'value':'0.000000'}
^
有人能帮我了解 gdbus 发送的通知提示的语法吗?
我读到过一些文章说我可以使用一些自定义修补版本的通知发送 (notify-send),但是我不喜欢将非官方二进制文件引入我的稳定系统。
顺便说一句,我在 xubuntu 中使用 xfce4-notifyd。
更新:
我试着不那么固执,尝试使用 python 的 dbus 模块来完成这项工作。但还是卡在了提示上。只有删除提示后它才有效。以下是新代码:
#!/usr/bin/env python3
"""Creates a Notification pop-up bubble"""
import dbus
item = "org.freedesktop.Notifications"
path = "/org/freedesktop/Notifications"
interface = "org.freedesktop.Notifications"
app_name = "brightness"
id_num_to_replace = 0
icon = "weather-clear"
title = "Message"
text = "Body"
actions_list = ''
hint = '"{'type':i, 'name':'value', 'value':'$(xbacklight -get)'}" "{'type':'string', 'name':'synchronous', 'value':'volume'}"'
time = 5000 # Use seconds x 1000
bus = dbus.SessionBus()
notif = bus.get_object(item, path)
notify = dbus.Interface(notif, interface)
notify.Notify(app_name, id_num_to_replace, icon, title, text, actions_list, hint, time)
错误如下:
File "/home/pygeek03/bin/brightness.py", line 13
hint = '"{'type':i, 'name':'value', 'value':'$(xbacklight -get)'}" "{'type':'string', 'name':'synchronous', 'value':'volume'}"'
^
SyntaxError: invalid syntax
答案1
这只是无效的 Python 语法。您对 hint 字符串所做的操作没有任何意义。例如,尝试查看匹配的引号。
提示应该是:
hint = {'type':'i', 'name':'value', 'value':int(os.system('xbacklight -get'))}
答案2
https://github.com/bkw777/notify-send.sh
除了用于gdbus call
执行实际的 dbus 事务之外,它是否是纯 bash。
它存在的主要原因实际上是替换现有通知,因此自述文件恰好显示了该示例。
除了阅读代码之外,您还可以启用调试并从调试日志中读取最终的 gdbus 命令。
gdbus 命令行倒数第二个参数包含 $h,从那里回溯 $h 是从 ${HINTS[*]} 构建的,它由对 process_hint 和 make_hint 的一次或多次调用构建(通过全局 $_r 返回其输出以避免子 shell)。即使您不提供任何 --hint 选项,也总是至少有一个设置紧急程度。
要替换通知,您需要知道它的 ID,而要知道它的 ID,您必须在第一次创建它时收集它。(或者您可以尝试生成自己的 ID,您希望它是唯一的并且永远不会覆盖其他通知,但干净的方法是让通知守护进程第一次生成通知,然后使用它来更新它。)
发送通知并收集其 ID,启用调试,以便您可以看到生成的 gdbus 命令
$ DEBUG_NOTIFY_SEND=true notify-send.sh --print-id --expire-time=0 --close-action="mainline-gtk --install 6.3.4" "New Kernel" "Install 6.3.4"
/usr/local/bin/notify-send.sh debug logging to /run/user/1000/.notify-send.sh.1044020.e
68
$
通知 ID 为 68
gdbus 命令是:
$ grep "gdbus call" /run/user/1000/.notify-send.sh.1044020.e
++ gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.Notify -- notify-send.sh 0 '' 'New Kernel' 'Install 6.3.4' '[]' '{"urgency":<byte 1>}' 0
$
现在使用 --replace=68 替换该通知
$ DEBUG_NOTIFY_SEND=true notify-send.sh --replace=68 --expire-time=0 --close-action="mainline-gtk --install 6.3.5" "New Kernel" "Install 6.3.5"
/usr/local/bin/notify-send.sh debug logging to /run/user/1000/.notify-send.sh.1044042.e
$ grep "gdbus call" /run/user/1000/.notify-send.sh.1044042.e
++ gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.Notify -- notify-send.sh 68 '' 'New Kernel' 'Install 6.3.5' '[]' '{"urgency":<byte 1>}' 0
$
因此提示的形式如下:{'name':<type value>}
有一些不太明显的规则和允许的偏差:
整个字符串必须用引号括起来或用反斜杠转义,因为这一切都在 bash 命令行上,确切的语法是“无论你想要什么,只要能产生有效的 bash 命令行...”,因为有多种方法可以引用事物。除了一个不太明显的,名称必须单独引用,单引号或双引号,即使它没有空格,名称的引号本身也必须转义或引用,这样 bash 就不会吃掉它们,使它们成为文字和字符串的一部分。
脚本正在生成:'{"urgency":<byte 1>}'
同样有效:"{'urgency':<byte 1>}"
同样有效:"{\"urgency\":<byte 1>}"
无效:\{'urgency':\<byte\ 1\>\}
有效:\{\'urgency\':\<byte\ 1\>\}
类型是可选的,至少对于某些类型,至少对于 byte 和 int32
有效:"{'urgency':<byte 1>}"
也有效:"{'urgency':<1>}"
https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html#hints有一个表显示所有类型为 BYTE INT32 STRING 等,但实际上必须以小写形式发送。
有效:"{'urgency':<byte 1>}"
无效:"{'urgency':<BYTE 1>}"
尚未显示,但括号内的多个提示项以逗号分隔
"{\"urgency\":<byte 1>,\"category\":<string \"info\">}"
这里是另一个填写了更多内容的内容,添加了图标名称和另一个类别提示以及操作按钮,因此所有字段都有内容,并且操作和提示都是多项列表:
$ notify-send.sh --expire-time=0 --force-expire --category=info --icon=mainline --action="Mainline App:mainline-gtk" --action="Install 6.3.4:mainline-gtk --install 6.3.4" "Mainlin Kernels" "New kernel available"
/usr/local/bin/notify-send.sh debug logging to /run/user/1000/.notify-send.sh.1148819.e
$ grep "gdbus call" /run/user/1000/.notify-send.sh.1148819.e
++ gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.Notify -- notify-send.sh 0 mainline 'Mainlin Kernels' 'New kernel available' '["0","Mainline App","1","Install 6.3.4"]' '{"urgency":<byte 1>,"category":<string "info">}' 0
$
您可能已经注意到,这些示例包含一个未在 gdbus 命令中显示的操作。
通过设置 gdbus 监视器命令并从监视器进程的输出中 grep 通知 ID,可以处理操作。gdbus
监视器将输出多条消息,您可以忽略任何没有 ID 的消息。当您获得包含 ID 的记录时,从该行解析出操作,并且根据操作的内容,可能运行您之前给出的命令。
操作命令行永远不会写入 dbus。发生的事情是,notify-send.sh 运行了 notify-action.sh,而 notify-action.sh 基本上等待“通知 ID 68 已关闭”,当它看到该消息时,它会运行 notify-send.sh 之前给它的命令。
如果您使用操作按钮而不是关闭操作,则可以为该按钮提供一些唯一的键(您可以自行设计,可以是任何东西,最简单的只是一个数字,每个按钮一个,每次都可以从相同的 0 或 1 开始,因为每个通知 ID 只需要唯一,所以 3 个按钮可以是键 1 2 3),然后进入 dbus,稍后观察者进程基本上会寻找“通知 68 得到操作 2”,并且 notify-action.sh 之前已经给出了按钮 ID 和相关命令的列表,所以当它看到“得到 ID 68 操作 2”时,它会运行操作 2 的命令。