main 5004296

Go bindings for Wayland protocols, generated from upstream XML

go-wayland-bindings

Go bindings for the Wayland protocols, generated from vendored upstream XML. One module is the single source of truth for both sides of the wire:

  • client/<pkg>: client bindings for the pure-Go wlturbo runtime.
  • server/<pkg>: server bindings for the libwayland-server runtime in purego-libwayland.

Everything builds with CGO_ENABLED=0.

Install

go get github.com/bnema/go-wayland-bindings@latest

Usage

Client (the runtime lives in github.com/bnema/wlturbo):

import (
	"github.com/bnema/wlturbo/wl"

	"github.com/bnema/go-wayland-bindings/client/wayland"
)

display, err := wl.Connect("")
// ...
compositor := wayland.NewCompositor(display.Context())
err = display.Registry().Bind(name, wayland.CompositorInterface, 1, compositor)

Server (the runtime lives in github.com/bnema/purego-libwayland/server):

import (
	"github.com/bnema/purego-libwayland/server"

	"github.com/bnema/go-wayland-bindings/server/wayland"
)

err := wayland.NewCompositorGlobal(display, 6, func(c server.Client, version, id uint32) {
	_, _ = wayland.NewCompositor(c, int32(version), id, myCompositorHandler{})
})

Packages

A package name derives from the XML file name: drop .xml, drop a trailing -unstable-vN, then a trailing -vN, then remove every -. So xdg-shell.xml is xdgshell, wlr-layer-shell-unstable-v1.xml is wlrlayershell, and wayland.xml is wayland. The package has the same name under client/ and server/. When several upstream versions of one protocol exist, the most stable and then highest version is used; there is one major version per protocol.

The full list, with upstream source, path, license and interfaces, is in spec/manifest.json.

Custom protocol XML

wlbgen generates bindings for a private protocol XML. Interfaces it references from the vendored protocols (such as wl_surface) are resolved automatically to the matching client/<pkg> or server/<pkg> package:

go run github.com/bnema/go-wayland-bindings/cmd/wlbgen \
    -side server -package mything -out mything_generated.go mything.xml

Use -side client for client bindings. -import iface=importpath overrides the package of one interface (repeatable); an interface that cannot be resolved is an error.

Development

Regenerate every binding from spec/manifest.json:

go generate ./...

Generated output is deterministic: a second run changes nothing. Hand-written files that live next to generated code (for example client/linuxdmabuf/table.go) are never touched.

Sync the vendored XML with upstream (needs network and git):

go run ./cmd/wlbsync            # update spec/xml and spec/manifest.json
go run ./cmd/wlbsync -check     # print changed=true|false, write nothing
go run ./cmd/wlbsync -notes notes.md

spec/manifest.json is written by wlbsync and is never edited by hand.

Releases

A scheduled workflow syncs upstream every day. When protocol XML changed it regenerates the bindings, runs the checks and publishes a new minor version v0.X.0 whose release notes list added and removed packages, interface version bumps and breaking changes. A moved upstream ref with identical XML publishes nothing, and neither does a failed run.

Tests

env CGO_ENABLED=0 go test ./...
go test -race ./...          # needs libwayland-server installed

The end-to-end tests in internal/e2e (and the race run) need libwayland-server.so.0, which the server runtime loads at run time. Without it those tests are skipped, with the reason shown by go test -v; any other server start failure still fails them.

Two environment variables enable tests that are skipped by default:

  • WLTURBO_HEADLESS: path to a headless compositor binary (NeferWL) for the end-to-end tests in client/.
  • WLTURBO_LIVE: set to 1 to run the tests that talk to the compositor of the current session.

Licenses

The code of this repository (generators, tooling, tests) is MIT licensed, copyright go-wayland-bindings contributors; see LICENSE.

The vendored XML and the bindings generated from it keep the license of the upstream protocol; each generated file carries the upstream copyright notice. Most protocols are MIT. The serverdecoration protocol (KDE server-decoration.xml) is LGPL-2.1-or-later; its text is in LICENSES/.

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 1

↑↓ moveenter openesc close