Skip to content

Instantly share code, notes, and snippets.

@halfwit
Forked from Earnestly/statusbar.adoc
Created February 17, 2017 01:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save halfwit/d011f8282924f2f30718c303b2470cf4 to your computer and use it in GitHub Desktop.
Save halfwit/d011f8282924f2f30718c303b2470cf4 to your computer and use it in GitHub Desktop.
Simple reactive statusbar

The main event loop

statusdir=$XDG_RUNTIME_DIR/statusbar
mkdir -pm0700 "$statusdir"

inotifywait -rqme close_write --format %f "$statusdir" | while read -r file; do
    if read -r -- "$file" < "$statusdir/$file"; then
        # ...
    fi
done

With inotifywait we can watch a directory of files. When one of those files triggers the close_write event we synthesise a new variable based on the file name using read if the file name is also a valid identifier. The new variable will contain the first line of data from the file itself.

These new variables can, for example, be used with printf to create a formatted string designed for use in a typical statusbar.

Note
This event loop can be arbitrarily fast. Any pre-formatting should be done before the values are written to files watched by inotifywait so only a minimum amount of work is needed to process them.

Using crond(8) or systemd.timer(5)

Some status updates which cannot be done using notification and have usually long intervals can be easily provided with per-user crond or systemd.timer services.

For example given a battery-status script, we could run it every five minutes using the following crontab:

*/5 *  *  *  * battery-status > "$XDG_RUNTIME_DIR"/statusbar/battery

Considerations

  • Pre-initialised data

  • Multi-user

  • Persistence

Examples

Although all these examples are simple sh scripts it does not mean only shell can be used. Any language capable of writing files (even to stdout) is suitable for this.

Currently playing title from MPD

#!/bin/sh --

statusdir=$XDG_RUNTIME_DIR/statusbar
mkdir -pm0700 "$statusdir"

fmt='[[%artist% - ]%title%]|[%file%]'

mpc current -f "$fmt" > "%statusdir"/mpd

mpc idleloop | while read -r event; do
    case $event in
        player) mpc current -f "$fmt" > "%statusdir"/mpd
    esac
done

Real-time pulseaudio volume monitor

Use pactl subscribe to provide real-time volume notification for default sinks.

Note
One potential improvement would be to pair this with another pacmd running as a "daemon" using exec_with_pipe to accept commands over a control fifo thereby avoiding execution of multiple pulseaudio clients.
#!/bin/sh --

statusdir=$XDG_RUNTIME_DIR/statusbar
mkdir -pm0700 "$statusdir"

pastat() {
    local command=$1
    local fmt=$2

    pacmd list-"$command" | awk -v fmt="$fmt" '
        # Default indices are marked with an * so we use that as a sentinel.
        /\* index/              {m = 1; next}
        m == 1 && /muted/       {muted = $2}
        m == 1 && /^\s+volume:/ {volume = $5}

        END{
            if(muted == "no")
                printf fmt, volume
            else
                print ""
        }'
}

# If pulseaudio isn't running, print something out and exit.
if ! pulseaudio --check; then
    printf 'VOL:N/A\n' > "$statusdir"/volume
    exit 1
fi

# Initialise something before we begin monitoring events.
pastat sinks 'VOL:%s\n' > "$statusdir"/volume

pactl subscribe | while read -r _ event _ type _; do
    if [ "$event" = \'change\' ]; then
        case $type in
            sink)   pastat sinks 'VOL:%s\n' > "$statusdir"/volume
        esac
    fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment