# NomadBSD HiDPI Support — Implementation Guide

This implements automatic HiDPI/4K display detection and scaling for
NomadBSD, per the agreed design: EDID-based DPI detection (never
resolution alone), integer 2x scaling for true HiDPI panels, fonts-only
scaling for the awkward middle band (27" 4K), a "never scale on
guesswork" rule, per-hardware fingerprinting so user choices are
respected, and a boot-menu kill switch mirroring the existing
"Disable automatic Graphics detection" toggle.

## What's in the patch

| File | New/Edit | Purpose |
|---|---|---|
| `config/usr/libexec/nomadbsd-dpi` | **new** (mode 755) | Core detect/apply/override script (build steps 1+2) |
| `nomad/.config/xfce4/xinitrc` | edit | Session hook: apply scaling before Xfce starts (step 2) |
| `src/nomadbsd-setup-gui/files/xinitrc` | edit | First-boot wizard scaling (step 3) |
| `config/etc/rc.d/initdpi` | **new** (mode 755) | Big vt(4) console font on high-res framebuffers (step 4) |
| `config/boot/lua/core.lua` | edit | Boot menu toggle plumbing (step 5) |
| `config/boot/lua/menu.lua` | edit | Boot menu entry: "Disable automatic DPI detection" (step 5) |

No changes to `build`, `build.cfg`, or `pkg.list` are needed:
everything under `config/` is tar-copied into the image by
`install_config_files()`, the `nomad/` skeleton becomes the user's home
directory, the wizard's `files/xinitrc` is installed by the
`nomadbsd-setup-gui` build, and `x11/xrandr` (the only runtime
dependency) is already in `pkg.list` (line 147).

## Applying the patch

    git apply --stat nomadbsd-hidpi.patch   # preview
    git apply nomadbsd-hidpi.patch
    chmod 755 config/usr/libexec/nomadbsd-dpi config/etc/rc.d/initdpi
    git add -A && git commit -m "Add automatic HiDPI display detection and scaling"

(`git apply` normally preserves the executable bit from the patch
metadata; the chmod is belt-and-braces.)

Then rebuild. For an already-built work tree, the cheap path is
`./build resume` after re-running the config install; for a clean test,
`./build all`. The wizard change requires the `setupgui` build step to
re-run (the `build` script exposes it as a target: `./build setupgui`).

## How it works (runtime flow)

1. **Boot**: `rc.d/initdpi` runs after `mount_uzip`, before LOGIN.
   It parses the `VT(efifb): resolution WxH` line from dmesg (fallback:
   `vidcontrol -i mode`) and, if the framebuffer is >= 1600 px tall,
   loads the `terminus-b32` console font so the console is legible.
   Resolution-only heuristic is acceptable here because a wrong guess
   is purely cosmetic.

2. **First boot**: root's `.profile` runs `nomadbsd-setup bootstrap-gui`,
   which starts X with the wizard's own xinitrc. That xinitrc now
   `eval`s `nomadbsd-dpi env`, so `QT_SCALE_FACTOR`/`QT_FONT_DPI` are
   set before the Qt wizard starts. On a 13" 4K laptop the very first
   screen is now readable.

3. **Every login**: SDDM autologin starts the Xfce session;
   `~/.config/xfce4/xinitrc` runs `nomadbsd-dpi apply` and sources
   `~/.config/nomadbsd/hidpi.env` before handing off to
   `/usr/local/etc/xdg/xfce4/xinitrc`, so every GTK and Qt process
   inherits the right environment.

`nomadbsd-dpi apply` state machine:
- Boot-menu toggle set (`kenv initdpi.detect.disable=1`)? Do nothing,
  remove the env file.
- Display-set fingerprint (md5 of connected outputs+modes+EDID sizes)
  unchanged and a decision on file? Reuse it — this is what stops the
  script from fighting a choice the user later made in Xfce's own
  Settings dialog.
- Otherwise: detect, honor `~/.config/nomadbsd/dpi.override` if set,
  write the env file, apply xfconf + xrdb, save the fingerprint.

Scaling policy (primary output = RandR primary > eDP/LVDS/DSI > first):

| Detected DPI | Action |
|---|---|
| EDID missing/implausible (<50 mm or >2000 mm width) | 1x — VMs, projectors, scfb/vesa fallback |
| < 135 | 1x |
| 135–149 | fonts-only: Xft/Qt DPI 120 |
| 150–169 | fonts-only: Xft/Qt DPI 144 |
| >= 170 | 2x: `/Gdk/WindowScalingFactor 2`, cursor 48, `QT_SCALE_FACTOR=2` |

Double-scaling avoidance: at 2x, xfconf `/Xft/DPI` is reset to -1
(GTK multiplies fonts by the window scale itself) and Qt gets
`QT_FONT_DPI=96` alongside `QT_SCALE_FACTOR=2`; xrdb `Xft.dpi: 192`
covers plain-X apps, which don't read XSETTINGS.

## User-facing controls

- Boot menu -> Boot Options -> "Disable automatic DPI detection" (key P),
  persisted the same way as the graphics-detection toggle.
- `nomadbsd-dpi set <auto|off|1|1.5|2>` — persistent per-user override.
- `nomadbsd-dpi status` / `nomadbsd-dpi detect` — inspection.
- `sysrc initdpi_enable=NO` — disable the console-font half only.
  `initdpi_font_2x` and `initdpi_height_2x` are also rc.conf-tunable.

## Testing checklist (in rough order of value)

1. **Any FreeBSD/Xfce box, no image build**: copy
   `config/usr/libexec/nomadbsd-dpi` to a machine with X running and
   run `detect`, `apply`, `set 2`, `status`. This exercises 90% of the
   logic.
2. **bhyve/VirtualBox boot of the built image**: VMs report no/absurd
   EDID -> must land in the "never scale on guesswork" branch (scale 1).
   Also verifies initdpi is silent on a small framebuffer and that the
   boot-menu entry renders and toggles.
3. **4K laptop**: console font loads; wizard is scaled on first boot;
   desktop comes up at 2x; `nomadbsd-dpi set off` + re-login returns
   to 1x.
4. **4K TV or 27" 4K monitor** if available: TV must stay 1x; 27" gets
   fonts-only 144.
5. **Dock/undock**: plug a different monitor, re-login, confirm
   re-detection (fingerprint change) — then set an override and confirm
   it survives the same swap.

## Known limitations (document in handbook)

X11 permits one global scale: mixed-DPI multi-monitor uses the primary
display's scale. No hotplug rescaling mid-session (takes effect at next
login). Fractional scaling is fonts-only by design — true fractional
window scaling on X11 (`xrandr --scale`) is blurry and compositor-
hostile, and was deliberately excluded.

## Suggested handbook addition

> **HiDPI / 4K displays.** NomadBSD detects the DPI of your display at
> login and scales the user interface automatically: 2x on true HiDPI
> panels (most 4K laptops), larger fonts on 4K desktop monitors, and no
> scaling on 4K TVs. If detection misbehaves, disable it in the boot
> menu under *Boot Options -> Disable automatic DPI detection*, or pin a
> scale with `nomadbsd-dpi set <auto|off|1|1.5|2>`. Scaling choices you
> make in Xfce's Settings are respected until the set of connected
> displays changes.

## Notes for upstreaming

The two Lua files under `config/boot/lua/` are NomadBSD's patched
copies of FreeBSD's loader menu; the additions mirror the existing
`disableGfxDetect` pattern exactly (same env-var style:
`initdpi.detect.disable`). Both files were syntax-checked. The two new
shell scripts pass `sh -n` and follow the repo's 2-clause BSD header
and rc.subr conventions from `initgfx`.
