RetroBSD Net
Title:
Simple status bar for NetBSD and CTWM(1)
Authors:
Paolo Vincenzo Olivo
Date:
Topics:
NetBSD
Id:
h7fg54

■ Introduction

I like to refresh my desktop layout from time to time and experiment with different configurations. My usual workflow involves just a simple Xlib/Xm based stacking wm, such as CTWM, Fvwm or Emwm.

Lately, I've been reconsiderig the idea of adding a status bar to my ctwm desktop, to monitor a number of system resources which are relevant on a laptop used to compile large programs.

■ Looking around

I wanted something simple, ideally with little to none dependency burden; eventually I came across @gonzalo's <termbar>, which is based on xterm and uses a looping sh script to display system's information on a docked horizontal terminal window.

Initially, I adapted termbar's functions to NetBSD, and while I got a working status bar, I was unconvinced about xterm as a backend for the script, given the following reasons:

* impossibility to align text to the center / right side of the screen without complex and fragile printf hacks * no way to set bar geometry at runtime based on screen size (xterm will only understand width in columns) * no EWMH support * tendency to print unwanted characters when output changes

I thought of <lemonbar> as a possible replacement for xterm, given its extreme lightweight and simplicity.

From lemonbar(1):

"lemonbar (formerly known as bar) is a lightweight bar entirely based on XCB. Provides full UTF-8 support, basic formatting, RandR and Xinerama support and EWMH compliance without wasting your precious memory."

■ The status bar script

After installing x11/lemonbar from pkgsrc, I made few modifications to my status bar script to adapt it to lemonbar's screenrc like syntax; here comes `bar' in its final version:

``` #!/bin/sh # configuration . $HOME/.barrc # alpha a="#cc" b="#00" # default colors bg="${a}${BG}" fg="${a}${FG}" sp="${a}${C5}" hi="${a}${C6}" # default geometry default_geometry() { width=$(xdpyinfo | awk '/dimensions:/ { print $2}' | cut -c 1-4) height=24 offy=0 offx=0

echo "${width}x${height}+${offx}+${offy}" }

GEOM=${GEOM:-$(default_geometry)}

PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R7/bin:/usr/pkg/bin"

statusbar() {

desktop() { desk_id=$(xprop -root 32c '\t$0' _NET_CURRENT_DESKTOP | cut -f 2) w_id=$(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2) win=$(xprop -id $w_id '\t$0' _NET_WM_NAME | awk -F '"' '{ print $2 }') echo [$desk_id] [$win] }

host() { vendor="$(sysctl machdep.dmi.system-vendor | cut -d "= " -f2)" host="$(sysctl machdep.dmi.system-version | cut -d "= " -f2)" for i in $vendor $host; do [ -z "${i}" ] || echo $i done }

cpu() { cpu_temp="$(envstat | grep "cpu0 temperature: " \ | awk '{print $3}' | cut -d "." -f 1)°C" cpu_speed="$(printf "%4s" $(sysctl machdep.cpu.frequency.current \ | awk '{ print $3 }' | cut -d "." -f 1)) MHz" echo $cpu_speed $cpu_temp }

mem() { memtotal="$(($(sysctl -n hw.physmem64) / 1024 / 1024))" memused="$(($(vmstat | awk 'END {printf $3}') / 1024))" mem="${memused}MB / ${memtotal}MB" echo $mem }

disk() { disk="$(df -h / | awk 'NR==2 {total=$2; used=$3; \ print used" / "total}')" echo $disk }

network() { ifconfig | grep -v 127.0.0.1 | grep -q "inet " || { net=$(printf '%s' "none") exit 1 }

for I in $( ifconfig -l | sed s/lo0//g ) do ifconfig ${I} | grep -q "inet " && { net=$(printf '%s' "(${I}) " ifconfig ${I} | grep "inet " | awk '{print $2}' | tr '\n' ' ') echo $net } done }

batt() { batt="$(envstat | grep charge: | sed 's/.*(\(.*\))/\1/' | head -1)"

if envstat | grep -Eq 'connected.*TRUE'; then batt_status=$(echo Connected) else batt_status=$(echo Disconnected) fi

echo $batt "($batt_status)" }

vol() { vol="$(mixerctl -n outputs.master | tr ',' ' ' \ | awk '{print ($1+$2)/5}')%" echo $vol }

clock() { time="$(date +"%I:%M %p")" date="$(date +" %a, %b %d")" # datetime=$(date '+%d/%m/%Y [%H:%M]') echo $date "@" $time }

echo %{l}%{F${hi}}$(host) %{F-}%{F${fg}}$(desktop)%{F-}%{c}%{F-}%{r}%{F${sp}}" \ | "%{F-}%{F${fg}}cpu: $(cpu)%{F-}%{F${sp}}" \ | "%{F-}%{F${fg}}mem: $(mem)%{F-}%{F${sp}}" \ | "%{F-}%{F${fg}}net: $(network)%{F-}%{F${sp}}" \ | "%{F-}%{F${fg}}disk: $(disk)%{F-}%{F${sp}}" \ | "%{F-}%{F${fg}}batt: $(batt)%{F-}%{F${sp}}" \ | "%{F-}%{F${fg}}vol: $(vol) %{F-}%{F${sp}}" \ | "%{F-}%{F${fg}}$(clock)%{F-}%{F${sp}}" "%{F-} }

while true do echo "$(statusbar)" sleep 1.0

done | lemonbar -d -n $NAME -g $GEOM -f $FONT -B $bg ```

The script launches a status bar at the top of the screen displaying the following information (from left to right):

- host (vendor and model) - number of current desktop/workspace - title of focused window - cpu frequency and temperature - used memory (out of total) - connected network interface(s) and associated address - used and total disk space - battery charge level and status (connected or not to power supply) - volume level - date and time

■ The status bar resources

The script sources a `barrc' configuration file (required), containing customizable colors and font respources. An example is provided below:

``` #!/bin/sh

FG=D8D8D8 BG=272c2d C0=000000 C1=9e1828 C2=aece92 C3=968a38 C4=414171 C5=963c59 C6=418179 C7=bebebe

NAME="bar" FONT="-misc-tamzen-medium-r-normal--16-116-100-100-c-80-iso8859-1"

export FG BG C0 C1 C2 C3 C4 C5 C6 C7 NAME FONT ```

This should be placed by default at ~/.barrc.

The bar script and its configuration file can be downloaded from <https://sehnsucht.multics.org/dots/lemonbar>.

■ Let ctwm(1) know about the bar

We want the status bar to: - have no decorations whatsoever - occupy all workspaces permanently - stay beneath focused and unfocused windows - not appear in IconManager and WorkspaceManager - be excluded from the window ring (when cycling through windows)

This can be achieved in ~/.ctwmrc by adding it to series of window lists:

``` NoTitle { "WorkSpaceManager" "TWM Icon Manager" "XClock" "bar" }

NoBorder { "WorkSpaceManager" "TWM Icon Manager" "bar" }

IconManagerDontShow { "WorkSpaceManager" "bar" }

OccupyAll { "XClock" "xsm" "xconsole" "bar" }

WindowRingExclude { "TWM Icon Manager" "WorkSpaceManager" "XClock" "xsm" "xconsole" "bar" }

AutoLower { "TWM Icon Manager" "WorkSpaceManager" "XClock" "xsm" "xconsole" "bar" }

■ Start it automatically

The bar script may be executed directly from ~/.xsession:

``` # [...] # Launch status bar sleep 1; ${HOME}/bin/bar & # Start CTWM exec /usr/pkg/bin/dbus-launch --exit-with-session \ --sh-syntax /usr/X11R7/bin/ctwm -W ```

Or you may have CTWM execute it upon startup, by adding:

``` # launch bar syscmd(`sh $HOME/bin/bar > /dev/null 2>&1')

```

To ~/.ctwmrc. CTWM bar

■ Thanks

* gonzalo (@x61sh) for having heavily inspired this work. * TuM'Fatig for their exhaustive review on termbar. See: <https://www.tumfatig.net/2020/a-simple-shell-status-bar-for-openbsd-and-cwm1/>

■ TODO

* Rewrite it in C, possibly starting from <https://got.x61.sh/?action=summary&path=termbarc>