High DPI under Linux (Debian)

For a long while, I've run with a mish-mash of settings in order to get the fonts and icons in various applications just right on my high DPI displays. Then I upgraded packages to Debian Bookworm, and various things randomly started using huge fonts.

Being a bit grumpy about this, from now on I'm going to fix the DPI setting to the correct value (about 176 in the case of my laptop), and then try and force applications to look right. i.e. spend time with a mish-mash of settings to get things looking just right. But hopefully after all that, it leads to reasonable results on different displays just by changing that one DPI setting (because this is Unix: those three DPI settings).

To be clear, dimensional accuracy doesn't bother me in most of what I use a computer for. Sometimes things displayed on a screen are better as some exact multiple of pixels, and maybe the DPI can give a hint as to what that multiple should be. Sometimes we work with a representation of some final printed output, byt I don't need my 12pt font to be exactly 4.2mm high on screen. All I care about is that things don't look stupid. Counter examples may be that a desktop publisher cares about page elements being shown accurately sized relative to each other, and a "print preview" may want to scale the output exactly.

I'm developing a strong suspicion that most application developers really want their UI elements to be enormous. When they change behaviour—which I assume is when they start respecting the DPI settings—the defaults always seem to be like playing with Duplo® instead of normal Lego®.

So fair warning: this whole page may simply be one guy railing against the norm of stupidly large UIs. Sorry not sorry, as I think they said in the noughties.

Debian Trixie: I've started to see UI elements changing as I upgrade various bits of my systems to Debian Trixie. Once the dust has settled on that, I'll see if I can figure out what's gone on.

The Arch Linux wiki has a bunch of useful information here: https://wiki.archlinux.org/title/HiDPI

DPI settings

In .xsession / .xinitrc:

/usr/bin/xrandr --dpi 176

In .xsettingsd (DPI × 1024):

Xft/DPI 180224

Note: xsettingsd is just one way of serving configuration using the XSETTINGS protocol. GNOME in particular provides its own called gnome-settings-daemon, and you may have to look into how to use it.

In .Xresources:

Xft.dpi: 176

Toolkits

Gtk

With the settings above (probably mostly the stuff served with the XSETTINGS protocol), GTK+/GTK applications seem to be mostly fine once the UI fonts are overridden. Shared across lots of applications, and the Xfce panel. In .xsettingsd:

Gtk/FontName "Noto Sans Regular 7"
Gtk/MonospaceFontName "Monospace Regular 8"

Qt

At some point from version 5.x, Qt started respecting DPI settings, but the default choice was (predictably) to make things too big, and originally you could only override scaling in integer multiples with the QT_DEVICE_PIXEL_RATIO environment variable. Now you can set the QT_SCALE_FACTOR environment variable to a floating point number. e.g. in .bashrc:

QT_SCALE_FACTOR="0.75"
export QT_SCALE_FACTOR

Some applications need an override from that default, mentioned below.

Applications

Chromium

Absolutely no idea. You can make the content the right size easily enough, but it seems to be using yet another scaling method for icons and UI, so they all look huge. The available settings seem to be incredibly minimal, but as this isn't my primary browser - I only fire it up to test stuff - I don't care enough to dig deeper.

Discord

I can't make head nor tail of this one, but it does at least have enough sliders to make things look right.

In User Settings → Appearance, set Chat Font Scaling to 15px, and Zoom Level to 75.

Discord will then want to waste lots of your screen space by not allowing you to make the window smaller. Put these lines at the top level in ~/.config/discord/settings.json:

  "MIN_WIDTH": 0,
  "MIN_HEIGHT": 0,

The splash screen as it's starting stays large, but that's short-lived.

Firefox

I'm guessing a lot of the problems with browsers comes from images not reliably having presentation DPI information in them. You can scale a font because you know how big it's supposed to be (at least you can if it's specified in points and not pixels), but for an image, the best you can do is assume "what displays used to be like". Probably 96DPI.

Even so, the way to configure that in Firefox is a bit mad. It is affected by the settings in .xsettingsd, but the end result of the UI text is much smaller than other Gtk users. What you then do is apply a scale factor to everything. End result: both images and text look right. Except the scale down doesn't seem to be in the same proportions, so the scale up ends up being a pretty random looking number. It's possible this only happens to work ok for the DPI of my screen.

In about:config, set layout.css.devPixelsPerPx to 1.375.

In Settings → General → Language and Appearance, set content fonts and sizes to whatever you're comfortable with. I'm happy with CMU Bright at size 15. Why? Because relative to most of the sites I use that override font size (stop doing that, people), that font at that size ends up making normal pages look about right.

Relatedly, if you want to be able to select "Compact" in the "Density" drop-down in "Customise Toolbar" (and you most assuredly do), you need to set browser.compactmode.show to true in about:config. This rather disturbingly implies that they want to get rid of this option entirely.

Not fixed: at higher DPI, scrollbar widths become super small. There are userChrome/userContent based (apparent) fixes for this online but I've not investigated them yet.

Debian Trixie / Firefox ESR 115: there appear to have been changes to DPI handling! The setting above will now turn Firefox into "Fisher-Price Baby's First Browser". I now set layout.css.devPixelsPerPx to 0.7—scaling in the opposite direction to previously—but as this reduces the UI font size noticeably, I uncomment this line in the userChrome.css of CustomCSSforFx (which I strongly recommend using anyway, as it can put the tab bar back where it's supposed to be, etc.):

@import "./css/generalui/increase_ui_font_size.css"; /**/

MAME

MAME links against Qt, and the debugger window only partly respects the QT_SCALE_FACTOR environment variable: the window geometry itself adjusts, but none of the fonts scale to fit. Thus if you have this set globally, you need to override it when running MAME:

$ QT_SCALE_FACTOR=1 mame -debug dragon64

Xpdf

After updating to Debian Bookworm, the UI fonts were much embiggened. The change in behaviour seems to have come in with a change to use render tables. This seems to be a Motif 2 thing.

Debian Xpdf git repo

96878f5a7050b99a7187eed864779dcceb436b68 is the first bad commit
commit 96878f5a7050b99a7187eed864779dcceb436b68
Author: Adam Sampson 
Date:   Wed Mar 3 21:46:24 2021 +0000

    Use render tables to select Xft Unicode fonts for the UI.
[...]

It can be worked around by adding these lines to .Xresources:

Xpdf*renderTable.default.fontSize: 5
Xpdf*renderTable.mono.fontSize: 5

XScreenSaver

Huge fonts arrived with the transition to version 6.02, but I've not so easily been able to narrow down what change caused this. There didn't seem to be any transition to render tables in the code like with Xpdf, but fonts in app-defaults are in the form "sans-serif bold 16", etc., so a workaround is to specify these with smaller values, in .Xresources:

XScreenSaver*Dialog.headingFont:    sans-serif bold 10
XScreenSaver*Dialog.bodyFont:       sans-serif 8
XScreenSaver*Dialog.errorFont:      sans-serif bold 8
XScreenSaver*Dialog.labelFont:      sans-serif bold 8
XScreenSaver*Dialog.unameFont:      sans-serif 6
XScreenSaver*Dialog.buttonFont:     sans-serif bold 8
XScreenSaver*Dialog.dateFont:       sans-serif 5

Note: XScreenSaver prior to 6.x doesn't know what to do with those font names, so wait until you need them.

Debian Trixie: I definitely noticed changes in Trixie, but nothing is unreadable, so as it only affects the unlock screen, who cares for now.

XTerm

These lines in .Xresources work for me:

*.vt100.faceName: DejaVu Sans Mono
*.vt100.faceSize: 5.7
*.vt100.scaleHeight: 1.05

(I'm actually not sure XTerm does anything with DPI information, so that's pretty much just my local preference and will have to change if the screen does).

Zoom

Zoom appeared to change high-DPI behaviour around version 5.16.0 (8131). Without a scale factor, it's now truly enormous. I even need to override my Qt default (above) to make things smaller still. About (96/DPI) seems to be right, so:

$ QT_SCALE_FACTOR=0.55 zoom

Updated 16 Jan 2024