WLTurbo - Wayland Client Library for Go
A performance-focused Wayland client library that provides the foundational protocol implementation for building Wayland applications and libraries.
Overview
WLTurbo is a low-level Wayland client library with generated core and extension bindings. Applications and higher-level libraries use it to communicate with any compositor that advertises the required protocols.
Architecture
WLTurbo provides the foundational Wayland client infrastructure:
- Core Protocol Objects: Display, Registry, Compositor, Surface, Seat, Region
- Event Dispatching: Efficient routing of Wayland events to handlers
- Connection Management: Unix socket communication with the compositor
- Memory Management: Shared memory support via file descriptor passing
Bindings handle wire messages and object lifecycle. Applications own rendering, input interpretation, capability fallbacks and desktop policy. WLTurbo provides client bindings, not compositor-side server implementations.
Generated protocols
Packages under protocol/ cover:
| Area |
Packages |
| Core and windows |
core, xdgshell, xdgdecoration, xdgactivation |
| Buffers and scaling |
linuxdmabuf, drmsyncobj, viewporter, fractionalscale |
| Presentation and color |
presentation, tearingcontrol, fifo, committiming, contenttype, alphamodifier, colormanagement, colorrepresentation, drmlease |
| Input |
cursorshape, tablet, textinput, relativepointer, pointerconstraints, pointerwarp, shortcutsinhibit, virtualkeyboard, inputmethod |
| Clipboard |
Core data-device, primaryselection, datacontrol (ext-data-control) |
| Desktop and outputs |
layershell, xdgoutput, outputmanagement, outputpower, workspace, foreigntoplevel (wlr), extforeigntoplevel, kdeserverdecoration |
| Idle |
idleinhibit, idlenotify |
| Capture |
screencopy (wlr), imagecapturesource, imagecopycapture |
Each package contains the upstream XML, generated Go bindings and a generation command. Protocol sources records pinned upstream revisions and checksums. A binding's presence does not imply that the compositor implements it.
After display.Roundtrip() discovers globals, call display.Registry().BindNegotiated(interfaceName, supportedVersion, proxy) to bind at the lesser of the advertised and supported versions. It returns the negotiated version; use errors.Is(err, wlturbo.ErrGlobalNotFound) to handle absent optional globals.
Features
- Stream framing: messages split across or coalesced within socket reads are framed exactly; event bodies are not copied.
- Descriptor ownership: received FDs belong to the event that declares them and are closed if a handler does not take them.
- Object lifecycle: destroyed objects stay as zombies until
delete_id, so events already in flight are dropped instead of failing the connection.
- Version checks: generated requests newer than the bound object version return
ErrVersionTooLow before anything is sent.
- Allocation-free numeric paths: numeric generated requests without object creation or descriptors, and typed numeric events, do not allocate after warm-up; representative cases have allocation regression tests. Object creation, received strings and descriptors have separate allocation costs.
Quick Start
package main
import (
"github.com/bnema/wlturbo/wl"
)
func main() {
// Connect to Wayland display
display, err := wl.Connect("")
if err != nil {
panic(err)
}
defer display.Close()
// Basic event loop. Handlers run inside Dispatch and must not call
// Dispatch or Roundtrip on the same display.
for {
if err := display.Dispatch(); err != nil {
break
}
}
}
For higher-level device control, libwldevices-go builds on WLTurbo.
Development checks
GOWORK=off go generate ./...
GOWORK=off go test ./...
GOWORK=off go test -race ./...
GOWORK=off go vet ./...
GOWORK=off go test ./protocol -run '^$' -bench . -benchmem
Tests verify that checked-in bindings reproduce from the vendored XML. Socketpair tests exercise wire messages, versions, object lifecycle and file descriptors without a compositor.
For isolated integration tests, build NeferWL with its headless backend and pass its executable path:
env GOWORK=off WLTURBO_HEADLESS=/path/to/neferwl go test ./protocol -run Headless -v -count=1 -timeout=90s
The tests start a separate compositor with temporary runtime/config directories and no terminal or Xwayland. They do not use the running desktop session. Headless tests do not validate physical display timing, DRM leasing or hardware HDR output.
Requirements
- Go 1.27+
- Linux with Wayland compositor
- Unix sockets support
License
The transport and scanner are MIT-licensed; see LICENSE.
Vendored protocol XML and generated bindings retain upstream notices and terms.
In particular, kdeserverdecoration is LGPL-2.1-or-later. See
protocol sources, the generated file headers and the
included LGPL text.
Contributing
Contributions welcome! Areas of focus:
- Performance improvements
- Additional protocol object support
- Documentation and examples
- Benchmark suite
source
1# WLTurbo - Wayland Client Library for Go
2
3A performance-focused Wayland client library that provides the foundational protocol implementation for building Wayland applications and libraries.
4
5## Overview
6
7WLTurbo is a low-level Wayland client library with generated core and extension bindings. Applications and higher-level libraries use it to communicate with any compositor that advertises the required protocols.
8
9## Architecture
10
11WLTurbo provides the foundational Wayland client infrastructure:
12
13- **Core Protocol Objects**: Display, Registry, Compositor, Surface, Seat, Region
14- **Event Dispatching**: Efficient routing of Wayland events to handlers
15- **Connection Management**: Unix socket communication with the compositor
16- **Memory Management**: Shared memory support via file descriptor passing
17
18Bindings handle wire messages and object lifecycle. Applications own rendering, input interpretation, capability fallbacks and desktop policy. WLTurbo provides client bindings, not compositor-side server implementations.
19
20## Generated protocols
21
22Packages under `protocol/` cover:
23
24| Area | Packages |
25|---|---|
26| Core and windows | `core`, `xdgshell`, `xdgdecoration`, `xdgactivation` |
27| Buffers and scaling | `linuxdmabuf`, `drmsyncobj`, `viewporter`, `fractionalscale` |
28| Presentation and color | `presentation`, `tearingcontrol`, `fifo`, `committiming`, `contenttype`, `alphamodifier`, `colormanagement`, `colorrepresentation`, `drmlease` |
29| Input | `cursorshape`, `tablet`, `textinput`, `relativepointer`, `pointerconstraints`, `pointerwarp`, `shortcutsinhibit`, `virtualkeyboard`, `inputmethod` |
30| Clipboard | Core data-device, `primaryselection`, `datacontrol` (ext-data-control) |
31| Desktop and outputs | `layershell`, `xdgoutput`, `outputmanagement`, `outputpower`, `workspace`, `foreigntoplevel` (wlr), `extforeigntoplevel`, `kdeserverdecoration` |
32| Idle | `idleinhibit`, `idlenotify` |
33| Capture | `screencopy` (wlr), `imagecapturesource`, `imagecopycapture` |
34
35Each package contains the upstream XML, generated Go bindings and a generation command. [Protocol sources](protocol/SOURCE.md) records pinned upstream revisions and checksums. A binding's presence does not imply that the compositor implements it.
36
37After `display.Roundtrip()` discovers globals, call `display.Registry().BindNegotiated(interfaceName, supportedVersion, proxy)` to bind at the lesser of the advertised and supported versions. It returns the negotiated version; use `errors.Is(err, wlturbo.ErrGlobalNotFound)` to handle absent optional globals.
38
39## Features
40
41- **Stream framing**: messages split across or coalesced within socket reads are framed exactly; event bodies are not copied.
42- **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them.
43- **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection.
44- **Version checks**: generated requests newer than the bound object version return `ErrVersionTooLow` before anything is sent.
45- **Allocation-free numeric paths**: numeric generated requests without object creation or descriptors, and typed numeric events, do not allocate after warm-up; representative cases have allocation regression tests. Object creation, received strings and descriptors have separate allocation costs.
46
47## Quick Start
48
49```go
50package main
51
52import (
53 "github.com/bnema/wlturbo/wl"
54)
55
56func main() {
57 // Connect to Wayland display
58 display, err := wl.Connect("")
59 if err != nil {
60 panic(err)
61 }
62 defer display.Close()
63
64 // Basic event loop. Handlers run inside Dispatch and must not call
65 // Dispatch or Roundtrip on the same display.
66 for {
67 if err := display.Dispatch(); err != nil {
68 break
69 }
70 }
71}
72```
73
74For higher-level device control, [libwldevices-go](https://github.com/bnema/libwldevices-go) builds on WLTurbo.
75
76## Development checks
77
78```sh
79GOWORK=off go generate ./...
80GOWORK=off go test ./...
81GOWORK=off go test -race ./...
82GOWORK=off go vet ./...
83GOWORK=off go test ./protocol -run '^$' -bench . -benchmem
84```
85
86Tests verify that checked-in bindings reproduce from the vendored XML. Socketpair tests exercise wire messages, versions, object lifecycle and file descriptors without a compositor.
87
88For isolated integration tests, build [NeferWL](https://github.com/bnema/neferwl) with its headless backend and pass its executable path:
89
90```sh
91env GOWORK=off WLTURBO_HEADLESS=/path/to/neferwl go test ./protocol -run Headless -v -count=1 -timeout=90s
92```
93
94The tests start a separate compositor with temporary runtime/config directories and no terminal or Xwayland. They do not use the running desktop session. Headless tests do not validate physical display timing, DRM leasing or hardware HDR output.
95
96## Requirements
97
98- **Go 1.27+**
99- **Linux** with Wayland compositor
100- **Unix sockets** support
101
102## License
103
104The transport and scanner are MIT-licensed; see [LICENSE](LICENSE).
105Vendored protocol XML and generated bindings retain upstream notices and terms.
106In particular, `kdeserverdecoration` is LGPL-2.1-or-later. See
107[protocol sources](protocol/SOURCE.md), the generated file headers and the
108[included LGPL text](LICENSES/LGPL-2.1-or-later.txt).
109
110## Contributing
111
112Contributions welcome! Areas of focus:
113- Performance improvements
114- Additional protocol object support
115- Documentation and examples
116- Benchmark suite