Emil Miler

Automatic X11 scaling with autorandr and dwm

This is a follow-up to my previous post about fractional display scaling. I have done more digging and finally created a working setup for scaling my displays automatically with autorandr and dwm.

In the past I have been trying to figure out fractional scaling on X11 and how to get QT and GTK applications to work (somewhat) properly. This post focuses on setting up a proper way of changing scaling factors without restarting X11.

My system looks like this: Laptop with a hidpi display (which I want to scale by 150%) and a docking station with two 1080p monitors (with default scaling). When connecting my laptop to the docking station autorandr reconfigures my displays and sets correct scaling. Same thing happens on disconnect. This is all done without needing to restart the running X11 session – though individual applications need to be restarted. Also note that mixed-dpi is not possible.

X11 Scaling

We can scale applications by setting our desired DPI in .Xresources. Refer to the previous post for more information. Here is a quick conversion table:

Scale:100%125%150%175%200%
DPI:96 (default)120144168192

Though because we want to switch DPI settings, we have to create separate files for both of our environments which we are going to load with autorandr later.

$ cat .Xresources.fhd
Xft.dpi: 96
Xcursor.size: 16
$ cat .Xresources.hidpi
Xft.dpi: 144
Xcursor.size: 32

autorandr

This program can be installed on most distributions via your package manager. Refer to the documentation for more information.

Save the settings for the laptop with autorandr --save laptop, then reconfigure the displays for the docking station and save that again with autorandr --save dock. This creates configuration files for both scenarios in ~/.config/autorandr/.

We also need a script which gets executed after autorandr runs on the event of connect or disconnect. This can be done with hook scripts. In our case we need postswitch which runs after displays are set up.

#!/bin/sh
EXTERNAL="^DP.*-8"
if $(xrandr --display :0.0 --prop | egrep -q "$EXTERNAL connected"); then
	xrdb -merge ~/.Xresources.fhd
else
	xrdb -merge ~/.Xresources.hidpi
fi
~/.fehbg

Don’t forget to make it executable as well by running chmod +x ~/.config/autorandr/postswitch.

The script checks whether a given external display is connected. In my case the display names are DP-2-3-8 and DP-2-3-1-8 due to DP daisy-chain. Check your own display names with xrandr. If any display matching the regular expression is found, the script merges ~/.Xresources.fhd, otherwise it merges the hidpi values.

It also runs my ~/.fehbg script which resets desktop background image, because it gets distorted on display layout change. The script is generated automatically if you use ranger. This can, of course, be left out.

dwm

In order do get correct scaling of dwm, mainly the statusbar, it has to be restarted, ideally without losing our session. One basic way of doing this is executing dwm trough a script with an endless loop, for instance:

while true; do
	dwm >/dev/null 2>&1
done

This would restart dwm right after the process ends. This option, though, will reset all window tags and they all get moved to tag 1.

Better way is to apply restoreafterrestart and restartsig patches, which allow us to restart dwm using kill -HUP and to preserve window tags and layouts.

Optionally you can omit the restartsig patch and save/restore the session manually.

2022-12-18, Emil Miler