7 Raw FFI Layer
dxtr edited this page 2026-10-17 10:13:26 +02:00

Raw FFI Layer

cl-wl/ffi is a direct transcription, on cl-ffi, of the libwayland-client functions cl-wl uses. It sits under the idiomatic layer, and cl-wl depends on it. It checks no errors and manages no memory. Prefer the cl-wl package for everything it covers. When you need a raw pointer, cl-wl:proxy-pointer, cl-wl:shared-memory-pointer or cl-wl:interface-pointer is usually all you need.

(asdf:load-system :cl-wl/ffi)

Loading it loads libwayland-client.so.0 (or libwayland-client.so) through cl-ffi. The foreign library is named cl-wl/ffi:libwayland-client.

Names

C names are spelled the Lisp way: wl_display_connect becomes wl-display-connect. Pointers are cl-ffi foreign pointers, and C strings are passed as pointers. Where the C name is already a Common Lisp symbol, the binding names what it does: close is close-fd, ftruncate is truncate-fd, and read and write are read-fd and write-fd.

Functions

Displays

Function C Returns
wl-display-connect name wl_display_connect display pointer, null on failure; name is a C string pointer or null
wl-display-connect-to-fd fd wl_display_connect_to_fd display pointer, null on failure
wl-display-disconnect display wl_display_disconnect —
wl-display-get-fd display wl_display_get_fd fd
wl-display-dispatch-pending display wl_display_dispatch_pending events dispatched, -1 on error
wl-display-roundtrip display wl_display_roundtrip events dispatched, -1 on error
wl-display-flush display wl_display_flush bytes sent, -1 on error
wl-display-get-error display wl_display_get_error errno of the fatal error, or 0
wl-display-get-protocol-error display interface id wl_display_get_protocol_error error code; stores the interface and id
wl-display-prepare-read display wl_display_prepare_read 0, or -1 if the queue must be dispatched first
wl-display-read-events display wl_display_read_events 0, or -1 on error
wl-display-cancel-read display wl_display_cancel_read —

Proxies

Function C
wl-proxy-marshal-array-flags proxy opcode interface version flags args wl_proxy_marshal_array_flags
wl-proxy-add-dispatcher proxy dispatcher implementation data wl_proxy_add_dispatcher
wl-proxy-destroy proxy wl_proxy_destroy
wl-proxy-get-version proxy wl_proxy_get_version
wl-proxy-get-id proxy wl_proxy_get_id
wl-proxy-get-class proxy wl_proxy_get_class (returns a Lisp string)

The marshal function is inlined, so that passing it a stack-allocated argument array allocates nothing: requests are sent every frame.

+marshal-flag-destroy+ is WL_MARSHAL_FLAG_DESTROY.

libc

The event loop and shared memory need a little libc, which is bound here too. Every constant has the same value on Linux and the BSDs.

Function C Used for
poll fds nfds timeout poll waiting for the connection and for pipes; inlined, so waiting allocates nothing
strerror errnum strerror error messages
memfd-create name flags memfd_create shared memory
truncate-fd fd length ftruncate sizing shared memory
mmap address length protection flags fd offset mmap mapping shared memory and keymaps
munmap address length munmap
memcpy destination source count memcpy write-shared-memory; inlined, with the destination as an integer address, so a copy allocates nothing
close-fd fd close cl-wl:close-fd and read-keymap; close a received fd with cl-wl:close-fd, which signals wl-error if it fails
pipe2 fds flags pipe2 make-pipe: stores the read and write ends at fds, an int[2]
read-fd fd buffer count read receive-text
write-fd fd buffer count write send-text

Struct and constants: pollfd (slots fd, events, revents), +pollin+, +pollout+, +eintr+, +epipe+, +prot-read+, +prot-write+, +map-shared+, +map-private+, +mfd-cloexec+, +o-cloexec+, whose value differs between Linux and the BSDs, and +map-failed+, the address mmap returns on failure, as an integer.

Structs and unions

Type Slots
(:struct wl-message) name, signature, types
(:struct wl-interface) name, version, method-count, methods, event-count, events
(:struct wl-array) size, alloc, data
(:union wl-argument) i, u, f, s, o, n, a, h

Note that the wl_interface tables are not static data in cl-wl. C bindings compile them in, but cl-wl builds them in foreign memory per display, and cl-wl:interface-pointer builds them for other code. See Internals.

Implementation-specific code

cl-wl has none. What it needs beyond standard Common Lisp comes from cl-ffi:

  • cl-ffi:errno: the calling thread's errno after a foreign call.
  • cl-ffi:make-pointer: a pointer to an integer address, which allocates nothing when only read through.