Windows, X11 and Wayland

Window systems through SDL3  ·  CNA snapshot c1c316b9  ·  CNA_PLATFORM=SDL3 with SDL’s windows, x11 and wayland video drivers

One windowing implementation: SDL3

A platform implementation owns windows, events, input, timing and host services (clipboard, dialogs, displays, controllers). CNA selects exactly one at configure time with CNA_PLATFORM, and offers three: SDL3, the windowing implementation and the default everywhere, and the windowless HEADLESS and TERMINAL hosts. All of them implement the same CNA::Platform::IPlatform contract and report what they can do through 32 capability flags.

Windows, X11 and Wayland are reached through SDL3. SDL chooses its video driver at run time from the drivers it was built with and what the session offers; SDL_VIDEODRIVER=windows, x11 or wayland selects one explicitly. Window-system specifics — the X selections, Wayland’s output scale, Windows’ per-monitor DPI — are SDL’s to implement, and CNA consumes them through the same IPlatform services on every host.

HostSDL video driverNativeWindowSystem and handlesRead directly by
WindowswindowsWin32: HWNDDIRECTX9, DIRECTX11, WEBGPU
Linux, X11 session (or Xwayland)x11X11: Display* + Window XIDWEBGPU
Linux, Wayland sessionwaylandWayland: wl_display* + wl_surface*WEBGPU
macOS / iOScocoa / uikitCocoa: NSWindow*; UIKit: UIWindow*METAL, WEBGPU
AndroidandroidAndroid: ANativeWindow*WEBGPU

The handle arrives through IPlatformWindow::GetNativeHandle() as a NativeWindowHandle; TryGetWin32, TryGetX11 and TryGetWayland return a validated view only when the window really is that system, so a renderer that expected an HWND refuses an X11 window by name instead of dereferencing it. An X11 Window is an integer XID and stays in windowId, never in a pointer field. The experimental C API exposes the same discriminator as CNA_NATIVE_WINDOW_SYSTEM_*.

Choosing a configuration

If you want…UseWhy
A windowed game on Windows, an X11 or Wayland desktop, macOS, iOS, Android or the webSDL3 (default)It is the one windowing implementation; the full capability set (gamepads and sensors, IME, drag-and-drop, tray, camera) comes with it.
A particular Linux window systemSDL3 and SDL_VIDEODRIVER=x11 or waylandBoth drivers are in the vendored SDL3 when their development packages were installed before its first configure.
A binary with no SDL in itCNA_ENABLE_SDL=OFF with HEADLESS or TERMINALAn SDL-free build has no window. See Building without SDL.
No window at all (servers, tests, batch rendering)HEADLESS or TERMINALSee Platform Support.
⚠

Requested means required. CNA_PLATFORM accepts SDL3, HEADLESS and TERMINAL (the last only off Windows). Any other value fails configuration by name and points at SDL3; nothing is substituted silently.

X11

On an Xorg session SDL uses its x11 driver; on a Wayland desktop it may use Xwayland through the same driver when its wayland driver is unavailable or not chosen. Renderers receive the Display* and the window XID: WEBGPU creates its surface from them, VULKAN asks the platform’s Vulkan-surface service and the EasyGL renderers its GL-context service, both implemented over SDL for the same window. The vendored SDL3 gets its X11 driver only when the X11 development packages (libX11, libXext, libXrandr, libXi, libXcursor, libXfixes, libXss, libXtst and xkbcommon) are present when it is first configured; Building lists the packages.

Wayland

On a Wayland session SDL uses its wayland driver when it was built with one, and the renderer receives the wl_display* and wl_surface*. The Wayland driver exists only if the wayland-client, wayland-protocols and xkbcommon development files were installed before the vendored SDL3 was first configured; a build without them still runs on a Wayland desktop through Xwayland. Output scaling and the other compositor specifics are SDL’s.

Windows

On Windows SDL uses its windows driver, and the HWND it owns is what the Direct3D 9 and 11 renderers create their swap chains for and what WEBGPU makes its surface from. CNA does not take over main() on Windows: a game keeps an ordinary main, and cna_windows_gui_executable() builds it for the GUI subsystem. HEADLESS is the windowless alternative; TERMINAL is not offered on Windows. An SDL-free Windows build is therefore windowless, and its only audio choice is NULL.

What each renderer takes from the window

RendererTakesOn
OPENGLES3, OPENGL33A GL context from the platform’s IPlatformGlContext serviceAny SDL3 window
VULKANA surface from the platform’s IPlatformVulkanSurface serviceAny SDL3 window where a Vulkan loader is available
DIRECTX9, DIRECTX11The HWNDWindows
WEBGPUThe native handle of the window system it is onWindows, X11, Wayland, macOS, Android; the browser canvas on the web
METALThe Cocoa or UIKit window, for its CAMetalLayer-backed viewmacOS, iOS
SDL_RENDERER, SDL_GPU, FNA3DThe SDL window itselfAny SDL3 window
SOFTWARE, HEADLESS, STUBNothing (off-screen; SOFTWARE is displayed by TERMINAL)Any platform

A GPU renderer on HEADLESS or TERMINAL has no native window to draw into and is refused where that is known, rather than failing on a null handle later.

Capabilities

The SDL3 platform reports one capability set whichever video driver it runs on; the full 32-flag table, with Headless and Terminal beside it, is on Platform Support. Whether a particular service works in a particular session (a global pointer position on Wayland, a system tray on a desktop without one) is decided by SDL and the window system at run time, and a service that is not available fails at the call rather than pretending to succeed.

Building without SDL

CNA_ENABLE_SDL takes AUTO (the default), ON or OFF. With OFF SDL is not downloaded, built, found or linked, and any selection that genuinely needs it is refused at configure time with the reason named: CNA_PLATFORM=SDL3, CNA_AUDIO_PLATFORM=SDL3, and the renderers SDL_RENDERER, SDL_GPU and FNA3D. Because SDL3 is the only windowing implementation, an SDL-free build is a windowless one — a game server, a test runner, a batch renderer or a terminal game:

# Linux: no SDL anywhere, ALSA audio through CNA's own mixer
cmake -S . -B build-sdl-free -G Ninja \
  -DCNA_ENABLE_SDL=OFF \
  -DCNA_PLATFORM=HEADLESS \
  -DCNA_AUDIO_PLATFORM=ALSA \
  -DCNA_GRAPHICS_RENDERER=HEADLESS

# A terminal game: CPU pixels presented as character cells
cmake -S . -B build-terminal -G Ninja \
  -DCNA_ENABLE_SDL=OFF \
  -DCNA_PLATFORM=TERMINAL \
  -DCNA_AUDIO_PLATFORM=NULL \
  -DCNA_GRAPHICS_RENDERER=SOFTWARE

To prove a binary contains no SDL, check ldd (no libSDL3) and the build tree (no SDL target was configured); the platform workflow’s SDL-free job does both. Tutorial 138 walks through it.

Build recipes

# Linux desktop: SDL3 with both of its Linux video drivers. Install the X11 and Wayland
# development packages (see Building) BEFORE the first configure, so the vendored SDL3 gets them.
cmake -S . -B build -G Ninja -DCNA_GRAPHICS_RENDERER=VULKAN
cmake --build build --parallel
SDL_VIDEODRIVER=wayland ./build/cna_house3d_demo     # or x11

# Windows, natively with MSVC (SDL3 is the platform; the HWND reaches DIRECTX11)
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=DIRECTX11
cmake --build build --config Release

Cross-compiling for Windows from Linux uses the mingw-w64 toolchain file (-DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64.cmake), with the same SDL3 platform; Wine (with DXVK for Direct3D) runs the result. Building has the sibling checkouts, presets and packages.

Validation

SDL3 on a real window system is tested on servers private to the run, never on the developer’s own desktop. CnaPlatformSdl3X11Tests runs the SDL3 window suite and the window conformance suite on a private Xvfb (tools/platform/x11_test_server.sh) with SDL_VIDEODRIVER=x11, and CnaPlatformSdl3WaylandTests does the same on a private headless Weston (tools/platform/wayland_test_server.sh) with SDL_VIDEODRIVER=wayland; Sdl3WindowTest.NativeHandleMatchesTheVideoDriver asserts the native handle each driver hands a renderer. Each skips (exit 77) where its server is not installed.

CNA’s recorded validation of this arrangement (2026-10-06, Linux x86-64 with a Radeon 780M; plans/plan_platform.md section 11c) ran CnaPlatformSdl3X11Tests (38 passed) and CnaPlatformSdl3WaylandTests (30 passed) with nothing skipped; seven renderers — OPENGLES3, OPENGL33, VULKAN, WEBGPU, SDL_GPU, FNA3D, SOFTWARE — ran the 3D house and 2D demos on both SDL drivers and exited cleanly; a mingw-w64 SDL3 cross-build ran the SDL3 window suite under Wine (30 passed, the handle reported as Win32) and the Direct3D 11 smoke presented into, and resized, an SDL3 window’s HWND under Wine + DXVK. On GitHub’s windows-latest image the manually dispatched platform workflow passed all 11 jobs, its native-MSVC sdl3-windows job among them.

What CI is configured to check

Job (platform-ci.yml)TriggerWhat it does
Platform contract, SDL3 cells (OPENGLES3, VULKAN, SOFTWARE)Push / PRBuilds and runs the platform suites, then CnaPlatformSdl3X11Tests and CnaPlatformSdl3WaylandTests on a private Xvfb and headless Weston; a skip fails the step, because both servers are installed.
sdl-free (Headless + Headless + ALSA)Push / PRCNA_ENABLE_SDL=OFF build; checks that nothing links SDL.
sdl-enable-matrixPush / PRConfigure-only: AUTO, ON and OFF succeed where they should, and OFF with the SDL3 platform fails.
sdl3-windows (native MSVC, windows-latest)ManualA real MSVC configure and build of CNA and the platform module suite on SDL’s windows driver.

Every Linux run uses virtual servers with Mesa’s software drivers. The Direct3D renderers’ Windows job (d3d-windows-ci.yml) is also manual; see Graphics Renderers.

Honest limits

  • No CI job runs on a real desktop compositor (GNOME, KDE) or on physical Windows hardware; the Windows jobs run only when dispatched by hand.
  • Which Linux video drivers a build has is fixed when the vendored SDL3 is first configured: install the X11 and Wayland development packages first.
  • An SDL-free build cannot open a window on any operating system.
  • Window-system behaviour (IME, DPI, clipboard formats, cursor capture) is SDL’s implementation; CNA’s tests pin the contract it consumes, not every compositor’s behaviour.

Further reading