Search code examples
awesome-wm

Awesomewm update watch widget on keypress


I am a new user to awesomewm (but have used other WMs before: i3, bspwm, xmonad, etc). I like to have some shell scripts that I have written in my wibar (I think that's what its called, the bar at the top of the screen with the taglist) to display stuff like battery, audio, etc (as I know is common). Currently I am using the "wibar.widget.watch" to do this, as shown below.

        -- 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),

In the code above stuff like "audiobar" are scripts that return information as standard output. It all works perfectly, even displays the emojis well :). I have one problem (maybe just an optimization).

Currently I have the audiobar running twice a second, this is because that is the only one which directly changes based on my input (changing volume) and so I want it to change immediately (obviously this still has a <= 0.5 second delay, which is annoying). This means that most of the time it is updating twice a second unnecesarily.

So, I'm wondering if there is a way to have it update when I change the volume, which I've bound to the XF86 audio keys in rc.lua, instead of changing based on a timer. Based on my reading of the documentation, there is no way to do this with the watch widget, but as I said I am new to awesome.

Below is how I bound the keys (shouldn't make a difference, but I imagine that this is where the change would be made).

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

I know that I can use some of the pre-made widgets on github to display volume and stuff but I like the shell scripts because they let me easily move between WMs and are simpler than those widgets (which I like because it means that I can more easily address problems with them and make them display exactly what I want, as well as learn).

edit: I am willing to learn to do this with lua, I just first want to see if I can easily do it with shell scripts.


Solution

  • You need to keep a reference to the timer around that awful.widget.watch creates internally. To do this, you need to do something like this in global context (i.e. outside of the definitions of the widgets or keybindings):

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

    You now add musicbar_widget to your wibox (instead of calling awful.widget.watch there). Now, you can "force-update" the widget via musicbar_timer:emit_signal("timeout"). This "pretends" to the widget that the timeout happened again.

    In your keybinding (yes, I am mixing up your widgets here, most likely musicbar has nothing to do with the volume):

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

    Note that this might or might not work. awful.spawn only starts the command, but does not wait for it to finish. So now you are changing the volume at the same time that your are querying it. If querying finishes faster than changing the volume, then the update does not actually occur.

    To only update the widget after changing the volume is done, do something like the following:

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