Setting Up Archlinux (on a Thinkpad x1 Carbon Gen5)


I go long years between fresh Linux installations, because I go long years between laptops, and entropy does not assume dramatic forms in Linux. I’ve recently made a hardware upgrade, meaning I’ve also had to install a fresh copy of Linux for the first time in years. Although I’d experimented with it before, this is also the first time I’m installing Archlinux on my primary device. Accordingly, the below account is as much intended to help guide my next lap around the track as it is to provide support and solutions to others. There’s a modest number of x1 Arch installation blog posts and videos already out there. This one focuses less on the specific hardware and more on configuring Archlinux for my particular needs, meaning with a tiling window manager, an emphasis on text processing in terminal emulators, and software I use for my work as a humanities scholar.


I’ve always been happy with Debian and Ubuntu: they’re stable and user-friendly, yet there is nothing you can’t customize. Also, official and unofficial Ubuntu support is everywhere. I’ve nevertheless long felt drawn to Arch for a number of reasons. It offers an especially tidy balance between a minimal base and a wide range of well-maintained and up-to-date optional packages. I like its philosophy of having users build their own configuration from a minimal installation, comparatively speaking; I’m attracted to efficient systems with small footprints. I’ve often experimented with extreme minimalist distributions such as Tiny Core Linux in the past, but those are generally not intended for hard disk installation, nor do they offer as full-featured a system as the traditional distributions. Arch is as capable as any distribution, yet it forces its users to do the legwork, which ensures they learn their way around the system. While I’ve always hogged the command line, I’d never bothered setting up networking in the console before, for instance, simply because I’d never had to. Furthermore, the peer support community is strong (though it tends to stop well short of spoonfeeding and can in fact be a little dismissive of people asking questions), the development community is very impressive, and the packages far more up to date than those of the Debian ecosystem. Finally, the heart of my productivity environment is the tiling window manager, and there is no reason to install a distribution that comes preloaded with a desktop manager if you don’t intend to use one. That may be one of the reasons why the tiling community is now strongly concentrated in the world of Arch.


Since the x1 has a cell phone-style microSD slot, I decided to set it up for backup to a permanently installed card. As the card was going to hold all my essential files anyway, I figured I might as well use it for file migration too, which has the benefit that even at the first backup job from the new system, it will only update modified files. However, it would be a major security risk to use an unencrypted microSD card that can be ejected by any passer-by even if the laptop itself is locked to a desk. Accordingly, I set up my backup card for LUKS encryption of the microSD card first, using my old machine:

# cryptsetup -y -v luksFormat /dev/mmcblk0p1
# cryptsetup open /dev/mmcblk0p1 cryptsd
# mkfs.ext4 -O ^has_journal -E stride=2,stripe-width=1024 -b 4096 -L sdbackup /dev/mapper/cryptsd
$ rsync -avhP ~/research /media/sd/
$ rsync -avhP ~/teaching /media/sd/


Preparing the New Machine

My first order of business was to enter the BIOS, check whether it was current (it wasn’t), and change a number of critical settings:

While we’re here, it’s important to note that you should never remove the laptop’s battery without first entering the BIOS utility and selecting “Disable Built-in Battery”!

The next step is to start the device’s pre-installed Windows installation, test that all the hardware works and you’ve been sent the storage, connectivity, and memory options you ordered, update the BIOS using the tool Lenovo provides for this (works straight from Windows, no USB boot required), and write the archiso installation image to a USB drive, which I did on my old machine:

# dd bs=4M if=archlinux.iso of=/dev/sdb && sync


The Arch Wiki is your main lifeline here. Also see blog posts and videos by Kai Hendry and others.

Boot archiso.

The default console font size is 16 (points? pixels?), which is unworkable at WQHD resolution on a 14-inch display. The largest font available is 32, which is still a little small if I’m going to use exemplary posture! But it will do for basic setup and maintenance:

# setfont latarcyrheb-sun32

This can be made persistent by setting

# echo FONT=latarcyrheb-sun32 > /etc/vconsole.conf

I encrypted my full system using LUKS. It’s advisable after completing the process to back up your encrypted partition’s header in case it is ever damaged. You can even store it on the boot partition, as the header contains no compromising information. I’ve done the same for my encrypted SD card as well:

# cryptsetup luksHeaderBackup /dev/nvme0n1p2 --header-backup-file /boot/ssdluksheader.img
# cryptsetup luksHeaderBackup /dev/mmcblk0p1 --header-backup-file /boot/sdluksheader.img

As a newcomer to UEFI/GPT, I was surprised by the apparent absence of a boot flag to mark a partition as bootable. I’m also relieved that one is no longer encouraged to create separate partitions for root and home, which would always lead to one partition running low on space while the other had at least a little to spare. systemd is an entirely new environment to me, but so far I’ve found it to be highly intuitive (except for that Wants/WantedBy business, on which see below).

Kernel Parameters and Boot Entry Options

# cat /boot/loader/entries/arch.conf
title Archlinux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
options rw cryptdevice=UUID=4d07e862-65f8-43ab-9137-7a9749969e64:cryptroot root=/dev/mapper/cryptroot psmouse.synaptics_intertouch=1 acpi_osi="!Windows 2012" acpi_brightness=vendor

(The intel-ucode option should be added only after installing the package by that name.)



While archiso automatically sets up a wired network connection, it will be gone once you boot into your new system. At that point, you’ll want to set up a wired connection first. A straightforward DHCP connection can be opened by running the stock tool dhcpcd (no arguments needed).

The canonical netctl solution, however, is to copy a profile such as /etc/netctl/examples/ethernet-dhcp into the containing directory and change the interface name, then run netctl start [profile-name] as root. You can find the interface name by running ip link. I actually had difficulty getting the wired connection up using netctl initially, so during the setup process I used dhcpcd directly instead.

I don’t think you’re supposed to run dhcpcd alongside netctl yourself in day-to-day use; instead, you are expected to specify dhcpcd as netctl’s default DHCP client. This is done by creating a file /etc/netctl/hooks/dhcp with the following contents:


Alternatively, that line can be contained in individual profile files.

For static setups, copy and modify /etc/netctl/examples/ethernet-static. Make sure to add /24 to the end of your IP address, as this equates to a netmask of and is required for the profile to work! An adapter’s MAC address (to register with your administrator) is found in /sys/class/net/[devicename]/address.

I use a docking station, whose ethernet adapter is assigned a different interface name depending on the port I use for docking. To improve naming predictibility, I have registered the dock’s MAC address in a systemd-networkd link file /etc/systemd/network/ and named the link dock:



To get rid of the confusing naming scheme, I’ve created similar links to rename my internal ethernet adapter eth0, my wireless adapter wlan, and another link to make my workplace dock register as dock as well. The WWAN link wouldn’t take for some reason, but I’m not currently using that adapter, so I’m not bothered.

To have systemd activate profiles when an ethernet cable is connected, don’t enable the interface services for startup at boot but instead install the ifplugd package, ensure static profiles contain the line ExcludeAuto=no, and enable the special systemd unit for the appropriate interface(s):

# systemctl enable netctl-ifplugd@eth0.service
# systemctl enable netctl-ifplugd@dock.service

I’ve also corrected the INTERFACES line in /etc/ifplugd/ifplugd.conf to match my (new) network adapter interface names. NB that dhcpcd can also do the work of ifplugd.

To avoid conflict, it is of critical importance not only that you not use more than one network manager, but indeed not install a second while the first is active, as e.g. installing networkmanager installs it to systemd as well, yielding instant conflicts if you already have netctl-auto enabled.


To set up a wireless connection, you may proceed along the same lines with netctl, only you’ll have to install wpa_supplicant first. Also, if you install the dialog package, you can use the more convenient wifi-menu, which will create the required configuration file for you and store passphrases obfuscated:

# pacman -S wpa_supplicant dialog
# wifi-menu -o

To open an available wireless connection automatically on startup, install wpa_actiond and

# systemctl enable netctl-auto@wlan.service

Setting up Eduroam was trickier. It boils down to the same procedure, but with a section WPAConfigSection that contains the authentication details. Your institution should provide you with the details, though typically they’ll only cover the Gnome interface if that. If you end up puzzling over this, the key is to try all the various combinations other Eduroam users have posted in forums until one works, but with the certificate, credentials, and other details provided by your university’s computing service obviously. This profile worked for me (note the uppercase V in MSCHAPV2, which may just have been key to getting my profile up):

     'proto=RSN WPA'

Once it works, you had best replace the passphrase with a hash. Enter the following command to obtain the hash:

python -c 'import getpass,hashlib; print("md4",getpass.getpass().encode("utf-16le")).hexdigest())'

Now prefix the hash with hash: in the password field. Don’t add quotation marks after the equals sign. Your password is now safe. If you additionally don’t want others to obtain the hash, which would give them access to the Eduroam profile but nothing else, simply change file permissions.


I won’t be using my simcard slot at least until my mobile contract is up for renewal. Some of the relevant information on the Arch wiki seems to be outdated.


I’ve mostly used wired USB tethering rather than a wireless variety, because USB charges rather than drains my phone’s battery, and if I’m on a long train ride I have the cable on me anyway. To set up USB Android tethering using dhcpcd, simply connect the cable, enable USB tethering on your phone, find the interface name by issuing ip link, and enter dhcpcd [interface-name] as root. This process can be automated by way of a udev rule (I haven’t yet bothered).

When I don’t have a cable on me, I can simply use my phone as a wireless hotspot and use wifi-menu to connect to it.


An approximate list of the software I installed from stock repositories (i.e. “extra” and “community” repositories) in the first days and weeks after installation:

# pacman -S sudo intel-ucode wpa_supplicant dialog wpa_actiond ifplugd python-dbus make wget bash-completion exfat-utils ntfs-3g fuse-exfat openssh openconnect gpm git pkg-config cups cups-pdf nss-mdns ntp samba xorg xinit xf86-video-intel gvfs gvim xterm xorg-xfontsel xorg-xlsfonts xbindkeys dconf-editor xsel trayer ranger w3m wireless_tools inotify-tools libnotify notification-daemon evince chromium firefox opera filezilla alsa-plugins pulseaudio pulseaudio-alsa pavucontrol scrot feh sxiv tlp powertop tpacpi-bat ethtools smartmontools rsync cmake gthumb gimp gphoto2 audacious audacity vlc qt4 unzip biber pandoc pandoc-citeproc pandoc-crossref libreoffice ttf-dejavu ttf-junicode ttf-linux-libertine ttf-inconsolata ttf-liberation ttf-ubuntu-font-family s3cmd udiskie zenity x11-ssh-askpass python2-pyaml rpmextract virtualbox linux-headers msmtp msmtp-mta getmail neomutt unrar kid3-qt pepper-flash newsboat fbreader inxi sane sane-frontends

Units that prompt for preferences include the package group texlive-most (choice of packages to install) and virtualbox (choose the version with Linux headers, not the DKMS version for custom kernel headers).

By default, pacman keeps tarballs of all installed versions of installed software in /var/cache/pacman/pkg/. Although this soon adds up, you are advised not to clean your pacman cache as long as you can spare the space, since you’ll need these files if you ever have to downgrade. If you do need to clear the cache, the command is pacman -Sc.

I also installed a number of packages from AUR. The Archlinux User Repository offers packages not in the official repository; many of these are scripts for downloading software from various sources and installing it into the Arch directory structure. I was surprised to see that there is no official Arch package for pdftk, a PDF manipulation tool I use all the time for teaching materials and for job applications, so I’m glad it’s available through AUR. It relies on another AUR package called gcc-gcj-ecj. To get documentation for TeX Live, you need texlive-most-doc from AUR. A number of common typefaces can be installed with the AUR packages ttf-ms-fonts, ttf-vista-fonts. Dropbox is also available from AUR, as is Skype, and Oracle’s implementation of Java. To view premium streaming video content in Chromium, you need a browser plugin available through AUR called chromium-widevine. Finally, I like the dclock app for timekeeping when teaching. When installing from AUR, include the -c flag to remove temporary build files so your system isn’t cluttered e.g. with an extra 5.9GB of TeX Live documentation. The makepkg command cannot be run as root:

$ makepkg -sic

I cover a number of apps built from source below, notably the suckless tools st (simple terminal), dwm (dynamic window manager), dmenu, slstatus, and wmname. Another useful suckless product is slock (simple lock), which I use to lock my screen if I have to step away from my laptop in a classroom or other nonprivate setting.

I also use multimarkdown currently to draft a book that’s heavy on tables (pandoc markdown lacks colspan). It may be git cloned (which is also how I obtain suckless apps) and built from source. Just keep in mind that multimarkdown requires cmake to build. Always keep non-AUR build trees: you’ll need them for clean removal, while you’ll need the suckless source for configuration at least in the case of dwm and st.

To be able to compile Haskell (XMonad, xmobar) in Arch in 2018, I’ve also had to use stack (see under X11 below).

I use a couple binary blobs from time to time: I own a licence for an aging command-line version of ABBYY FineReader, but I never quite managed to transfer the licence from my second-last unit to my last. It’s also been declared at its end of life this month, so I’m giving the latest edition a test run, though I may hold off purchasing for a few more weeks to see whether they aren’t preparing to release a new version.

A second blob I will have to use once my boss sorts out the licensing is oXygen XML Editor, which runs on Java. Technically, the jre9-openjdk package ought to do the trick, but oXygen support recommend installing Oracle’s own; in fact, if you have no JRE installed (or is it regardless?), oXygen’s Linux installation script installs Oracle Java SE of its own accord.

I also use another commercial Java product, an indoor cycling sensor tracker and virtualization suite called WattzAp, though I normally use a dedicated machine for this.

I go over some issues with this software under Java below.

Time Synchronization

To stop your clock from drifting, enable the ntp daemon as follows:

# systemctl enable ntpd

There is no need to pen a service file by hand: a ready-made service file sits in /usr/lib/systemd/system/, to which a symbolic link is created to enable the service.

TeX Live

My choice of LaTeX distribution is TeX Live. Arch divides it up into a range of packages, in turn bundled into the package groups texlive-most and texlive-lang. Installing the former takes care of all my needs; texlive-lang is only required for languages at least as exotic as Greek and Hebrew (which are better installed individually as needed), but mostly Asian and Cyrillic languages. However, the Arch package group is more likely to run into issues that require updates to fix, but texlive-most does without tlmgr, relying instead on a heavily broken tllocalmgr, so updates are often impossible. You are better off not installing TeX Live using the package manager but instead straight from TUG.

I have previously worked with vim-latexsuite to make life easier editing TeX files in VIM. It allows ensuite compiling by adding the following lines to my .vimrc:

let g:tex_flavor='latex'
let g:Tex_CompileRule_pdf = 'xelatex --interaction=nonstopmode --shell-escape $*'

This worked on my old machine. In my fresh Arch installation, for some reason, \ll still started pdflatex rather than xetex though. So I’ve uninstalled vim-latexsuite and replaced it with vimtex. This is a plugin, which requires a VIM plugin manager. I’ve settled on vim-plug, which can be automatically installed by adding these lines to .vimrc (or executing the central command after installing VIM):

if empty(glob('~/.vim/autoload/plug.vim'))
   silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
     autocmd VimEnter * PlugInstall --sync | source $MYVIMRC

It then requires a further section in .vimrc loading plugins like so:

call plug#begin()
Plug 'lervag/vimtex'
call plug#end()

Then when .vimrc is reloaded and the command :PlugInstall is run (which is run automatically on opening VIM given the first code block above), the listed plugins are automatically installed from GitHub.

vimtex uses latexmk. To set it up for xelatex compilation, I’ve created a file ~/.latexmkrc containing the following line:

$pdflatex = 'xelatex --interaction=nonstopmode --shell-escape %O %S';

It is important with vimtex to start VIM with a server; to this end, I have added the line

alias vim='vim --servername VIM'

to ~/.bashrc.

If you’d like to use a different PDF viewer than the one opened by vimtex, you had best set a different default application in ~/.config/mimeapps.list (see File Associations below). Alternatively, you can change this locally for vimtex by adding a line like

let g:vimtex_view_general_viewer = 'evince'

to .vimrc.

A big advantage of latexmk over using the compiler directly is that after the first compile command, it actually autocompiles in the background whenever you save your .tex, so there is no more need to send subsequent compile commands. If your file generates errors though, even if they are just overfull/underfull hbox warnings, these pop up every time you save. I’m sure you can suppress alerts if need be.

I keep my document images in a subdirectory /img below the document location. This has to be indicated in a global variable $TEXINPUTS, which I define in my .bashrc to include all directories below the document root:


Documentation is not included in the texlive-*-packages; it can be obtained from the AUR package texlive-most-doc. Again, you’ll want to set your default PDF viewer in ~/.config/mimeapps.list or you might be surprised with LibreOffice Writer when you use the texdoc command to access a manual.

ABBYY FineReader Engine CLI for Linux

ABBYY provide an installer file. Once the engine is installed, you’ll need to run their licensing service as a daemon, or, perhaps marginally more frugally, write a script that starts their daemon when calling the OCR engine; if the service is not running, the program will fail to run. The service is started as follows:

# /opt/ABBYYOCR11/abbyy-fre11-licensing-service start

That command won’t work straightforwardly in systemd unfortunately, but a member of the ABBYY support team has come up with a working systemd service file.

I have set up an inotifywait monitor that reads for incoming PDF files, then performs OCR as follows:


inotifywait -me create --format '%f' /home/username/scan | while read FILE
    if [[ "$FILE" == *.pdf || "$FILE" == *.PDF ]];
        abbyyocr11 -if /home/username/scan/$FILE --detectImageOrientation --splitDualPages --skipEmptyPages --outputFileFormat PDF --pdfTextExportMode ImageOnText --pdfScenario MaxQuality --pdfResolution 600 --pdfColority ForceToBw -of /home/username/ocr/$FILE


I use DejaVu Sans Mono for terminal windows and Junicode for a fair bit of graphical typesetting, so I was pleased to see these are available as packages through pacman. The same is not true of Andron Scriptor Web and Brill. Arch recommends that fonts only be installed as packages, so they can be managed by pacman. I couldn’t afford the time to learn how to write up a PKGBUILD, so I simply copied the .ttf files into /usr/share/fonts/TTF/ and ran fc-cache as root.

X11, xrandr, and Window Managers

Installing XMonad in the Wake of ghc-Linking-Gate

I’ve long used XMonad. I adopted it because I wanted a lightweight tiling window manager for use across two monitors, and some online chatter suggested XMonad was especially good at multihead setups. XMonad, like pandoc, is written in Haskell, however, which for anyone not accustomed to Haskell development can be a real pain to work with. Because XMonad, like some other minimalistic window managers, needs to be customized in a source file and compiled from source after every tweak.

Haskell and its library landscape are fussy. The latest disaster consists in ghc (the Glasgow Haskell Compiler)’s move from statically linking its packages to dynamic linking, which apparently renders the use of statically linked Haskell libraries in Arch impossible. Consequently, building Haskell code in Arch is ridiculously difficult at the time of writing.

The consensus is that the best way around this train wreck is to install the Haskell Tool Stack (stack; not using pacman but from here) and use it to install everything else you need. This is a particularly helpful walkthrough, but it’s not enough, as the stack install build command returns a number of fails. After digging around bugtracker comment threads like this one for a bit, I managed to overcome this using step 5 of this solution, i.e.

cd ~/.stack/programs/x86_64-linux
rm -rf ghc-tinfo6-nopie-[version-number] # the directory only!
tar xvfJ ghc-tinfo6-nopie-*.tar.xz
cd ghc-[version-number]
./configure --with-hs-cpp-flags='-E -undef -traditional -fPIC -fno-PIE' --prefix=/home/username/.stack/programs/x86_64-linux/ghc-tinfo6-nopie-[version-number] make install

Then change the C compiler flags in ~/.stack/programs/x86_64-linux/ghc-tinfo6-nopie-[version-number]/lib/ghc-[version-number]/settings to

("C compiler flags", "-fno-PIE -fPIC -fno-stack-protector")

Then return to ~/.xmonad (where you have previously git cloned the relevant repositories and initialized stack) and run stack install. Phew!

Now we can resume following Brian Buccola’s instructions, which have one more step to go so we can recompile XMonad. Create an executable file ~/.xmonad/build with the following contents:

# ~/.xmonad/build
exec stack ghc -- \
   --make xmonad.hs \
   -i \
   -ilib \
   -fforce-recomp \
   -main-is main \
   -v0 \
   -o "$1"

Now XMonad and dependencies should work as expected; just add ~/.local/bin to your path and add exec xmonad to the end of your .xinitrc. To update XMonad and dependencies, simply rerun stack install within ~/.xmonad.

To be honest, upgrading XMonad is always a huge pain. Past configurations soon become obsolete, so I frequently have to relearn how to rewrite my xmonad.hs. For XMonad 0.13, I see that I’ll have to figure out how to keep my workspace from intruding on my xmobar (a measure known as avoidStruts). I’ll effectively have to relearn to do up a configuration from scratch on a rainy Saturday.

Installing dwm

Soon after getting stuck with my initial efforts to install XMonad using stack, I decided it might be time to try dwm. I’d always been interested in this window manager, both because it is written in C and thus more useful to learn to work than XMonad and Haskell, and because it is developed by the suckless folks, who believe in small, efficient code bases.

As convoluted as the Haskell infrastructure is, dwm is a breeze in comparison. It’s written in straight C; it can be installed simply by

$ git clone
$ cd dwm
# make clean install
$ cd ..
$ git clone
$ cd dmenu
# make clean install

and adding exec dwm to the end of your .xinitrc (instead of exec xmonad). The window manager can be customized by copying config.def.h to config.h in the source tree, modifying that last file, and recompiling.

On a sidenote: don’t remove the source tree even for a program that offers no customization: you’ll need it if you ever want to remove it cleanly. But you’ll definitely want to keep the dwm directory for future tweaking and recompiling! In fact, you may want to run all the proper git commands to start a branch, i.e.

git branch dwm-custom
git checkout dwm-custom
git add *

and then run git commit whenever you modify your copy of dwm so you keep track of your changes.

The dwm status bar can be customized by way of xsetroot -name; a bash script can be written to obtain the required information and pass this to xsetroot, and this script can then be added to .xinitrc. However, this can get a little unwieldy. I have therefore settled on the slstatus app, which does the legwork in C, offers a range of display monitors preconfigured, and can be extended to your heart’s content.

To indicate what status monitor indicates what resources, I’ve settled on a loosely meaningful combination of younger futhark runes. These are not contained in my monospace font, so dwm relies on Xft to use a fallback font to display them. In my case, it defaults to Junicode, which is fine except stock dwm cannot do TrueType: the runes appear vertically displayed, dropping below the bar, although they look great in VIM. Fortunately, Google’s astonishing Noto font package includes a special runic typeface, and dwm allows for the specification of fallback fonts as follows:

static const char *fonts[] = { "DejaVu Sans Mono:pixelsize=17",
                               "Noto Sans Runic:pixelsize=17" };

Eventually, I’d like to install an updated version of the pango patch that allows TrueType and colour in the status bar.

Scaling on a small 2560x1440 panel requires a little tweaking as well, particularly with multihead setups, which often require monitors to be scaled differently. xrandr accomplishes this. I use the following syntax in my .xinitrc:

EXT=`xrandr --current | sed 's/^\(.*\) connected.*$/\1/p;d' | grep -v ^eDP | head -n 1`
if [ -n "${EXT}" ]; then
   xrandr --output eDP-1 --auto --scale 0.5x0.5 --output "${EXT}" --auto --scale 1x1 --primary --above eDP-1
   xrandr --output eDP-1 --auto --scale 0.5x0.5

For terminals it can be further tweaked in the terminal’s configuration, e.g. in ~/.Xdefaults (or .Xresources) for XTerm or urxvt, or in config.h for st.

dwm versus XMonad

I find a major drawback of dwm to be its lack of layouts. Apart from floating, which is only interesting for dialogs, apps playing media in the background, and heavily windowed programmes such as GIMP, dwm has a stack tiling mode, with the master window typically on the left and all further windows stacked on the right, and monocle mode, with a single window maximized. XMonad has these too but furthermore includes a horizontal (or “vertical” in tmux-speak; I mean one above the other, so split along the horizontal axis) split mode, which is helpful when you want visual contact with two windows without compromising line width. In dwm I can only do that in terminal windows if I use tmux (or modify dwm to meet my needs), but tmux comes with its own complicated keybindings if you want to use any of its other features; it is essentially a separate window manager for terminal windows, in addition to being a multiplexer that allows you to rejoin existing bash sessions locally or remotely. I liked being able to just cycle through layouts in XMonad using a single key command, and also the fact that I could define exactly what layouts were available for each workspace (or “tag”, as they are often called in the world of tiling window managers because you can have several in view at a given time, a feature that I have yet to explore), and in what order I would cycle through them. Have a look at this elaborate example of an XMonad configuration. In dwm, there is a keyboard command for cycling through the most recent two display formats only, which for some reason is tiling and floating by default, whereas I would much sooner use monocle mode than floating mode. Also, switching layouts affects all workspaces of the active monitor rather than just the active display, which further limits the point of having multiple layout options. (Patches are available to change this.) Mod+Tab cycles between the active windows of the last two active workspaces, where I expect it to cycle through all the windows of the workspace currently active. I have no use for this “last visited” philosophy! Finally, XMonad’s default keybindings allow me to access all my workspaces and layouts with my left hand, whereas dwm’s default keybindings require two hands either to switch between windows within a workspace, between monitors, and between layouts. Though it is trivial to rewire the keybindings as such, dwm’s C function focusmon was actually not written to take an absolute monitor as an argument, while the setlayout function conversely was not written for toggling. Although these may be rewritten, this entails substantial changes to the dwm source files, which substantially problematizes any future updates or patches to dwm. XMonad allows greater flexibility from within xmonad.hs, and is thus far more configurable without rewriting the application itself.

Another out-of-the-box XMonad feature that has to be hacked in dwm is restarting the window manager without logging out or losing windows. To achieve this in dwm, simply call the executable from within a while do loop as follows (a separate script called at the end of .xinitrc):

while true; do
   dwm 2> ~/.dwm.log

To emulate XMonad behaviour, the keybinding for exiting can be set to Mod+Q, with Mod+Shift+Q running killall xinit. I find, however, that while all my windows survive, they are all gathered in workspace 1 of the active monitor as soon as dwm is reloaded. There’s also a very simple selfrestart patch that achieves the same effect as the while do loop, but it too loses window positions. In addition, for some reason I find it to be unreliable, so I have reverted to the external-script solution.

Another shortcoming of dwm is that it does not support system trays out of the box (see under Dropbox below).

Furthermore, stock dwm does not allow colours in its status bar. Colours speed up identification of status monitors, because these tend to be full of numbers. A patch is available that allows colours, but like most dwm patches I’ve tried, it fails to apply cleanly (meaning it is out of date, though it claims to be valid for the current version of dwm). I’m frankly not to keen to sort out the conflicts by hand, only to have to do it again once a new version of dwm comes out. Also, once you have applied one patch, no subsequent patch will work without substantial manual damage control. Kai Hendry would argue that this is a good thing, since it makes you think twice whether you really need that extra functionality.

Another notable difference between XMonad and dwm, which I have yet to decide how I feel about, is the fact that dwm multiplies its number of workspaces by the number of active monitors, granting each monitor its own private set of workspaces. I’ve limited my number of workspaces to five, but with two monitors, that means each has its own set of five, and a browser opened on the external display will never show up on the internal display unless I manually push it there with a dedicated keyboard command. XMonad has those key combinations too, but it has only a single count of workspaces by default, so I can call up any one workspace on whichever display is currently focused simply by using the shortkey for that numbered workspace while the monitor in question is active. Admittedly in XMonad this can lead to confused bouts of workspace shifting, since it’s easy to forget on what workspace you have opened a particular window and hence how to return to the last active combination of windows, and you’re likely to swap the currently visible workspaces between the monitors in the process. In stock dwm, on the other hand, there is no fixed key combination for selecting a monitor; there is only cycling between them, so you always need to confirm visually what monitor is focused before deciding whether to reselect, while XMonad allows ensuring the right monitor is focused simply by pressing the fixed, familiar key combination. (Bicycle gearheads will recognize this as analogous to SRAM eTap Red shifting as opposed to traditional mechanical shifting.) The XMonad philosophy is a lot more useful on configurations using more than two screens. Another concrete scenario that seems to speak against dwm is when I am watching fullscreen video content on one screen and another window I want to access on the second screen is open on a different workspace belonging to the monitor currently displaying video: I don’t know of a way to shift that content to the unused monitor without momentarily calling it up on the video display, moving the video offscreen. Similarly, if I disconnect the external display in a hypothetical case where xrandr would not adapt to the new display count, I have just lost access to half my workspaces, even if they have windows still open in them. If xrandr does adapt to a single-screen display when I unplug, on the other hand (as it does), all my extra windows are now packed into the one workspace that happened to be active on the internal display. Worse, if I restart the dwm binary without quitting dwm, all my open windows are gathered in the one workspace that happened to be active! What I do like about the default dwm setup is that its status bar by default moves with the focus to the active monitor, so in the same fullscreen video scenario I can view my status monitors (clock etc.) simply by focusing the unused display using the mouse or keyboard. I remember spending a fair bit of time setting up my xmobar across two monitors and never getting it quite as intended. On dwm, I have manually implemented this patch that keeps the status monitor active across all screens, though that has the downside that I can’t tell which screen is active if I have a fullscreen application on one screen and nothing on the other without using the mouse pointer to activate a workspace.

Finally, on my internal display, dwm floating space does not extend to the menu bar, so I can’t stash my minimized Audacious player there as I would in XMonad. It works on the external (primary) display though. A bug?

Terminal Emulators

After a day of tweaking my setup, I noticed my VIM screen wasn’t being redrawn in XTerm. I later discovered that a sequence in my .vimrc was the culprit. Since part of the troubleshooting process involved trying a different terminal emulator, however, I finally got a chance to test st by suckless at greater length, and once I had it running (which required installing pkg-config prior to compiling), I did not immediately want to switch back to XTerm. Mind you, st has drawbacks, notably its lack of a built-in scrollback function. Though it may be modified to include one, the canonical workaround is to run it with a multiplexer with scrollback functionality, such as tmux:

$ st -e tmux

In dwm, this means setting the default terminal as follows:

static const char *termcmd[ = { "st", "-e", "tmux", NULL };

This also enables me to use tmux effectively as a window manager within dwm just for terminal windows, as it is capable of running, tiling, and tabbing multiple terminal emulators. It’s a whole new environment with a lot of options and keybindings to learn! Its default status bar is a little bright. This, and many other settings, may be changed by creating a configuration file ~/.tmux.conf with something along the lines of

set -g status-style bg=colour24

(see man).

To have the dwm status bar display the tmux window title, add lines like the following to ~/.tmux.conf:

set-option -g set-titles on
set-option -g set-titles-string "#W"

By default, however, the tmux status bar does not show the file currently open in VIM, or even the current working directory, but rather the most recently issued command or just bash. By default, it also indicates time and date, which I have in my dwm status bar, so I’ve removed those fields from tmux as superfluous. In fact, I haven’t yet found a use for tmux’s status-right (i.e. right-hand half of the status bar), so I’ve set it to empty in .tmux.conf for the time being until I think of a better use for it:

set -g status-right ""

I’ve set status-left to display the file currently open in VIM, but I don’t yet have that working quite as intended, as resetting it when closing VIM is a little tricky. Indeed, if I could get the working directory or filename through to my dwm status bar, I wonder whether I’d not rather do away with the tmux status bar entirely. Depends whether I end up using its tabbing/tiling functions I suppose.

I’ve found that stock st doesn’t yet work well with ranger’s image preview feature (see below), so I’ve also installed urxvt, which has a lot going for it in comparison with st, as it allows me to ditch tmux and restores dynamic dwm window titles. Another shortcoming of st is that it doesn’t have a built-in command to clear the screen, so I have to type clear at the terminal prompt instead. Critics will point to urxvt’s larger size and the fact that it reads an external configuration file, which goes against the suckless philosophy. That’s urxvt four, st one. People have managed to merge nearly all these features into st forks, however, and on-the-fly font size changes as well, so I’m currently running this fork of st for the near-perfect marriage between efficient code and necessary features. Please note that to enable the delete key in bash with st, you have to add the following line to `~/.bashrc`:

printf '\033[?1h\033=' >/dev/tty

and still it doesn’t seem to work half the time. Perhaps I’ll go back to running my terminal in vi mode for efficient text manipulation.

I chose the base16-default-dark theme for my st color scheme but set black and white to #000000 and #ffffff for greater contrast, then installed the VIM plugin base16-vim (see under TeX Live above on how to work vim-plug) and set colorscheme base16-default-dark in .vimrc. This particular combination of st and VIM colours unfortunately rendered the “comment” syntax highlighting colour practically invisible, so I additionally changed the “bright black” colour in st to a more usable #888888 grey. Finally, since the st colour scheme made non-sticky, other-writable files in ls difficult to read, I ran dircolors -p > ~/.dircolors and modified the OTHER_WRITABLE variable in the newly generated configuration file to 30;41 (black on ochre red). For this file to be evaluated, add the following line to ~/.bashrc:

eval "$(dircolors ~/.dircolors)";


My trackpad and trackpoint did not initially work in Arch. Adding a kernel parameter solved this. I imagine future kernels will make this unnecessary.

However, somehow Arch did not respect the BIOS disabling of the trackpad. So I added a line

$ xinput --disable 15

to ~/.xinitrc. (The trackpad’s device name can be found in xinput --list).

For the console, running gpm with any settings somehow enabled all pointer devices, and since I don’t want the trackpad active, I chose not to activate the mouse in the console at all rather than fiddle with it any longer. I wonder why the BIOS setting is ignored?

I use xset to tweak key repeater delay and speed in ~/.xinitrc:

xset b 100 0 0 &
xset r rate 220 45 &

For some reason, xset m commands appear not to affect my mouse cursor acceleration, so I’ve switched to using xinput instead:

xinput set-prop 'TPPS/2 IBM TrackPoint' 'libinput Accel Speed' -0.6 &


Also ignored was my BIOS PC speaker beep setting. The beep was gone initially but somehow recurred (coincidentally I imagine) after setting up my mouse input. It’s easy enough to disable to PC speaker altogether in Linux with

# rmmod pcspkr # echo "blacklist pcspkr" > /etc/modprobe.d/nobeep.conf

(reboot required). This doesn’t affect the boot environment, but I bypass the boot menu anyway, going straight to LUKS decryption and the startup sequence.

The onboard soundcard works out of the box (though not the volume/mute keys). I additionally use a USB soundcard, however. It offers somewhat better quality (24 bit/48000 Khz), and for some reason it won’t play as long as pulseaudio is set to 16/44100. It was the same in Ubuntu on my x61. I have to change at least the sample rate up to 48000 in /etc/pulse/daemon.conf for it to work. Don’t forget to uncomment the lines in question! Mine now look as follows:

default-sample-format = s24le default-sample-rate = 48000 alternate-sample-rate = 44100

After changing the values, restart pulseaudio:

$ pulseaudio -k
$ pulseaudio --start

For Skype to work with PulseAudio, you may have to install the pulseaudio-alsa package in addition to pulseaudio so ALSA sound is properly redirected.

Power Management

Having installed tlp, powertop, and tpacpi-bat, I should be able to achieve considerable power savings. My main tweak to /etc/defaults/tlp [edit 2020: now /etc/tlp.conf] so far has been to activate the battery charging thresholds, as the leading opinion of the day is that the charge should be maintained around 70~80 percent. This can only be done on supported hardware; running # tlp-stat (see under “Recommendations” at the very bottom) and # tlp-stat -b (see under “ThinkPad Battery Features”) will give you some information. Note that tpacpi-bat is equivalent with acpi-call.

Don’t forget to enable and mask the appropriate services so tlp starts at boot and conflicts are avoided:

# systemctl enable tlp.service
# systemctl enable tlp-sleep.service
# systemctl mask systemd-rfkill.service
# systemctl mask systemd-rfkill.socket

To effect a full charge when leaving your desk for a longer stint:

# tlp fullcharge BAT0

The system returns to configured values on next boot or when issuing

# tlp setcharge BAT0


Keyboard backlighting works out of the box using Fn + Spacebar (cycles through three modes). I don’t much care for the fade-in effect, which is rather too form over function for my tastes.

The easiest way to control volume and brightness by keyboard, and to set up additional keybindings, is to install xbindkeys and create a file ~/.xbindkeysrc rather than finicking with xmonad.hs or dwm’s config.h; xbindkeys can be used in all your window managers, so you don’t have to duplicate functionality when you swap. Because I have multiple sound adapters but want only one status monitor and set of keybindings, I’ve decided to manage all three sinks in sync:

"pactl set-sink-volume 0 +5000 && pactl set-sink-volume 1 +5000 && pactl set-sink-volume 2 +5000"
"pactl set-sink-volume 0 -5000 && pactl set-sink-volume 1 -5000 && pactl set-sink-volume 2 -5000"
"pactl set-sink-mute 0 toggle && pactl set-sink-mute 1 toggle && pactl set-sink-mute 2 toggle"

I’ve set up bindings for display brightness control as well:


The brightness commands are scripts I wrote along the following lines:


CURBRIGHTNESS=`cat /sys/class/backlight/intel_backlight/brightness`
MAXBRIGHTNESS=`cat /sys/class/backlight/intel_backlight/max_brightness`
TRIM=`echo $PERCENTAGE | grep -Po '(?<=~)[0-9]*'`
echo "$NEWBRIGHTNESS" > /sys/class/backlight/intel_backlight/brightness
xsetroot -name "brightness ${TRIM%.*}%"

and its opposite. The xsetroot command results in an onscreen display for a maximum of a second, until the next update of my slstatus status monitors is issued to take its place. Add xbindkeys to ~/.xinitrc for persistence.

Displaying how you cycle through keyboard layouts has always been tricky without use of a desktop manager. In my setup, I create a config file ~/.kblayout with the initial value “en” (established in .xinitrc), which is read out into my status bar (using slstatus, on which see below). I have set up a keybinding for right-hand shift in my window manager that executes a simple bash script cycling through the values en, de, is, and se, outputs the new value to setxkbmap, and reports it back to .kblayout as well. Naturally, curses ensue every time someone other than myself attempts to use my computer.

For the display brightness settings, I did end up passing the parameters acpi_osi="!Windows 2012" and acpi_brightness=vendor to the kernel. I also had to sort out permissions. I gave normal users access to the brightness settings by adding a udev rule at /etc/udev/rules.d/backlight.rules:

ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", RUN+="/bin/chgrp video /sys/class/backlight/intel_backlight/brightness"
ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", RUN+="/bin/chmod g+w /sys/class/backlight/intel_backlight/brightness"

To keep my hands on the home row, I have remapped Caps Lock to Escape. Initially, I used xmodmap for this, calling the following ~/.Xmodmap:

clear Lock
keycode 0x42 = Escape

I initially called it directly in .xinitrc as xmodmap ~/.Xmodmap. I soon found, however, that xmodmap frequently crashes, locking me out of an Escape button and into VIM’s insert mode until I restart xmodmap in a different window. I then had .xinitrc call a script containing a while do loop to ensure xmodmap is launched again within two seconds of it crashing. That worked better, but it ran the risk of me accidentally activating Caps Lock in the two seconds when xmodmap was down. I have now moved the remapping to /etc/X11/xorg.conf.d/, where I have created a file 10-keymappings.conf reading as follows:

Section "InputClass"
     Identifier "keyboard-layout"
     MatchIsKeyboard "on"
     Option "XkbOptions" "escape:none,caps:escape"

I have not run into any issues since and accordingly see no need to look for a udev solution.

Having freed up the escape key, I have bound it to chromium (or the intermediate script that launches it, see under Browser below) in .xbindkeyrc, alongside Shift + Escape to run chromium using a proxy server by way of an intermediate script:

     Shift + Escape


Clipboard Registers

Between VIM, GNU/Linux, and X, you have three different clipboard registers available to you:

You can always paste from the * and + registers in VIM using the middle mouse button (or both mouse buttons if you have only two) or CTRL+SHIFT+V in insert mode, respectively. But you cannot by default paste external content in normal mode, or paste VIM yank content into external programs. In fact, the vim package in Arch comes without clipboard support. (You can check your copy by way of vim --version | grep clipboard; look for a plus sign). That’s why instead of vim, I have installed the package gvim, which is just as up to date but includes clipboard support (as well as a graphical counterpart of the editor, which I don’t use). Now you can bind the unnamed register to the + register by adding a line set clipboard=unnamedplus to ~/.vimrc, so you can copy and paste between X and VIM in both directions.

To enrich my X clipboard experience, I have also installed a simple pair of scripts called clipmenu, which require xsel and recommend clipnotify. The idea is you run clipmenud as a daemon, and then whenever you trigger clipmenu using your choice of keybinding, it offers you a dropdown list of recent clipboard content.

Special Characters

I use a lot of special characters for work. Some of the obvious ones are found on the Icelandic keyboard layout, so I have that set up as one of my layouts; a few more are on the Swedish and German layouts I also have installed using setxkbmap. Beyond that, I use VIM mapping for insert mode (imap). Such mappings consist of straightforward commands taking two arguments, the first being the key combination while the second contains the desired output:

imap \7 ⁊
imap \. ·
imap \O Ǫ
imap \o ǫ
imap \G Ȝ
imap \g ȝ
imap \W Ƿ
imap \w ƿ
imap =A Ā
imap =a ā " etc.

Reestablishing ssh Credentials

After installing the openssh package, simply generate a new key pair as per Arch wiki instructions. Then run ssh-copy-id [user@]hostname to copy the public key to the remote server. To manage multiple key pairs (for multiple hosts), create a file ~/.ssh/config with entries like the following before running ssh-copy-id:

     IdentitiesOnly yes
     IdentityFile ~/.ssh/rsa_id_server1

To connect to servers allowing campus connections only, establish a VPN connection using openconnect (run as root) before establishing your off-campus ssh connection.

File Management

I’ve only just discovered ranger, which has huge potential to improve my file management, which I’ve previously mostly just carried out from the command line. ranger offers the perfect combination of keyboard navigation and filetype assocation, so it previews and opens anything from text-based documents to images and PDFs, but is itself just as text-based as the terminal itself. Indeed, PDFs are by default previewed in text mode according to their text layer, though I’m sure this can be modified. Images can be previewed, too; this requires that w3m be installed and ~/.config/ranger/rc.conf be generated (ranger --copy-config=all) and its option preview_images set to true. At the time of writing, there is a known issue using this option with st that causes the preview to disappear within a second or so. This is one of three arguments in favour of urxvt. The issue is absent from Luke Smith’s fork, though.

By default, directories in GTK’s file-chooser are sorted mixed in with regular files. For some reason, entering

gsettings set org.gtk.Settings.FileChooser sort-directories-first true

does nothing for me (check with gsettings get etc.), but installing dconf-editor and modifying the same key’s value there does the trick with immediate effect.


To take screenshots, I’ve installed scrot and added the following lines to my ~/.xbindkeysrc:

"date +%Y%m%d_%H%M%S | while read TIME; do scrot ~/Pictures/Screenshot_${TIME}.png; done"

Dropbox and Desktop Notifications

Dropbox can be installed from AUR. The daemon can be set up to run at boot or login, but I’ve opted simply to start it from my .xinitrc.

One thing to note about Dropbox in dwm is that dwm does not by default play nice with a system tray such as trayer. Suckless provide a patch for this, but it’s a lengthy one to problem-solve. For the most part, Dropbox works fine without a system tray, but the AUR version doesn’t appear to have implemented the command-line options found in the official package for other distributions. As such, on the rare occasions when I need to access the settings, I keep a copy of trayer on hand: it does show, its positioning and behaviour are just unhelpful, so I don’t open it until I need it. As for notifications, these appear of their own accord once you install a handful of tools (inotify-tools, libnotify, and notification-daemon). The notifications aren’t exactly pretty by default; this could probably be improved upon either by configuring notification-daemon itself or by using notify-osd instead.

Backup Solutions

Locally, as mentioned above, I rsync to a microSDXC card. Cloud backup is the more critical solution; for this I use DreamObjects, which uses the ubiquitous Amazon S3 system. This requires the s3cmd package.

Local Backup: microSDXC

To automatically mount my microSDXC card for backup purposes, I had to generate a keyfile with it and store it in crypttab, then add an entry to fstab, as is explained here. The device is now automatically mounted on startup. After first mounting it, I synced my data to my new homedir:

$ rsync -avhP /media/sd/ /home/username/

I then had to set up rsync with a scheduling service for backup. To this end, I’ve set up a file in ~/scripts/ containing rules like the following:

$ rsync -avhP /home/username/research /media/sd/
$ rsync -v /home/username/\.* /media/sd/

(That last one covers my dotfiles.) I was going to add an entry to crontab next, but in the world of systemd it turns out that is no longer necessary. The alternative is a little more laborious, but letting systemd handle scheduling is more efficient than running an additional daemon.

As this blog post explains, the systemd method requires the creation of two files: /etc/systemd/system/jobname.service to contain the command to be executed, and /etc/systemd/system/jobname.timer for scheduling. The latter’s [Install] section with its WantedBy parameter is almost everywhere explained as a weak dependency configuration, which is a little misleading, as this implies they are optional. They are in fact mandatory, as these indicate when the timer service is triggered. WantedBy in this context means “in parallel with” rather than “prior to”; that’s why it is described as a weak dependency. As such, I’ve chosen to use a pretty random existing dependency rather than spawn a new one. So far I’ve found this to be the trickiest part of systemd I’ve had to grapple with, but I found this explanation to be more helpful than most. My /etc/systemd/system/sdbackup.service:



And my /etc/systemd/system/sdbackup.timer:

Description=Executes sdbackup.service hourly at ten to the hour with persistence



Activate and enable:

# systemctl start sdbackup.timer
# systemctl enable sdbackup.timer

Test that the timer has been scheduled:

$ systemctl list-timers

My bash script tests whether the backup drive is mounted (using mount and grep in a conditional clause) before issuing my battery of rsync commands.

Remote Backup: S3

To (re)configure s3cmd, run s3cmd --configure and follow the prompts. For some reason the prompt tells you not to change your endpoint URL from the default, but you clearly should unless your storage is directly with Amazon.

I have created a backup script resembling the one I wrote for local backups to microSD card, but using the s3cmd command rather than rsync for synchronization. I have enabled a systemd service along the same lines as well, calling a script with lines like the following:

s3cmd sync /home/username/research s3://[bucketname]/ --delete-removed -v

I am running the script as a user rather than root because it exits when it cannot find ~/.s3cfg, and this way I can call it manually as user as well. To do this, add a line User=[username] (and/or Group=[groupname]) to your .service file under [Service].


Ever since I switched to chromium/google-chrome as my primary browser on my previous machine, I’ve had this “Chromium/Chrome didn’t shut down correctly” popup at pretty well every first concurrent session. Remarkably, there doesn’t seem to be a straightforward switch for turning this off, although there appears to have been one in the past. I’ve settled on a solution that manipulates the brower’s shutdown logs before starting up:


sed -i 's/Crashed/None/' ~/.config/chromium/Default/Preferences

I then modified my xbindkeysrc to launch the intermediate script rather than chromium itself. Works.

Video Issues

Before I had installed Intel video drivers, I experienced a number of issues related to video and video acceleration:

Nearly all these issues can be solved simply by installing xf86-intel-video (for my Intel HD 620 video card). The last two issues on my list are specific to chromium but rooted in issues with hardware acceleration, so an alternative way of addressing them is to disable hardware acceleration locally in chrome://settings. (chrome://gpu also listed a range of warnings about features not supported on Linux until I enabled the setting “Override software rendering” under chrome://flags.) Installing the Intel drivers has gone some way to solving my docked suspending to RAM issue as well: both displays now come back online some of the time when the system wakes. Note that some of the output names change when you install xf86-intel-video, so if you already have an xrandr line in your .xinitrc you may have to update it after installing the drivers. I’ve also created a file /etc/X11/xorg.conf.d/20-intel.conf containing the following:

Section "Device"
   Identifier "Intel Graphics"
   Driver "intel"
   Option "AccelMethod" "sna"

I could not tell a difference in performance, except when I tried adding the line Option "NoAccel" "True", which made xrandr misinterpret display sizes somehow.

With the Intel drivers installed, xrandr even reestablishes the external display automatically on redocking, but when the dock’s VGA port is used, or a VGA monitor is dongled from the dock’s HDMI port, the monitor remains in standby mode until I exit X and redock while on the terminal. Redocking works using the laptop’s own HDMI port though, even using a VGA dongle, and I don’t need to issue an xrandr command for the second display to come back online.

If using vlc, you’ll want to install qt4 as well or you will have no on-screen control interface. Alternatively, an AUR package provides vlc with qt5, which don’t normally work together (yet).

Dock and Hotplugging

The Thinkpad Thunderbolt 3 dock used to require a driver from AUR for the ethernet port to work, but I believe this is no longer necessary with current kernels. Do note the BIOS settings listed at the top of this post.

Hotplugging the dock works except for VGA monitors attached by way of the dock while in X (see under Video Issues above). Also, my ifplugd systemd service fails to bring back my ethernet connection some of the time, and resuming from RAM while docked does not work while in X.

File Associations and Default Applications

Bash autocompletion does not discern file types until you install bash-completion.

Default applications are managed by a number of different services. For some basic apps, mostly on the console, you can set environment variables in ~/.bashrc:

export EDITOR="vim"
export BROWSER="chromium"

For other, desktop filetypes, edit ~/.config/mimeapps.list, adding lines like the following:


Your changes to the latter file will have immediate effect. For the former, enter source ~/.bashrc or open a new terminal window for changes to take effect.

File Metadata

While we’re on the subject of evince, I should mention that it will only remember page and zoom if gvfs is installed.


You’ll want the cups package for printing, samba for access to network printers using the Samba protocol, nns-mdns for Avahi hostname resolution, and cups-pdf for printing to PDF. Start and enable the CUPS daemon:

# systemctl start org.cups.cupsd.service
# systemctl enable org.cups.cupsd.service

Avahi offers “zero-configuration” network printing. You’ll just have to (start and) enable the daemon using systemd:

# systemctl start avahi-daemon.service
# systemctl enable avahi-daemon.service

Now to configure a new printer, locate its address using lpinfo -v and find the driver using lpinfo -m. If CUPS doesn’t list your model among its drivers, then you’ll need to obtain a separate driver. Often you can find these in AUR. In my case, I use a Canon imageRUNNER 1133iF at work and thus need a special driver for Canon’s proprietary UFRII protocol, or else one of the other protocols supported by the printer. I eventually got it to use with a PCL driver (not with UFRII) by a combination of two methods, manual and AUR:

    Installing, first, cndrvcups-common-lb, then cndrvcups-lb from AUR. The second wouldn’t work until I enabled the multilib repository in /etc/pacman.conf, since it uses a 32-bit library.
  1. cndrvcups-lb failed to build because I had already done some manual work, so it found files already in place. I had obtained Canon’s UFRII Linux driver package here and unpacked the .rpm file using, then copied the contents of the /usr/ directory into my own. Because the archive contained a directory usr/lib64, which on my own system is a symlink to /usr/lib, I then still had to copy the contents of that directory into /usr/lib/ manually. Check lpinfo -m again; then add the queue like so:
# lpadmin -p Canon_imageRUNNER_1133 -L “HiWi-Raum Mediävistik” -E -v dnssd://Canon%20imageRUNNER1133%20series._pdl-datastream._tcp.local/ -m CNCUPSIR1133ZK.ppd

The first two arguments are your own descriptions of the printer and its location; the latter is optional. -E sets the printer to enabled and accepting print jobs.

If you experience issues with your printer, you can monitor it using the commands lpstat -p (list installed printers), lpstat -o (list queued print jobs), and cancel -a [printer_name] (cancel all queued jobs for the specified printer).

Since I couldn’t get the UFRII driver to work, I downloaded Canon’s CQue TGZ driver package as well and gunzipped all files containing *1133* into /usr/share/cups/model/, trying the various protocols one by one. It was the PCL driver that did the job eventually. Note that when I tried the PCL driver in an earlier attempt, the printer spouted gibberish, perhaps because library files were missing which one or other of the AUR packages or their dependencies supplied.

LibreOffice Window Selection Flicker Issue

LibreOffice suffers from an awful flickering issue when using dialog windows in XMonad, effectively locking your system. It doesn’t appear to occur in dwm, although I haven’t spent enough time in LibreOffice lately to make sure. For reference, the XMonad issue is addressed here.


Standalone window managers typically don’t support reparenting, while Java expects it by default. This results in blank “grey blob” windows. Java runtime environments allow for reparenting to be disabled by one of two means. It can be a binary set through an environment variable; in these cases, adding the following line to .xinitrc suffices:


This did not do the trick for my dwm + OpenJDK 9 setup. OpenJDK apparently identifies the window manager and checks against a list of its own whether it supports reparenting. This means that lesser-known window managers, including dwm, are incorrectly identified. For these situations, suckless offer the wmname tool, which allows the user to enter the window manager description string used by Java. Adding wmname LG3D to .xinitrc sets it to impersonate a nonreparenting window manager the JRE is familiar with (Sun’s Looking Glass 3D), which leads it to disable reparenting. (XMonad allows for this string to be set within xmonad.hs in the startupHook with setWMName "LG3D".)

WattzAp requires some further tweaking. It depends on a USB ANT+ device that is automatically recognized in Linux but not with write permissions. This means I’ve had to add a udev rule to set persistent write permissions. After obtaining the device ID with lsusb, I entered the following line into /etc/udev/rules.d/45-persistent-usb.rules:


On Arch with OpenJDK, WattzAp would now start the debug panel but nothing else, throwing an error:

Exception in thread "AWT-EventQueue-0" java.lang.ExceptionInInitializerError

Apparently, WattzAp uses functions not compatible with OpenJDK; I had to uninstall the latter and install Oracle’s JRE from AUR instead. In fact, though, installing the AUR package resulted in the presence of both on my system, with a script archlinux-java serving to select the default between the two. Thus I had to set

# archlinux-java set java-9-jre/jre

to set the Oracle JRE as my standard runtime environment. Unfortunately, WattzAp still failed to complete initialization, though it manages one more initialization step than OpenJDK before failing.


Initially, I had plans to keep a copy of Windows 10 in VirtualBox. I use Windows too rarely to waste a partition and a boot menu delay on it, but I have thus far been forced to use MS Word when finalizing copy for a book or collaborative project because LibreOffice failed to play nice with Microsoft’s implementation of the “Track Changes” feature. When I looked the other day, this seemed much improved in the current version; I’ll have to do some more testing to see whether it renders a purchase of Windows unnecessary. For the time being, I fire up an office machine whenever finalizing copy.

The Windows licensing scheme has much changed since I last used it. When Windows 10 was first launched, there was the free upgrade, but I couldn’t find a licence purchase option anywhere (cf. here); Microsoft instead encouraged would-be users to buy whitelisted devices with Windows already on them. Once the trial phase ended, licences became available for purchase. It is also still possible to download a full ISO image before purchasing a licence key today, though it takes a bit of googling foo to find it. At the time of writing, it’s at This means that at least I can spin it up to see whether it works before splashing on a licence.

When installing the virtualbox package, always first make sure pacman is up to date, or it may look for superseded package versions. Blink once and your Arch is out of date! Also install linux-headers whenever installing virtualbox.

During installation of Windows to a virtual disk, everything looked fine. I did little testing beyond that, but what results came in were impressive though slightly wobbly: the Windows interface was fast and responsive almost like a native install, but for some reason the two times I fired up the configuration panel (I mean “Settings”), I couldn’t select any submenus for the first twenty-odd seconds. A capture malfunction on Oracle’s part? No idea. I never did reactivate my Office licence to see how it fared.

Of course, with the advent of secure boot and all that, my motherboard knows it shipped with an OEM copy of Windows 10 Professional before I wiped the drive, and it would have been nice (also, fair) if the licence had been acknowledged in my virtual installation of Windows 10. A guest operating system does not, however, directly access the hardware, so Windows won’t see it as the machine that was sold with a Windows licence. Thus to license Window within Linux, one has to purchase a fresh licence on top of the OEM purchase included with most devices. I’ll do it if I really need it, but my current situation doesn’t necessitate it. If I occasionally use my office machine, that saves me a personal subscription to MS Office, too.

It seems by now that a virtual installation of Windows would be overkill for my purposes anyway, as the latest version of Crossover (the commercial implementation of wine) apparently runs MS Office 2016 flawlessly, though the free implementation doesn’t yet. Also, the latest version of LibreOffice appears to do a much better job of handling Microsoft’s implementation of Track Changes, so here’s hoping I won’t have to MS Office at all going forward; though I still have my doubts concerning one or two other features (what’s with footnote formatting?).

Automounting and udev Rules

I’m finally beginning to grow tired of manual mounting; I’m ready to automate the process for trusted UUIDs. udiskie is a udisks helper that I thought would enable me to do that, but either it lacks the configuration options to ignore unknown UUIDs or my YAML skills are lacking.

Depending on your udiskie configuration, you may need to install a few other packages, such as a password prompter (x11-ssh-askpass), notifier (zenity), and a PyYAML parser (python2-pyaml) to read the configuration file. That file goes into /.config/udiskie/config.yaml; an example configuration is provided in the man page. I was a little surprised to see that setting the option notify to false was not sufficient to disable mount notifications; I additionally had to set timeout to false. You can set a filter for known UUIDs, for instance to ignore them:

- id_uuid: ae352b76-6bd3-4f25-894b-0c486ed4084a
   ignore: true

Thus one would think that the option could be set to automount: true, thereby only mounting trusted devices. However, when the global option automount is set to false, udiskie doesn’t override it for those individual devices that have it set to true. This seems to me a shortcoming in the app rather than an error on my part, but I’d like to hear otherwise. Guess I’m automounting untrusted devices for now?

udiskie mounts to /run/media/[username]/[drive-label]; this cannot be configured from within udiskie. A udev rule is required to achieve this, or else a symlink from /run/media/[username] to the desired location (/mnt or /media). I chose the udev rule:

ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{UDISKS_FILESYSTEM_SHARED}="1"

saved under /etc/udev/rules.d/99-udisks2.rules. To clean mountpoints at boot, create a file /etc/tmpfiles.d/media.conf with the content

D /media 0755 root root 0 -

To start udiskie with X, add it to your ~/.xinitrc.

For convenient unmounting, I have modified this script to allow lowercase alphabetical characters in the mount point (UUID).


See Arch wiki: with an Intel processor, it is important to install intel-ucode and load it in your bootloader for security updates.


I’ve set up command-line email mostly so my scripts can warn me by email if something is wrong. I’ve settled on msmtp for outgoing mail, and msmtp-mta to make this app a sendmail alias. Account information is stored in ~/.msmtprc (see here for password encryption), and then email can be sent like so:

$ echo "email body" | msmtp -a default

Or, alternatively,

$ echo "Subject: subject line" | msmtp -a default

Having both a subject and a body is a little trickier with msmtp:

$ printf "From:\nTo:\nSubject: Subject line\n\nMessage body" | msmtp -a default

It’s easier to use mailx, which will work if you’ve installed msmtp-mta, since mailx looks for sendmail:

$ echo "Message body" | mailx -s "Subject"

For incoming mail, I have tried fetchmail and getmail, but I won’t be using either. getmail doesn’t seem to have a count function, while fetchmail can’t not mark a fetched message as read. So instead, I’ve taken one of the many Python 2 scripts that are floating around the web for counting unread messages in Gmail, added a few parentheses to convert it to Python 3, and arranged for the desired monitor output to be written to a file. I’ve set up a systemd service and timer to run it once per minute, and I have slstatus read out the monitor file into a status monitor.

I’ve also set up NeoMutt for terminal IMAP email in case that ends up working for me.

System Hygiene

It’s happened in the past that my remote backup solution failed and it took weeks for me to clue in, much less do anything about it. Also, I don’t like my ~/Downloads folder cluttering up. Finally, with Arch it’s risky to go too long between system upgrades. So I’ve added this information into my shutdown script:

  1. It runs systemctl list-units --state=failed | awk 'NR==1{print $1}' to count the number of failed systemd services and throws a warning if it exceeds 0, else gives a thumbs up;
  2. It prints the contents of ~/Downloads if non-empty and conducts a line count on the result;
  3. It prints the number of days since my last pacman update if greater than six (comparing today’s date to the most recent upgraded timestamp from /var/logs/pacman.log);
  4. If one or both of tests 2 and 3 return positive, it prompts for the appropriate combination of clearing out ~/Downloads, running sudo pacman -Syu, and doing nothing before shutting down. If all tests return negative, the system shuts down with no prompt or delay.

Since there’s a new kernel out every week or so, some Arch users disable kernel upgrades in /etc/pacman.conf to decrease the odds of things breaking in the middle of their workaday lives. I’m including kernel upgrades in my regular updates for the time being; if something breaks, I’ll just have to free up an hour to downgrade the kernel.

Unresolved Issues

posted by paul on 13 feb mmxviii at 20:00 EST
blog comments powered by Disqus