ENOSUCHBLOG

Programming, philosophy, pedaling.


A few HiDPI tricks for Linux

Dec 24, 2020     Tags: workflow    

This post is at least a year old.

Background

I recently switched my home office to a 2-by-4K HiDPI setup, like so:

A picture of my home office.

As part of that switch, I needed to configure parts of my Linux environment (which was originally stock Ubuntu, but is now i3 with a heavily customized userspace) to function correctly on HiDPI displays.

This post will document most of the changes I applied. Hopefully others will find it useful for their own HiDPI setups.

90% of the way: X11 resources

As it turns out, there’s a (nearly) one-stop location for configuring the default DPI for X11 applications: the Xft.dpi setting.

There are lots of ways to configure X11, but I personally use an ~/.Xresources file:

1
2
3
Xft.dpi: 163
# not used directly; more on this later
janus.fractionalDpi: 1.63

Where 163 and 1.63 are my DPI and its fractional form, respectively.

On my system, ~/.Xresources gets loaded into the X resource database automatically by some magic that I never configured. However, if yours doesn’t (or you use a different resource file), you can always tell i3 (or your WM of choice) to load it explicitly with xrdb.

For example, in ~/.config/i3/config:

1
exec --no-startup-id xrdb ~/.Xresources

With just this, about 90% of my applications (including GTK based ones, like Firefox) scaled correctly and were usable without any font or custom scaling changes. Not bad for a single line!

Per-application fixes

Spotify

Spotify’s Linux application is a CEF shell. For reasons that are unclear to me, it doesn’t respect Xft.dpi while normal Chromium (via snap or apt) does.

To get it to scale correctly, I needed to pass --force-device-scale-factor=1.63 to it:

1
spotify --force-device-scale-factor=1.63

At this point, it became clear to me that the fractional form of my DPI would be nice to set in as few places as possible, to avoid duplication. Hence the janus.fractionalDpi1 above, and this little spotify wrapper:

1
2
3
4
5
6
# see the actual script linked above for some program-finding stupidity
real_spotify=/snap/bin/spotify

# grab the correct fractional DPI from the X resource DB
dpi=$(xrdb -query | grep "$(hostname).fractionalDpi" | cut -f2)
"${real_spotify}" --force-device-scale-factor="${dpi}" "${@}"

Sublime Text

I use Sublime Text 3 as my primary editor. As far as I can tell it doesn’t use either GTK or Qt (or any other open-source GUI framework), which is probably why it doesn’t respect Xft.dpi.

To get Sublime Text to scale correctly, I had to set ui_scale to the appropriate fractional DPI in my user preferences (~/.config/sublime-text-3/Preferences.sublime-settings):

1
2
3
{
  "ui_scale": 1.63,
}

Some lingering pain points:

Open Broadcaster Software (OBS)

I haven’t used it recently, but I used to use OBS to stream myself working on open source projects.

When I switched monitors, I noticed that the embedded preview window for my scenes had stopped working. OBS itself was still fully functional and the separate preview window still worked, but the embedded preview was always filled in with black pixels.

After a decent bit of hair-pulling, I found a Qt environment variable that “fixed” it:

1
QT_AUTO_SCREEN_SCALE_FACTOR=0 obs

I still don’t understand why that fixed it, but now my OBS is scaled correctly and has a functional preview embed. I also posted this fix to the OBS forum.

feh

I use feh as my image viewer. By default, it seems to use a bitmap font that’s incredibly small on HiDPI displays.

To fix it, I modified by default theme to use my distro supplied Ubuntu Roman-face font in 14pt.

In ~/.config/feh/themes:

1
2
feh --borderless --scale-down --conversion-timeout 1 \
  --fontpath /usr/share/fonts/truetype/ubuntu --menu-font Ubuntu-R/14

One thing I haven’t figured out: when I open some higher-resolution images in feh, they’re occasionally shifted to the right with transparent pixels where some of the image should be. Clicking and dragging inside the image window causes it to re-render correctly, as does resizing the window. Not a huge deal, but slightly annoying.

dunst

I use dunst as my notification daemon.

It didn’t need any HiDPI-specific configuration, but I took the opportunity to make its notifications slightly more readable on these newer displays.

In ~/.config/dunst/dunstrc (among many other settings):

1
2
3
4
5
6
monitor = 0
follow = mouse
geometry = "600x120-30+20"
icon_position = left
max_icon_size = 64
icon_path = /usr/share/icons/gnome/64x64/status/:/usr/share/icons/gnome/64x64/devices/

Other bits

Mouse acceleration

My new displays are individually larger and significantly more dense than my previous ones, making my mouse feel sluggish. I originally configured my mouse acceleration with xset, but at some point my system switched to libinput and libinput-based inputs apparently don’t respect xset anymore (or never did?). Sigh.

The fix is to use xinput instead, with either symbolic names or XIDs for the device and setting being controlled. For example, this is what I use to set my mouse’s acceleration to the maximum (1.0):

1
xinput --set-prop "USB Optical Mouse" "libinput Accel Speed" 1.0

Your device and setting names may vary, of course, as may their value ranges (mine happened to be 0.0 to 1.0). You can use xinput on its own to list the names and XIDs of your devices; xinput list-props <XID-or-name> can be used to dump a particular device’s properties and their current values.

i3 workspaces

I use i3’s layout saving/restoring functionality to automatically load all of my workspaces and their applications when I log in.

Those layouts are stored in a (relaxed) JSON format via i3-save-tree, and contain hardcoded coordinates. To update them for my new monitors, I just had to recreate each of my workspaces once on my new monitors and dump them:

1
2
# for each workspace (1A, 1B, ...)
i3-save-tree --workspace 1A > ~/.config/i3/workspaces/1A.json

…and then fix them up manually to enable the appropriate application swallowing rules.

HexChat

I use HexChat for IRC.

HexChat’s config file includes individual offsets for each of the sub-panes in the GUI, which means that it breaks badly if you change your monitor dimensions. I couldn’t figure out how to fix them, so I ended up deleting my main ~/.config/hexchat/hexchat.conf entirely and recreating my preferred layout from memory. YMMV.

System icons

I didn’t have to make any changes with respect to my system icon sizes, which is probably because I actually see very few icons during normal i3 usage. Once again, YMMV.

Wrapup

Switching from a set of 3 FHD monitors to two 4K HiDPI ones was relatively painless. The problems that I had, unsurprisingly, were primarily with the few proprietary applications I use needing to be spoon-feed DPI information in their own ways — every other problem was either a bug (OBS + Qt) or a matter of more general reconfiguration.


  1. janus is my desktop’s hostname. 


Discussions: Reddit