This page documents the Wayland host/plugin embedding path for winelib hosts that need Wine plugin surfaces to live inside a native Wayland application.
The Wayland embed path lets a winelib host render Wine plugin windows as
wl_subsurface children of a host-owned wl_surface. It is the Wayland
counterpart to the X11 embed protocol, but the ownership model is stricter:
Wayland only allows subsurface parentage when both surfaces live on the same
wl_display connection.
Wine-NSPA solves that by letting the host publish its wl_display before
winewayland.drv initializes. In host mode, the driver adopts that display,
binds its own Wayland globals on the same connection, and creates plugin
surfaces as children of host surfaces.
The supported interface lives in include/wine/nspa_wayland_embed.h.
| Symbol | Meaning |
|---|---|
WINE_NSPA_WAYLAND_HOST |
host-mode marker; tells winewayland.drv to wait for display adoption instead of opening its own connection |
WINE_NSPA_WAYLAND_DISPLAY |
PID-stamped pointer handoff for the host wl_display |
wine_nspa_wayland_set_display() |
host helper that publishes the current process id and wl_display pointer |
WM_WAYLANDDRV_NSPA_EMBED_WINDOW |
request that a Wine HWND become a wl_subsurface of a host wl_surface |
WM_WAYLANDDRV_NSPA_EMBED_DONE |
async completion message posted after the subsurface install path runs |
The display handoff is process-local. Child Wine helper processes that inherit
the environment do not reuse the parent’s pointer because the value is checked
against getpid().
Wayland embedding has to avoid a load-order race. A driver export would be too
late because winewayland.drv initializes as soon as it is loaded. The host
therefore publishes the display pointer before the first Wine GUI call.
The host-side sequence is:
setenv ("WINE_NSPA_WAYLAND_HOST", "1", 1);
wine_nspa_wayland_set_display (juceWaylandDisplay);
Then winewayland.drv initializes against the host connection:
WINE_NSPA_WAYLAND_HOSTWINE_NSPA_WAYLAND_DISPLAYwl_compositor, wl_subcompositor, wl_shm, xdg_wm_base,
wp_viewporter, and wl_seat on that displaywl_display_connect() path for this processWhen the environment is absent or invalid, the Wayland driver follows the normal standalone Wine path.
Once the plugin has an HWND, the host sends
WM_WAYLANDDRV_NSPA_EMBED_WINDOW to that window.
| Message field | Meaning |
|---|---|
wParam |
host parent wl_surface* |
lParam |
packed parent-relative peerX, peerY coordinates |
The driver path:
wayland_win_data for the HWNDwl_displaywl_surfacewl_subsurface of the host parentWM_WAYLANDDRV_NSPA_EMBED_DONEThe fresh-surface step is important. Wayland surface roles are not mutable once
a buffer has committed in a role such as xdg_toplevel, so the embed message
must run before plugin editor attach paths cause a first commit.
Two follow-on changes make the host-mode path usable for plugin editors in an RT-oriented process.
| Area | Current behavior |
|---|---|
| Foreign-surface enter events | pointer and keyboard enter events on host-owned foreign surfaces are ignored by winewayland.drv; the host remains owner of its own surface focus |
| Driver mutexes | winewayland.drv internal pthread mutexes are converted to Wine-NSPA pi_mutex_t so Wayland driver locks follow the same priority-inheritance policy as the rest of the RT stack |
| Initialization guard | the lazy Wayland initialization path avoids a non-PI pthread mutex on the RT thread |
This matters because host-mode embedding puts native host surfaces and Wine plugin surfaces in one process and one Wayland connection. The Wine driver must not claim input focus for the host shell, and it must not introduce ordinary pthread-mutex inversion into the RT process.
The X11 and Wayland protocols solve the same application problem with different window-system primitives.
| Area | X11 path | Wayland path |
|---|---|---|
| Parent type | X11 Window id |
wl_surface* |
| Wine child type | Wine X11 child window | Wine wl_surface |
| Attach primitive | XReparentWindow() + embedded-state bookkeeping |
wl_subsurface under a foreign host surface |
| Connection rule | host and Wine can use independent X11 clients | host and Wine must share one wl_display |
| Display handoff | not needed | host publishes wl_display before driver init |
| Completion message | WM_X11DRV_NSPA_EMBED_DONE |
WM_WAYLANDDRV_NSPA_EMBED_DONE |
The consumer pump discipline is shared: embedded editors need input-first queue passes and a bounded general drain so plugin redraw or timer traffic cannot starve the native host loop.
| Consumer | Use |
|---|---|
| JUCE-NSPA | provides the Wayland peer surface and exposes the host wl_display used by Wine-NSPA’s Wayland driver |
| Lulada | enables the JUCE-NSPA Wayland backend for the application shell and embeds Windows plugin editors through the Wine-NSPA Wayland path on Wayland sessions |
Yabridge-NSPA still uses the X11 embed path because its editor bridge keeps a wrapper X11 window as the immediate foreign parent.
include/wine/nspa_wayland_embed.hdlls/winewayland.drv/window.cdlls/winewayland.drv/wayland.cdlls/winewayland.drv/wayland_pointer.cdlls/winewayland.drv/wayland_keyboard.c