Files
AstralZX 89cbf733b3 Add C++20 RAII wrapper around wlroots 0.20 + scenefx
Wraps wlroots' C ABI behind owning types (Display, Backend, Compositor,
Output, XdgShell/Toplevel, Seat/Cursor/Keyboard, Scene/Node/Tree) with
wl_signal -> std::function callbacks. Links the scenefx effect engine and
ships a wlr::fx animation helper. Includes a runnable tinywl-style compositor
and a scene/blur demo.

License: AGPL-3.0-only.
2026-08-29 09:12:28 +02:00

143 lines
4.5 KiB
Markdown

# wlroots++
A modern **C++20 RAII wrapper** around the
[wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.20 Wayland
compositor library. It wraps wlroots' C ABI behind owning object types so a
compositor can be written in idiomatic C++, and it links in the
[scenefx](https://github.com/wlrfx/scenefx) effect engine (blur, shadows,
rounded corners) plus a small `wlr::fx` animation helper.
wlroots has no stable ABI across versions, so wlroots++ pins a target and
exposes the scene graph, surface tree, seat, output and XDG-shell plumbing as
RAII classes with `wl_signal` → `std::function` callbacks.
## License
**AGPL-3.0-only.** This is a deliberate strong-copyleft choice: any project that
links against or uses wlroots++ must itself be released under the AGPL-3.0. See
`COPYING`.
## Target
wlroots has no stable ABI across versions, so wlroots++ pins a target:
* **wlroots 0.20** (pkg-config name `wlroots-0.20`)
* **scenefx 0.5** (pkg-config name `scenefx-0.5`)
## Building
```sh
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
```
Requires development files for: `wlroots-0.20`, `scenefx-0.5`, `wayland-server`,
`xkbcommon`, `pixman`. The library is compiled with `-DWLR_USE_UNSTABLE`, which
is propagated as a public definition to consumers.
This produces `libwlrootspp.a` plus the `scene_demo` and `tinywl` examples.
## Layout
```
include/wlr/wlr.hpp C++20 compat shim + wlroots/scenefx includes
include/wlr/signals.hpp SignalSink: wl_signal -> std::function<void(void*)>
include/wlr/display.hpp Display (wl_display lifecycle, socket, run loop)
include/wlr/backend.hpp Backend (autocreate, start, new_output/new_input)
include/wlr/compositor.hpp Renderer, Allocator, DataDeviceManager, Compositor
include/wlr/output.hpp Output, SceneOutput, OutputLayout
include/wlr/xdg_shell.hpp XdgSurface, Toplevel, XdgShell
include/wlr/seat.hpp Cursor, Keyboard, Seat
include/wlr/scene.hpp Scene, Box, Color, CornerRadii
include/wlr/node.hpp Node, Tree, Rect, Shadow, Blur, OptimizedBlur, Buffer, Surface
include/wlr/scenefx/anim.hpp wlr::fx::Easing, wlr::fx::Animated<>
include/wlr/scenefx/effect.hpp wlr::fx::Effect
src/wlrootspp.cpp version() and Node::as<T> conversions
examples/ runnable demos (scene_demo, tinywl)
```
## Examples
* `examples/scene_demo.cpp` — exercises the scene graph and scenefx blur.
* `examples/tinywl.cpp` — a minimal C++ compositor: boots, creates a headless
output, serves the full Wayland protocol (xdg_wm_base, wl_seat, wl_output,
…), and maps XDG toplevels into the scene graph.
Run the compositor (headless, for testing):
```sh
WLR_BACKENDS=headless WLR_HEADLESS_OUTPUTS=1 ./build/examples/tinywl
# prints: tinywl: WAYLAND_DISPLAY=wayland-N
WAYLAND_DISPLAY=wayland-N your-wayland-client
```
## Usage
```cpp
#include "wlr/display.hpp"
#include "wlr/backend.hpp"
#include "wlr/compositor.hpp"
#include "wlr/output.hpp"
#include "wlr/xdg_shell.hpp"
#include "wlr/scene.hpp"
int main() {
wlr::Display display;
wlr::Backend backend(display);
wlr::Renderer renderer(wlr_renderer_autocreate(backend.raw()));
renderer.init_wl_display(display);
wlr::Allocator alloc(wlr_allocator_autocreate(backend.raw(), renderer.raw()));
wlr::Compositor comp(display, renderer);
wlr::XdgShell xdg(display);
wlr::OutputLayout layout(display);
wlr::Scene scene;
backend.on_new_output([&](void* data) {
auto* o = static_cast<struct wlr_output*>(data);
wlr_output_init_render(o, alloc.raw(), renderer.raw());
wlr_scene_output_create(scene.raw(), o);
layout.add_auto_output(o);
});
xdg.on_new_toplevel([&](void* data) {
auto* t = static_cast<struct wlr_xdg_toplevel*>(data);
wlr_scene_xdg_surface_create(scene.root(), t->base);
wlr_xdg_surface_schedule_configure(t->base);
});
display.add_socket_auto();
backend.start();
display.run();
}
```
## Effects
`wlr::Scene` exposes scenefx blur controls directly:
```cpp
wlr::Scene scene;
scene.set_blur_radius(14);
scene.set_blur_num_passes(2);
scene.set_blur_brightness(1.0f);
```
Per-node corner radii, shadows and blur are available through the `Rect`,
`Shadow`, `Blur` and `Buffer` node wrappers in `wlr/node.hpp`.
## Animation helper
`wlr::fx` provides easing and an `Animated<T>` value plus an `Effect` aggregator
for driving per-node properties over time:
```cpp
wlr::fx::Effect fx;
fx.opacity().set_duration(300);
fx.opacity().set_easing(wlr::fx::Easing::InOutQuad);
fx.opacity().set(0.3f);
for (std::uint64_t t = 0; fx.animating(); t += 16) {
fx.on_frame(t);
fx.apply_to(node);
}
```