WLTurbo - Wayland Client Library for Go
A performance-focused Wayland client runtime for Go, the foundation for protocol bindings and Wayland applications.
Overview
WLTurbo is a low-level Wayland client runtime: connection, wire framing, descriptor passing, object lifecycle and the bootstrap registry. Protocol bindings are provided separately (see Protocol bindings).
Architecture
WLTurbo provides the foundational Wayland client infrastructure:
- Bootstrap Objects: Display and Registry
- 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
Applications own rendering, input interpretation, capability fallbacks and desktop policy. WLTurbo is client-side only, not a compositor-side server implementation.
Protocol bindings
Generated protocol bindings are not part of this module. They live in github.com/bnema/go-wayland-bindings, one package per protocol under client/<pkg>, for example client/wayland, client/xdgshell and client/wlrlayershell:
import "github.com/bnema/go-wayland-bindings/client/xdgshell"
Those packages are built on this runtime. 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: requests newer than the bound object version return
ErrVersionTooLow before anything is sent.
- Allocation-free numeric paths: numeric requests sent with
Context.RequestArgs without object creation or descriptors, and typed numeric events, do not allocate after warm-up. 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 test ./...
GOWORK=off go test -race ./...
GOWORK=off go vet ./...
GOWORK=off go test -run '^$' -bench . -benchmem
Socketpair tests exercise wire messages, versions, object lifecycle and file descriptors without a compositor.
Requirements
- Go 1.27+
- Linux with Wayland compositor
- Unix sockets support
License
MIT; see LICENSE.
Contributing
Contributions welcome! Areas of focus:
- Performance improvements
- Transport correctness and hardening
- Documentation and examples
- Benchmark suite
source
1# WLTurbo - Wayland Client Library for Go
2
3A performance-focused Wayland client runtime for Go, the foundation for protocol bindings and Wayland applications.
4
5## Overview
6
7WLTurbo is a low-level Wayland client runtime: connection, wire framing, descriptor passing, object lifecycle and the bootstrap registry. Protocol bindings are provided separately (see [Protocol bindings](#protocol-bindings)).
8
9## Architecture
10
11WLTurbo provides the foundational Wayland client infrastructure:
12
13- **Bootstrap Objects**: Display and Registry
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
18Applications own rendering, input interpretation, capability fallbacks and desktop policy. WLTurbo is client-side only, not a compositor-side server implementation.
19
20## Protocol bindings
21
22Generated protocol bindings are not part of this module. They live in [github.com/bnema/go-wayland-bindings](https://github.com/bnema/go-wayland-bindings), one package per protocol under `client/<pkg>`, for example `client/wayland`, `client/xdgshell` and `client/wlrlayershell`:
23
24```go
25import "github.com/bnema/go-wayland-bindings/client/xdgshell"
26```
27
28Those packages are built on this runtime. A binding's presence does not imply that the compositor implements it.
29
30After `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.
31
32## Features
33
34- **Stream framing**: messages split across or coalesced within socket reads are framed exactly; event bodies are not copied.
35- **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them.
36- **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection.
37- **Version checks**: requests newer than the bound object version return `ErrVersionTooLow` before anything is sent.
38- **Allocation-free numeric paths**: numeric requests sent with `Context.RequestArgs` without object creation or descriptors, and typed numeric events, do not allocate after warm-up. Object creation, received strings and descriptors have separate allocation costs.
39
40## Quick Start
41
42```go
43package main
44
45import (
46 "github.com/bnema/wlturbo/wl"
47)
48
49func main() {
50 // Connect to Wayland display
51 display, err := wl.Connect("")
52 if err != nil {
53 panic(err)
54 }
55 defer display.Close()
56
57 // Basic event loop. Handlers run inside Dispatch and must not call
58 // Dispatch or Roundtrip on the same display.
59 for {
60 if err := display.Dispatch(); err != nil {
61 break
62 }
63 }
64}
65```
66
67For higher-level device control, [libwldevices-go](https://github.com/bnema/libwldevices-go) builds on WLTurbo.
68
69## Development checks
70
71```sh
72GOWORK=off go test ./...
73GOWORK=off go test -race ./...
74GOWORK=off go vet ./...
75GOWORK=off go test -run '^$' -bench . -benchmem
76```
77
78Socketpair tests exercise wire messages, versions, object lifecycle and file descriptors without a compositor.
79
80## Requirements
81
82- **Go 1.27+**
83- **Linux** with Wayland compositor
84- **Unix sockets** support
85
86## License
87
88MIT; see [LICENSE](LICENSE).
89
90## Contributing
91
92Contributions welcome! Areas of focus:
93- Performance improvements
94- Transport correctness and hardening
95- Documentation and examples
96- Benchmark suite