Docs menu<app> and <webview>
<app> and <webview>
How the engine's two embedding elements route input and focus.
Event names and full types are in src/app-element.ts and
src/webview-element.ts.
<app>
<app app-id="…"> embeds a Wayland client. The engine provides the element.
- Shell only:
<app>and<webview>exist only in the shell's document. In any other page, such as a site in a<webview>or an<iframe>, they are unknown elements. - Size: the element's layout box is the client's size. The engine sends it
as the
xdg_toplevel.configure. There is nothing to call. - Resize sync: a new box holds the page's frame until the client draws at
it, up to viz's default deadline. Set the
resizingattribute (orelement.resizing = true) while the user drags an edge: each box then shows at once, without waiting, with the client's latest frame at its own size in the top left corner until the client draws at the new box. Removing it waits once for the final size. - Synced frames: the
frameattribute (orelement.frame) names the synced frame of the window to show. Setting it holds the page's frame until the window has that frame, up to viz's default deadline. Unset, the element shows the newest frame the control channel named for the window, so a page that ignores frames never shows a stale one. Set it fromDomicileWindow.frame, in the same render as a popup's move. The compositor syncs frames only for a page that calledwindows.syncFrames(); see Synced frames. - Scale: call
domicile.windows.setBounds(appId, { x, y, width, height })with the element's box in page pixels whenever it moves or resizes. The client draws at the scale of the monitor holding most of the box. An unreported window draws for the densest monitor. - Hidden: call
domicile.windows.setBounds(appId, { x: 0, y: 0, width: 0, height: 0 })for an<app>the page does not draw. The client gets a frame callback once a second and issuspendeduntil the next box with an area, unless a cast shows it. It keeps its monitor and scale. - Window events (bubbling
CustomEvents, not cancelable, withdetail.appId; the compositor sends them):domicile-presented: the window reached the screen. Fired once for its first frame, and once for the first frame its client draws after its box changes size. A move, a box at the same size and a hidden window shown again fire nothing.domicile-suspended: the compositor marked the windowsuspended.domicile-resumed: the compositor clearedsuspended. A new page'shelloclears it on every window.- An
<app>not in the page when one is sent misses it.
- Pointer: the element sends pointer and wheel events over it to the
client, in the client's surface coordinates, through its layout box and
every transform above it (
zoomand perspective included). ApreventDefault()on the event takes it from the client. - Press capture: a press the client gets captures the pointer for the
element until the button is up, so the client gets the drag and the release
wherever the pointer goes. A page that captures the pointer itself in its
pointerdownlistener loses that capture to the element; callpreventDefault()to keep the press. - Keyboard: the engine sends the keystrokes
documenthears to the window that has the keyboard.domicile.windows.focus(appId)anddomicile.windows.focusShell()move it in code, both in the compositor's seat and for the page's keys. - Focus events (both cancelable; call
preventDefault()to decide focus yourself):domicile-focus-requested: a click on a window, before it is focused. A popup's click asks for its window.domicile-focus-release-requested: a press off every window, fired on the window that has the keyboard, before focus returns to the page.
- Context menu: a right-click over an
<app>suppresses the browser's menu. The press goes to the client, which draws its own. Elsewhere the browser menu is left alone. - No setup. Routing covers every
<app>on the page, including ones added later.
<webview>
<webview src="…"> embeds a web page. <webview window="id"> shows one of
the desk's browser windows, which the engine owns; the engine reads window
once, when the view connects. The SDK provides types only.
- Moving: a view moved in the document, as React's
insertBeforedoes, connects again where it lands. A browser window shows there; asrcview loadssrcagain, as an<iframe>does. - Resize sync: as an
<app>'s, a new box holds the page's frame until the page draws at it. Set theresizingattribute while the user drags an edge: each box then shows at once, with the page's latest frame at its own size in the top left corner until the page draws at the new box. - Properties:
src,goBack(),goForward(),stop(),reload(),canGoBack,canGoForward,loading,focus(),inspect()(opens DevTools as a new window),print()(the desktop's print dialog). - Events (selected; see
src/webview-element.tsfor all):domicile-close: the page in a shell's own view (nowindow) calledwindow.close(). The shell removes the view. A browser window closes in the browser.domicile-focus-request: the page calledwindow.focus()orclient.focus()(how a site answers a click on its notification), or an extension asked for the tab. The shell raises the view.domicile-context-menu: a right click the page left alone, with what was under it. The shell draws the menu;event.run(action)does the browser's part of an item.domicile-content-size-change:contentWidth/contentHeightchanged. Use it to size anextensionpopupview.domicile-render-process-change: the page's renderer died or came back.renderProcessGonesays why, or is"";reload()recovers it. See Crashed pages.
- Browser windows:
domicile.browser.windowsis the desk's whole list;browser.on("change")reports changes.browser.open(url)andbrowser.close(id)are for the shell's own UI. A link withtarget="_blank",domicile openand an extension'stabs.createorwindows.createopen windows without the shell. See Browser windows. - Extension popups: for a tray row with a
popup, callextensions.activate(id)(which grantsactiveTab), then open a<webview extensionpopup>at the popup address. Setextensionpopupon first render. - Private pages:
<webview private>puts a shell's own page in the off-the-record profile, andbrowser.openPrivate(url)opens a private window. Setprivateon first render. See Browser windows. - Partitions:
<webview partition="persist:work">gives a page storage of its own, kept on disk; any other name keeps it in memory.browser.open(url, { partition })opens a window in one. Setpartitionon first render. See Browser windows. - Navigations:
domicile-will-navigatefires before the page navigates itself;preventDefault()cancels it. See Browser windows.
Reading held modifiers
Read modifiers from your own KeyboardEvents. The page sees every key press,
whichever window has focus:
const [altHeld, setAltHeld] = useState(false);useEffect(() => { const follow = (event: KeyboardEvent) => setAltHeld(event.altKey); document.addEventListener("keydown", follow); document.addEventListener("keyup", follow); return () => { document.removeEventListener("keydown", follow); document.removeEventListener("keyup", follow); };}, []);// Let clicks reach the page while Alt is held.// <app style={{ pointerEvents: altHeld ? "none" : undefined }} … />Do not use the host's altKey, ctrlKey, shiftKey and metaKey for this.
They report the compositor's seat, which only sees keys forwarded while a
client had focus. A modifier pressed while the page had focus is missing from
them.