Help us shape the future of Go! Take the 2026 Go Developer Survey

neferclient

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 29 Imported by: 0

README

neferclient

A Wayland client toolkit library for Go: connection, outputs, surface roles, seat and DMA-BUF presentation. It does not render and holds no application policy. No cgo required.

[!WARNING] Early development. No release yet. Expect bugs and breaking changes.

Requirements

  • Linux, kernel 6.6 or newer (DRM syncobj eventfd).
  • A compositor advertising zwp_linux_dmabuf_v1 (v4) and wp_linux_drm_syncobj_manager_v1.
  • libxkbcommon at runtime for keyboard input.

Usage

The library does not render. The examples module pairs it with NeferGUI (a pure graphics library with no Wayland code); the two never import each other, and the examples copy plain fields between them. The loop runs on one owner goroutine:

conn, err := neferclient.Connect(ctx, "")
if err != nil {
	return fmt.Errorf("connect: %w", err)
}
defer conn.Close()
surf, err := conn.NewLayerSurface(neferclient.LayerConfig{Level: neferclient.LayerTop, Width: 240, Height: 90})
if err != nil {
	return fmt.Errorf("layer surface: %w", err)
}
for {
	select {
	case <-conn.Wake():
		if err := conn.Dispatch(handler); err != nil { // Configure, FeedbackDone, Frame, Pointer, Key, FDReady...
			return fmt.Errorf("dispatch: %w", err)
		}
	case <-ctx.Done():
		return nil
	}
	// render with NeferGUI, then surf.ImportBuffer / surf.ImportTimeline / surf.Present
}
Popups

Conn.NewPopup creates an xdg_popup on a layer surface, a toplevel or another popup: a menu or tooltip placed relative to an anchor rectangle of its parent. With Grab the popup takes the keyboard and the compositor dismisses it on a click outside; the grab needs the PointerEvent.Serial of the button press that opened it. The compositor can dismiss a popup at any time, so a handler must implement PopupDone (embedded NopHandler ignores it) and close the popup; close popups before their parent.

func (h *handler) Pointer(ev *neferclient.PointerEvent) {
	if ev.Kind != neferclient.PointerButton || !ev.Pressed {
		return
	}
	popup, err := h.conn.NewPopup(neferclient.PopupConfig{
		Parent: h.bar, // a layer surface
		Place: neferclient.PopupPlacement{
			Anchor: neferclient.Rect{X: 100, Y: 0, Width: 24, Height: 30}, // on the parent, logical px
			Edge:   neferclient.EdgeBottom, Gravity: neferclient.EdgeBottomRight,
			Adjust: neferclient.AdjustSlideX | neferclient.AdjustFlipY,
			Width:  200, Height: 120,
		},
		Grab: true, Serial: ev.Serial,
	})
	if err != nil {
		h.err = err
		return
	}
	h.popup = popup // presentable after Configure, like any surface
}

func (h *handler) PopupDone(id neferclient.SurfaceID) {
	if h.popup != nil && h.popup.ID() == id {
		h.err = h.popup.Close()
		h.popup = nil
	}
}

Surface.Reposition moves a mapped popup (xdg_wm_base version 3).

  • examples/layer: a layer surface with a counter button.
  • examples/lock: a session lock with a masked password field. It is a demo and authenticates nothing; read its header before running it.

Run them against a compositor with cd examples && go run ./layer. make examples-check builds, vets and lints them; the headless test needs a NeferWL binary: cd examples && NEFERCLIENT_HEADLESS=/usr/sbin/neferwl go test -run Headless ./....

License

MIT

Documentation

Overview

Package neferclient is a Wayland client toolkit library for Go: connection, outputs, surface roles, seat and DMA-BUF presentation. It does not render and holds no application policy.

Rebuilding after a dmabuf feedback change

The compositor may change its linux-dmabuf preference at any time (another main device or format table, for example when a surface moves to a GPU on another output). Every complete round calls Handler.FeedbackDone, also when nothing changed. A renderer built from the first feedback must then be rebuilt from the new one. On the owner goroutine:

  1. Keep a Feedback.Clone of the feedback each renderer was built from. In FeedbackDone, return when Feedback.Equal says the preference is the one in use.
  2. Stop watching the renderer's descriptors, call Surface.DestroyImports (a frame may be pending: that is allowed), then close the old renderer.
  3. Build the new renderer from Surface.Feedback and import its buffers and timelines on demand, as for the first one. Ids may be reused.
  4. Present again when Handler.Frame reports the pending frame; Present refuses until then, with the old renderer or the new one.

Destroying the wl_buffer and timeline objects never withdraws a commit the compositor already holds, and the duplicated descriptors are owned by the requests, so rebuilding cannot touch a destroyed object or close a descriptor twice. The compositor holds its own references to the DMA-BUFs and timelines it received, so closing the old renderer at once is safe; what the explicit-sync rule forbids is writing to or recycling storage before its release point signals.

Index

Constants

View Source
const (
	AxisVertical   = 0
	AxisHorizontal = 1
)

Scroll axes of PointerEvent.Axis.

View Source
const DefaultLayerNamespace = "neferclient"

DefaultLayerNamespace is used when LayerConfig.Namespace is empty.

Variables

View Source
var (
	// ErrClosed is returned by calls on a closed Conn.
	ErrClosed = errors.New("neferclient: connection closed")
	// ErrGlobalNotFound is returned by [Conn.Bind] when the compositor does
	// not announce the interface. Test it with errors.Is.
	ErrGlobalNotFound = wlturbo.ErrGlobalNotFound
)

Functions

This section is empty.

Types

type Anchor

type Anchor uint8

Anchor is a bit set of output edges a layer surface attaches to.

const (
	AnchorTop Anchor = 1 << iota
	AnchorBottom
	AnchorLeft
	AnchorRight
)

type Buffer

type Buffer struct {
	Width, Height int32 // physical pixels
	FourCC        uint32
	Modifier      uint64
	Planes        [4]Plane
	PlaneCount    int
}

Buffer describes a DMA-BUF to import as a wl_buffer.

type CapabilityError

type CapabilityError struct {
	Name  string
	Cause error
}

CapabilityError reports a missing or too old required protocol global.

func (*CapabilityError) Error

func (e *CapabilityError) Error() string

func (*CapabilityError) Unwrap

func (e *CapabilityError) Unwrap() error

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is one Wayland connection. Two goroutines run beside the owner: the reader, which only decodes wire events into a fixed queue, and an epoll waiter for Conn.WatchFD. Everything else — event handling, requests, Bind, Roundtrip, Outputs, Close — belongs to the owner goroutine, the one that calls Conn.Dispatch.

func Connect

func Connect(ctx context.Context, display string) (*Conn, error)

Connect dials the compositor and completes the registry setup: every wl_output announced at that point is bound and its first description is available from Conn.Outputs. display names the socket relative to $XDG_RUNTIME_DIR, or is an absolute path; "" uses $WAYLAND_DISPLAY, then "wayland-0". Cancelling ctx abandons setup; afterwards ctx is not used.

func (*Conn) Bind

func (c *Conn) Bind[P wl.Proxy](iface string, version uint32, newProxy func(*wl.Context) P) (P, uint32, error)

Bind binds the global named iface at min(announced, version) and returns the proxy and the negotiated version. newProxy creates the proxy on the given context; register its event handlers inside newProxy: the reader is paused until Bind returns, but the bound object's first events can arrive right after, so a handler added later may miss them. A missing global yields an error matching ErrGlobalNotFound.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the connection and stops both goroutines. It never requests an unlock or any other protocol shutdown; those are explicit calls. It is safe to call more than once.

func (*Conn) Context

func (c *Conn) Context() *wl.Context

Context returns the wlturbo context that generated proxies are created on.

func (*Conn) Dispatch

func (c *Conn) Dispatch(h Handler) error

Dispatch applies the events the reader queued and calls h for each one that matters to the application, on the calling goroutine. It handles at most one ring of events per call and signals Conn.Wake again if more are pending. A nil h discards the notifications but still applies the state changes. It returns the transport error once the queue is drained after the connection failed, and ErrClosed after Close.

func (*Conn) Display

func (c *Conn) Display() *wl.Display

Display returns the underlying wlturbo display. Only the owner goroutine may call Dispatch or Roundtrip on it; use Conn.Dispatch and Conn.Roundtrip instead.

func (*Conn) Lock

func (c *Conn) Lock() (*Lock, error)

Lock requests a session lock. At most one lock is live per connection. The compositor answers through Handler.Locked or Handler.LockFinished.

func (*Conn) NewLayerSurface

func (c *Conn) NewLayerSurface(cfg LayerConfig) (*Surface, error)

NewLayerSurface creates a wlr-layer-shell surface. It becomes presentable after the first Handler.Configure.

func (*Conn) NewPopup added in v0.4.0

func (c *Conn) NewPopup(cfg PopupConfig) (*Surface, error)

NewPopup creates an xdg_popup on a layer surface, a toplevel or another popup. It becomes presentable after the first Handler.Configure, which reports the size the compositor gave it. Handle Handler.PopupDone: the compositor dismisses the popup on an outside click or when the grab is denied, and the popup must then be closed.

The parent must be mapped: configured by the compositor and, for the compositor to place the popup, presented at least once. NewPopup returns an error for a parent that has not been configured yet; a compositor dismisses (PopupDone) a popup whose parent shows nothing.

A grab needs a seat and the serial of the user action. Its parent must be a toplevel or layer surface, or the grabbing popup that is the topmost of the connection's grab chain; only one chain exists at a time. Other grabs return an error before any request is sent (xdg-shell would raise a protocol error).

Close popups before their parent: Close of a surface with open child popups fails.

func (*Conn) NewToplevel

func (c *Conn) NewToplevel(title string, w, h int32) (*Surface, error)

NewToplevel creates an xdg-toplevel window with the given title and initial logical size. It becomes presentable after the first Handler.Configure.

func (*Conn) Outputs

func (c *Conn) Outputs() []Output

Outputs returns the outputs that finished their first description, ordered by Global. The slice is reused by the next call; owner goroutine only.

func (*Conn) Roundtrip

func (c *Conn) Roundtrip() error

Roundtrip sends wl_display.sync and dispatches until it returns. The reader is paused meanwhile; when Roundtrip returns, every event handled before the sync reply is queued for Conn.Dispatch (up to the ring capacity; the rest follows as the reader resumes).

func (*Conn) Seat

func (c *Conn) Seat() *Seat

Seat returns the connection's seat (nil after Close), binding wl_seat on first use. The seat is also bound when the first surface is created. Input starts flowing to the Handler once the compositor announces the capabilities.

func (*Conn) UnwatchFD

func (c *Conn) UnwatchFD(fd int) error

UnwatchFD stops watching fd. A notification already queued is dropped.

func (*Conn) Wake

func (c *Conn) Wake() <-chan struct{}

Wake returns a channel with capacity 1 that is signaled whenever events are queued: call Conn.Dispatch when it fires. A signal can be stale (the events were already drained), so Dispatch may find nothing to do.

func (*Conn) WatchFD

func (c *Conn) WatchFD(fd int, id uint64) error

WatchFD reports readability of fd through Handler.FDReady(id). The watch is one-shot: it is re-armed after each FDReady call returns. fd stays owned by the caller and must be unwatched before it is closed.

type CursorShape

type CursorShape uint32

CursorShape is a wp_cursor_shape_v1 shape. The values are the protocol's.

const (
	CursorDefault CursorShape = iota + 1
	CursorContextMenu
	CursorHelp
	CursorPointer
	CursorProgress
	CursorWait
	CursorCell
	CursorCrosshair
	CursorText
	CursorVerticalText
	CursorAlias
	CursorCopy
	CursorMove
	CursorNoDrop
	CursorNotAllowed
	CursorGrab
	CursorGrabbing
	CursorEResize
	CursorNResize
	CursorNEResize
	CursorNWResize
	CursorSResize
	CursorSEResize
	CursorSWResize
	CursorWResize
	CursorEWResize
	CursorNSResize
	CursorNESWResize
	CursorNWSEResize
	CursorColResize
	CursorRowResize
	CursorAllScroll
	CursorZoomIn
	CursorZoomOut
	CursorDndAsk    // needs cursor-shape version 2
	CursorAllResize // needs cursor-shape version 2
)

type Feedback

type Feedback struct {
	MainDevice uint64   // dev_t of the compositor's main device
	Formats    []Format // every tranche's formats, flattened in tranche order
}

Feedback is the latest complete linux-dmabuf feedback of a surface.

func (*Feedback) Clone added in v0.2.0

func (f *Feedback) Clone() *Feedback

Clone returns a deep copy that stays valid after later rounds. The value from Surface.Feedback shares memory the library reuses, so keep a Clone of the feedback a renderer was built from. A nil Feedback clones to nil.

func (*Feedback) Equal added in v0.2.0

func (f *Feedback) Equal(o *Feedback) bool

Equal reports whether f and o have the same main device and the same formats in the same order. Feedback flattens tranches, so a change limited to a tranche's target device or scanout flag is not visible here. A nil Feedback equals only nil. The compositor sends a complete round again whenever it re-evaluates its preference, often unchanged, so compare against the feedback a renderer was built from before rebuilding it.

type Format

type Format struct {
	FourCC   uint32
	Modifier uint64
}

Format is one DRM format and modifier pair from linux-dmabuf feedback.

type Handler

type Handler interface {
	// OutputAdded reports an output that became complete after [Connect]
	// returned: the compositor sent its first wl_output.done. Outputs that
	// existed during Connect are not reported; read them with [Conn.Outputs].
	// Later property changes are applied to [Conn.Outputs] silently. out is
	// valid only during the call.
	OutputAdded(out *Output)
	// OutputRemoved reports that the wl_output global went away. The output is
	// already gone from [Conn.Outputs].
	OutputRemoved(global uint32)
	// FDReady reports that a descriptor registered with [Conn.WatchFD] is
	// readable. The watch is re-armed when the call returns. It can be
	// spurious: drain the descriptor without blocking.
	FDReady(id uint64)
	// Error reports a non-fatal failure while handling an event, for example
	// a wl_output that could not be bound. Fatal transport errors are returned
	// by Dispatch instead.
	Error(err error)

	// Configure reports the logical size of a surface after the compositor's
	// configure was acknowledged (the library acks internally). The first
	// call makes the surface presentable. For layer surfaces an axis the
	// compositor leaves unchanged keeps its previous size.
	Configure(id SurfaceID, width, height int32)
	// Scale reports a changed preferred scale: fractional (n/120) when the
	// compositor supports wp_fractional_scale, else the integer buffer scale.
	// Re-read [Surface.PhysicalSize] and render again.
	Scale(id SurfaceID, scale float64)
	// Frame reports that the frame callback requested by the last
	// [Surface.Present] fired; the next Present is allowed.
	Frame(id SurfaceID)
	// Closed reports that the compositor closed the surface (toplevel close,
	// layer surface closed). Call [Surface.Close]; nothing else happens
	// automatically.
	Closed(id SurfaceID)
	// PopupDone reports that the compositor dismissed a popup created with
	// [Conn.NewPopup]: an outside click, a denied grab, or a gone parent. Call
	// [Surface.Close] on it (and on its own child popups first).
	PopupDone(id SurfaceID)
	// FeedbackDone reports that a complete linux-dmabuf feedback round was
	// applied; [Surface.Feedback] holds the new main device and formats. It
	// is sent again whenever the compositor changes its preference.
	FeedbackDone(id SurfaceID)
	// Locked reports ext_session_lock_v1.locked for the live [Lock]: every
	// output is protected. Only now may [Lock.Unlock] be called.
	Locked()
	// LockFinished reports ext_session_lock_v1.finished: the compositor
	// refused or ended the lock. Destroy it with [Lock.Close].
	LockFinished()

	// Pointer reports pointer input over one of the connection's surfaces:
	// enter, leave, motion, buttons and scrolling. ev is valid only during the
	// call.
	Pointer(ev *PointerEvent)
	// Key reports a key press, repeat or release for the surface that has
	// keyboard focus. Text is the text the key produced (nil for releases and
	// keys without text) and is valid only during the call. While a
	// [SecretBuffer] is installed with [Seat.SetSecret], Text is always nil
	// and the text goes into the buffer; see [Handler.SecretChanged]. For
	// those keys (press, repeat and release) ev.Secret is set and Keycode and
	// Keysym are 0, so the event does not reveal the typed character; Enter,
	// Escape, BackSpace and Control combinations keep their keysym. ev is
	// valid only during the call.
	Key(ev *KeyEvent)
	// KeyboardFocus reports that a surface gained or lost keyboard focus.
	KeyboardFocus(id SurfaceID, focused bool)
	// SecretChanged reports that a key press, repeat or backspace changed the
	// installed [SecretBuffer]; count is its length in code points. It is
	// called after the [Handler.Key] call of that key.
	SecretChanged(count int)
}

Handler receives the events Conn.Dispatch drains. Every method is called on the goroutine that called Dispatch, never on the reader goroutine, so an implementation may send requests and call Conn.Bind, Conn.Roundtrip, Conn.WatchFD and Conn.UnwatchFD from inside any method. It must not call Dispatch.

type KeyEvent

type KeyEvent struct {
	Surface   SurfaceID
	Keycode   uint32 // evdev key code; 0 when Secret is set
	Keysym    uint32 // xkb keysym in the current layout and modifier state; 0 when Secret is set
	Modifiers Modifiers
	Group     uint32 // effective layout index
	Pressed   bool
	Repeat    bool
	// Secret is set while a [SecretBuffer] is installed, for the press,
	// repeats and release of a key that produced text (or is a dead or compose
	// key): the text went into the buffer, and Keycode and Keysym are 0 so the
	// event does not reveal which character was typed. Other keys (Enter,
	// Escape, BackSpace, modifiers, Control combinations) keep their keysym.
	Secret bool
	// Text is the UTF-8 text of the key, nil for releases and keys without
	// text. It aliases library storage that is wiped when Handler.Key
	// returns. It is always nil while a [SecretBuffer] is installed.
	Text []byte
}

KeyEvent is one key press, repeat or release.

type KeyboardMode

type KeyboardMode uint8

KeyboardMode is the layer surface keyboard interactivity. The zero value is KeyboardNone. KeyboardOnDemand needs zwlr_layer_shell_v1 version 4.

const (
	KeyboardNone KeyboardMode = iota
	KeyboardExclusive
	KeyboardOnDemand
)

type LayerConfig

type LayerConfig struct {
	Output        string // wl_output name; empty lets the compositor choose
	Namespace     string // defaults to [DefaultLayerNamespace]
	Level         LayerLevel
	Anchors       Anchor
	Keyboard      KeyboardMode
	ExclusiveZone int32    // >0 reserves, 0 neutral, -1 ignores other zones
	Margin        [4]int32 // top, right, bottom, left
	// InputRects, when non-nil, restricts pointer input to these rectangles
	// (logical pixels). An empty non-nil slice makes the surface click-through.
	InputRects []Rect
	// Width and Height are the requested logical size. They are required on
	// every axis that is not anchored to both opposite edges.
	Width, Height int32
}

LayerConfig requests a wlr-layer-shell surface. Width and Height give the initial logical size; an axis anchored to both opposite edges is sized by the compositor and reported through Handler.Configure.

type LayerLevel

type LayerLevel uint8

LayerLevel is the wlr-layer-shell stacking layer. The zero value is invalid.

const (
	LayerBackground LayerLevel = iota + 1
	LayerBottom
	LayerTop
	LayerOverlay
)

type Lock

type Lock struct {
	// contains filtered or unexported fields
}

Lock is an ext-session-lock-v1 session lock. It reports Handler.Locked once every output is protected and Handler.LockFinished if the compositor refuses or ends it. Closing the connection or destroying surfaces never unlocks; only Lock.Unlock after Locked does. Owner goroutine only.

func (*Lock) Close

func (l *Lock) Close() error

Close destroys a lock that never reached Locked (refused or abandoned). A locked session is only ended by Unlock, so Close fails once Locked was applied. Because the compositor may have sent locked before it processes the destroy request (which would then be a protocol error), Close first roundtrips and looks through the queued events: if a locked event for this lock is already queued it is treated as applied (Handler.Locked is still delivered by the next Dispatch) and Close fails with the same error.

func (*Lock) Locked

func (l *Lock) Locked() bool

Locked reports whether the compositor confirmed the lock (applied by Dispatch) and it has not finished.

func (*Lock) NewSurface

func (l *Lock) NewSurface(output uint32) (*Surface, error)

NewSurface creates the lock surface covering the output with the given registry name (see Output.Global). It becomes presentable after the first Handler.Configure; a lock surface is always opaque and takes all input.

func (*Lock) Unlock

func (l *Lock) Unlock() error

Unlock sends unlock_and_destroy and roundtrips so the compositor processed it before the caller closes anything. It is only valid after Handler.Locked. The lock surfaces must be closed afterwards (or before: both are legal).

type Modifiers

type Modifiers uint8

Modifiers is the set of active keyboard modifiers.

const (
	ModShift Modifiers = 1 << iota
	ModCtrl
	ModAlt
	ModSuper
	ModCapsLock
	ModNumLock
)

type NopHandler

type NopHandler struct{}

NopHandler implements every Handler method as a no-op. Embed it in a handler and override only the methods you need; methods added to Handler in later versions get their no-op here, so embedding keeps the type compiling.

func (NopHandler) Closed

func (NopHandler) Closed(SurfaceID)

func (NopHandler) Configure

func (NopHandler) Configure(SurfaceID, int32, int32)

func (NopHandler) Error

func (NopHandler) Error(error)

func (NopHandler) FDReady

func (NopHandler) FDReady(uint64)

func (NopHandler) FeedbackDone

func (NopHandler) FeedbackDone(SurfaceID)

func (NopHandler) Frame

func (NopHandler) Frame(SurfaceID)

func (NopHandler) Key

func (NopHandler) Key(*KeyEvent)

func (NopHandler) KeyboardFocus

func (NopHandler) KeyboardFocus(SurfaceID, bool)

func (NopHandler) LockFinished

func (NopHandler) LockFinished()

func (NopHandler) Locked

func (NopHandler) Locked()

func (NopHandler) OutputAdded

func (NopHandler) OutputAdded(*Output)

func (NopHandler) OutputRemoved

func (NopHandler) OutputRemoved(uint32)

func (NopHandler) Pointer

func (NopHandler) Pointer(*PointerEvent)

func (NopHandler) PopupDone added in v0.4.0

func (NopHandler) PopupDone(SurfaceID)

func (NopHandler) Scale

func (NopHandler) Scale(SurfaceID, float64)

func (NopHandler) SecretChanged

func (NopHandler) SecretChanged(int)

type Output

type Output struct {
	Global        uint32 // registry name; identifies the output for its lifetime
	Name          string // wl_output.name, empty before version 4
	Scale         int32  // integer scale, 1 until announced
	Width, Height int32  // current mode in physical pixels
}

Output describes one wl_output after its latest wl_output.done. Only wl_output globals of version 2 or later are bound (version 1 has no done event, so its description is never known to be complete); older ones are ignored.

type Plane

type Plane struct {
	FD     int
	Offset uint32
	Stride uint32
}

Plane is one DMA-BUF plane of a Buffer. FD stays owned by the caller.

type PointerEvent

type PointerEvent struct {
	Surface  SurfaceID
	Kind     PointerKind
	X, Y     float64
	DX, DY   float64 // PointerAxis: continuous scroll value
	Button   uint32  // PointerButton: evdev button code
	Pressed  bool    // PointerButton
	Axis     uint32  // PointerAxis, PointerAxisStop: AxisVertical or AxisHorizontal
	Value120 int32   // PointerAxis: wheel value in 1/120 notches
	Serial   uint32  // PointerEnter, PointerButton: the event serial (popup grabs, activation)
}

PointerEvent is one pointer event over a surface of the connection. X and Y are surface-local logical pixels (already logical: never divide by scale) and hold the latest position for every kind.

type PointerKind

type PointerKind uint8

PointerKind tells which pointer event a PointerEvent is.

const (
	PointerEnter PointerKind = iota + 1
	PointerLeave
	PointerMotion
	PointerButton
	// PointerAxis is a scroll step on Axis. DX or DY carry the continuous
	// value in logical pixels; Value120 carries the wheel value in 1/120 of a
	// notch. A compositor can send both for one physical step: use one.
	PointerAxis
	// PointerAxisStop ends a scroll sequence on Axis.
	PointerAxisStop
)

type PopupAdjust added in v0.4.0

type PopupAdjust uint8

PopupAdjust is a bit set telling the compositor how to move a popup that would not fit on the output. The bits equal xdg_positioner constraint_adjustment.

const (
	AdjustSlideX PopupAdjust = 1 << iota
	AdjustSlideY
	AdjustFlipX
	AdjustFlipY
	AdjustResizeX
	AdjustResizeY
)

type PopupConfig added in v0.4.0

type PopupConfig struct {
	// Parent is a layer surface, a toplevel or another popup. It must be open.
	Parent *Surface
	Place  PopupPlacement
	// Grab takes an explicit grab: the popup gets the keyboard and is
	// dismissed by a click outside it. It needs a bound seat.
	Grab bool
	// Serial is the [PointerEvent.Serial] of the press that opened the popup.
	// It is required (non-zero) with Grab.
	Serial uint32
}

PopupConfig requests an xdg_popup.

type PopupEdge added in v0.4.0

type PopupEdge uint8

PopupEdge names an edge or corner, used both as the anchor on the parent's anchor rectangle and as the gravity of the popup. The values equal the xdg_positioner anchor and gravity enums.

const (
	EdgeNone PopupEdge = iota
	EdgeTop
	EdgeBottom
	EdgeLeft
	EdgeRight
	EdgeTopLeft
	EdgeBottomLeft
	EdgeTopRight
	EdgeBottomRight
)

type PopupPlacement added in v0.4.0

type PopupPlacement struct {
	Anchor        Rect // on the parent surface; Width and Height must be > 0
	Edge, Gravity PopupEdge
	Adjust        PopupAdjust
	Offset        [2]int32
	Width, Height int32 // popup size; must be > 0
}

PopupPlacement tells the compositor where a popup goes relative to its parent. Every length is in logical pixels.

type Present

type Present struct {
	Buffer          uint64
	AcquireTimeline uint64
	ReleaseTimeline uint64
	AcquirePoint    uint64
	ReleasePoint    uint64
	Damage          []Rect // nil or empty damages the whole buffer
	Opaque          bool   // the whole surface is opaque
}

Present describes one commit: which imported buffer, the explicit-sync timelines and points, and the damage in buffer pixels.

type Rect

type Rect struct{ X, Y, Width, Height int32 }

Rect is an integer rectangle: surface-local logical pixels for input regions, buffer pixels for damage.

type Seat

type Seat struct {
	// contains filtered or unexported fields
}

Seat is the connection's first wl_seat: pointer, keyboard and cursor. It belongs to the owner goroutine. Without a seat global every method is a no-op. The seat is bound once, at first use: a seat announced later is not picked up, and a removed one is not replaced (no seat hotplug).

func (*Seat) SetCursor

func (s *Seat) SetCursor(shape CursorShape) error

SetCursor asks the compositor to show shape for the pointer. It is a no-op when the compositor has no cursor-shape support, the pointer is outside the connection's surfaces, or shape is unchanged since the last enter.

func (*Seat) SetSecret

func (s *Seat) SetSecret(b *SecretBuffer)

SetSecret installs b to receive typed text, or removes it with nil. While installed, printable text goes only into b and never into KeyEvent.Text; BackSpace removes one code point; every other key is still delivered as a KeyEvent without text. Keys that produced text are delivered with KeyEvent.Secret set and Keycode and Keysym 0, for the press, repeats and release; Enter, Escape, BackSpace and Control combinations keep their keysym. Installing or removing cancels held keys and repeat. The previous buffer is not wiped: that is the caller's call.

Limits: runtime/secret (GOEXPERIMENT=runtimesecret) erases Go registers, stack and heap temporaries, but not the native memory of libxkbcommon, which processes the key text.

type SecretBuffer

type SecretBuffer struct {
	// contains filtered or unexported fields
}

SecretBuffer collects text typed while it is installed with Seat.SetSecret, for example a password. Its storage is allocated once at full size, so it never reallocates and leaves no stale copies behind; the text is never turned into a string by the library.

Only the owner goroutine (the one calling Conn.Dispatch) may use it.

func NewSecretBuffer

func NewSecretBuffer(capacity int) *SecretBuffer

NewSecretBuffer returns a buffer holding up to capacity code points. capacity is clamped to 1..4096.

func (*SecretBuffer) Bytes

func (b *SecretBuffer) Bytes() []byte

Bytes returns the UTF-8 text held. The slice aliases the buffer: do not retain it, convert it to a string or log it; it changes on the next edit.

func (*SecretBuffer) Len

func (b *SecretBuffer) Len() int

Len returns the number of code points held.

func (*SecretBuffer) Wipe

func (b *SecretBuffer) Wipe()

Wipe zeroes the whole storage and empties the buffer.

type Surface

type Surface struct {
	// contains filtered or unexported fields
}

Surface is one wl_surface with its role and the DMA-BUF presentation objects. Every method belongs to the owner goroutine.

func (*Surface) Close

func (s *Surface) Close() error

Close destroys the surface, its buffers, timelines and role objects, children before parents. It is safe to call more than once. The caller must stop using buffers it imported first (the compositor keeps them until it processes the destruction).

xdg-shell requires the topmost popup to go first: Close fails, and destroys nothing, while popups created on this surface are still open. Close them first.

func (*Surface) DestroyBuffer

func (s *Surface) DestroyBuffer(id uint64) error

DestroyBuffer destroys an imported wl_buffer. The compositor may still read it until its release point signals; see the explicit-sync rules.

func (*Surface) DestroyImports added in v0.2.0

func (s *Surface) DestroyImports() error

DestroyImports destroys every imported buffer and timeline of the surface, so a renderer built from older dmabuf feedback can be replaced by one that imports its buffers again under any ids (the old ids are free afterwards). It is safe while a frame is pending and when nothing is imported.

Present refuses the old ids from now on, so nothing is sent on a destroyed object. A frame callback already requested still fires and is delivered as usual; the next Present waits for it as always. The compositor keeps the content and the DMA-BUF references of a commit it already received: destroying a wl_buffer or a timeline never withdraws a commit, and the descriptors were duplicated at import, so none is closed twice. The caller may drop its own references to the storage (close the renderer) at once, but must not write to or recycle it before the release points of the commits that used it signal (the explicit-sync rule).

Every object is destroyed exactly once, even if a request fails; the errors are joined. It returns ErrClosed after Surface.Close or Conn.Close. See Feedback.Equal and the package documentation.

func (*Surface) DestroyTimeline

func (s *Surface) DestroyTimeline(id uint64) error

DestroyTimeline destroys an imported timeline object. The id is the one given to Surface.ImportTimeline; it may be imported again afterwards. Do not destroy a timeline that a pending commit still references. Surface.Close destroys every remaining timeline.

func (*Surface) Feedback

func (s *Surface) Feedback() *Feedback

Feedback returns the latest complete dmabuf feedback, or nil before the first Handler.FeedbackDone. The value and its slice stay valid until the next FeedbackDone; use Feedback.Clone to keep it, and Feedback.Equal to tell a changed preference from a repeated one.

func (*Surface) ID

func (s *Surface) ID() SurfaceID

ID returns the surface's identifier used in Handler callbacks.

func (*Surface) ImportBuffer

func (s *Surface) ImportBuffer(id uint64, b *Buffer) (err error)

ImportBuffer creates a wl_buffer from b under the caller's id. The plane descriptors are duplicated internally; the caller keeps ownership of its own.

func (*Surface) ImportTimeline

func (s *Surface) ImportTimeline(id uint64, fd int) error

ImportTimeline imports a DRM syncobj timeline. fd is duplicated internally.

func (*Surface) PhysicalSize

func (s *Surface) PhysicalSize() (int32, int32, error)

PhysicalSize returns the buffer size in pixels for the current logical size and scale.

func (*Surface) Present

func (s *Surface) Present(p *Present) error

Present commits an imported buffer. It refuses before the first configure, before the first complete dmabuf feedback and while the previous frame callback is pending.

func (*Surface) Reposition added in v0.4.0

func (s *Surface) Reposition(p PopupPlacement) error

Reposition asks the compositor to place the popup again. The following Handler.Configure reports the resulting size. It needs xdg_wm_base version 3.

func (*Surface) SetInputRegion

func (s *Surface) SetInputRegion(rects []Rect) error

SetInputRegion sets the input region (logical pixels). nil restores the whole surface; a non-nil empty slice passes all input through. The region is double-buffered state: it is committed immediately only once the surface presented a buffer; before that the next Present applies it (committing earlier would map a surface without a buffer, which lock surfaces forbid and layer surfaces answer with an error). Lock surfaces always take all input and refuse it.

func (*Surface) Size

func (s *Surface) Size() (w, h int32, scale float64)

Size returns the current logical size and scale (1 until announced). Before the first configure the size is the requested one (zero for lock surfaces).

func (*Surface) WLSurface added in v0.3.0

func (s *Surface) WLSurface() *wayland.Surface

WLSurface returns the wl_surface proxy, for requests of protocol extensions bound with Conn.Bind that take a surface argument, or nil after Surface.Close. The Surface owns it: use it only as a request argument; do not call its methods or add handlers. Owner goroutine only.

Handlers of objects bound with Conn.Bind run on the reader goroutine. To wait for their answer, keep calling Conn.Dispatch on Conn.Wake: the reader stops reading while the event queue is full.

type SurfaceID

type SurfaceID uint32

SurfaceID identifies a Surface in Handler callbacks. IDs are never reused within a connection.

Directories

Path Synopsis
internal
secret
Package secret runs key translation that touches secret text under runtime/secret when the toolchain provides it (GOEXPERIMENT=runtimesecret), and plainly otherwise.
Package secret runs key translation that touches secret text under runtime/secret when the toolchain provides it (GOEXPERIMENT=runtimesecret), and plainly otherwise.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL