My X11 Desktop in April 2022

seninha.org
2022-04-12

In this post, I document how I set up my X11 desktop (mostly for myself for future reference). This is basically a tour through my ~/.xsession file.

Xenodm

The first interaction with X11 in my OpenBSD system is the display manager, Xenodm(1), which prompts for my name and password for logging in. I've done just the following few changes in /etc/X11/xenodm/Xsetup_0:

#!/bin/sh
# $OpenBSD: Xsetup_0,v 1.8 2020/07/04 13:32:50 matthieu Exp $

xsetroot -bg "#000000" -fg "#121212" -mod 3 3

#xconsole -geometry 480x130-0-0 -daemon -notify -verbose -fn fixed -exitOnFail
xset b off

xkbcomp /etc/X11/xenodm/xkeymap $DISPLAY

#  install package openbsd-backgrounds
#  then uncomment:
#
# if test -x /usr/local/bin/openbsd-wallpaper
# then
# 	/usr/local/bin/openbsd-wallpaper
# fi

# sxpm OpenBSD.xpm &
/etc/X11/xenodm/Xsetup_0

My Xenodm is the standard one, I have not riced it. But if you want to customize Xenodm, check out this, and this.

After logging in as my user, Xenodm(1) runs /etc/X11/xenodm/Xsession as my user (not as root). The main job of this system-wide script is to call the user-specific ~/.xsession script. But it does some other things before so:

From now on, I will document what my ~/.xsession does. To read it at the time of this writing, check it here.

Preparation

My ~/.xsession is a POSIX sh(1) script. The first thing it does is to enable sh's monitor mode (enable job control) on the script. It then traps the EXIT special signal to call the atexit function when the script exits. This function just kills the processes in the same process group as the shell itself and in the process groups of the shell's background jobs.

Here is the snipped of my ~/.xsession that preparates the shell process:

#!/bin/sh

set -m

atexit() {
	kill -TERM -- -$$ $(printf "-%s " $(jobs -p))
}

trap 'atexit' EXIT

Xenocara DPI fix

In OpenBSD 7.0, it may be necessary to fix a problem caused by the update of Xenocara to version 21.1.1. So the following line may be necessary:

xrandr --dpi 96

Variables and Resources

I set my environment variables in ~/.profile. This file is then sourced by ~/.xsession for my X11 programs to have access to those variables.

My X11 programs also need access to the X resources (which are basically environment variables, but for X11 programs). I use xrdb(1) to load the file ~/rules/Xresources, which define them. However, this file uses some environment variables, which have been defined before, but xrdb does not expand environment variables in the file it reads. To solve this, I created an awk script called expenv to expand environment variables in a file. I then pass the output of expenv to xrdb.

# Load environment variables and xresources
. $HOME/.profile
expenv $HOME/rules/Xresources | xrdb -merge -load -

My X resources define the 16 basic terminal colors, the terminal background and foreground colors, and the look and feel of X11 programs (especially those based on Motif and Xaw/Athena). You can check my Xresources file here

The following image shows how my system looks like with those resources set:

The Keyboard

The next command in ~/.xsession uses xkbcomp to set up my customized keyboard layout, which is based on ABNT-2 keyboard layout (which is itself a QWERTY-like layout). In particular, I moved Esc to the first key and reorganized some symbols. The image below shows part of my keyboard layout (there is much more to it, but I'm too lazy to edit the image).

# Load keymap
xkbcomp $RULESDIR/xkeymap $DISPLAY 2>/dev/null

Pointer

The following commands make the mouse pointer invisible after a brief period of time and make Thinkpad's trackpoint work as expected on X11.

# make mouse invisible after a brief period
unclutter &

# thinkpad trackpoint
xinput set-prop "/dev/wsmouse" "WS Pointer Wheel Emulation" 1
xinput set-prop "/dev/wsmouse" "WS Pointer Wheel Emulation Button" 2
xinput set-prop "/dev/wsmouse" "WS Pointer Wheel Emulation Axes" 6 7 4 5
synclient TapButton1=1
synclient TapButton2=2
synclient TapButton3=3
synclient AccelFactor=0
synclient HorizTwoFingerScroll=1

Compositor

I use picom as my X11 compositor. I invoke it with a set of command-line arguments that creates a “blue aura” around the active window, as you can see in the image below.

# compositor
picom -c -l -15 -t -15 \
      --shadow-radius 15 \
      --shadow-green 1.0 \
      --shadow-blue 1.0 \
      --use-ewmh-active-win \
      --shadow-exclude '!focused' &

Desktop Notifications

I use xnotify for displaying notifications on the screen. Xnotify reads notification strings from the standard input and display each notification on a small window on the screen. To be usable, it must read from a named pipe, which other programs should write into. The commands below create the named pipe, invoke xnotify reading from it, and invoke some notification daemons that write into it.

export XNOTIFYFIFO="$HOME/cache/xnotify$DISPLAY.fifo"
coverfile="$HOME/cache/cover.png"
rm -f "$XNOTIFYFIFO"
mkfifo "$XNOTIFYFIFO"
xnotify -ws 10 <"$XNOTIFYFIFO" &

notifycpu >"$XNOTIFYFIFO" &
notifymus >"$XNOTIFYFIFO" &

I currently use only two notifications, implemented as functions in my ~/.xsession: notifycpu, which reads the /var/log/daemon log file and checks for battery and CPU temperature, notifying when the battery gets low and the CPU gets hot; and notifymus which uses mpc to notify when the current song changes. Below is an image of one of such notifications, which appear at the top right corner of my screen.

Xnotify can create notification windows in two different modes:

Dockapps

Shod, the window manager I use, can swallow little windows called dockapps into a panel called dock. The usual dockapps are those used on the WindowMaker window manager, but shod also supports them. The dockapps I use are the following:

# dockapps
paginator -iw -g64x192 -l1x5 &
bubblemon &
wmapm &
wmclock &
WMmp &

The image below shows my dock and the dockapps in it.

The menu system

There are a lot of ways to spawn an application. You can open a terminal and invoke it. Or you can use something like sxhkd to bind a key combination to a command. You can also use dmenu to spawn an application; or use the right-click context menu offered by some window managers, such as Openbox. I used to use all those methods, until I realized that I was specifying the same configuration twice (or three times): once for sxhkd, once for dmenu, and once for the right-click menu. After realizing that, I hacked my right click menu to support all those input methods.

xmenu -ew rules/control &

Xmenu is first of all a menu system. It can present itself as a dockapp which I dock on the dock. I can navigate through the menus and select an entry to be executed by the shell.

Each entry in the menu can be bound to a key press. For example, I bind Alt+T to open a terminal, and Alt+Shift+5 to move the active window to the fifth virtual desktop. I also bind Alt+Space to the run entry, which is explained in the paragraph below. Xmenu grabs those key combinations and runs the same command it would run when selecting those entries in the menu.

One of the entries of xmenu is special. It is the runner. When it is entered (either through the menu or via a keypress) it opens an interactive filter (either dmenu or, in my case, xfilter) and pipes all the entries, one per line, to that filter. Then, I can type in an entry and select it, as you can see in the video below:

(There was a bug on my config... I opened the acme manpage on section 3, and it opened the manpage on section 1.)

The right-click menu.

I use an alternative menu system, with way fewer entries, called πmenu. I use it as a right-click menu for the desktop. It only works on the plain desktop (not on maximized or full-screen windows), although I can invoke it with Super+Button1 click.

pmenu -ex Super-3 <rules/rootmenu &

The Window Manager

Then, at the end of my ~/.xsession, I call shod, my window manager.

shod

The main feature of shod is the possibility to tile, and even tab, windows inside floating containers. The image below shows a floating container with some windows inside it.

This feature was inspired mainly on acme, Plan 9's text editor and general user interface. Acme can also tile windows (but it is limited to text windows only) inside a single main, floating major window.

Conclusion

I need to focus on other things. Ricing is not a normal-person hobby.