Bspwm With Lembar Panel

Table of Contents

Preface

The Arch Wiki doesn't provide any information on how to get lemonbar setup with workspace switching, window titles, etc. Most people have their custom bars run on a timer. We're going to do them one better and have our script only update PARTS of our bar when necessary. This is going make things run much more efficiently and make displaying workspaces possible. I'm citing these two pages:

Protesilaos MelonPanel Config

Brodie Robertsons Lemonbar Config

Adding XFT support

Lemonbar doesn't work with glyph fonts, such as the NerdFonts. Compile this fork of lemonbar to get your fonts working. This is optional.

git clone https://github.com/drscream/lemonbar-xft.git
cd lemonbar-xft
sudo make install

The lemonconfig script

This is my fork of BrodieRobertson's lemonbar script. I'll explain the nitty gritty of the script at the end of this page

#!/bin/bash
#A fork of Brodie Robertsons lemonbar script with ideas taken from Protesilaos' "melonpanel"
#https://gitlab.com/protesilaos/dotfiles/-/blob/v2.2.0/bin/bin/melonpanel
#https://raw.githubusercontent.com/BrodieRobertson/scripts/master/lemonbar/lemonconfig
#https://gitlab.com/protesilaos/lemonbar-xft.git

#background="#efefef"
_Format() {
        echo "%{+u}%{B$background} "$@" %{B}%{-u}"
}

_Workspaces() {
        desktops=$(bspc query -D --names)
        focused=$(bspc query -D --names -d focused)

        for desktop in $desktops; do
                nodes=$(bspc query -N -d $desktop)
                if [ ! -z "$nodes" ]; then
                        desktops=$(echo $desktops | sed "s/$desktop/%{F#f48888}$desktop%{F-}/")
                fi

        done

        desktops=$(echo $desktops | sed "s/$focused/%{B$background}%{+u}_$focused\_%{-u}%{B-}/")
        echo $desktops | sed "s/_/ /g"
}

_WindowName(){
        xdotool getwindowfocus getwindowname
}

_CurrentWorkspace(){
        bspc query -D --names -d
}


_Clock(){
        TIME=$(date "+%H:%M")
        #_Format "${TIME}"
        echo ${TIME}
}

_Battery(){
        #_Format $(bat)
        echo $(bat)
}

_Modules(){
        while true; do
                echo "B: $(_Battery)"
                echo "C: $(_Clock)"
                sleep 5s
        done
}

lemonbar_fifo='/tmp/lemonbar.fifo'
[ -e "$lemonbar_fifo" ] && rm "$lemonbar_fifo"
mkfifo "$lemonbar_fifo"

_Modules > "$lemonbar_fifo" &
bspc subscribe desktop> "$lemonbar_fifo" &
bspc subscribe node> "$lemonbar_fifo" &

# This function takes stdin from the fifo file.
_Main(){
        wm=$(_CurrentWorkspace)
        while read -r report; do
                case $report in
                        B*) batt="$(echo $report | cut -d':' -f2-)";;
                        C*) clock="$(echo $report | cut -d':' -f2-)";;
                        node*) window_name=$(_WindowName);;
                        desktop*) wm=$(_CurrentWorkspace) window_name=$(_WindowName);;
                esac
                echo -e "%{l} $wm %{c} $window_name %{r} $batt $clock "
        done
}

_Main < "$lemonbar_fifo"
#end_src

* Usage
Here's a launcher script that I have run with bspwm.
#+begin_src shell
#!/bin/sh
killall -q lemonbar
lemonconfig | lemonbar -p \
       -f 'TerminessTTF Nerd Font Mono:size=13' \
       -g x27

How does it work?

Modules

Each of your modules is just a function that ends outputting plain text.

The "_Format" module was written by Brodie, and it adds some lemonbar syntax to arguments passed to, allowing for some more stylish modules.

The "_Format" function isn't used in my fork, but it's still included.

You'll notice the "_Modules" function echoes out a character and then the output of a module.

The reason for this is that our loop in "_Main" uses a simple regex to run a particular command if a line contains a specific pattern.

Adding a letter to the beginning of each line makes parsing the line A LOT simpler.

**# Fifo file (named pipe) A named pipe acts the same a traditional pipe, except it stores the stdout into a file which can be used as stdin.

Every time one of our modules updates, it outputs the content to the named pipe.

The same goes for bspwm. We output data to the same named pipe whenever we select different nodes or switch desktops.

The "_Main" function uses a "read" prompt to run a case statement on each line that is sent to the named pipe.

If the line contains text with the pattern "node*", the case statement updates the variable "window_name" and echoes out the string to lemonbar

So if our "_Modules" function hasn't automatically looped yet, but our current desktop has changed, then the script updates the workspace module and displays the output to the bar. The stored variable data for the other modules remains unchanged.

**# FYI The "_Workspaces" function was from BrodieRobertson and it really sucks (no offense).

I only use "_CurrentWorkspace". You have to tweak these to match your needs.

The battery module sources an external script to show my battery status.

#!/bin/sh

batteries=$(find -P /sys/class/power_supply/ | grep -iE "*bat*")

for battery in $batteries; do
       status=$(cat $battery/status)
       capacity=$(cat "$battery"/capacity 2>/dev/null || break)
       case "$status" in
               Discharging) echo ": ${capacity}%" ;;
               Full) echo ": ${capacity}%" ;;
               Charging) echo ": ${capacity}%" ;;
               Unknown) echo ": ${capacity}%";;
       esac
done

Image

Recreated my website from old source and lost my images :p