Troubleshooting

NVIDIA EGL/dmabuf, cursor theme, nested-under-Hyprland quirks, screen sharing and the portal env, spawn latency — the things that bite first.

Practical fixes for the things that actually come up. When in doubt, read the session log first: a real session redirects stderr to $XDG_STATE_HOME/atlaswm/session.log (~/.local/state/atlaswm/session.log, plus .old for the previous run). Turn on debug { trace #true } for an action trace when a keybind misbehaves.

NVIDIA

atlaswm's DRM backend is developed and daily-driven on a GeForce RTX 3080 (Ampere) on the nvidia-open open kernel modules — that path works on that exact card. A few things to know:

EGL is provided by the system driver. NVIDIA's EGL comes from /run/opengl-driver (the NixOS driver path) via GLVND; the session needs no nixGL wrapping. nvidia-drm.modeset=1 must be set — it already is if you run any Wayland compositor today.

dmabuf + explicit sync go together. atlaswm advertises zwp_linux_dmabuf_v1 together with wp_linux_drm_syncobj_manager_v1 (explicit sync). On NVIDIA these are a pair: NVIDIA's egl-wayland reads its render device from the dmabuf global and then takes the dmabuf + explicit-sync path — advertising dmabuf without explicit sync makes NVIDIA client EGL init fail with EGL_BAD_ALLOC / "failed to allocate resources", and GL clients (kitty, …) won't spawn. atlaswm ships both, so this is handled; it's listed here because if you ever see those EGL allocation errors in session.log, this is the area to look at.

Benign warnings. MESA-LOADER / libEGL … fd -1 warnings are Mesa's loader probing and failing before NVIDIA's EGL succeeds — they're noise, not a failure. The Unable to become drm master warning under logind is also benign (it only gates VT-switch master handoff; a modern kernel grants modeset).

A hard GPU freeze is usually a firmware fault, not atlaswm. A frozen screen that needs a reboot on this hardware has been an NVIDIA GPU firmware fault (Xid 62 GSP/PMU halt), not a compositor bug. atlaswm has GPU-hang resilience: a sustained render failure drops you cleanly back to your greeter within ~5 s (with a clear session.log error) instead of holding a silently-broken frozen session. It can't un-wedge the GPU — that needs a reboot — but you won't sit on a black screen wondering.

Cursor looks like a plain X arrow

The DRM backend draws its own cursor and loads the XCursor theme from XCURSOR_THEME / XCURSOR_SIZE. If you get the default arrow, set those env vars to your theme (e.g. a catppuccin cursor) in your session environment. (The nested backend lets the host draw the cursor, so this only affects the real session.)

Nested under Hyprland (and other hosts)

Running nested is the dev path, with a couple of quirks:

  • Mod is Alt nested. mod "auto" resolves to Alt while nested so it never fights the host's Super binds. If a bind seems dead, check whether the host compositor grabbed that chord first.
  • Some host binds win. A chord the host compositor has bound globally may never reach atlaswm. Pick binds the host doesn't use, or test the conflicting ones in a real session.
  • Keyboard layout. Nested follows XKB_DEFAULT_LAYOUT until you set input { xkb-layout "fr" } in the config. Don't test azerty binds with bare qwerty assumptions.

Screen sharing

atlaswm captures the screen via wlr-screencopy (shm and dmabuf zero-copy paths, cursor exclusion honored). For the desktop-portal flow (Google Meet, Discord, OBS PipeWire capture), it rides xdg-desktop-portal-wlr (xdpw), which does the D-Bus portal, the picker and the PipeWire stream.

Install and route xdpw (NixOS):

xdg.portal.wlr.enable = true;
xdg.portal.config.atlaswm."org.freedesktop.impl.portal.ScreenCast" = [ "wlr" ];

The activation-environment gotcha. xdg-desktop-portal is started by D-Bus/systemd with its own environment. For the portal to route ScreenCast to the wlr backend it must see XDG_CURRENT_DESKTOP=atlaswm in that environment — and on a real session atlaswm pushes it there (dbus-update-activation-environment), exactly like sway/Hyprland sessions do. If a share still fails with "must be authorized to share your screen" even after you allow it, the ScreenCast interface probably wasn't exposed because that env wasn't set — make sure you're on a freshly-rebuilt session (a stale running compositor from before a rebuild is the usual culprit; relogin, or reboot if relogin doesn't kill it).

Two monitors. Full-monitor capture works; the portal picker (a slurp/dmenu chooser via xdpw) selects which monitor.

If xdpw won't start with Compositor supports neither ext_image_copy_capture or wlr_screencopy!, it needs both zwlr_screencopy_manager_v1 and zwp_linux_dmabuf_v1 — atlaswm advertises both, so this points at an old binary; clear the systemd failure with systemctl --user reset-failed xdg-desktop-portal-wlr and relogin into the current build.

Self-driven tools confirm the path independently: grim (full-output and -g "x,y wxh" region), grim -o DP-1 (one monitor), and wf-recorder all capture correctly oriented frames.

GL clients are slow to spawn

A noticeable delay opening each GL client (a terminal, a browser) on NVIDIA is the Mesa EGL probe failing before NVIDIA's EGL succeeds (~300 ms/client). It's cosmetic — the client does start. (A glvnd pin that skips the Mesa probe was tried and reverted because it broke EGL after a bundled rebuild; it's a known trade-off, not a bug to fix in the config.)

A config change didn't apply

Config is live-reloaded within a second of saving — if it parses. A typo, an unknown verb or a broken regex makes the whole reload fail, the error is logged, and the previous config keeps running. So if a change seems ignored, check session.log (or run atlasctl default-config to confirm exact syntax) — you've probably got a parse error keeping the last-good config alive. Fix and save to re-apply.

XWayland app issues

atlaswm runs X11 apps (Steam, Discord, older toolkits) via XWayland — no extra setup. echo $DISPLAY in a terminal should print :N. Tiled X11 windows ignore client-side move/resize (the layout owns tiled geometry, same as Wayland); float them (Mod+space or a float #true rule) to drag/resize freely. Override-redirect surfaces (some menus/tooltips) are best-effort positioned when the plane is panned/zoomed.