A code-generation tool and companion C++23 framework for the
Wayland display protocol. Given a Wayland
XML protocol definition it produces type-safe, zero-overhead C++23 headers that
replace the handwritten C bindings normally provided by wayland-scanner.
- Type-safe protocol bindings — CRTP proxy and resource classes with
compile-time event/request dispatch (no
void*casts in user code). - Zero-overhead event dispatch — generated callbacks use direct CRTP
static_castdispatch, identical in cost to raw Cwayland-scanneroutput (no intermediate opcode scan, novoid*packing/unpacking). - Multiple output modes — client C++ header, server C++ header, and C-compatible header from a single XML source.
- C++ standard selection — generate code targeting C++17, C++20, or C++23
(
--stdflag). - Header-only framework — the
wayland-cxxlibrary installs to${includedir}/wl/and requires no link-time dependencies of its own. - Type-safe object construction —
wl::construct<ChildTraits, Opcode>()andwl::construct_at_end<>()encode interface type and opcode at compile time, replacing error-prone_MarshalNewcalls. - RAII everywhere —
WlPtr<T>(owning proxy wrapper),FdHandle(file descriptor),FileHandle(C FILE*),ScopeExit(scope guard). - Keyboard repeat —
KeyboardHandler<App>provides full xkbcommon keymap processing with POSIX-timer-based key repeat out of the box. - Client-side decorations — pluggable CSD framework with Cairo and GTK back-ends.
- Strict quality gates — CI enforces
-Werror, clang-tidy, clang-format, and CodeQL on every push.
| Tool / Library | Minimum | Notes |
|---|---|---|
| Meson | 1.1 | Build system |
| C++23 compiler | GCC 13+ / Clang 17+ | c++23 is the default standard |
| pugixml | — | Auto-fetched via Meson wrap if missing |
| wayland-client / wayland-server | — | Optional; required for examples |
| wayland-protocols | — | Optional; required for some tests and examples |
| Google Test | — | Optional; required for tests (auto-fetched) |
| libxkbcommon | — | Optional; required for keyboard examples/tests |
| SDL3 | 3.x | Optional; required for sdl3-presentation-shm |
Ubuntu / Debian:
sudo apt install meson ninja-build libpugixml-dev \
libwayland-dev wayland-protocols libxkbcommon-dev \
libgtest-devFedora:
sudo dnf install meson ninja-build pugixml-devel \
wayland-devel wayland-protocols-devel libxkbcommon-devel \
gtest-devel# Clone the repository
git clone https://github.com/jwinarske/wayland-cxx-scanner.git
cd wayland-cxx-scanner
# Configure (scanner only)
meson setup build
# Build
ninja -C buildMost examples require wayland-client, wayland-protocols, and their
protocol-specific dependencies (see the Examples table below).
# Configure with examples enabled
meson setup build -Dexamples=true
# Build everything
ninja -C build
# Or build a single example
ninja -C build examples/presentation-shm/presentation_shm
ninja -C build examples/sdl3-presentation-shm/sdl3_presentation_shmmeson setup build -Dtests=true
ninja -C build
meson test -C buildmeson setup build --prefix=/usr/local
ninja -C build installThis installs:
wayland-cxx-scanner— the code-generation tool.${includedir}/wl/*.hpp— the framework headers.wayland-cxx.pc— pkg-config file for downstream consumers.
wayland-cxx-scanner [--mode=<mode>] [--std=<std>] <protocol.xml> [<output.hpp>]
| Flag | Values | Default | Description |
|---|---|---|---|
--mode |
client-header, server-header, c-header |
client-header |
Kind of header to generate |
--std |
c++17, c++20, c++23 |
c++23 |
Target C++ standard |
If <output.hpp> is omitted the generated code is written to stdout.
wayland-cxx-scanner \
--mode=client-header \
/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml \
xdg_shell_client.hppThe scanner integrates into Meson builds with custom_target or generator.
Every example under examples/ demonstrates this pattern — see
examples/minimal/meson.build for the simplest
case.
See ARCHITECTURE.md for the full design document. A brief overview follows.
┌───────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ protocol.xml │────▶│ XML Parser │────▶│ Intermediate │
│ (Wayland) │ │ (xml_parser) │ │ Representation │
└───────────────┘ └──────────────────┘ │ (ir.hpp) │
└────────┬────────────┘
│
┌──────────────────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ codegen_client │ │ codegen_server │ │ codegen_c │
│ _cxx │ │ _cxx │ │ │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │
▼ ▼ ▼
client proxy .hpp server resource .hpp C-style .h
wayland-cxx-scanner/
├── include/wl/ Framework headers (installed as wayland-cxx)
├── src/ Scanner tool source code
├── protocols/ Bundled Wayland XML protocol definitions
├── tests/ Unit and integration tests (Google Test)
├── examples/ Example Wayland client/server applications
├── subprojects/ Meson wrap files (pugixml, gtest)
├── scripts/ Developer tooling (format.sh)
└── meta-wayland-cxx-scanner/ Yocto / OpenEmbedded recipe
| Header | Purpose |
|---|---|
proxy.hpp |
Non-owning CProxy<Traits> handle (≈ WTL CWindow) |
proxy_impl.hpp |
CRTP CProxyImpl<Derived, Traits> + wl::construct<> / wl::construct_at_end<> |
resource_impl.hpp |
Server-side CResourceImpl<Derived, Traits> |
event_map.hpp |
Optional CEventMap base + BEGIN_EVENT_MAP macros (for hand-written code) |
wl_ptr.hpp |
Owning WlPtr<T> (≈ WTL CAutoPtr) |
registry.hpp |
CRegistry client registry + CGlobal<Traits> server global factory |
display.hpp |
CDisplay RAII display wrapper + RunEventLoop() |
fd_handle.hpp |
RAII file descriptor wrapper |
raii.hpp |
FileHandle (C FILE*) + ScopeExit scope guard |
client_helpers.hpp |
SetupHandler() / BindHandler() convenience functions |
keyboard.hpp |
KeyboardHandler<App> — xkbcommon keymap + key repeat |
seat.hpp |
SeatManager<App> — seat capability tracking |
xdg_shell.hpp |
Pre-built wl_interface tables for XDG shell |
xdg_decoration.hpp |
XDG decoration protocol support |
linux_dmabuf.hpp |
Linux DMA-BUF protocol support |
agl_shell.hpp |
AGL (Automotive Grade Linux) shell protocol support |
csd_plugin.hpp |
Client-side decoration plugin interface |
csd_fallback.hpp |
Fallback CSD implementation |
csd_cairo.hpp |
Cairo-based CSD implementation |
csd_gtk.hpp |
GTK-based CSD implementation |
wayland.hpp |
Umbrella include for common framework headers |
All examples live under examples/ and are built when -Dexamples=true is
passed to meson setup (requires wayland-client and wayland-server).
| Example | Description | Extra dependencies |
|---|---|---|
| minimal | Client ↔ server roundtrip with a custom protocol | — |
| wayland-info | Print compositor globals and capabilities | wayland-protocols (optional) |
| key-input | Keyboard input handling with xkbcommon | xkbcommon |
| simple-egl | Animated EGL/GLES triangle | EGL, GLESv2 |
| subsurfaces | Subsurface protocol demonstration | EGL, GLESv2 |
| presentation-shm | Frame-timing feedback via wp_presentation |
wayland-protocols |
| sdl3-presentation-shm | SDL3 window with wp_presentation frame-timing |
SDL3, wayland-protocols |
| agl-presentation-shm | AGL compositor integration | wayland-protocols |
| ivi-presentation-shm | IVI shell integration | wayland-protocols |
| xdg-csd | Client-side decorations (Cairo / GTK back-ends) | cairo or gtk+-3.0 |
| xdg-simple-dmabuf-vulkan | Vulkan rendering with DMA-BUF export | Vulkan |
The project uses Google Test with automatic download via Meson wraps when the system package is not found.
meson setup build -Dtests=true
meson test -C build| Category | Tests | Timeout |
|---|---|---|
| Unit — scanner | ir, xml_parser, name_transform, codegen_c, codegen_client_cxx, codegen_server_cxx, cli | 15–30 s |
| Unit — framework | raii, event_map, proxy, proxy_impl, resource_impl, client_helpers, display | 15 s |
| Unit — protocols | agl_shell, xdg_shell (optional), seat/keyboard (optional) | 15 s |
| Integration | roundtrip (client + server in forked processes) | 60 s |
| Option | Type | Default | Description |
|---|---|---|---|
tests |
boolean | false |
Build and run unit/integration tests |
examples |
boolean | false |
Build example applications |
docs |
boolean | false |
Generate Doxygen HTML documentation |
All C++ sources follow the Chromium
formatting style enforced by clang-format-19. Run locally:
scripts/format.sh # reformat in-place
scripts/format.sh --check # dry-run (CI mode)A comprehensive .clang-tidy configuration enables checks from bugprone-*,
cert-*, cppcoreguidelines-*, modernize-*, performance-*,
readability-*, and clang-analyzer-security.*. All findings are treated as
errors (WarningsAsErrors: '*').
GitHub's CodeQL analysis runs on every push and pull request, and weekly on a
schedule. The security-extended and security-and-quality query suites are
enabled.
| Platform | Compilers | Workflow |
|---|---|---|
| Ubuntu 24.04 | GCC, Clang 19 | ci.yml |
| Fedora (latest) | GCC, Clang | ci.yml |
| Ubuntu 24.04 | clang-format-19, clang-tidy-19 | lint.yml |
| Ubuntu 24.04 | CodeQL (C/C++) | codeql.yml |
| Ubuntu 24.04 | Doxygen + Sphinx (Read the Docs) | docs.yml |
A BitBake recipe is provided in meta-wayland-cxx-scanner/ for integration
into Yocto-based embedded Linux builds.
- Fork the repository and create a feature branch.
- Run
scripts/format.shbefore committing. - Ensure
meson test -C buildpasses with-Dtests=true. - Open a pull request — CI will verify formatting, clang-tidy, CodeQL, and the full test suite.
MIT — Copyright © 2026 Joel Winarske