Skip to main content

Module backend

Module backend 

Source
Expand description

Choosing a backend at runtime.

§The decision: runtime selection, one registry, Box<dyn Shell>

The windowing rules in docs/notes/backends.md require it in one sentence — “backend selection at runtime, not compile time, on Linux: try Wayland socket → fall back to X11 (both compiled in; CRCBL_SHELL=x11 override)” — and that sentence has consequences the API has to absorb now, because retrofitting them costs a rewrite of every consumer:

  1. Shell must be object-safe. A generic Shell would make the backend a compile-time parameter, and “try Wayland, fall back to X11” would then have to monomorphise every consumer twice and pick between the two instantiations with an enum wrapper — which is a hand-written vtable with extra steps. crcbl-hal reached the same conclusion for the same reason and states the costs; they apply here in a milder form, since the shell is called a handful of times per frame rather than per draw.
  2. The entry point cannot be a constructor. WaylandShell::new() puts the platform name in the caller’s source, which is the regression the whole seam exists to prevent. So the entry point is open, and the only concrete shell type a consumer ever names is HeadlessShell — deliberately, because a test asking for determinism is asking for a specific implementation.

§What is registered today

Wayland then X11 on Linux, Win32 on Windows, AppKit on macOS, and HeadlessShell everywhere — the last only when asked for by name. P0.6 confirmed the property this module was shaped to have and P5C confirmed it twice more: adding a whole X11 backend touched REGISTRY and these tests, and no other file outside src/x11/ (plus src/linux/, which is the evdev table and libxkbcommon moving up one level to be shared rather than copied); adding the Win32 backend touched this file, src/lib.rs and src/win32/, and adding the AppKit one touched this file, src/lib.rs and src/appkit/. No consumer changed, no trait method was added, and no #[cfg] appeared anywhere above this crate.

Every variant of ShellBackend is now registered somewhere, which changes how the “a backend this build does not have” property is tested. It used to be asserted against whichever variant had not landed yet — X11 until P0.6, Win32 until P5C, AppKit until this slice — and there is no fourth candidate. The tests below now derive the absent set from the table itself and assert the property per platform, which is what was actually meant all along: asking for a backend this build lacks is an honest UnknownBackend. It also cannot go stale again — a future backend is covered the day it is added, on the platforms that do not have it.

Headless is registered with auto: false, so open never selects it implicitly. A game that silently ran headless because a compositor was missing would look like a hang; failing with ShellError::NoBackend names the actual problem.

§Why both Linux entries are dlopen-backed, and the Windows one is not

The registry is a fall-through list, so every entry has to be able to fail at runtime. A backend linked against libwayland-client.so.0 — or libxcb.so.1 — with DT_NEEDED cannot: the process dies in ld.so before main, on any machine without the library, and this list never runs. src/wayland/ffi.rs has the full argument and src/x11/ffi.rs sharpens it, since X11 is the fallback and is reached only after Wayland has already failed.

The Win32 and AppKit entries link their libraries instead, and the difference is this list’s shape rather than a change of mind: each of those platforms has one backend, so nothing falls through to anything, and neither user32.dll nor AppKit can be missing from a system that is running a process at all. src/win32/ffi.rs states it in full and src/appkit/ffi.rs repeats it for the frameworks.

Enums§

ShellBackend
Which implementation is behind the Shell trait.

Constants§

BACKEND_ENV_VAR
The environment variable that overrides automatic backend selection.

Functions§

open
Opens the best available shell for this process.
open_backend
Opens a specific backend, ignoring BACKEND_ENV_VAR.