Awesomewm 在按键上更新手表小部件

Awesomewm update watch widget on keypress

我是 awesomewm 的新用户(但之前使用过其他 WM:i3、bspwm、xmonad 等)。我喜欢在我的 wibar 中写一些 shell 脚本(我想这就是它的名字,屏幕顶部带有标签列表的栏)来显示电池、音频等内容(因为我知道是常见的)。目前我正在使用 "wibar.widget.watch" 来执行此操作,如下所示。

        -- Right widgets
    layout = wibox.layout.fixed.horizontal,
    awful.widget.watch('musicbar', 5),
    wibox.widget.textbox('  |  '),
    awful.widget.watch('wifibar', 5),
    wibox.widget.textbox('  |  '),
    awful.widget.watch('audiobar', 0.5),
    wibox.widget.textbox('  |  '),
    awful.widget.watch('batbar', 5),

在上面的代码中,"audiobar" 是将 return 信息作为标准输出的脚本。一切都很完美,甚至可以很好地显示表情符号 :)。我有一个问题(也许只是一个优化)。

目前我有音频条 运行 每秒两次,这是因为这是唯一一个根据我的输入(改变音量)直接改变的,所以我希望它立即改变(显然这仍然有 <= 0.5 秒的延迟,这很烦人)。这意味着大多数时候它会不必要地每秒更新两次。

所以,我想知道是否有一种方法可以在我更改音量时更新它,我已将音量绑定到 rc.lua 中的 XF86 音频键,而不是根据计时器进行更改.根据我对文档的阅读,无法使用手表小部件执行此操作,但正如我所说,我是 awesome 的新手。

下面是我绑定键的方式(应该不会有什么不同,但我想这是要进行更改的地方)。

awful.key(
 {},
 "XF86AudioLowerVolume",
 function()
        awful.spawn("amixer -q set Master 5%-")
 end,
 {description = "lower volume", group = "control"}
),

我知道我可以使用 github 上的一些预制小部件来显示音量和其他东西,但我喜欢 shell 脚本,因为它们让我可以轻松地在 WM 之间移动并且更简单比那些小部件(我喜欢它们,因为这意味着我可以更轻松地解决它们的问题并使它们准确显示我想要的内容,以及学习)。

编辑:我愿意学习用 lua 来做这件事,我只是想先看看我是否可以用 shell 脚本轻松地做到这一点。

您需要保留对 awful.widget.watch 内部创建的计时器的引用。为此,您需要在全局上下文中执行类似的操作(即在小部件或键绑定的定义之外):

local musicbar_widget, musicbar_timer = awful.widget.watch('musicbar', 5)

您现在将 musicbar_widget 添加到您的 wibox(而不是在那里调用 awful.widget.watch)。现在,您可以通过 musicbar_timer:emit_signal("timeout") "force-update" 小部件。这"pretends"到超时再次发生的小部件。

在你的键绑定中(是的,我在这里混淆了你的小部件,很可能 musicbarvolume 无关):

awful.key(
 {},
 "XF86AudioLowerVolume",
 function()
        awful.spawn("amixer -q set Master 5%-")
        musicbar_timer:emit_signal("timeout")
 end,
 {description = "lower volume", group = "control"}
),

请注意,这可能有效也可能无效。 awful.spawn 只启动命令,但不等待它完成。所以现在您在查询音量的同时更改音量。如果查询比更改卷更快地完成,则更新实际上不会发生。

要仅在更改音量完成后更新小部件,请执行以下操作:

awful.spawn.with_line_callback(
    "amixer -q set Master 5%-", {
    exit = function()
        musicbar_timer:emit_signal("timeout")
    end
})

我 运行 遇到了与 streetturtle 的 volumearc widget 类似的问题。默认情况下,它 运行 是一个更新命令:

  • 每次通过小部件修改音量
  • 每秒 捕获任何外部音量变化(例如 rc.lua 中定义的键绑定)。
watch(get_volume_cmd, 1, update_graphic, volumearc)

当然这有以下缺点:

  • 音量更新轻微延迟(一秒仍然非常明显)。
  • 在我的机器上,常量 1% CPU load 仅用于此任务。我知道一些小事,但小事加起来。

使用 returned 更新函数

一个可能的解决方案是 return 更新函数,在 rc.lua 的上下文中可用,并在卷修改时调用此更新。

volumearc.lua中,在worker函数中,我们把widget更新放到了一个专门的函数中:

local ext_update = function()
        spawn.easy_async(get_volume_cmd,
            function(stdout, stderr, exitreason, exitcode)
            update_graphic(volumearc, stdout, stderr, exitreason, exitcode) end)
      end

我们 return 它都来自 worker 函数:

return volumearc, ext_update

从小部件本身:

volumearc, ext_update = { __call = function(_, ...) return worker(...) end }
return setmetatable(widget, volumearc), ext_update

现在我们可以在rc.lua中使用它了:

local volumearc_widget = require("widgets.volume-widget.volumearc")
-- ...
local GET_VOLUME = "amixer sget Master"
local INC_VOLUME = "amixer sset Master 3%+"
local DEC_VOLUME = "amixer sset Master 3%-"
local TOG_VOLUME = "amixer sset Master toggle"
myvolume, volume_update = volumearc_widget({get_volume_cmd=GET_VOLUME,
                           inc_volume_cmd=INC_VOLUME,
                           dec_volume_cmd=DEC_VOLUME,
                           tog_volume_cmd=TOG_VOLUME})
-- `myvolume` is the widget that can be added as usual in the wibox.
-- `volume_update` is the function to call in order to trigger an update.
-- ...
-- In the key bindings:
    awful.key({}, "XF86AudioMute",
      function () awful.spawn(TOG_VOLUME) volume_update() end,
      {description="mute", group = "media"}),
    awful.key({}, "XF86AudioRaiseVolume",
      function () awful.spawn(INC_VOLUME) volume_update() end,
      {description="raise volume", group = "media"}),
    awful.key({}, "XF86AudioLowerVolume",
      function () awful.spawn(DEC_VOLUME) volume_update() end,
      {description="lower volume", group="media"}),

现在音量将在从小部件或媒体键更改时更新,即时无需轮询 .

警告

  • 这不会捕获通过其他接口所做的更改,例如 alsamixer。要捕捉这些变化,您可能希望 运行 具有非常低的时间频率(比如每分钟一次)的 watch 函数。
  • 此处给出的代码特定于 streetturtle 的小部件,但 return 内部更新功能的概念适用于任何小部件。