main e82a709

README.md RawHistoryFolder

WLTurbo

A performance-focused, low-level Wayland client runtime for Go.

Overview

WLTurbo is the transport layer: connection, wire framing, descriptor passing, object lifecycle and the bootstrap registry. It is not a complete Wayland client. It has no windows, surfaces, seats, input handling or rendering, and it knows no protocol beyond the bootstrap objects. Protocol bindings are provided separately (see Protocol bindings).

Where it fits

Application or toolkit    windows, input, rendering, policy
└─ Protocol bindings      generated code, one package per protocol
   └─ WLTurbo             transport and objects  (this module)

Use WLTurbo directly to speak raw Wayland or to write your own bindings or toolkit. Ready-made bindings are available in go-wayland-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

This opens a connection and dispatches events. Binding globals needs the protocol packages from go-wayland-bindings.

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
2
3A performance-focused, low-level Wayland client runtime for Go.
4
5## Overview
6
7WLTurbo is the transport layer: connection, wire framing, descriptor passing, object lifecycle and the bootstrap registry. It is not a complete Wayland client. It has no windows, surfaces, seats, input handling or rendering, and it knows no protocol beyond the bootstrap objects. Protocol bindings are provided separately (see [Protocol bindings](#protocol-bindings)).
8
9## Where it fits
10
11```
12Application or toolkit    windows, input, rendering, policy
13└─ Protocol bindings      generated code, one package per protocol
14   └─ WLTurbo             transport and objects  (this module)
15```
16
17Use WLTurbo directly to speak raw Wayland or to write your own bindings or toolkit. Ready-made bindings are available in [go-wayland-bindings](https://github.com/bnema/go-wayland-bindings).
18
19## Architecture
20
21WLTurbo provides the foundational Wayland client infrastructure:
22
23- **Bootstrap Objects**: Display and Registry
24- **Event Dispatching**: Efficient routing of Wayland events to handlers
25- **Connection Management**: Unix socket communication with the compositor
26- **Memory Management**: Shared memory support via file descriptor passing
27
28Applications own rendering, input interpretation, capability fallbacks and desktop policy. WLTurbo is client-side only, not a compositor-side server implementation.
29
30## Protocol bindings
31
32Generated 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`:
33
34```go
35import "github.com/bnema/go-wayland-bindings/client/xdgshell"
36```
37
38Those packages are built on this runtime. A binding's presence does not imply that the compositor implements it.
39
40After `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.
41
42## Features
43
44- **Stream framing**: messages split across or coalesced within socket reads are framed exactly; event bodies are not copied.
45- **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them.
46- **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection.
47- **Version checks**: requests newer than the bound object version return `ErrVersionTooLow` before anything is sent.
48- **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.
49
50## Quick Start
51
52This opens a connection and dispatches events. Binding globals needs the protocol packages from `go-wayland-bindings`.
53
54```go
55package main
56
57import (
58    "github.com/bnema/wlturbo/wl"
59)
60
61func main() {
62    // Connect to Wayland display
63    display, err := wl.Connect("")
64    if err != nil {
65        panic(err)
66    }
67    defer display.Close()
68
69    // Basic event loop. Handlers run inside Dispatch and must not call
70    // Dispatch or Roundtrip on the same display.
71    for {
72        if err := display.Dispatch(); err != nil {
73            break
74        }
75    }
76}
77```
78
79For higher-level device control, [libwldevices-go](https://github.com/bnema/libwldevices-go) builds on WLTurbo.
80
81## Development checks
82
83```sh
84GOWORK=off go test ./...
85GOWORK=off go test -race ./...
86GOWORK=off go vet ./...
87GOWORK=off go test -run '^$' -bench . -benchmem
88```
89
90Socketpair tests exercise wire messages, versions, object lifecycle and file descriptors without a compositor.
91
92## Requirements
93
94- **Go 1.27+**
95- **Linux** with Wayland compositor
96- **Unix sockets** support
97
98## License
99
100MIT; see [LICENSE](LICENSE).
101
102## Contributing
103
104Contributions welcome! Areas of focus:
105- Performance improvements
106- Transport correctness and hardening
107- Documentation and examples
108- 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