Protesilaos Stavrou
Philosopher. Polymath.

About the top panel

Prot's Dots For Debian - Book index

The panel that appears at the uppermost area 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.
  • Core temperature.
  • Speaker volume strength and status.
  • Keyboard indicators for alternate layout and caps lock.
  • Date and time.

This is what a module looks like:

# Core temperature.
_temperature() {
	command -v acpi > /dev/null || return 1

	local therm_label therm_status

	therm_label='T:'
	therm_status="$(acpi -t | awk -F '[[:space:]]+|,' '{ print $5 }')"
	therm_status="${therm_status:0:2}"

	# Up to 59 degrees celcius keep text colour same as default.  60-79
	# turn the colour red on normal background.  Else turn the whole
	# indicator red.
	case "$therm_status" in
		[12345][0-9])
			echo "$therm_label ${therm_status}°C"
			;;
		[67][0-9])
			echo "$therm_label %{F$color1}${therm_status}°C%{F-}"
			;;
		*)
			echo "%{F$background}%{B$color1} $therm_label ${therm_status}°C %{B-}%{F-}"
			;;
	esac
}

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 _modules(), which I need to explain a bit:

_modules() {
	while true; do
		echo "B" "$(_battery)"
		echo "T" "$(_temperature)"
		echo "D" "$(_datetime)"
		echo "K" "$(_keyboard)"
		echo "V" "$(_volume)"
		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#?}"
			;;
		T*)
			# temperature
			therm="${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}$key $bat $therm $vol $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, point-and-click program out there. But hey, neither is BSPWM, Xterm, Tmux, Vim, etc.

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] *

The numbers correspond to the names of the available desktops. Because I have implemented dynamic desktops (see chapter about the advanced features of my BSPWM), there is only one desktop on the panel. If you navigate to desktop number two, the module will be like this, if desktop 1 is empty:

[2] *

If desktop 1 is occupied, the module will be:

1^ [2] *

The desktop inside square brackets (and also drawn with a bold font) is the current one, while the caret sign denotes an occupied desktop.

Next to the desktop numbers there is at least one asterisk. If the desktop contains windows, then the asterisks are two:

  • The first asterisk always indicates the layout of the desktop. If the view is set to monocle, then the letter M will take the place of the asterisk. 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.
  • The second asterisk contains information about the active window’s flags. The flags I define in my sxhkdrc_bspc are: Sticky, Private, Locked, Marked (see man bspc for their meaning). When a flag for the current node is active, its initial letter is displayed on the panel. More than one flags can be activated at once.

If all indicators are toggled on at once, you will see something like this:

[1] 2^ * SPLM

Urgent and unfocused desktops are denoted by the column sign and are coloured red:

[1] 2# * *

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

[1] 2^ * 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 typographic marker next to desktop 4: the hyphen is for showing the focused desktop on the unfocused monitor. 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 "$fontmain" -f "$fontbold" -n "Melonpanel" &

Take a closer look at the segment of the command that controls the background colour: -B "#ff${background:1}". I have designed it 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 to 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. A running compositor is required to enable transparency effects (I use compton as already mentioned in previous chapters).

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 upstream 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 (see ANNEX below for Lemonbar with proportional fonts).

Finally, you may notice that pgrep melonpanel always lists two running processes. This is because it is running _modules() (mentioned above) as well as bspc subscribe report that displays desktop information and the like. The report needs to be its own process because it has its own synchronicity, controlled by the window manager itself (please let me know if there is a way of merging every modules functionality into a single process).

ANNEX for lemonbar-xft

I maintain a personal fork of lemonbar with support for Xft (the fontconfig library). This basically means running the panel using proportional/outline fonts.

I will not provide any further information herein. I do not encourage you to compile stuff from random sources or to create what is known as a “FrankenDebian”. I use this fork as part of my own system and am prepared to deal with any possible breakage. If you are not or do not trust my fork (you should not trust any random source), then stick with the package provided by Debian: it includes the upstream code that only uses bitmap fonts.