v0.4.0 9c230c3

README.md RawHistoryFolder

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

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 8

↑↓ moveenter openesc close