Protesilaos Stavrou
Philosopher. Polymath.

Prot's Dots For Debian

Book contents

  1. Prior notice to using PDFD
  2. Introduction to Prot's Dots for Debian
  3. Installing Debian 10
  4. Installing the core packages
  5. Set up my dotfiles and base configs
  6. Basics of my BSPWM
  7. About the default terminal setup
  8. Why choose the MATE Desktop
  9. Notes about my shell setup
  10. Notes about my Tmux and Vim
  11. About the top panel
  12. Fonts and their configs
  13. Per-user MPD setup
  14. Quick guide to set up Newsboat
  15. The Tempus themes
  16. About my local ~/bin
  17. Closing notes and additional resources

The purpose of Prot’s Dots For Debian (PDFD) is to guide you through the process of replicating my custom desktop session on Debian 10 ‘buster’. As Debian’s upcoming stable release is not out yet, this book is only meant for early adopters or volunteers who know how to set up Debian 10 prior to its release.

I have tried every step in this guide on real hardware, my Lenovo ThinkPad X220. The initial installation was done on Saturday 12 January 2019 using the latest netinstall iso for Debian 9 ‘stretch’ and retried on 2019-04-17 using the same method.


All code by Protesilaos Stavrou presented herein is available under the terms of the GNU General Public License Version 3 or later.

The non-code parts of this book by Protesilaos Stavrou are distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.

The canonical link to “Prot’s Dots for Debian” is an extension of my website:


The following disclaimers apply to this work.

Excerpt from the GPLv3:


And this is from the CC BY-SA 4.0 License:

a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.

The purpose of this book is to help you reproduce my custom desktop session on Debian 10 ‘Buster’. The set of configurations that make up my system shall hereinafter be referred to as “my dotfiles” or other notions that are described in context.

My dotfiles apply to a BSPWM session. That tiling window manager is the core package. Complementing it, are programs that draw a system panel at the top of the viewport, display desktop notifications, set the wallpaper, perform live theme changes to the terminals and graphical applications, and the like. The idea is to have a lightweight yet perfectly functional desktop environment by combining small, specialised tools.

A short description of my custom desktop session:

  • Debian stable because rolling release distros tend to be overrated.
  • bspwm for fine-grained window management.
  • tmux to make the terminal power user even more powerful (no plugins).
  • vim to edit files inside the terminal (no plugins).
  • Carefully-defined font configurations to complement my hardware and satisfy my aesthetic preferences.
  • Full integration of my Tempus themes for considerate colour contrast and easy live theme switching for the entire session.
  • The superb Maté desktop environment as a fallback option and provider of some important programs and system-wide base configurations.

A book, not an

Some of PDFD’s chapters or sections thereof can, at times, be read as a shell script with extensive inline documentation. While I could have provided a script to automate the installation process, along with some basic guidelines on how to use it, I have opted to use this format instead. It is to ensure that no random user attempts to install something they do not fully understand, both in terms of its content and scope.

A book makes the installation process fully transparent to the user. You can read what I am doing, inspect the relevant files and, if needed, make changes on the spot.

By following the steps in Prot’s Dots For Debian (PDFD), you will develop an intimate understanding of my dotfiles, which will help you further customise the environment to your liking.

Prepare to adapt things to your liking

Please understand that my dotfiles have been designed with my use case in mind. There are bits and pieces you might find surplus to your requirements or outright unsuitable to your needs. Hopefully this manual will help you identify them at an early stage and address them accordingly.

By sharing my work, I do not purport to be an expert on the matter. I am just a regular user who has spent enough time documenting their practices. If you happen to identify areas in my setup that could be improved or altogether reworked, your contribution shall be taken into consideration.

Not for hipsters

The target audience of this book is the experienced GNU/Linux user who wants to run Debian 10 ‘buster’ as a desktop OS. PDFD may also appeal to existing BSPWM users of other distros who would like to test my custom desktop session in a virtual setup. Newbies are welcome as well, provided they are willing to learn and understand who this book is for.

You do not need to be a programmer to follow the instructions in PDFD—I am not one either. Though it is recommended you have at least some knowledge of shell scripting: it is required to make certain adaptations to programs such as the one that controls the system panel.

Why Debian and not some rolling-release distro?

Exactly because I do not need the latest version of every package ever released. I was an Arch Linux user for a good amount of time. While I did learn a lot and consider that distro my second favourite, I did not find any compelling reason to cling on to the rolling-release model for the entire operating system.

Debian is exciting because it is predictable, boring even. It takes a very conservative stance towards introducing breaking changes. It does not chase new technology trends for innovation’s sake. Debian is reliable. Simple and super effective.

This is exactly what we need for the custom desktop session: a stable OS that we can expect to remain constant for at least another couple of years. Else we are trapped in a state of flux where we need to track every changelog out there in order to keep our custom desktop environment in good working condition.

In an ever-changing OS, the broader the scope of customisations, the greater the chance of experiencing breakage or minor annoyances that require manual interventions. For someone like myself, who tends to document the various types of functionality that affect my setup, with this book being a prime example, it simply is too much trouble to constantly update everything for whatever marginal benefit there is to be gained from a fresh package version.

Speaking of “fresh”, we should avoid thinking of packages in terms of groceries. That is a pernicious metaphor. Programs remain relevant for as long as they work and receive security fixes (where appropriate). The criterion for evaluating a program is not its recency, but its serviceability. “If it ain’t broke, don’t fix it”. Programs that fall in that category do not become “stale” just because their last upstream release was a few months or years ago.

Stability means predictability and peace-of-mind. This is the constant against which one may develop habits to meet their computing requirements. Having a stable basis means that you ultimately treat customisations as a means to the end of a more efficient workflow. You do not care about incessant “ricing” per se; constantly tweaking things for the sake of fitting in with the cool kids. You are interested in a custom desktop session that behaves the way you intend. Every customisation, every minute refinement, every careful tweak, serves the purpose of minimising perceived friction, of shortening the distance between your mind and the machine. Nothing more, nothing less.

As of this writing, 2019-06-04, the current stable version of Debian is version 9, codenamed “stretch”. As such, Prot’s Dots For Debian (PDFD) is not meant for the general public yet, but only for early adopters (“beta testers”). The instructions below will not get you Debian 10 ‘buster’. You will instead be installing the current stable version.

To actually get ‘buster’ prior to its release you need to configure your APT sources accordingly and then manually upgrade from Stretch to Buster (sudo apt update && sudo apt full-upgrade). This process is prone to failure, might require manual interventions, could remove critical packages, and should never be attempted on mission critical hardware or without full understanding of its potential consequences. I leave you with the contents of my /etc/apt/sources.list and wish you good luck:

deb buster main non-free contrib
deb-src buster main non-free contrib

deb buster/updates main
contrib non-free
deb-src buster/updates main
contrib non-free

# buster-updates, previously known as 'volatile'
deb buster-updates main contrib non-free
deb-src buster-updates main contrib

The following information will be valid after the official release of Debian 10. This book’s relevant sections shall be updated accordingly.

To get Debian 10 ‘buster’ on our machine, we are going to use one of the netinstall iso images. The official way is to follow the standard method, which includes only free/libre software, or to use the unconventional method which comes preconfigured with the contrib and non-free package repos. The latter is intended for awkward hardware setups that absolutely require certain non-free packages (firmware drivers) to run the installer. Here are the corresponding links:

Short note about free software

Debian refers to the second iso as “unofficial”. Do not let that mislead you. It is still provided by the team responsible for the installer images. In this context, “unofficial” means that it does not fully conform with Debian’s Free Software Guidelines.

While understandable, this is a rather unconvincing attempt to maintain the line that Debian only ships with free/libre software. I can, thus, understand why the Free Software Foundation and GNU1 do not include Debian in their list of approved distributions that do not sacrifice software freedom for convenience.2

Personally, I use Debian with a single non-free package that is necessary to enable my Wi-Fi card. Otherwise I could not run a free OS at all. Still, Debian can be run with only free software by simply removing any “contrib” and “non-free” entries from its APT sources list. System administration of this sort is outside the scope of PDFD. I have, nonetheless, taken care to only recommend libre software in the pages of this book.

Writing the latest release iso

Politics aside, let us proceed with the installation. You need to verify your iso with information provided by Debian (from the pages you get the iso from). Once the checks are done, write the iso to a flash drive. I usually follow these steps after I insert the medium and open a new terminal:

# prints information about devices
sudo fdisk -l

# the flash drive I insterted is usually at /dev/sdb
# unmount the flash drive
umount /dev/sdb

# write to it
sudo dd if=/path/to/iso/file of=/dev/sdb

# eject the flash drive
sudo eject /dev/sdb

Please be extemely careful with the above commands, especially when identifying the flash drive. Pay attention to the output of sudo fdisk -l and make sure you correctly spot the writeable medium you intend to use. Carelessness might result in data loss or other damages.

The installation process

Now on to get Debian on the machine. Insert the flash drive and power on the computer. You are given the choice of a graphical or textual interface, as well as advanced options. If in doubt, go with the graphical option. Once the installer starts, you will have to choose your language and keyboard settings, set your root user’s password, create a regular user, and the like.

At some point in the installation process, you will be asked to select your major system components. These include a Desktop Environment, an SSH server, a print server, and a web server. I always keep the first option checked, then using the space key to toggle on/off I add MATE, SSH server, remove the print server, and keep the standard system utilities.

The selection screen looks like this:

[x] Debian desktop environment
[ ] ... GNOME
[ ] ... Xfce
[ ] ... KDE
[ ] ... Cinnamon
[x] ... MATE
[ ] ... LXDE
[ ] web server
[ ] print server
[x] SSH server
[x] standard system utilities

You can omit the SSH server if you have no use for it. Follow the remaining steps and after a while you will have successfully installed Debian on your machine. Congratulations!

Later in the book I explain why you should also choose MATE. For the time being, let us proceed to the next chapter of actually installing the core packages and configuring things accordingly.

Boot up your newly-installed Debian 10 ‘buster’. When you reach the display manager screen, enter your user credentials (user name and password). This will put you in a default MATE session (pronounced ma-TE, not like its more familiar homonyms). From here, we will be installing all the packages we need and doing the rest of the preparatory work.

Enable sudo

First things first: we need to grant superuser privileges to your user account. This is necessary in order to use sudo with the various commands, rather than having to switch to the root user.

Open a terminal. For this initial step, you need to switch to the root account.

su -

While being root, make sure you update the package lists. Then install Vim and the package that enables “sudo”.

apt update && apt install vim sudo

Also install these core utilities, which are needed for getting and deploying my dotfiles.

apt install git stow

Once that is done, add your user account to the “sudo” group, replacing USER with your username.

adduser USER sudo

Reboot if you want to use the regular user, or continue as root. For the sake of this manual, I assume you rebooted, logged back in to the default MATE session and are now prepared to run all commands from your regular user but with escalated privileges (prepending “sudo” to all relevant commands).

Getting BSPWM and related components

We start by installing:

  • the window manager (bspwm) as the irreducible factor of my custom desktop session,
  • the hotkey daemon (sxhkd) for handling custom key bindings that control BSPWM,
  • the standard terminal emulator xterm,
  • the suckless-tools, which provide the simple screen locker (slock) and the dynamic menu (dmenu),
  • the program that manages the wallpaper and can display images (feh),
  • the display compositor (compton) for smooth transitions and no screen-tearing,
  • the notification daemon and concomitant library for sending desktop notifications (dunst and libnotify-bin respectively),
  • the system bar (lemonbar) that is used by one of my scripts to draw a bespoke panel on the top of the viewport,
  • and the secrets’ manager (gnome-keyring).

Run this:

sudo apt install bspwm sxhkd xterm suckless-tools feh compton dunst libnotify-bin lemonbar gnome-keyring

To make sure dunst works unencumbered, we better remove MATE’s own notification daemon:

sudo apt remove mate-notification-daemon

For more on this set of packages, see the chapter about the basics of my BSPWM as well as the one about the top panel.

GTK widget and icon themes

Now we get the GTK theme and the icon theme. I choose these because they are very well crafted and actively developed.

sudo apt install materia-gtk-theme papirus-icon-theme

Fixed and proportional fonts

We need outline/proportional typefaces for the various UI components and graphical applications, plus a fixed-size (bitmap) typeface for use in the system panel.

The outline fonts are:

sudo apt install fonts-hack fonts-roboto fonts-dejavu fonts-dejavu-extra fonts-noto-color-emoji fonts-symbola

The bitmap font is Terminus. This is optional, though highly recommended:

sudo apt install xfonts-terminus

The typographic considerations are discussed in the chapter about the fonts and their configs.

Terminal tools

My user session makes heavy use of a terminal multiplexer (tmux), while I occasionally need to use Vim’s external register or graphical application (vim-gtk3).

sudo apt install tmux vim-gtk3

The use of these tools is documented in the chapter about my Tmux and Vim combo. Of relevance is the chapter about the default terminal setup.

General CLI tools

Then we need the RSS/Atom feed reader for the console (newsboat) and a simple utility to capture screenshots (scrot).

sudo apt install newsboat scrot

Are you using a laptop or a screen with built-in brightness controls? You need this:

sudo apt install xbacklight

The music setup

For my music, I choose to use the Music Player Daemon and connect to it with a client program (mpc and/or ncmpcpp). I also want MPD to expose itself to applications that implement the MPRIS protocol (mpdris2 with python-mutagen for album covers), in order to be able to control it through other means than its own clients (playerctl). To this end, I install the following:

sudo apt install mpd mpc ncmpcpp mpdris2 python-mutagen playerctl

Detailed instructions about these are provided in the chapter about the Per-user MPD setup.

Extra packages for convenience and added functionality

I do not want my BSPWM session to be primitive. I just want it to be configurable and catered to my needs, while being light on system resources.

I therefore need a multimedia player that I can launch from the console, which also streams online content (mpv with youtube-dl), a tool that can edit/transform/convert images from the command line (imagemagick), a program to perform file transfers (rsync), a graphical frontend to my password manager (qtpass, which pulls in pass), a frontend for PulseAudio (pavucontrol), a very capable image viewer (sxiv), and a calculator for the console (apcalc—the executable is calc).

sudo apt install mpv youtube-dl imagemagick rsync qtpass pavucontrol sxiv apcalc

Thunderbird setup (optional, but recommended)

In the same spirit, I use Thunderbird as my primary email client (I also use Neomutt, which is not covered in this book due to its configuration being highly dependent on the user). Thunderbird is a robust tool that can easily filter spam, handle my CalDAV and CardDAV accounts, and cope with large volumes of email traffic. The following command will get you the email client, plus extensions for GPG encryption (enigmail) and calendaring (lightning).

sudo apt install thunderbird enigmail lightning

While still on the topic of Thunderbird, I also install the following package for handling {Cal,Card}DAV services. I put it here on its own as you might have no need for it, unless your host also uses SOGo.

sudo apt install xul-ext-sogo-connector

For further language support, I also get these (the latter with extension -el is for the Greek language):

sudo apt install hunspell {a,hun}spell-el

Firefox setup (optional, but recommended)

The Extended Support Release of Firefox (firefox-esr) is my web browser of choice. This is shipped by Debian as the default option. Users normally install whatever web extensions they may need via the browser’s own interface. However, I have found that I prefer to let apt handle things. The following packages are sufficient for my use case:

sudo apt install webext-noscript webext-https-everywhere webext-ublock-origin webext-privacy-badger

These extensions are NoScript, HTTPS Everywhere, UBlock Origin, Privacy Badger.

To make the browser better suited to my needs, I also disable the Pocket bloatware, from inside Firefox’s interface.

  • First type the address about:config and accept the warning message.
  • Then search for the entry extensions.pocket.enabled.
  • Double click to change it to false.

Then we need to address an age-old bug that affects dark GTK themes where Firefox may display light text on a light action element, like a search box.

  • Visit about:config.
  • Do: left click on some empty space > select New > select String.
  • Add this: widget.content.gtk-theme-override.
  • Its value should be Adwaita (the default GTK light theme).

Optional packages

Sometimes I need to edit photographs (darktable), record audio (audacity), and use a different web browser (epiphany-browser).

# other packages
sudo apt install audacity darktable epiphany-browser

And here are some other console tools that might come in handy. vrms displays information about non-free software on your system, htop is a process manager, while neofetch prints details about your machine and distro.

sudo apt install vrms htop neofetch

I just ran vrms and it tells me that I have 1 non-free package on my ThinkPad X220 out of a total of 1727. ABSOLUTELY PROPRIETARY! The offending package is firmware-iwlwifi for making Wi-Fi work, else I cannot access the Internet…

Optional: set up Flatpak with Flathub as its remote repo

I think that, when used in moderation, Flatpak is a compelling proposition for a stable OS like Debian. Your system will remain rock solid, while the Flatpak’ed applications will use their latest version, while being confined to a sandboxed environment.

To get started, install the core package:

sudo apt install flatpak

Now add Flathub as a remote package repository. Note that you can have multiple remote repos. This is something that, in my opinion, distros should provide themselves (would much rather trust Debian’s curated list of flatpak packages).

flatpak remote-add --if-not-exists flathub

And with the following command, we make sure that the Materia theme (in all its variants) is used by GTK-based Flatpak applications:

flatpak install flathub org.gtk.Gtk3theme.Materia{,-dark,-light}{,-compact}

The above command expands into this one:

flatpak install flathub org.gtk.Gtk3theme.Materia org.gtk.Gtk3theme.Materia-compact org.gtk.Gtk3theme.Materia-light org.gtk.Gtk3theme.Materia-light-compact org.gtk.Gtk3theme.Materia-dark org.gtk.Gtk3theme.Materia-dark-compact

For the record, Flatpak needs a running settings daemon to known which theme to apply. It is for this reason that I use the mate-settings-daemon in my BSPWM session (more on that in the chapter about the basics of BSPWM).

Note that Flathub does not discriminate against non-free software. If you care about freedom, exercise caution. That granted, the only flatpaks I tend to use are libre:

flatpak install org.gnome.Podcasts org.gnome.clocks org.kde.kdenlive

Next steps

We are done installing software. Thanks for your patience! Let us proceed to the next chapter where we actually get the dotfiles and stow them in place.

Stay logged in to the current MATE session for the time being and keep reading.

You have installed all the necessary packages and are now ready to fetch the code that makes up my custom desktop session. It is assumed you are running the stock MATE session and have an open terminal.

The latest fixed release of my dots

The “Code for PDFD” (CPDFD) is the repository that contains the latest fixed release of my dotfiles. Such tagged releases are versions that I have tested extensively and am confident that others can use. We shall be using CPDFD, because my dotfiles’ git repository is an unstable environment, intended for running tests and developing new features that eventually end up in a fixed release.

CPDFD is hosted on GitLab’s own instance ( If you have an account there and have configured SSH access, you can clone the repo with the following command:

git clone ~/cpdfd

Otherwise, just clone over HTTPS:

git clone ~/cpdfd

Bear in mind that we clone the repo into the user’s home directory. The rest of this manual will assume ~/cpdfd as a constant.

Primer to managing dotfiles with GNU Stow

You will not be copying anything manually. That is a recipe for disaster! Instead we leverage the power of symbolic links, aka “symlinks”, by using GNU Stow.

The way Stow works is to read the filesystem paths defined by a target and create equivalent symlinks to them at the parent of the present working directory (or a given destination). In practice, since cpdfd is in your home directory, all symlinks will be extensions of /home/USERNAME/, else the ~ path.

Let us take a closer look at what we mean by providing stow with a target. In my dotfiles, I have a directory call “vim”. Its structure looks like this:

~/cpdfd $ tree -aF vim
├── .vim/
│   ├── colors/
│   │   ├── tempus_autumn.vim
│   │   ├── tempus_classic.vim
│   │   ├── tempus_dawn.vim
│   │   ├── tempus_day.vim
│   │   ├── tempus_dusk.vim
│   │   ├── tempus_fugit.vim
│   │   ├── tempus_future.vim
│   │   ├── tempus_night.vim
│   │   ├── tempus_past.vim
│   │   ├── tempus_rift.vim
│   │   ├── tempus_spring.vim
│   │   ├── tempus_summer.vim
│   │   ├── tempus_tempest.vim
│   │   ├── tempus_totus.vim
│   │   ├── tempus_warp.vim
│   │   └── tempus_winter.vim
│   └── spell/
│       ├── el.utf-8.spl
│       ├── el.utf-8.sug
│       ├── en.utf-8.add
│       └── en.utf-8.add.spl
└── .vimrc

3 directories, 21 files

It includes a .vimrc file and a .vim directory with more content. So if you run stow vim from within ~/cpdfd all those paths will be added to your home directory as symlinks.

~/cpdfd $ stow -v vim
LINK: .vim => cpdfd/vim/.vim
LINK: .vimrc => cpdfd/vim/.vimrc

This means:

  • ~/.vim links to ~/cpdfd/vim/.vim.
  • ~/.vimrc links to ~/cpdfd/vim/.vimrc.

The contents of .vim are accordingly expanded into:


From now on, we will be referring to the immediate subdirectories of ~/cpdfd as “Stow packages”, as per man stow.

Using GNU Stow is essential because many of my Stow packages contain complex structures such as the one shown above. Plus, keeping everything symlinked provides the benefit of controlling things with git. If you need to make changes or pull my latest fixed release, you will be able to do so centrally at ~/cpdfd.

About my Stow packages

Switch to my dotfiles:

cd ~/cpdfd

Now list only the directories that are relevant for stow (they are always written in lower case letters):

~/cpdfd $ ls --ignore='[A-Z]*'
bin  bspwm  colours  compton  dunst  fontconfig  gtk  keyring  music  newsboat  shell  tmux  vim  xterm

Note though, that the directories that are named “NO-STOW-" still contain useful configs. However, they need to be manually adapted to each use case.

Target them all at once (we pass the -v flag so that you see where everything is linked to—though you can always just browse through my dotfiles’ contents):

stow -v bin bspwm colours compton dunst fontconfig gtk keyring music newsboat shell tmux vim xterm

If Stow throws and error and complains that some files already exist, you must delete them, rename them, or otherwise move them to another location. The common offenders are the default ~/.bashrc and ~/.profile which will block the Stow package called “shell”.

The rest of this book assumes that you have used GNU Stow on all the appropriate packages, otherwise things will not work as intended.

Now a few words about each Stow package:

  • bin contains my custom scripts. Some of these are an integral part of my custom desktop session. More on this is included in the chapter about my local ~/bin.
  • bspwm includes the configuration files for the window manager (BSPWM) and the hotkey daemon (SXHKD). The former is where we define settings such as the width of the border that is drawn around windows, the ratio at which windows are split, and the like. The hotkey daemon stores all the custom key bindings we use to control the session. For more, read the chapter about the basics of my BSPWM.
  • colours is where my Tempus themes for the shell are located. These files are used by various scripts of mine and should never be edited manually. For more, read the chapter about the Tempus themes.
  • compton refers to the display compositor and has the relevant config file. We use this to avoid screen tearing, add some subtle shadows around windows, enable smooth transitions, and create some blur behind transparent backgrounds.
  • dunst includes configurations for the daemon that displays desktop notifications. For the most part, these control the look and feel of desktop notifications.
  • fontconfig includes all of my custom font configurations. For the specifics, refer to the chapter about fonts.
  • gtk defines the settings for the graphical toolkit. It also adds ports of the Tempus Themes for the GTK3 Source View widget (used by text editors such as Gedit, Pluma, Mousepad) as well as the GTK4 equivalent (used by GNOME Builder).
  • keyring contains the files necessary for autostarting the GNOME Keyring, the tool that stores passwords and secrets. You can use this to store access to SSH keys and the like.
  • music refers to the configuration files for the Music Player Daemon and its ncmpcpp client. Please note that you need to read the chapter about the music setup in order to make this work properly.
  • newsboat stores the files needed by the RSS/Atom reader of the same name. In order to use this program, you need to add some URLs to valid feeds. Read the chapter about Newsboat.
  • shell defines my Bash-related configurations, including aliases for common commands, the command line prompt, and various useful options. Read the chapter about my shell setup.
  • tmux is about the terminal multiplexer used in my default terminal. Details are included in the chapter about my Tmux and Vim configurations.
  • vim is my editor of choice, which I use without any plugins or whimsical tweaks. As with the above Stow target, refer to the chapter about Tmux and Vim.
  • xterm contains all the necessary files for configuring the terminal emulator according to my preference.

Ready to go!

You are now ready to log in to BSPWM. Just to be sure, reboot your system. When you reach the login screen, look for the drop-down menu on the top-right corner of the screen, where desktop sessions are listed. Select bspwm and then proceed to add your username and password.

But before you actually log in, read the following chapter about the basics of my BSPWM, how to control it and move around, and the like.

You used GNU Stow to place all my configurations in the right filesystem path and are now eager to start using the custom desktop session. Just hold on a little longer, while you read through this chapter. The rest of this book is mostly recommended reading but not absolutely essential.

I have a short video demonstration of BSPWM’s main motions. Here we will inspect the underlying configurations and core files that control the Binary Space Partitioning Window Manager.

~/cpdfd $ tree -aF bspwm/
├── .config/
│   ├── bspwm/
│   │   └── bspwmrc*
│   └── sxhkd/
│       ├── cheatsheet_sxhkdrc.txt
│       ├── sxhkdrc
│       └── sxhkdrc_bspc
└── .local/
	└── share/
		└── my_bspwm_wallpaper_fallback.png

5 directories, 5 files

What matters right now is the content of the .config directory. We have:

  • BSPWM’s configuration file: bspwmrc
  • The daemon that handles key bindings: sxhkdrc

Both are put in place by running stow bspwm from inside my dotfiles’ directory. I recommend you spend some time reading them. They are heavily commented and should answer whatever questions you may have. For the sake of this manual, let us discuss the headline features.

Overview of bspwmrc

The nice thing about bspwmrc is that it is an executable shell script. It is thus possible to add conditional logic and other aspects of shell scripting in order to exercise a more fine-grained control over the desktop session.

Each setting is a bspc command that can be run in a terminal (bspwmrc is a shell script). This is quite convenient: just execute the command to get an idea of what it does. The options are descriptive enough to offer a clear idea of what they pertain to. Here is a snippet of code:

bspc config border_width 2       # outer border around nodes/windows
bspc config window_gap 4         # empty space between nodes
bspc config split_ratio 0.50     # the ratio of new:existing node

The file is divided in three sections, the description notwithstanding:

  1. Visual options for the window manager.
  2. Autostart programs at BSPWM launch.
  3. Per-host configurations.

1. Visual options

These define such things as the border that is drawn around windows, or the gap between them. They also govern the colours that are applied to the various states of the window border.

The colours are taken from my Tempus themes collection. The theme that is defined as the current default is Tempus Classic, which features warm hues on a dark background (the Tempus themes apply to the entire environment—see the chapter on the Tempus themes).

I will let you read the file for the specifics. Below are some settings that require a little bit of explaining:

bspc config single_monocle true          # smart borders
bspc config borderless_monocle true      # smart borders
bspc config gapless_monocle false        # use "true" for smart gaps

The notion of “smart” options concerns the application of the desired settings only when multiple windows are present. So single_monocle true means that desktops with only one open window will behave as if their layout was set to “monocle”.

The “monocle” layout displays windows in their maximised state, stacked on top of each other. We can control the appearance of windows in monocle view, such as by removing borders around them, with borderless_monocle true while still preserving the outer gaps by applying gapless_monocle false.

Another highly opinionated setting is:

bspc config ignore_ewmh_focus true # prevent focus stealing

Set it to false if you want programs to steal focus. Personally, I dislike that behaviour. One specific case where I do not want focus stealing is while running newsboat: I go through the feed list opening all interesting links in browser tabs (or use mpv in the console for multimedia). Once I am done, I close newsboat: no need to go back and forth between it and whatever program steals its focus each time I try to open a new item in the background.

2. Autostart

This is where we instruct BSPWM to run the programs that are essential to the desktop session. The most important of them is sxhkd, which is the hotkey daemon that stores all our custom key bindings, including those that control the window manager.

Some notable points:

  • Each program leverages shell scripting, so as to be run only if it is indeed present.
  • melonpanel is the script that draws the panel at the top of the screen. This is my implementation of lemonbar (read the chapter about the top panel).
  • compton is a display compositor, which is configured to provide a slight blur behing transparent regions, and add subtle shadows around windows, and the like. Its real necessity is to eliminate or at least minimise screen tearing.
  • feh is the tool that sets the wallpaper. I manually define a “{light,dark}.jpg” at ~/Pictures/theme. The last used file path is stored in ~/.fehbg, while I also set a ~/.wallpaper.jpg. In case you have not assigned any wallpaper, you will get ~/.local/share/my_bspwm_wallpaper_fallback.png. That is a pure black (#000000) background with this inscription in pure green (#00ff00): where there is a shell, there are dotfiles_.
  • setxkbmap sets the keyboard layout to US QWERTY and assigns the Compose key to the “Menu” button. Note though that own_script_current_keyboard_layout is designed to switch layouts betwen the default and Greek. To change this behaviour, you need to either edit sxhkdrc (find that script’s invocation) or adapt the script to your needs.
  • A settings daemon is also launched. If you have followed the instructions in this manual, it should be mate-settings-daemon. We need such a tool for a couple of reasons: (1) to be able to change the theme of GTK applications, (2) to apply the same theme to Flatpak apps. As a bonus, the settings daemon allows for live theme switching (as discussed in the chapter about the Tempus themes).
  • The last two programs that are launched are mpd and mpDris2. These are for our music player, as documented in the chapter about the music setup.

3. Per-host configurations

Here I execute a single command: own_script_bspwm_per_host_configs. This contains some additional bspc commands for defining the number of desktops (workspaces) and their mapping to one or two monitors. The default is to set six desktops:

# all workspaces on the primary monitor
bspc monitor -d 1 2 3 4 5 6

While these settings can be stored in bspwmrc directly, I have decided to keep them in their own file. It is a prime example of an external script that configures BSPWM in a context-aware manner (and why having bspwmrc as an executable is a powerful feature).

Bear in mind that, as with all of my dots, own_script_bspwm_per_host_configs is documented extensively. If, however, you have no use for such functionality, just define the workspaces directly inside BSPWM’s config file (see the bspc monitor command shown above).

Also note that own_script_laptop_dual_monitor contains an xrandr command that slightly adjusts the brightness and gamma channels of the LVDS1 display. I have sanitised this behaviour by running a check against the HOSTNAME, to make sure this only runs on my laptop. Still, it is important for you to know, as you might need to adapt things to your liking.

Outlines of SXHKD

There are two config files, sxhkdrc and sxhkdrc_bspc, which are meant to separate custom hotkeys between those that are specific to BSPWM actions and others that are WM-independent.

Each of the SXHKD configs stores custom key bindings, internally known as “key chords”. There are two types of patterns: the direct and the chained. To illustrate the difference:

# key chord
Super + <key>

# key chord chain
Super + <key> ; <key>

Sample of an actual direct key chord is:

# Session management (log out, lock, switch users, reboot, shutdown).
ctrl + alt + {Home,End,Delete}

This means that while holding down the Ctrl and Alt modifiers, you can press either of Home, End, Delete to invoke the command poweroptionsmenu (a script of mine for running common session management operations, such as logging out, locking the screen, rebooting…).

Now this is a simplified version of an actual key chord chain:

super + e ; {p,t}
	{ \
	pkill -x melonpanel && melonpanel, \
	tempusmenu, \

This pattern means that you first hold down Super, then press e, then release Super and press any of the keys defined to the right of the semicolon ; to invoke the corresponding command. To that end, super + e ; t will execute tempusmenu.

All key chord chains are designed with mnemonics in mind:

  • Everything that concerns the entire session, else “the environment”, starts with super + e ; <keys>.
  • All graphical applications are launched with super + g ; <keys>.
  • All the command line programs you would normally run in a terminal are super + x ; <keys>.
  • To assign flags to nodes, we have super + a ; <keys>.
  • For node splits we go with super + s ; <keys>.

A note on the selection of keys for launching common programs:

super + g ; {1-3}
	{ \
	notify-send -i firefox "Run GUI program" "Launching Web Browser" && firefox-esr, \
	notify-send -i system-file-manager "Run GUI program" "Launching File Manager" && caja, \
	notify-send -i thunderbird "Run GUI program" "Launching Email Client" && thunderbird \
super + x ; {3-5}
	mate-terminal --disable-factory -x {neomutt,newsboat,ncmpcpp}

You might wonder why I have not started numbering the CLIs from 1: because I want to remember that while launching programs I have the following mappings, regardless of whether they are graphical or textual:

  • 1 == web browser
  • 2 == file manager
  • 3 == email client
  • 4 == RSS/Atom reader
  • 5 == music player

I have not found any CLI tools that I consider good enough for web browsing and file management. Given that most websites are not designed to work without javascript and CSS, I believe there will be no truly decent console-based web browser. As for a file manager, I used to use ranger but have realised that I have no real need for it: I mostly manipulate files the UNIX way.

The point is that you might find this indexing useful in case you choose to add your own programs.

Cheat sheet with common key bindings

To help you get started, I provide the cheatsheet_sxhkdrc.txt. It includes the most common key chords, accompanied by short descriptions or explanations. Type super + F1 or super + Home. This will launch a floating terminal window that runs less on the cheat sheet.

The first section of the cheat sheet covers the basics about key chords and key chord chains. It also notes that the main motions that correspond to the four cardinal directions are the same as with Vim: h, j, k, l for left, down, up, right respectively.

So go ahead and run super + F1 once you log in to the BSPWM session for the first time. Below I present the entirety of the cheat sheet, with a reminder that you must always look at the source code that I strive to keep clean, readable, and well-documented:

List of common key bindings.  All definitions are stored at:


The latter is for definitions that control the window manager.  While
the former has WM-independent keys.

Last review 2019-06-04.

Explanation of the basics

The Super key, aka "mod4", is the one that most keyboards mark with the
Windows logo.  While the key "Return" is also known as "Enter".

Motions are the same as Vim: h,j,k,l (left,down,up,right).

This is the general format of a key chord (aka key binding):

	Super + <key>

And this is a key chord chain:

	Super + <key> ; <key>

The keys "Super", "Alt", "Shift", "Ctrl" are known as "modifiers".

To run a key chord, hold down the modifier and press the key.  Key chord
chains build on that principle: you type the key binding to the left of
the semicolon (;), release the modifier and then type the key (or key
chord) to the right of the semicolon.

In this document, the notation {h,j,k,l} means "any one among" the
comma-separated items.  Whereas {1-4} denotes a range: 1,2,3,4.

Getting started

Super + Return            |-Open a terminal running the "Default" tmux session
Super + Shift + Return    |-Open a generic terminal (xterm)
Super + q                 |-Close focused node
Super + Shift + q         |-Kill focused node
Ctrl + Alt + Delete       |-Launch poweroptionsmenu, where you can choose to log out, reboot, etc.

Window motions

Super + {h,j,k,l}         |-Move focus in the given direction == determine which node has attention
Super + Shift + {h,j,k,l} |-Swap focused node with the one in the given direction
Super + Ctrl + {h,j,k,l}  |-Expand/contract tiled node in that direction, provided there is a split
Super + Alt + {h,j,k,l}   |-Set preselection (manual tiling) for next window
                          |---Cancel presel by inputting same command again
Super + Alt + {1-9}       |-Set the presel ratio, relative to the focused node
Super + Shift + <arrows>  |-Move floating window
Alt + right click         |-Drag floating window
Alt + left click          |-Resize floating window from the nearest edge

Window and desktop actions

Super + Space             |-Toggle between tiled and floating states
Super + m                 |-Toggle between tiled and monocle layout (monocle == maximised nodes)
Super + f                 |-Toggle focused node's full screen view
Alt + Tab                 |-Cycle through windows on the current desktop
Alt + Shift + Tab         |-Cycle backwardly through windows on the current desktop

Desktop operations

Super + {1-6}             |-Switch to the designated desktop (workspace)
Super + Shift + {1-6}     |-Send focused node to the given desktop
Super + Tab               |-Cycle through desktops on the current monitor
Super + Shift + Tab       |-Cycle backwardly through desktops on the current monitor
Super + r                 |-Rotate the node tree 90 degrees clockwise
Super + Shift + r         |-Rotate the node tree 90 degrees counter-clockwise
Super + Alt + r           |-Mirror/flip the node tree (top left becomes bottom right)
Super + s ; {b,e}         |-Balance or equalise node splits (better try it to get an idea)
Super + Shift + {[,]}     |-Incrementally decrease or increase the gaps between the tiled nodes
Super + Shift + {y,u,i,o} |-Change to gap presents {0,5,10,20}

Launching programs

Super + d                 |-Run dmenu with access to all binaries in PATH
Super + Shift + d         |-Run flatpakmenu with access to all flatpak apps
Super + g ; {1-3}         |-Open graphical apps {firefox,caja,thunderbird}
Super + x ; {3-5}         |-Run a terminal with {mutt,newsboat,ncmcpp}
Super + x ; 0             |-Launch a floating terminal running calc

Useful extras

Super + {F1,Home}         |-Launch a floating window with this cheat sheet
Print                     |-Get a screenshot of the focused node saved to the ~/Desktop
Super + Print             |-Get a screenshot of the entire viewport saved to the ~/Desktop
Super + p                 |-Run passmenu to copy a password stored with the UNIX tool "pass"
Super + x ; w             |-Run a floating image browser, from where you can also set the wallpaper
Super + e ; c             |-Toggle the display compotisor (do this if you have performance issues)
Super + e ; f             |-Toggle BSPWM "focus mode", to remove gaps, the padding, the panel
Super + e ; t             |-Run tempusmenu to select a Tempus theme for a live theme switch
                          |---The Tempus themes:
                          |---Some ports of the Tempus themes are distributed with my dotfiles

Further reading

Study the ~/.config/sxhkd/sxhkdrc and ~/.config/sxhkd/sxhkdrc_bspc.
They are extensively documented.  You will find key chords for tasks not
included herein, such as multimedia keys, setting node flags, and more.

In the chapter about setting up my dotfiles, I concluded with a section about configuring the default terminal emulator. Here I want to go into some further detail about this integral part of my custom desktop session.

My default terminal emulator is the standard for the X Window System: xterm. This has not always been the case. Until fairly I was using my custom build of the Simple Terminal, by suckless. Prior to that I was a urxvt user. I have also worked extensively with {gnome,mate,xfce4}-terminal (VTE-based) and others.

I only tried Xterm last, due to the false belief that it was legacy software, more or less. That misconception was quickly cast aside once I started reading through the program’s manpage and then checked its upstream provider. Xterm is a very capable tool that continues to receive regular updates.

To be clear: no terminal is perfect. The choice of terminal is a matter of weighing the pros and cons. I find that Xterm meets the following criteria better than its alternatives:

  1. Is in the Debian repos. True for all other options. However, note that st only makes sense to use as a custom build, so it technically does not meet this criterion. Overall, Xterm is more suited to Debian than a custom build of the Suckless Terminal, because it does not depend on development packages and therefore is not going to have any issues over the long term (e.g. the upstream has build dependencies that are not available in Debian Stable).
  2. Is highly configurable and easy to reproduce. In large part this is true for all options though there are differences in degree and ways of doing things: xterm uses the .Xresources file, making it the most dotfile-friendly option.
  3. Has good performance. My totally-not-scientific tests suggest that only unpatched st has a slight edge over Xterm. But the unpatched tool lacks all sorts of features, meaning that this is not a one-to-one comparison. At any rate, I think the use of tmux renders this largely irrelevant, since we no longer need to spawn multiple windows.
  4. Is agnostic to the choice of desktop environment or toolkit. True for st as well, though not for the others.
  5. Has good font-drawing capabilities. This is particularly important when using tmux and other programs that draw borders. The VTE-based programs have no issues whatsover. Xterm requires some careful font configurations, which I have taken care of. st can only cope well if it is extensively patched. urxvt has weird issues with letter spacing.

If you find that xterm does not fit your use case, I also have a script that configures mate-terminal to my liking: own_script_mate_terminal_setup. If you still want to use something else, I recommend my custom build of st (has no upstream patches): Be warned that only Xterm is integrated with my dotfiles to keep things maintainable.

The uses of Xterm

The many uses of xterm are defined in my sxhkdrc. In short:

  • Serves as a container for tmux, the terminal multiplexer (see chapter about my Tmux and Vim setup)
  • Can be run on its own. Offers everything you expect from a feature-complete terminal (though I strongly encourage you to learn tmux).
  • Launches CLI tools (mutt, newsboat, ncmpcpp) in a standalone tiled window.
  • Runs a console calculator in a standalone floating window.
  • Displays the cheat sheet with the most common key chords in a standalone floating window.

With these granted, type super + F1 or super + Home to get started on my sxhkd keys (as noted in the chapter about the basics of my BSPWM).

You should already be up-and-running with the custom desktop session. But there is still much to learn from the rest of this book. Let us review the choice of MATE (Maté) as the default option for the desktop environment.

In the chapter about installing Debian 10 ‘buster’ on your machine, I suggested you select MATE as a core part of your new system. The installer’s major component selection should look like this:

[x] Debian desktop environment
[ ] ... GNOME
[ ] ... Xfce
[ ] ... KDE
[ ] ... Cinnamon
[x] ... MATE
[ ] ... LXDE
[ ] web server
[ ] print server
[x] SSH server
[x] standard system utilities

You may be wondering why I recommend this step: is not the purpose of this manual to set up a custom BSPWM session? The reasons are basically three:

  1. You get all the Xorg and GTK dependencies in place. You need these anyhow for running a graphical session and some of the most common application software, such as Firefox and Thunderbird.
  2. You install some MATE programs that my custom desktop session makes use of. These are caja (file manager) and mate-settings-daemon (touched upon in the chapter about the Tempus themes).
  3. You have a robust fallback option in case you need to use the computer without BSPWM (e.g. multiple users on a single computer).

What about ‘minimalism’?

Minimalism is about striving to achieve a state of minimum viability, but not less. We still want something that works without any “gotchas”.

Personally, I do not keep track of the package count to determine the ‘bloat’ installed on my machine. This is not a game where the user with the fewer packages wins. If a piece of software is useful, and is known to be fairly stable and maintained, then I keep it. Installing a DE at the very outset makes things simpler. Bloat is when you run a modified web browser as your text editor, or whatever the latest trend is with Electron-based applications and web apps.

With a DE, all the components that are needed for a graphical session are set in place, same with the networking stack, the policy kit agent, the display manager. In case you ever wondered, BSPWM also counts as a “graphical session”. Even the terminal emulator is a GUI: it is called an “emulator” for a reason.

To my eyes, setting up Xorg is a task that falls outside the scope of dotfile management. Same with configuring the network stack and similar basic utilities. The moment we enter into that domain we start creating our own distro or bespoke sysadmin setup. Let Debian handle that, while we focus on stowing the dotfiles in place, so that we may get our desired workflow going.

Why specifically MATE and not “foo”?

MATE is the most complete GTK-based desktop environment after GNOME, without using the GNOME shell stack (in which case we should mention Cinnamon and Budgie). This is to be expected due to its heritage: it is the fork and subsequent continuation of the GNOME 2 code base.

MATE’s main apps are very competent tools. The file manager, Caja, is a good piece of software. The document viewer, Atril, gets the job done. Same with the image viewer, Eye of MATE. Meanwhile, the archive manager, Engrampa, will handle compressing or decompressing data without any problem.

Make no mistake: MATE is far from perfect. Otherwise it would be frivolous to set up a custom desktop session.

Compared to the other options provided by the Debian installer:

  • MATE is ideal for a stable distro such as Debian 10 (same with Xfce). It is developed at a rather slow yet steady pace, perfectly complementing the stability and predictability of the underlying OS. Debian is a poor fit for tracking DEs like GNOME and KDE Plasma that are developed at a rather fast pace. For instance, the GNOME version in ‘buster’ is already one release behind upstream and will be almost two by the time it becomes the new ‘stable’ (expected in the summer of 2019). The gap will continue to widen every six months, ceteris paribus. Similar story with KDE.
  • MATE is fairly modular, much like Xfce. You can use its individual components without having to run the entire session. And unlike Xfce, MATE has already completed the migration to GTK3 (last checked: 2019-06-04).
  • Unlike GNOME (GNOME 3), MATE is committed to preserving the traditional desktop metaphor instead of turning the desktop into an oversized phone UI. It also is considerably less taxing on system resources.
  • Compared to Xfce, MATE does not need to pull in packages from another DE in order to function properly. Whereas Xfce lacks its own archive manager, document viewer, calculator, among others.
  • MATE is more lightweight than GNOME and at least on par with—if not lighter than—KDE Plasma, without losing out on any of the core functionality. For our use case, being light-yet-complete and self-contained is exactly what we are looking for.

My point is clear: MATE is the best GTK-based option we could go for.

I only use bash as my CLI shell. It is ubiquitous. It works. And, because I have no need for fancy extras or technology previews, my shell’s setup has no plugins, external add-ons, or other obscure extensions (same as with my Vim and Tmux, by the way).

~/cpdfd $ tree -aF shell
├── .bash_profile
├── .bashrc
├── .inputrc
├── .local/
│   └── share/
│       └── my_bash/
│           └── dircolors
├── .profile
└── .xsessionrc

There are a couple of files that are only read at startup: .xsessionrc and .profile. The former exists for the sole purpose of sourcing the latter. In .profile I have instructions to:

  • Use my .bashrc.
  • Add ~/bin to the PATH.
  • Launch the keyring (mostly for storing SSH credentials).

.bash_profile is also just a placeholder for sourcing the .bashrc. Meanwhile, .inputrc provides some basic options for slightly modifying the behaviour of the command line interpreter. These concern the (1) reduction of key presses for tab completion, (2) textual and colourised information about files and directories, (3) colours that enhance the visuals of tab-completion’s feedback.

About the .bashrc

As is the norm with my dotfiles, the .bashrc is heavily documented. This is an overview of its headline options:

  • PAGER and MANPAGER is less with the option to quit after reaching the end of a file and trying to read further below.
  • The EDITOR is vim, while its GUI variant is the VISUAL.
  • The default browser is whatever is defined by the MIME list (should be firefox-esr).
  • The prompt is simple and super effective: <filesystem path> $ by default or, if running via an SSH connection, it becomes slightly more informative with <user>@<host>: <filesystem path> $ .
  • Enable tab-completion when starting commands with sudo.

Then I have a comprehensive list of aliases, that you may or may not like to keep in place. Run alias from the command prompt to get the full list and/or filter its output accordingly:

~ $ alias | grep 'apt'
alias aac='sudo apt autoclean'
alias aar='sudo apt autoremove -V'
alias adl='apt download'
alias afu='sudo apt full-upgrade -V'
alias ai='sudo apt install'
alias air='sudo apt install --reinstall'
alias ali='apt list --installed'
alias alu='apt list --upgradable'
alias ama='sudo apt-mark auto'
alias amm='sudo apt-mark manual'
alias apc='sudo aptitude purge ~c'
alias ar='sudo apt remove -V'
alias ard='apt rdepends'
alias as='apt search'
alias ash='apt show'
alias au='sudo apt update'
alias aug='sudo apt upgrade -V'
alias aulu='sudo apt update && apt list --upgradable'
alias auu='sudo apt update && sudo apt upgrade -V'
alias auufu='sudo apt update && sudo apt upgrade -V && sudo apt full-upgrade -V'

The most opinionated aliases are those that change the default behaviour of core utilities like cp, mv, rm. They make their output verbose and introduce a prompt for confirming user input where appropriate. I believe these are sound defaults, as they protect you from accidents. That granted, you can always run an unmodified command by prepending a backslash \. For example:

# This uses the alias for `cp`
~/cpdfd $ cp README test
'README' -> 'test'
~/cpdfd $ 

# This uses the original `cp`
~/cpdfd $ \cp README test
~/cpdfd $ 

Finally, there are a few functions:

  • man() configures man to show some colours and formatting for the various parts of its syntax.
  • cd() tells cd to list in a clean way the directory’s contents when entering it, including the hidden items, though not the implicit ones.
  • backupthis() can be run as backupthis <file> to create a copy of the target, with a time stamp as its extension and identifier.

That just about covers it. I wish you luck on your PATH; make sure to get HOME safe.

Both Tmux and Vim are essential to my workflow. It is thus pertinent to inform you about their respective configuration files so that you know what to expect. This is with the proviso that you already are familiar with these tools.

About my tmux setup

Let’s start with the terminal multiplexer (I also have a video demo about TMUX and BSPWM). It is the first thing you will interact with when you log into the session and type super + return:

~/cpdfd $ tree -aF tmux
└── .tmux.conf

0 directories, 1 file

Only its config is distributed with my dotfiles, which is another way of saying that I do not use any plugins whatsoever. What is provided by the program itself is more than enough.

To send commands to tmux you must first press its prefix key, which I have kept to the default of Ctrl + b as it is the one that causes no issues with other programs’ main functionality, in the way I use them (it conflicts with command line motion for moving one character backwards, as well as Vim’s full page back scroll). Then, while releasing the prefix key, you can either access the command prompt by pressing the colon : or type one of the many keys that are assigned to direct actions. In the configuration file, modifier keys are shortened. So Ctrl + b is written as C-b, Alt is A, Shift is S (just to be sure: S- inserts the majuscule, so when you see a capital letter, add it that way). We use this notation from now on.

Here are the main key bindings to get you started:

# Those that involve C-b (prefix)
# -------------------------------
<prefix> s        # split current pane horizontally
<prefix> v        # split current pane vertically
                  ### these are the same as Vim's C-w {s,v}
<prefix> S        # split the whole window horizontally
<prefix> V        # split the whole window vertically
<prefix> x        # kill current pane
<prefix> C-x      # kill all panes except the current one
<prefix> r        # reload the tmux conf
<prefix> m        # mark active pane
<prefix> C-m      # toggle maximise active pane
                  ### the default is <prefix> z (too close to x)
<prefix> A-{1-5}  # switch to one of the five layout presets
<prefix> E        # evenly spread out active and adjacent panes
<prefix> c        # create a new window (windows contain panes)
<prefix> !        # break pane from current window
<prefix> J        # the opposite of break-pane
<prefix> Tab      # swap active pane with the previous one
<prefix> C-Tab    # swap active pane with the marked one

# Keys without the prefix
# -----------------------
A-{h,j,k,l}       # navigate panes in the given direction
A-S-{h,l}         # move to left/right window

Read .tmux.conf for the entirety of my settings and custom key bindings. That file is heavily documented, as is the norm with practically every item in my dotfiles.

Now if you are thinking that you do not need a terminal multiplexer and have no time to learn how to use one, I urge you to think again. This is a great skill to master. It greatly improves the overall use of the terminal. It is a skill that is highly portable. It will come in handy in a variety of situations whereas, to be honest, learning bspwm may not be particularly useful outside the narrow confines of a custom desktop session.

About my Vim setup

That last piece of advice holds true for vim as well. Spend some time learning its basics. Over time you will become proficient at editing text.

And here is another piece of advice, before we delve into the specifics of my Vim setup: set a very high bar for the use of plugins or, as in my case, do not use plugins at all. The more comfortable you are with the generic program, the higher the portability of your knowledge.

Now on to my customisations.

~/cpdfd $ tree -aF vim
├── .vim/
│   ├── colors/
│   │   ├── tempus_autumn.vim
│   │   ├── tempus_classic.vim
│   │   ├── tempus_dawn.vim
│   │   ├── tempus_day.vim
│   │   ├── tempus_dusk.vim
│   │   ├── tempus_fugit.vim
│   │   ├── tempus_future.vim
│   │   ├── tempus_night.vim
│   │   ├── tempus_past.vim
│   │   ├── tempus_rift.vim
│   │   ├── tempus_spring.vim
│   │   ├── tempus_summer.vim
│   │   ├── tempus_tempest.vim
│   │   ├── tempus_totus.vim
│   │   ├── tempus_warp.vim
│   │   └── tempus_winter.vim
│   └── spell/
│       ├── el.utf-8.spl
│       ├── el.utf-8.sug
│       ├── en.utf-8.add
│       └── en.utf-8.add.spl
└── .vimrc

3 directories, 19 files

A quick rundown of my short and simple .vimrc:

  • I stick to the default key bindings.
  • I expect Vim to ask for confirmation when closing a modified buffer.
  • I use tabs instead of spaces for indentation, setting the width of the tab character to be equal to four spaces. I used to use spaces when I first started using a text editor, because that was the default. However experience suggests that tabs are semantically more appropriate for indentation. The tab key inserts its own characters, which can have an arbitrary width defined by the program that reads it. In short, tabs are better for indentation, while spaces are better for tabular layouts such as the tmux key table I presented above.
  • The text width is 72 characters long. This is particularly important for writing good git commit messages. And, because git is designed with email in mind, this line length is ideal for sending plain text email, such as with mutt.
  • Sentences in a paragraph start with two spaces after a period or full stop. This is better visually when typing in a monospaced font. The various parsers, e.g. Markdown to HTML, know how to convert that to a single space, just as they know how to turn hard line wraps between consecutive lines of text into uniform paragraphs (a blank line marks a new paragraph).
  • Syntax highlighting is on and uses my Tempus themes. Do not edit this part manually, as it will be changed when running own_script_update_environment_theme or its tempusmenu interface (see chapter on Tempus themes).

Read the .vimrc for an in-depth understanding of my customisations (it is a fairly short config).

Neither Tmux nor Vim is an OS

Now you may be wondering how it is possible to use Tmux and Vim without plugins and all the accoutrements of a modern workflow. The answer is rather simple: let Tmux+Vim be specialised tools and leave the rest to other programs.

Do you really need Vim’s sub-par approach to multiplexing (its own approach to splits, buffers, tabs) when you can just be a tmux ninja? Why do you require a plugin to check git information inside Vim when you can just use the command line? Open a new tmux split and type git status, git log, git diff… You need to commit only parts of a changed file? Know that git add --patch is your friend.

In the same spirit, use the core utilities like cd, ls, find, grep, cp, mv, rm. Keep things simple and avoid feature creep. Let the text editor edit text. Keep the multiplexer true to its spirit. If you truly need an extensible, fully-customisable integrated development environment, then you should seriously consider GNU Emacs (which is a Lisp interpreter that implements a text editor among many others).

Of course, there are scenaria where a plugin makes a program better for the task at hand. My point is that you should be very picky about your choice of external functionality. GNU/Linux is a powerful OS (Emacs too!). You do not need to incorporate every kind of feature in the core tool. Perhaps there are other operating systems that make things difficult for the power user: if you are using one of those, then a hodgepodge of plugins is the least of your troubles.

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_output=$(sed 1q $battery_path/capacity)
	battery_status="$(sed 1q $battery_path/status)"

	if [ -d "$battery_path" ]; then
		case "$battery_status" in
				echo "%{F$color14}$battery_label <c>%{F-} ${battery_output}%"
				case "$battery_output" in
						echo "%{F$color1}$battery_label <d>%{F-} ${battery_output}%"
						echo "%{B$color1}%{F$background} $battery_label ${battery_output}% %{F-}%{B-}"
						echo "%{F$color11}$battery_label <d>%{F-} ${battery_output}%"
				echo "%{F$color2}$battery_label%{F-} Full"
				echo "%{F$color3}$battery_label <?>%{F-} ${battery_output}%"
		echo ''

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

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
			# battery status
			# current date and time
			# keyboard layout (en or gr)
			# volume level

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, Marked (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

Typography is essential to a good computing experience. I would even argue that type is the irreducible factor of a computer’s user interface. But let’s keep things in focus: good fonts are essential to a setup that strongly emphasises the use of a text terminal.

My opinionated font-related settings are stored in my dotfiles’ “fontconfig” directory (stow package). These take precedence over system-wide defaults that are defined in /etc/fonts/.

~/cpdfd $ tree -aF fontconfig/
└── .config/
	└── fontconfig/
		├── conf.d/
		│   ├── 10-hinting-full.conf
		│   ├── 10-sub-pixel-rgb.conf
		│   ├── 11-lcdfilter-default.conf
		│   ├── 20-unhint-small-hack.conf
		│   ├── 45-generic.conf
		│   ├── 45-latin.conf
		│   ├── 50-enable-terminus.conf
		│   ├── 60-generic.conf
		│   ├── 60-latin.conf
		│   ├── 80-condensed-large-dejavu.conf
		│   └── README
		└── fonts.conf

3 directories, 12 files

The fonts.conf includes basic rules for adding emoji character support to all generic font family definitions: serif, sans-serif, monospace.

Inside conf.d we find the important rules (sorry, I do not really care about emoji). Some file names will suggest what each rule is about. For example, 50-enable-terminus.conf overrides the default settings that disable fixed-size typefaces (bitmap fonts).

The file 20-unhint-small-hack.conf applies to the “Hack” typeface. It concerns small point sizes. This rule serves mostly as an example, but also because that family is my preferred choice of monospaced font. You can copy and then edit the rule to match whatever typeface fails to display properly at certain point sizes.

On the other end, 80-condensed-large-dejavu.conf will substitute the default DejaVu fonts for Serif and Sans with their condensed equivalents. This makes either DejaVu variant better as a fallback font for UI elements and long form texts, because it removes the rivers of white space that run through its widely-spaced letter forms.

The file names that start with “45” attribute a generic family to each typeface. For example, I assign “Hack” to the “monospace” group.

While the “60-*” rules concern the priority of font selection. Here is a snippet of XML that I will explain:

		<family>Noto Sans</family>
		<family>Liberation Sans</family>
		<family>DejaVu Sans</family>

When selecting the fontconfig alias “sans-serif” (or just “Sans”), the actual typeface is, in order of priority from top to bottom: Roboto, Noto Sans, Liberation Sans. If none of these are installed or available, then DejaVu Sans shall be used instead.

As already discussed in the chapter about installing core packages, these are the fonts I use and consider solid defaults:

sudo apt install fonts-hack fonts-roboto fonts-dejavu fonts-dejavu-extra fonts-noto-color-emoji fonts-symbola xfonts-terminus

Honourable mentions:

fonts-monoid fonts-firacode

Note that fonts-symbola is mostly required to display symbols in terminals that have trouble with ambiguous characters.

Modifying the font configurations

My settings are tailored to my hardware and aesthetic preferences. I strongly encourage you to spend some time inside my conf.d to get a sense of how things work. For more, run man fonts-conf. Settings provided by Debian, are stored at /usr/share/fontconfig/conf.d/, while the applicable rules are defined in /etc/fonts/conf.d/.

Graphical applications read the configuration files that are specific to their toolkit. I only have GTK apps, so we get these files:

~/cpdfd $ tree -aF gtk
├── .config/
│   ├── gtk-3.0/
│   │   └── settings.ini
# Irrelevant files
├── .gtkrc-2.0
# More files that do not concern fonts

You only need to check .gtkrc-2.0 and the GTK3 settings.ini. The default typeface is the fontconfig alias “sans” at 10 point size. If you have followed the instructions in the chapter about installing core packages, “Sans” or “Sans-serif” should stand for “Roboto” (package is fonts-roboto).

The panel (top bar) only supports bitmap fonts, as explained in the chapter about the top panel. It is configured to use Terminus (xfonts-terminus) else fall back to whatever the “fixed” typeface is.

The notification daemon—dunst—uses “Sans-10”, in large part because its configuration file is static and cannot run shell logic. A sans-serif font is the safest default. Besides, notifications can display a big chunk of text, where a monospaced font will make the notification’s box expand out of proportion. We want them to be discreet.

All the above notwithstanding, you should know that not all applications out there will faithfully follow your rules. For example, Flatpak apps will use their own settings because they do not read from the user’s font configurations. Graphical tools that are launched with escalated privileges will read from the root user’s configs. And so on.

What makes a good choice of font

Some closing notes on the criteria that determine the choice of my default typefaces: Hack and Roboto.

  • Good unicode coverage. Support extended latin and greek glyphs at minimum.
  • Have at least two weights: regular and bold. Ideally, also support true italics, or at least oblique forms with some effort put into them, rather than some procedurally generated slanted variant of the regular letters.
  • Be legible at small point sizes. Do not create rivers of white space that flow through the text at larger sizes.
  • Have good typographic colour. In other words, do not have too thin letter forms. Typefaces that are too thin are harder to read, make colours less distinct from each other, while they tend to create a certain “halo effect” around letter forms when using them against a light backdrop.
  • Do not have a very high x-height. I need to easily tell apart miniscules from majuscules.
  • Do not rely too much on serifs and fine details. Such letters can become the standard when our displays have a pixel density that is at least as good as printed text. Until then, they can be hard to read in certain conditions.
  • For monospaced fonts: all vaguely similar glyphs should be easy to tell apart, such as 0, o, O, i, I, l, L 1, s, 5
  • Be available in Debian’s main archives. Comply with Debian’s Free Software Guidelines.

All this can be summarised as “do not be frivolous; be frugal, be accessible, and get the job done”.

The Music Player Daemon is a program that stores information about your music collection. It manages metadata and playlists of currently queued songs or ones that are saved.

MPD uses a server/client model. To interface with it we need to use one of the many available client programs. The simplest one is mpc, a console utility with basic functionality for querying the daemon’s status, handling media controls, and the like. A more feature-rich client is ncmpcpp, which also runs in the console.

Basic configuration

MPD may be run as a system-wide server and can be controlled remotely as well. For my use case, all I need is a local, user-specific setup. This is what we will be doing.

Assuming you have followed the instructions in the chapter about installing the core packages, you should have these in place:

sudo apt install mpd mpc ncmpcpp mpdris2 python-mutagen playerctl

Then switch to the base of my dotfiles’ directory and proceed to create symlinks for the music-related programs:

~/cpdfd $ stow music

Now you need to run a series of commands to configure mpd in accordance with our per-user requirements. Start by disabling the systemd service, since we autostart mpd from within the bspwm session:

sudo systemctl disable mpd

Now switch to the local config directory:

cd ~/.config/mpd

Create the directory where saved playlist data is stored:

mkdir playlists

Generate the files mpd needs in order to run:

touch database log pid state sticker.sql

Configuration is done! You might need to reboot for changes to take effect.

Update the database

To update the mpd database (assuming the presence of audio files at ~/Music) either run mpc update in a terminal or type ncmpcpp and then press u. If your music is in a different directory, edit the relevant path in ~/.config/mpd/mpd.conf.

Basics of ncmpcpp

The “Ncurses Console Media Player C++”. To start interfacing with this excellent tool, simply type ncmpcpp in a terminal, or use the key chord chain super + x ; 5 (see the chapter about the basics of my BSPWM).

To play music, learn how to use ncmpcpp by studying the corresponding manpage. I typically switch to screen 4, by hitting 4, then A and hit enter. This inserts an empty prompt which adds all available music to the playlist. Then I toggle on repeat mode with r, random playback order with z, and a 5 second cross-fade with x.

If you do not like ncmpcpp, I highly recommend cantata, a graphical MPD front end using the Qt toolkit which, however, does not integrate well with my mostly GTK- and text- based environment (as such, Cantata is not part of my custom desktop session).

Why we also need mpc

The comparatively simpler mpc tool performs the role of a remote control. We use it to assign key chords with which to control mpd even when no client is running. In a similar fashion, mpc provides a simple way of querying the status of the server for the sake of, say, displaying information about the current song on the panel (see the chapter about the top panel).

The MPRIS bridge

By default, mpd does not behave like most up-to-date music players in the GNU/Linux world. Put differently, it cannot be controlled by dedicated media keys, nor interact with specialised tools that might be offered by the desktop environment.

This kind of functionality is part of the MPRIS protocol. To make mpd a good citizen, we have fetched the mpdris2 package as well as a dedicated, console-based program for controlling MPRIS-aware applications: playerctl.

With these in place, the Music Player Daemon (and all other MPRIS-aware media players, like the ever-popular vlc) can be controlled using the keyboard’s dedicated media keys. See man playerctl for more demanding types of interaction. The key chords are defined in my sxhkdrc as explained in the chapter about the basics of my BSPWM.

Peace of mind

MPD is great because while it is powerful and can cater to the needs of the most avid audiophile, it also works seamlessly once you set it up. I prefer it over its alternatives because it is very much laissez faire, to the point you almost forget it is even there.

When you log back in to the custom BSPWM session, mpd will be up and running, waiting for your input in a paused state (or stopped, in case that was the last interaction with it).

You do not need to keep any window open, nor run some resource-hungry web app just for the sake of playing audio from your local collection. Hit the keyboard’s dedicated key for play or type super + down arrow: music will start playing, while you get on with your work (do not forget to see my sxhkdrc for the relevant key chords).

Part of my customisations concerns newsboat, a decent RSS/Atom reader for the console. If you have never heard what an RSS or Atom feed is, it is a data stream that is meant to be read by client programs, known as “readers” or “feed readers”. Whenever the source that publishes the feed makes a new entry (publishes something), the stream is populated with the new content, which the reader can then fetch. This makes it possible to keep track of multiple websites from a single interface. Having all that in the terminal makes things even better.

~/cpdfd $ tree -aF newsboat/
└── .config/
	└── newsboat/
		├── config
		├── queue
		├── themes/
		│   ├── tempus_theme_dark.theme
		│   └── tempus_theme_light.theme
		└── urls -> /path/to/my/symlink # not part of the dotfiles

3 directories, 5 files

All you need to get started is to first put things in place:

~/cpdfd $ stow -v newsboat
LINK: .config/newsboat => ../dotfiles/newsboat/.config/newsboat

Then to actually read some feeds, you must manually create a urls file at ~/.config/newsboat/ with a single feed source per line, like this:

I personally exclude this file from the dotfiles because it might contain sensitive information.

If you want to filter feeds, you can add one or more tags to them, with a space demarcating each entry: "Distro" "Distro Community" "GNU Linux Distro"

Tags are used to aggregate content from multiple sources:

# A catch-all filter for unread items
"query:Unread Articles:unread = \"yes\""

# Some tag-specific filters
"query:GNU plus Linux:tags # \"Distro\""
"query:ARBITRARY NAME OF FILTER:tags # \"Tag\""

Once you launch the program, either from the command line or with the key chord chain super + x ; 4 (see chapter on the basics of BSPWM) you will start seeing news items pop up, grouped by source URL. From there you can use Vi motions or the arrow keys to select the desired item and either read it in place by hitting the Return key (Enter) or open it in the browser by hitting o (firefox-esr is the default and what I use).

The config file is fairly simple, with each setting usually describing what it does:

# General
# -------
show-read-articles no
show-read-feeds no
prepopulate-query-feeds no
feed-sort-order unreadarticlecount
show-keymap-hint yes
swap-title-and-hints no
text-width 72
save-path "~/Documents/archived-articles/rss"
browser /usr/bin/xdg-open %u
confirm-exit yes
display-article-progress yes

For more, see the source for the actual configurations as well as man newsboat.

PRIOR NOTICE: all the scripts referenced herein are discussed in greater detail in the chapter about my local ~/bin.

All the colours you see are part of a project of mine called Tempus themes. These are colour schemes for Vim, terminal emulators and relevant tools. They consist of sixteen hues that correspond to the standard escape sequences for terminal colour definitions, in order from 0 to 15:

0-7: black, red, green, yellow, blue, magenta, cyan, white
8-15: bright {black, red, green, yellow, blue, magenta, cyan, white}

I have designed Tempus with the purpose of filling a perceived void in the theming space: that of accessible, functional, yet still presentable colour schemes. Tempus is designed to work well for as many users as possible, myself included.

In more technical terms, the Tempus themes are compliant at minimum with the Web Content Accessibility Guidelines (WCAG) level AA for colour contrast between foreground and background values. This stands for a relative luminance ratio of 4.5:1. That ratio is but a threshold as some members of the collection conform with the even higher standard of 7:1 (WCAG AAA).

Accessibility is about good design

To dispel any misconceptions, “accessibility” is not only useful for a subset of users. Accessibility is another way of describing thoughtful design. It benefits everyone. Being forced to read light grey on a white background or green text on a red backdrop is a major failure, indicating a lack of forethought and empathy with the user.

For us who spend considerable amounts of time interfacing with a computer, a good contrast ratio is essential to a subconsciously pleasant session (just as with good typography, as discussed in the chapter about fonts). Whether you read, write, code, your eyes will appreciate the improved legibility of text on the screen.

Try this: miscalibrate your monitor and/or your font configurations to make text look blurry and irritating to the eye. Work in that environment for a while to realise how much more painful it is. Eye strain is real, so do yourself a service by prioritising legibility over whimsy.

If you are used to inaccessible colour combinations, you may find Tempus themes a bit too sharp at first. Give it some time: your eyes will adapt to the improved presentation. I know from experience, as I used to work with inaccessible themes. In fact, I had developed an entire collection of them: Prot16. Those were not designed with accessibility and functionality in mind. Some might even “look better” than the Tempus themes, but none works better.

The Tempus themes collection

As of this writing (2019-04-25) the Tempus themes collection consists of the following items (WCAG rating in parentheses):

# Light themes
dawn       (AA)
day        (AA)
fugit      (AA)
past       (AA)
totus      (AAA)

# Dark themes
autumn     (AA)
classic    (AA)
dusk       (AA)
future     (AAA)
night      (AAA)
rift       (AA)
spring     (AA)
summer     (AA)
tempest    (AAA)
warp       (AA)
winter     (AA)

The one you get by default is Tempus Classic, which is a dark theme with warm hues.

Tempus and my dotfiles

With the exception of GTK widget and icon themes, Tempus is applied everywhere colours can be defined. Some notable examples are bspwm, vim, tmux, newsboat, neomutt, dunst, and my lemonbar script called melonpanel. Even GTK-based text editors are covered, such as gedit (GNOME default), pluma (MATE default), and gnome-builder.

A shell script is responsible for changing themes across all those applications. This is the own_script_update_environment_theme. You can run it directly from the terminal by adding a scheme’s name as its first argument. For example, to switch to the light theme day, you would do:

own_script_update_environment_theme day

A more convenient way is to use tempusmenu. This is a dmenu script that interfaces with the aforementioned command. It is bound to a hotkey sequence for your convenience. To invoke tempusmenu, type super + e; t (hold super and press e, then release super and just press t—this is a key chord chain, as discussed in the chapter about the basics of my BSPWM). A menu with all available items will appear. Either type your choice and press enter or use the arrow keys (or CLI/Emacs motions) and press enter.

My dotfiles are designed in such a way that the following changes will occur when performing a theme switch across the entire environment:

  • All running GTK applications, including Flatpaks, will convert to a light or dark variant of their current theme, depending on whether the selected Tempus theme is light or dark (assuming you followed the instructions in the chapter about installing core packages). So if you choose totus, for example, which is dark text on a light background, the GTK themes will also be light, and vice versa. This is courtesy of a running settings daemon. If you have followed the instructions in the chapters about installing Debian 10 ‘buster’ and adding the core packages, this is the mate-settings-daemon.
  • All running terminals will “live reload” their colours using escape sequences. Thanks to my own_script_update_running_terminals. Similarly, all running CLI programs like vim, newsboat, neomutt, less will gracefully adjust to the theme change.
  • My default terminal emulator, mate-terminal, will also write the new colour definitions to its database (also see the chapter about the default terminal).
  • The terminal multiplexer (tmux) will be instructed to reload its configurations in order to parse the new colours.
  • The top panel (melonpanel) will be re-run and display the new colours. Same with the notification daemon (dunst).
  • The wallpaper will change accordingly, if you have defined images at ~/Pictures/theme/{dark,light}.jpg.

All this happens in the blink of an eye. A desktop notification is sent once the process is done, informing you that everything went well and that the new theme is the one you selected. If you care about the specifics (or wish to contribute) you need to examine the script that does the heavy lifting: own_script_update_environment_theme.

In my opinion, this is a very neat feature. Having it bound to a key chord makes it even better. Now if you need any convincing of why you should ever be able to switch themes on the fly, try coding using a dark theme under direct sunlight…

Additional resources

The Tempus themes is a standalone project that happens to be integrated with my dotfiles. There are a number of git repos. The specialised ones are specific to the program they reference:

Also see the Tempus themes Generator: the tool that produces all these ports and the place where you could contribute new templates, code, ideas.

Known issues

The “live reloading” of all running instances of vim is contingent on tmux (see chapter on my Tmux+Vim combo). If you are running the text editor outside of the multiplexer’s control (e.g. a GUI), then the theme switch requires manual intervention. Either exit Vim and enter again or run :source ~/.vimrc. To fix this, I would need a program that can send key chords to running applications: this is possible within tmux, as can be seen in own_script_update_tmux_running_vim, but I have yet to find a standalone utility.

If you open a terminal while the theme switch is underway, it will likely retain its older colour scheme in the database, even if it might catch the step where terminals are live reloaded via escape sequences. In such a case the theme switch needs to be performed again or you must manually run own_script_mate_terminal_setup.

An integral part my dotfiles is the bin directory. It includes various scripts that I have written for use in my custom desktop session. Some of these are essential to various functions and workflows. Others are convenient extras.

~/cpdfd $ tree -aF bin
├── bin/
│   ├── bspwm_focus_mode*
│   ├── clr*
│   ├── dotsmenu*
│   ├── flatpakmenu*
│   ├── gev*
│   ├── melonpanel*
│   ├── nbm*
│   ├── own_script_bspwm_external_rules_command*
│   ├── own_script_bspwm_node_resize*
│   ├── own_script_bspwm_per_host_configs*
│   ├── own_script_current_keyboard_layout*
│   ├── own_script_laptop_dual_monitor*
│   ├── own_script_local_build_tempus_themes*
│   ├── own_script_mate_setup*
│   ├── own_script_mate_terminal_setup*
│   ├── own_script_notify_send_keyboard_layout*
│   ├── own_script_notify_send_mpc_status*
│   ├── own_script_print_colour_table*
│   ├── own_script_run_dmenu_xcolors*
│   ├── own_script_run_passmenu_xcolors*
│   ├── own_script_toggle_compton*
│   ├── own_script_update_environment_theme*
│   ├── own_script_update_running_terminals*
│   ├── own_script_update_tmux_running_vim*
│   ├── passmenu*
│   ├── poweroptionsmenu*
│   ├── ptp*
│   ├── sbg*
│   ├── sbgmenu*
│   ├── stm*
│   ├── stmmenu*
│   ├── tempusmenu*
│   └── tmr*
└── .local/
	└── share/

3 directories, 34 files

Let’s first get out of the way the This file contains the font definition that is used in my various dmenu implementations. The code part:

if [ -n "$(fc-list 'dejavu sans condensed')" ]; then
	my_font_family='DejaVu Sans Condensed'


Now a few words about the scripts:

  • Scripts that have a rather long name are labelled as such for a variety of reasons: (1) their function is ancillary to something else, (2) I might develop a better replacement, (3) avoid naming conflicts, (4) be descriptive about what each item is about.
  • All items have inline documentation, except passmenu which is provided by another source referenced therein.
  • While on the topic of passmenu, this is a dmenu interface for copying to the clipboard a password stored with pass. Such an awesome feature! To put it succinctly, this is what sold me on both the power of dmenu and the idea of a dedicated password manager that works seamlessly with core UNIX utilities.
  • Many of these scripts are assigned to custom key bindings. Better check my sxhkdrc to find out the relevant key chords (as explained in the chapter about the basics of my BSPWM).
  • The items nbm, sbg, and sbgmenu cover various ways of setting the desktop backdrop. I guess it is better explained in this short video: My UNIX-y ways to wallpapers.
  • The stm and stmmenu are tools for handling my task list, in accordance with my own methodology. They are complementary to each other. This short video of mine should be enough to get you started: UNIX way to task management.
  • gev must be run in the terminal to print a table with the status of all git repositories inside the user’s home directory. Better see this video: Demo of my Git’s Eye View.
  • The own_script_run_* commands are wrappers around dmenu_run and passmenu respectively. They are meant to customise the looks to my liking, in order to keep things consistent.
  • If you have Flatpak applications on your system, flatpakmenu will provide a nice interface to launching them. As a bonus, it will display their corresponding icon in a desktop notification (using the notify-send command provided by libnotify-bin, as noted in the chapter about installing core packages).
  • melonpanel is the script that draws the session’s panel. It is what provides content/information to lemonbar for display on the screen. This is discussed at length in the chapter about the top panel.
  • Then there are a few items that are meant to integrate my themes into the various parts of the running session (as explained in the chapter about the Tempus themes): tempusmenu is a front end to selecting the theme you want; own_script_update_environment_theme does the actual work of applying the new theme across all supported programs; running terminals are re-coloured with own_script_update_running_terminals; while the running Vim sessions inside of Tmux are re-styled with the use of own_script_update_tmux_running_vim.
  • own_script_toggle_compton will enable or disable the display compositor. A very useful feature under certain circumstances where running compton is detrimental to the task at hand. For instance, I use this to shut down the compositor when I am screen casting.
  • bspwm_focus_mode will remove all the visual niceties of the running session to maximise screen real estate. Gaps between windows and padding are set to zero. The panel is removed. Borders are configured to overlap between neighbouring windows.
  • ptp is a script that prints a table with the colour palette of the active Tempus theme. The table is “context-aware”, so that it displays information depending on the width of the running terminal.
  • clr calculates the contrast ratio between two colours. You run it by passing two arguments to it, each representing a colour that is written in valid hexadecimal RGB notation.
  • tmr is a simple timer. Run it with a single argument that represents a unit of time in seconds, minutes, hours, such as tmr 10m. Once the time has elapsed, it will print a message informing you of the time it started and end. It will also ring an alarm for a few seconds.

Finally, it is worth pointing out that the quality of these scripts may vary considerably. This is all part of a learning process as I am not a programmer by trade. Despite that, I hope my work here is enough to set you up and running on a custom desktop session centred around the Binary Space Partitioning Window Manager.

That is all from my side. Thank you for reading through the pages of Prot’s Dots for Debian (PDFD). You should now have a solid basis to build upon.

Remember: we customise our session to improve our workflow. Efficiency is all that matters. What gets upvoted in various fora for *NIX enthusiasts does not always work as well (e.g. low-contrast colour schemes, excessive transparency and wanton use of blur effects).

I leave you with some links:

  • The canonical link to PDFD (part of my website).
  • My website, where I publish all sorts of things apart from libre software stuff.
  • Source files for Prot’s Dots For Debian:
    1. PDFD repo.
    2. Site repo.
  • The Code for PDFD contains the latest fixed release of my dotfiles. It was our reference point throughout this book.
  • My dotfiles is where I push regular changes to my custom desktop session. I include them in a “fixed release” when I feel they are ready for broader adoption.
  • Tempus themes. This is just the main repo, which includes information about the entirety of the project, as noted in the chapter about the Tempus themes.