Status bar

2025-07-11

bar!

# xbps-install lemonbar-xft xtitle stalonetray dzen2 libX11-devel
  • lemonbar-xft lightweight bar, fork of lemonbar adding xft support

bar.sh (based on bspwm example):

#! /bin/sh
PANEL_HEIGHT=16
PANEL_FONT="Terminus:size=8"
PANEL_WM_NAME=bspwm_panel

PANEL_FIFO=/tmp/panel-fifo
[ -e "$PANEL_FIFO" ] && rm "$PANEL_FIFO"
mkfifo "$PANEL_FIFO"

pkill -9 lemonbar
pkill stalonetray
#pkill bar_parse.sh

trap 'trap - TERM; rm -f "$PANEL_FIFO"; kill 0' INT TERM QUIT EXIT

xtitle -sf 'T%s\n' > "$PANEL_FIFO" &
dwmstatus | stdbuf -oL sed 's/^/S/' > "$PANEL_FIFO" &
bspc subscribe > "$PANEL_FIFO" &

. colors.sh
bar_parse.sh < "$PANEL_FIFO" | lemonbar -a 32  -g x$PANEL_HEIGHT -u 0 -d -f "$PANEL_FONT" -F "$COLOR_FG" -B "$COLOR_BG" | sh

bar_parse.sh (basically the same as bspwm example):

#! /bin/sh
. colors.sh

num_mon=$(bspc query -M | wc -l)
while read -r line ; do
	case $line in
		S*) # info output
			sys="${line#?} %{B-}%{F-}"
			;;
		T*)
			# xtitle output
			title="${line#?} %{B-}%{F-}"
			;;
		W*)
			# bspwm's state
            cmon=0
			wm=""
			IFS=':'
			set -- ${line#?}
			while [ $# -gt 0 ] ; do
				item=$1
				name=${item#?}
				case $item in
					[mM]*)
						[ $num_mon -lt 2 ] && shift && continue
						case $item in
							m*)
								# monitor
								FG=$COLOR_FG
								BG=$COLOR_BG
								;;
							M*)
								# focused monitor
								FG=$COLOR_FG
								BG=$COLOR_FOCUSED_MONITOR_BG
								;;
						esac
                        wm="${wm}%{l}%{S${cmon}}%{F${FG}}%{B${BG}}%{A:bspc monitor -f ${name}:} ${name} %{A}%{B-}%{F-}"
                        cmon=$((cmon+1))
						;;
					[fFoOuU]*)
						case $item in
							f*)
								# free desktop
								FG=$COLOR_FREE_FG
								BG=$COLOR_BG
								;;
							F*)
								# focused free desktop
								FG=$COLOR_FREE_FG
								BG=$COLOR_FOCUSED_BG
								;;
							o*)
								# occupied desktop
								FG=$COLOR_OCCUPIED_FG
								BG=$COLOR_BG
								;;
							O*)
								# focused occupied desktop
								FG=$COLOR_OCCUPIED_FG
								BG=$COLOR_FOCUSED_BG
								;;
							u*)
								# urgent desktop
								FG=$COLOR_URGENT_FG
								BG=$COLOR_BG
								;;
							U*)
								# focused urgent desktop
								FG=$COLOR_URGENT_FG
								BG=$COLOR_FOCUSED_BG
								;;
						esac
						wm="${wm}%{F${FG}}%{B${BG}}%{A:bspc desktop -f ${name}:} ${name} %{A}%{B-}%{F-}"
						;;
					L*)
						# layout
                        #WMLVDS1:OQ:oW:oE:fA:fS:fD:LT:TF:G example state string from bspc subscribe
                        case $name in
                            T*)
                                symbol="#"
                                ;;
                            M*)
                                symbol="[]"
                                ;;
                        esac
						wm="${wm}%{F${COLOR_FREE_FG}} %{A:bspc desktop -l next:}${symbol}%{A}%{B-}%{F-}"
						;;
					[TG]*)
						# state and flags
						;;
				esac
				shift
			done
			;;
	esac
	printf "%s\n" "%{l}${wm}      ${title}%{r}${sys}"
	if [ $? -ne 0 ]; then
    	exit 1
	fi
done

colors.sh:

#! /bin/sh
COLOR_FG="#bea786"
COLOR_BG="#000000"

COLOR_FOCUSED_MONITOR_BG="#292216"
COLOR_FOCUSED_BG="#292216"

COLOR_FREE_FG="#a3804b"
COLOR_OCCUPIED_FG="#ffe5bb"
COLOR_URGENT_FG="#cd9641"

Launching the bar at the end of ./config/bspwm/bspwmrc:

exec bar.sh

Window titles

  • xtitle outputs X window titles

In bar.sh:

xtitle -sf 'T%s\n' > "$PANEL_FIFO" &
  • s: snoop mode (keep running and output new title whenever it changes)
  • f: format (%s - window title)

Bspwm integration

In bar.sh:

bspc subscribe > "$PANEL_FIFO" &

Status

I based my status gathering and printing program on dwmstatus.

  • libX11-devel X11 development headers necessary to compile dwmstatus

Launching in bar.sh:

dwmstatus | stdbuf -oL sed 's/^/S/g' > "$PANEL_FIFO" &
  • stdbuf -oL: buffer the output of dwmstatus by lines
  • sed ’s/^/S/g’: put letter S on at start of every line (needed to parse $PANEL_FIFO)

Tray icons

  • stalonetray lightweight standalone system tray for X11

stalonetray below lemonbar

In lemonbar you can define clickable areas that will launch a command:

"%{A:bar-tray.sh:}click this to toggle tray%{A}"

I set my bar so when I click on the time, bar-tray.sh is launched and toggles displaying stalonetray:

#!/bin/sh

if pgrep -x stalonetray > /dev/null ; then
    pkill stalonetray
    exit 0
fi

stalonetray --window-type dock &

Stalonetray’s settings in ~/.stalonetrayrc:

decorations none
dockapp_mode simple
fuzzy_edges 0
geometry 1x1+1349+17
grow_gravity SE
icon_size 8
log_level err
kludges force_icons_size
max_geometry 0x0
no_shrink false
scrollbars none
skip_taskbar true
sticky true
tint_color white
tint_level 0  # color range - 0 255
transparent false
vertical false
window_layer normal
window_strut none
window_type toolbar
xsync false
parent_bg true
  • dzen2 general purpose messaging, notification and popup menu for X11

Define clickable area in lemonbar that launches custom script, for example clicking on battery percentage displays more info about battery:

"%{A:bar-dropdown.sh bat:} B:100 %{A}"

battery info in dzen2

bar-dropdown.sh:

#!/bin/sh
(
	case "$1" in
	"conn")
		echo "eth in/out: $(( $(cat /sys/class/net/eth0/statistics/rx_bytes) / 1048576 ))/$(( $(cat /sys/class/net/eth0/statistics/tx_bytes) / 1048576 )) (MB)"
		echo "wlan in/out: $(( $(cat /sys/class/net/wlan0/statistics/rx_bytes) / 1048576 ))/$(( $(cat /sys/class/net/wlan0/statistics/tx_bytes) / 1048576 )) (MB)"
		ip route
	;;
	"disc")
		df -hTx 'tmpfs' -x 'devtmpfs'
	;;
	"temp")
		sensors
	;;
	"cpu")
		ps -Ao user,comm,pid,pcpu,time --sort=-pcpu | head -n 12
	;;
	"mem")
		free -g; echo ""; ps -Ao user,comm,pid,%mem,time --sort=-rss | head -n 12
	;;
	"bat")
		acpi -bita
	;;
	"cal")
		TODAY=$(date +%d | sed 's/^0*//')
		MONTH=$(date +%m | sed 's/^0*//')
		YEAR=$(date +%Y)

		echo "$(date +'%A %d %B %Y')"
		echo

		cal | sed -E \
  		  -e "s/(^|[[:space:]])($TODAY)([[:space:]]|\$)/\1^fg(#ffffff)^bg(#4f3d52)\2^fg()^bg()\3/"

		echo

		if [ "$MONTH" -eq 12 ]; then
  		  NEXT_MONTH=1
  		  NEXT_YEAR=$((YEAR + 1))
		else
  		  NEXT_MONTH=$((MONTH + 1))
  		  NEXT_YEAR=$YEAR
		fi

		cal "$NEXT_MONTH" "$NEXT_YEAR"
	;;
esac) | bar-dzen2.sh "$1"

The text is piped to bar-dzen2.sh, which displays dzen2 at the position of cursor and makes a lock file, if the lock file already exists, it kills dzen2 for this type of info, that is how the dropdown is toggled:

#!/bin/sh
NAME="$1"
shift
LCK="/tmp/dzen-$NAME.lock"

if [ -f "$LCK" ]; then
    kill -9 "$(cat "$LCK")" 2>/dev/null
    rm -f "$LCK"
    exit 0
fi
TMP="$(mktemp)"
echo "" > "$TMP"
cat >> "$TMP"

LINES=$(wc -l < "$TMP")
CHARS=$(sed 's/\^..([^)]*)//g' "$TMP" | awk '{ print length }' | sort -nr | head -n1)

CHAR_WIDTH=8 #adjust depending on font 
WIN_WIDTH=$((CHARS * CHAR_WIDTH))

eval "$(xdotool getmouselocation --shell)"
X_POS=$((X - WIN_WIDTH / 2))
Y_POS=$Y

dzen2 \
    -x "$X_POS" \
    -y "$((Y_POS + PANEL_HEIGHT))" \
    -w "$WIN_WIDTH" \
	-l "$LINES" \
    -p \
    -e "onstart=uncollapse;button1=ungrabkeys,exit;onexit=exec:rm $LCK" < "$TMP" &

echo $! > "$LCK"

Dzen2 font and colors can be set in ~/.Xresources:

dzen2.font:         -*-terminus-*-*-normal-*-14-*-*-*-*-*-*-u
dzen2.foreground:   #cac0b7
dzen2.background:   #111111

Run xrdb ~/.Xresources for changes take effect.