Protesilaos Stavrou
Philosopher. Polymath.

About the top panel

Prot's Dots For Debian - Book index

The panel that appears at the uppermost side of the viewport is drawn by lemonbar. This is a beautifully simple tool. On the face of it, all it does is place an empty bar at either the top (default) or bottom of the screen, while offering a syntax for formatting any output it may display. It is up to the user to add content to it.

This is where my melonpanel comes into play. It is a shell script that fetches and parses some useful information about the system and the running session, and lays it on the bar. Each snippet of info is internally referred to as a “module” and has its own dedicated logic inside the script.

The modules are the following:

  • BSPWM report about the workspaces, nodes, their flags and state (see next section about it).
  • Battery status and current capacity.
  • Speaker volume strength and status.
  • Active keyboard layout.
  • Date and time.

This is what a module looks like:

# Battery status: charging (c), discharging (d), full (f), unknown (?).
battery_status() {
	local battery_path battery_status battery_label battery_output

	battery_path='/sys/class/power_supply/BAT0'
	battery_output=$(sed 1q $battery_path/capacity)
	battery_status="$(sed 1q $battery_path/status)"
	battery_label='Bat'

	if [ -d "$battery_path" ]; then
		case "$battery_status" in
			'Charging')
				echo "%{F$color14}$battery_label <c>%{F-} ${battery_output}%"
				;;
			'Discharging')
				case "$battery_output" in
					1[0-9])
						echo "%{F$color1}$battery_label <d>%{F-} ${battery_output}%"
						;;
					[0-9])
						echo "%{B$color1}%{F$background} $battery_label ${battery_output}% %{F-}%{B-}"
						;;
					*)
						echo "%{F$color11}$battery_label <d>%{F-} ${battery_output}%"
						;;
				esac
				;;
			'Full')
				echo "%{F$color2}$battery_label%{F-} Full"
				;;
			*)
				echo "%{F$color3}$battery_label <?>%{F-} ${battery_output}%"
				;;
		esac
	else
		echo ''
	fi
}

How the modules are placed on the panel

All modules will grab some piece of text and clean it up so that it looks nice on the panel. However, each individual module does not output directly to the named pipe where the data is read from. Instead, all modules are called from my_modules(), which I need to explain a bit:

my_modules() {
	while true; do
		echo "B" "$(battery_status)"
		echo "D" "$(date +'%a %d %b %H:%M')"
		echo "K" "$(keyboard_layout)"
		echo "V" "$(volume_status)"
		sleep 1s
	done
}

You will notice that each individual item echoes a majuscule and then the output of the module it references. These capital letters are important because they demarcate each set of data in the named pipe, making it possible to put the right thing in the right place. We see this in practice at melonpanel(), specifically this part:

while read -r line ; do
	case $line in
		B*)
			# battery status
			bat="${line#?}"
			;;
		D*)
			# current date and time
			date="${line#?}"
			;;
		K*)
			# keyboard layout (en or gr)
			key="${line#?}"
			;;
		V*)
			# volume level
			vol="${line#?}"
			;;

What this does is identify the part that contains the data of each module and assign a variable to it. The variables are then placed on the panel with the following:

panel_layout() {
	echo "%{l}$wm%{r}$bat $vol $key $date "
}

Focus on the content of the echo. The syntax %{l} places things on the left, while %{r} aligns them to the right (this notation is provided by lemonbar—see its manpage).

I believe this pretty much covers the essentials of how melonpanel is designed. As with all my scripts, this too is heavily documented. So do read it. That granted, I admit that lemonbar is not the most user-friendly program out there.

The BSPWM module

On the left side of the panel lies the set of indicators that report on the status of the window manager (based on the output of the command bspc subscribe report). This is what you see when starting the session (note that I have taken care to use the appropriate spacing, so that all typographic elements are evenly spread out):

[1] 2 3 4 5 6 *

The numbers correspond to the names of the available desktops. While the desktop inside square brackets is the current one. As shown below, the asterisk is a placeholder for the layout of the current desktop. It displays the letter M when monocle is toggled on. The layout cycles between tiled and monocle, but because the former is what we normally use, I have opted to hide the T behind the asterisk and only display the M.

[1] 2 3 4 5 6 M

If you open a window, another asterisk will be appended to the module. This one is a placeholder for the active node’s flags. The flags I define in my sxhkdrc are: Sticky, Private, Locked (see man bspc for their meaning). When a flag for the current node is active, its first letter is displayed on the panel. More than one flags can be activated at once. Such as:

[1] 2 3 4 5 6 * SPL

Other indicators concern occupied and urgent desktops that are not already in focus. For example, the following means that desktop 2 holds nodes, while 1 is focused:

[1] 2^ 3 4 5 6 * *

While urgent and unfocused desktops are denoted thus and are coloured red:

[1] 2# 3 4 5 6 * *

On multi head setups, the BSPWM report will divide desktops and their corresponding indicators per monitor. Combined with the above, we get the following:

[1] 2^ 3 * L  4- 5# 6 M SP

Notice how the indicators that display the * (asterisk) are visible for each set of desktops. Also look at the use of another indicator, the - (hyphen), for showing the focused desktop on the unfocused monitor: desktop 4. The letter M in this case concerns desktop 4. Same with the node flags S and P. While L applies to the focused node in desktop 1 and the asterisk next to it informs us that the layout is the default, i.e. tiled.

I believe all this will become easier to grasp once you start using the system. For the record, this design bears close resemblance to the status line of my tmux setup.

Panel transparency

By default, the panel is opaque, though I have made it fairly trivial to add a transparency effect to its background. The following is an excerpt from the relevant melonpanel section:

melonpanel < "$melonpanel_fifo" | lemonbar -u 1 -p -g "x${melonpanel_height}" \
-F "$foreground" -B "#ff${background:1}" -f "$melonpanel_font" -n "Melonpanel" &

Taken a closer look at the segment of the command that controls the background colour: -B "#ff${background:1}". I have designed so that you can tweak its alpha value, which is governed by the ff part. This is hexadecimal notation and means that the alpha channel is set to full, which translates into complete opacity. 00 is the opposite.

Try replacing ff with aa to get some subtle transparency, or with 55 for a more pronounced effect. Possible values for each digit are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f.

As a rule of thumb, light themes will require a greater adjustment than dark themes to create a noticeable see-through style. The choice of wallpaper will also affect your perception of it.

For changes to be applied, reload the panel with the key chord chain super + e ; p (as explained in the chapter about the basics of my BSPWM). Otherwise, you can always just use tempusmenu to switch to another Tempus theme (as discussed in the chapter about my themes), thus forcing a panel reload.

Known issues

Sometimes, seemingly at random, the panel will not be hidden when entering a window’s full screen view. The less-than-ideal workaround is to reload melonpanel with the key chord chain super + e ; p. This seems to be an upstream bug.

Another thing to bear in mind is that lemonbar does not support proportional or outline fonts (e.g. the “DejaVu” family). It can only display fixed-size, else bitmap, typefaces such as “Terminus”. If you have followed the instructions in the chapter about installing the core packages, you will have xfonts-terminus available on your system. This is an optional dependency, as the panel will fall back to the fixed typeface which comes pre-installed with Debian. I just think that Terminus is more consistent and is better suited for such a UI task.

Finally, I have noticed that pgrep melonpanel always lists two running processes. I have not been able to troubleshoot this problem just yet, assuming it is a “problem” to begin with, given that pgrep tmux gives two results as well (any help is much appreciated).

At any rate, this is the load on my system while using my custom desktop session (with compton and mate-settings-daemon active), with a single terminal that runs tmux, plus mpd playing music:

~ $ free -mt
			  total        used        free      shared  buff/cache   available
Mem:           3829         310        2990          59         528        3234
Swap:          3979           0        3979
Total:         7809         310        6970