185 lines
9.9 KiB
Markdown
185 lines
9.9 KiB
Markdown
# wo compositor
|
|
|
|
Wo is an Electron-centered Smithay Wayland compositor. The portal backend is
|
|
available as `xdg-desktop-portal-wo`; run `wo portals` to start it directly.
|
|
The packaged xdg-desktop-portal configuration also starts it on demand.
|
|
|
|
## User-local install
|
|
|
|
With Rust, Bun, and Python 3 installed, run `just install` from this checkout.
|
|
It builds Wo, Electron, and comraw, then installs them under `~/.local` and
|
|
`$XDG_DATA_HOME/wo`. On first install it copies `config.example.toml` to
|
|
`$XDG_CONFIG_HOME/wo/config.toml` and configures the copied comraw build to be
|
|
served locally. Existing user configuration is preserved. Add `~/.local/bin`
|
|
to `PATH` and select the Wo session from your display manager.
|
|
|
|
## Portal requests in the Wo API
|
|
|
|
Renderer code can subscribe to compositor-mediated requests and resolve them
|
|
through the context-isolated API. Requests are denied by default if the
|
|
application does not respond.
|
|
|
|
```ts
|
|
const unsubscribe = window.woClient.portals.onRequest(async ({ requestId, payload }) => {
|
|
const allowed = await showConsentDialog(payload);
|
|
await window.woClient.portals.respond(requestId, {
|
|
allowed,
|
|
type: 'monitor', // or 'window'
|
|
windowName: null,
|
|
});
|
|
});
|
|
```
|
|
|
|
The API is also available as `window.compositor.portals` in compositor UI
|
|
contexts. Portal approval transport uses a per-user runtime socket with owner
|
|
only permissions.
|
|
|
|
## Desktop and system APIs
|
|
|
|
Wo exposes a typed convenience layer as `window.compositor` and
|
|
`window.woClient`:
|
|
|
|
```ts
|
|
const directories = await window.compositor.xdg.directories();
|
|
const apps = await window.compositor.desktop.applications.list();
|
|
await window.compositor.desktop.applications.launch('org.gnome.Terminal.desktop');
|
|
const icon = await window.compositor.icons.resolve('utilities-terminal', { size: 48 });
|
|
const names = await window.compositor.dbus.listNames('user');
|
|
```
|
|
|
|
Desktop entries are read from the XDG data directories, localized names and
|
|
user directories are honored, icons are resolved from XDG icon themes, and
|
|
desktop `Exec` fields are launched as argument vectors without a shell. The
|
|
D-Bus helpers use `busctl`; call arguments should include a D-Bus signature.
|
|
`window.compositor.audio` lists PipeWire audio sources and can forward PCM from
|
|
a desktop monitor source to the renderer. PipeWire and `pw-cat` must be
|
|
available. Audio forwarding is exposed separately from ScreenCast because the
|
|
standard XDG ScreenCast stream contains video, not a companion audio stream.
|
|
|
|
## Website-first Wo API and component overlays
|
|
|
|
Wo treats loaded pages as websites first: ordinary pages receive no compositor
|
|
bridge. A site can publish `/_wo.capabilities.json` and
|
|
`/_wo.components.css`. The manifest requests named APIs and binds the request to
|
|
the exact `index.html` SHA-256, a stylesheet SHA-256, and SHA-256 values for its
|
|
script assets. Wo prefetches and verifies those files before navigation, caches
|
|
verified assets by URL and hash, then asks the user before exposing the
|
|
requested API groups. Granting access applies only to that page/window; a
|
|
top-level navigation revokes it. Scripts for a manifest-enabled page are served
|
|
from Wo's verified cache, and unlisted script loads are blocked. A saved grant
|
|
is reused only for the same origin, document hash, declared script hashes, and
|
|
capability request.
|
|
|
|
The available permission names are `window-management`, `overlay-rendering`,
|
|
`desktop-applications`, `xdg`, `dbus`, `portals`, `filesystem`,
|
|
`process-launch`, `system-control`, `notifications`, `audio-capture`, and
|
|
`settings`. A
|
|
page can inspect `window.wo.permissions.requested`, `.granted`, and `.has(name)`.
|
|
The compositor bridge groups (`window.compositor` and `window.woClient`) are
|
|
present only after at least one API group is approved; unapproved groups are
|
|
omitted and their IPC operations remain denied by the main process.
|
|
|
|
Pages granted `portals` can open a desktop context menu with
|
|
`await window.wo.portals.contextMenu({ x, y, items })`. It resolves with the
|
|
selected item ID after dismissal. Electron delegates the menu to the native
|
|
desktop popup implementation, so Wayland presents it as a popup surface and it
|
|
uses the desktop's native menu theme. Root portal UIs such as comraw's screen
|
|
share prompt can be themed with `_wo.components.css`.
|
|
|
|
Comraw publishes `_wo.capabilities.json`, its schema, and `_wo.components.css`
|
|
from `comraw/public`. The schema is `_wo.capabilities.schema.json`. Its Vite
|
|
production build writes the current `index.html` hash, stylesheet hash, and
|
|
script hashes into the public manifest, so the request stays tied to the exact
|
|
build. The development server generates the matching index and stylesheet
|
|
hashes on request. Wo sends the verified
|
|
document and stylesheet bytes to the compositor, which computes SHA-256 itself
|
|
and stores both hashes against the owning window. `_wo.components.css` provides
|
|
component theme tokens and keyboard focus styling that Wo preloads and applies
|
|
to the page. Websites can use the same manifest format to request a window
|
|
surface or use the overlay-rendering bridge for HTML/CSS/JS surfaces.
|
|
|
|
API consent is remembered per origin and exact site build. Wo records the
|
|
verified HTML hash, the declared JavaScript asset hashes, and the requested
|
|
capability set. The grant survives restarts; changing the HTML, a declared
|
|
script, or requested capabilities produces a new consent request. Sites with
|
|
`settings` can use `window.wo.settings` (`get`, `set`, `remove`, `keys`) for
|
|
persistent JSON values. Wo keeps each web origin in its own user settings file
|
|
with owner-only permissions, so apps can share their settings across pages on
|
|
the same origin without sharing them with other hosts. Store passwords and
|
|
tokens with `getSecret`, `setSecret`, and `removeSecret`; Wo encrypts these using
|
|
GNOME Keyring/Secret Service or KDE Wallet and declines secret writes when a
|
|
secure desktop keyring is unavailable.
|
|
|
|
Sites with `window-management` can subscribe to the compositor's monitor
|
|
layout with `window.wo.windows?.monitors(callback)`. Sites with
|
|
`overlay-rendering` can pin an element to a monitor's global desktop rectangle:
|
|
|
|
```ts
|
|
const unmount = window.wo.overlay?.mount(element, monitor.id);
|
|
// Call unmount() to restore the element's original inline positioning.
|
|
```
|
|
|
|
Monitor coordinates are global desktop coordinates, so pointer positions and
|
|
window placement remain consistent when an element is mounted on another
|
|
display.
|
|
|
|
Comraw provides four persistent virtual desktops. Windows and their transient
|
|
dialogs are assigned together, hidden from other desktops, and can be moved
|
|
from the window titlebar; each monitor has an independent desktop selection,
|
|
and Ctrl+Alt+Left/Right switches desktops on the monitor under the pointer.
|
|
The DRM backend discovers connected outputs, assigns compatible CRTCs, places
|
|
them side by side, and composites the shared desktop scene into a per-output
|
|
swapchain. Native Wayland windows use the same global Smithay `Space` and can
|
|
span monitors. Newly connected DRM outputs are detected by a two-second
|
|
topology poll and attached when a compatible free CRTC is available. Unplug
|
|
cleanup and live mode replacement are not implemented yet; restart Wo after
|
|
removing a monitor or changing its mode. Workspace hiding remains a comraw
|
|
shell feature; it does not isolate native Wayland clients. Portal monitor
|
|
capture currently publishes the primary output rather than a stitched
|
|
multi-monitor image.
|
|
|
|
## Native offscreen frames
|
|
|
|
On Linux the Electron renderer requests `webPreferences.offscreen.useSharedTexture`
|
|
and forwards the native-pixmap DMA-BUF planes to Wo over SCM_RIGHTS. This avoids
|
|
the JS bitmap readback and Wo's RGBA-to-DMA-BUF import for normal offscreen
|
|
frames. Wo still imports the DMA-BUF into Smithay for composition. The Electron
|
|
and CEF source trees used to verify upstream support are separate checkouts;
|
|
their Linux shared-texture/accelerated-paint APIs already expose native pixmap
|
|
planes, so Wo's integration uses those APIs rather than carrying a fork of the
|
|
frame capture implementation. The CEF tree is not a current runtime backend.
|
|
|
|
`packaging/engines` contains GN argument presets for an optional source build.
|
|
For Electron, copy `electron-wo.gn` into the Electron checkout's
|
|
`build/args/wo.gn` and import it from the Chromium `out/<config>/args.gn` as
|
|
`import("//electron/build/args/wo.gn")`. For CEF, copy `cef-wo.gn` into the CEF
|
|
checkout's `tools/wo.gn` and import it as `import("//cef/tools/wo.gn")`. Both
|
|
source builds need the matching Chromium checkout and platform toolchain. The
|
|
Arch package currently links to the system Electron package, so those presets
|
|
do not change its Electron binary. Ubuntu builds bundle Electron with
|
|
`packaging/ubuntu/build-deb.sh` and install a matching launcher/runtime pair.
|
|
See `packaging/ubuntu/README.md` for the build requirements and install command.
|
|
|
|
## GPU rendering and native input
|
|
|
|
Wo's compositor renderer uses Smithay GLES through EGL. Electron/Chromium
|
|
content leaves GPU backend selection to Chromium by default. Vulkan is disabled
|
|
for native Wayland Electron clients because Chromium's Wayland surface factory
|
|
does not support it; this leaves Chromium free to use its GL/EGL path. Set
|
|
`WO_ELECTRON_GPU_BACKEND=angle` or `gl` to select ANGLE OpenGL, `vulkan` for
|
|
ANGLE/Vulkan, or `desktop` for native X11 GL. To test XWayland/GLX for Electron
|
|
while Wo itself remains a Wayland compositor, launch with
|
|
`WO_ELECTRON_OZONE_PLATFORM=x11 WO_ELECTRON_GPU_BACKEND=desktop`. Wo's nested
|
|
backend prefers an inherited `WAYLAND_DISPLAY`, or discovers a `wayland-*`
|
|
socket under `XDG_RUNTIME_DIR` when launchers omit that variable. GPU support
|
|
still depends on the system driver and Chromium build.
|
|
|
|
Wayland clients receive pointer motion, buttons, scroll axes, relative pointer
|
|
motion, and locked-pointer cursor hints through Smithay's native protocols.
|
|
Forwarded input accounts for client-surface geometry offsets so window borders
|
|
and client-side decorations do not skew pointer coordinates.
|
|
|
|
## Headless tests
|
|
|
|
Run the Electron renderer and buffer tests with `cd electron && bun run test`.
|
|
Run configuration tests without starting Wayland with `cargo test --lib config::tests`.
|