4 Wayland Backend
dxtr edited this page 2026-10-18 16:01:10 +02:00

Wayland Backend

The system cl-windowing/wayland is the Wayland backend, registered as :wayland. It talks to the compositor through libwayland-client, by way of cl-wl, compiles keymaps with libxkbcommon, by way of cl-xkbcommon, and draws cursor themes with libwayland-cursor where the compositor draws no cursors by name. Everywhere but on Windows, it is the backend open-window-system uses without :backend.

Its package, cl-windowing/wayland, exports the classes wayland-window-system, wayland-window, and its subclasses wayland-toplevel and wayland-popup. Programs do not need them: everything goes through cl-windowing.

Options

open-window-system passes these to the backend:

Option Meaning
:display-name The compositor's socket, such as "wayland-1". By default $WAYLAND_DISPLAY.
:connection A cl-wl:display connected already. The window system uses it, and flushes it but does not disconnect it when it closes.

With :connection, process-events dispatches every event of that display, those of objects you made yourself included. cl-windowing's own tests use it to run against cl-wl's in-process compositor.

Protocols

Global Version Needed What for
wl_compositor up to 6 Yes Surfaces. From version 6, the preferred buffer scale.
xdg_wm_base up to 6 Yes Top-level windows and popups. cl-windowing answers its pings. From version 3, popups can be placed again with reposition-popup.
zxdg_decoration_manager_v1 1 No Server-side decorations.
wp_viewporter 1 No With fractional scales: showing a frame at the window's size.
wp_fractional_scale_manager_v1 1 No Fractional scales. Used only together with wp_viewporter.
wl_seat up to 9 No Keyboard and pointer, from the first seat. cl-windowing repeats keys itself, so version 10 is not needed.
wl_output up to 4 No Output scales, for compositors without the preferred buffer scale. Followed as outputs are plugged in and out.
wp_cursor_shape_manager_v1 1 No Cursors the compositor draws by name.
wl_shm 1 No Cursor images from the user's theme, where the compositor offers no cursor shapes.
zwp_text_input_manager_v3 1 No Input methods, through text-input-v3.
wl_data_device_manager up to 3 No The clipboard. :clipboard is in window-system-capabilities with it.
zwp_pointer_constraints_v1, zwp_relative_pointer_manager_v1 1 No Confining and capturing the pointer, and the captured pointer's motion. :pointer-capture is in window-system-capabilities with both.
xdg_wm_dialog_v1 1 No Marking dialogs as dialogs, modal or not.

Without a needed global, open-window-system signals window-system-error naming it.

Windows

A window is an xdg_toplevel on a wl_surface, a wayland-toplevel.

  • create-window sets the title and the app ID, asks for server-side decorations where offered, and commits the surface without a buffer, which asks the compositor for the first configure.
  • The xdg_toplevel.configure and xdg_surface.configure events are a size proposal. A width or height of 0 leaves that dimension to the window. The serial is acknowledged with xdg_surface.ack_configure at once for a first or unchanged size, otherwise in adopt-window-size. See Resizing and Scaling.
  • xdg_toplevel.close becomes a :close event.
  • The states a configure carries decide who sizes the window. While it is maximised, fullscreen or tiled, or the user is resizing it, the compositor does, and set-window-size asks nothing. Otherwise the window takes the size set-window-size asks for by drawing at it, as xdg-shell lets a window size itself, and a configure that comes before the compositor has seen a frame at that size, proposing the old one, does not undo it.
  • window-fullscreen-p follows the fullscreen state of the configures: setting it sends set_fullscreen or unset_fullscreen, and the compositor makes the window fullscreen on the output it chooses.

A popup is an xdg_popup on a wl_surface, a wayland-popup, placed by the compositor as an xdg_positioner describes create-popup's placement. A popup that grabs takes the grab with the serial of the latest key or button press. xdg_popup.popup_done becomes a :close event, and popup-dismissed-p becomes true. See Popups.

Dialogs

A dialog is a wayland-toplevel given its parent's toplevel with xdg_toplevel.set_parent before its first commit, and, where the compositor offers xdg_wm_dialog_v1, an xdg_dialog_v1 that marks it as a dialog, with set_modal for a modal one. The xdg_dialog_v1 is destroyed before the toplevel. xdg-shell honours set_parent only for a parent that has been drawn: a dialog made on one that has not been is a toplevel of its own to the compositor, though cl-windowing still counts it the parent's dialog. The compositor places the dialog, and may show a modal one specially, as attached to its parent; it may still deliver input to the parent, which the core drops, as xdg-dialog asks of clients. See Dialogs.

Scale

Offered Scale from Told back with
wp_fractional_scale_v1 and wp_viewporter preferred_scale, in 120ths wp_viewport.set_destination, to the window's size in units; unset at scale 1
wl_surface version 6 wl_surface.preferred_buffer_scale wl_surface.set_buffer_scale
Neither The largest wl_output.scale of the outputs the surface has entered, or 1 wl_surface.set_buffer_scale

The scale is told back to the compositor in adopt-window-size, just before the frame drawn at it.

Input

  • Input comes from the first wl_seat the compositor offers. Its keyboard and pointer are taken when the seat gains them and released when it loses them, and window-system-capabilities follows.
  • Keymaps must be in the xkb_v1 format. The keymap is read from the file descriptor the compositor sends, compiled by libxkbcommon, and replaced whenever the compositor sends a new one.
  • Dead keys and compose sequences use the compose table of the locale ($LC_ALL, $LC_CTYPE or $LANG) and the user's ~/.XCompose.
  • Keys are repeated by cl-windowing, at the rate and delay of wl_keyboard.repeat_info, inside process-events.
  • Pointer events are gathered per wl_pointer.frame, from version 5. Scroll steps come from axis_value120 or axis_discrete for wheels, and from axis divided by 10 for continuous scrolling.
  • The cursor over a window is set after each wl_pointer.enter. With wp_cursor_shape_manager_v1, the compositor draws it from its name. Otherwise the backend draws it from the user's Xcursor theme, named by $XCURSOR_THEME and $XCURSOR_SIZE, through libwayland-cursor, at the window's scale, on a surface of its own, and animates animated cursors. A cursor the theme lacks is shown as :default.
  • Input methods speak text-input-v3. The caret and the surrounding text are sent when they change, and the input method's preedit_string, commit_string and delete_surrounding_text become :preedit, :text and :delete-surrounding events, in the order the protocol applies them.
  • The pointer is confined and captured through pointer-constraints-v1, with persistent constraints, and the captured pointer's motion comes from relative-pointer-v1's unaccelerated motion.
  • The clipboard is the seat's wl_data_device. Its text is read through a pipe from the program whose text it is, and offered from a wl_data_source in the MIME types text/plain;charset=utf-8, UTF8_STRING and text/plain. Setting it needs the serial of an input event, so it signals window-system-error while no window of the program has the keyboard focus.

Compositors

What to expect on some compositors:

Compositor Decorations Scales
KDE Plasma (KWin) Server-side Fractional
Sway and other wlroots compositors Server-side Fractional, in recent versions
GNOME (Mutter) None: GNOME offers no server-side decorations Fractional, in recent versions, when fractional scaling is enabled
Weston None Whole numbers, from the outputs; weston --scale=2 gives 2

On compositors without server-side decorations, windows have no title bar until the engine draws its own. They can still be moved and resized with the compositor's keyboard and pointer shortcuts.

A headless Weston, weston --backend=headless, is what the Vulkan tests present to. It has no seat, so no keyboard, pointer or clipboard to set, but it offers pointer constraints and relative pointers.

Locking

Everything the backend does on the connection happens holding the window system's lock, except the wait for the compositor, cl-wl:read-events, which cl-wl allows to run while another thread uses the display. See Threads.