enum LavaApp
Swift
enum LavaApp
Reusable window/input/invalidation/render loop, so a second LavaUI
executable is a main.swift of a dozen lines instead of a copy of
HelloWorldApp's ~350.
Split into open + run because asset loading a specific app owns
(an app icon, a brand image) has to happen once, against an already-open
Editor, before the first makeRoot() — folding it into run's hot path
would either re-load it every rebuild or force every caller to thread a
cache through their own view. Two calls keeps that ordering explicit:
guard let editor = LavaApp.open(title: "My App") else { exit(1) }
let icon = ImageStore.loadAsset(
named: "icon.png", bundle: .module, into: editor)
LavaApp.run(editor: editor) { MyRootView(icon: icon) }
Sources/LavaUI/LavaApp.swift:20
Properties
static var currentWindow: WindowID { get }
The window whose frame is being built or whose handler is running.
Ambient rather than passed down, for the reason WindowScope gives at
length: a view genuinely does not know which window it is in, and every
view in a tree would have to thread the answer through to the one place
that wants it. Outside a frame this is the first window.
Sources/LavaUI/LavaApp.swift:554
static var mainLayoutHost: LayoutHost? { get }
The layout host of the window the app started with, once run has
brought it up. Nil before that, and after teardown.
For the app that has to know how big the tree it just laid out actually
is — agentFrame(sid:) on a committed layout answers it. A context
menu is the case this exists for: it has to tell the compositor its
size before the compositor will place it, and the only honest source
for that number is the layout pass, not a second pile of font
arithmetic that agrees with Yoga until a face changes.
Everything else about a window's geometry is told to the app. This is the one question that runs the other way.
Sources/LavaUI/LavaApp.swift:261
static var windowCount: Int { get }
How many windows are open, counting ones opened this frame that are not yet on screen.
Sources/LavaUI/LavaApp.swift:237
Methods
static func closeCurrentWindow()
Closes the window this handler is running in. What a "Close" button in a secondary window wants, without the window having to know its own id.
Sources/LavaUI/LavaApp.swift:558
static func closeWindow(_ id: WindowID)
Closes a window this app opened. Closing the window the app started
with ends run, the same as its titlebar X.
Takes effect at the end of the current frame, so it is safe from a handler running inside that window's own tree.
Sources/LavaUI/LavaApp.swift:523
static func isWindowOpen(_ id: WindowID) -> Bool
Whether id is still open.
Sources/LavaUI/LavaApp.swift:544
static func layoutHost(for id: WindowID) -> LayoutHost?
The layout host of one open window, once run has brought it up.
A fly-out measures itself the same way the root menu does — the plate's frame after a layout pass — and that frame lives on the fly-out's own host, not the window the process started with.
Sources/LavaUI/LavaApp.swift:244
static func open(title: String, assetsRoot: String? = nil, width: Float = 1280, height: Float = 800) -> Editor?
Opens the window and does one-time framework setup: default font
bootstrap, clipboard bridge. Logs and returns nil if the window
failed to open — the caller should exit(1).
assetsRoot- Engine resource root (directory with
shaders/). Default is the SwiftPMCanvasResourcesbundle. Fonts always load from LavaUI's own resource bundle.
Sources/LavaUI/LavaApp.swift:28
@discardableResult static func openMenuPlate<V>(width: Float, height: Float, onClose: (() -> Void)? = nil, makeRoot: @escaping () -> V) -> WindowID? where V : View
A menu fly-out: its own window, hidden until the compositor places it.
Not openPopup. A popup hangs below an anchor the panel named, and
this hangs beside a row of a menu the compositor is already showing.
Where that is — and which side of the row still fits on the work
area — is decided when the plate has been measured, not here.
Frosted the way a popup is, by its root view (see openPopup); the
plate comes up with the fly-out, since the compositor captures when it
places it, not before.
Sources/LavaUI/LavaApp.swift:453
@discardableResult static func openPopup<V>(title: String, width: Float = 280, height: Float = 240, anchor: SurfaceAnchor, onClose: (() -> Void)? = nil, makeRoot: @escaping () -> V) -> WindowID? where V : View
A borderless popup of the window the app started with, placed just
below anchor (a rectangle in that window) and dismissed by a press
that misses it.
The anchor is this window's own coordinates. Where that window sits on the screen is the compositor's, and so is the press that lands somewhere else — a client cannot hit-test a foreign window. Under a window manager that is not ours this is an ordinary second window; the placement and the dismiss are compositor work.
The frost behind it is the root view's to state, like everything else it draws:
LavaApp.openPopup(title: "Network", anchor: anchor) {
NetworkWindow()
.backdropBlur(radius: 12)
.glassEffect(refraction: 20, frost: 1)
}
On a view that fills the window those two are the window's plate of the desktop, cut to the window's own corner radius — the same mask as the popup, so the two are one outline. The blur is what makes a plate; glass without it draws only the rim, because there is no sharp plate. A windowed app frosts nothing: nothing there can see the desktop behind the window.
Views inside can frost rectangles of their own instead: in a window
whose backdrop is the desktop (WindowBackdrop.showsDesktop),
.backdropBlur(radius:) on a smaller view asks the compositor to frost
that view's rectangle, cut to its corner radius, and .glassEffect
bends that plate alone — so two siblings can be a flat frost and a bent
one, with desktop between them.
Sources/LavaUI/LavaApp.swift:418
@discardableResult static func openWindow<V>(title: String, width: Float = 800, height: Float = 600, onClose: (() -> Void)? = nil, makeRoot: @escaping () -> V) -> WindowID? where V : View
Opens a second window running its own view tree, sharing this process's GPU, font atlas, texture cache and frame loop.
Under a compositor this is a second surface, not a second process: its
own arena and its own input stream, closed without ending the app.
That only happens when ClientSurfaceBridge is installed, which
LavaClient.run does. A client that calls Editor.openWindow directly
gets the arena and the queue and nothing on screen.
Safe to call from a button handler: the window is created immediately but brought up at the end of the current frame, so it never draws against a half-updated tree, and the caller's own window still presents the frame the click belongs to.
The new window gets its own focus, invalidation and hover state (see
WindowScope) and the app-level onRawKey from run. It does not
get the menubar: a second menubar strip is a decision for the app, not
a default, and the DBus global menu is registered per process.
Returns nil if the engine could not open it, or if called before
run.
Sources/LavaUI/LavaApp.swift:356
static func resolveAssetsRoot(_ override: String? = nil) -> String
Back-compat alias — engine root only. App images should use
ImageStore.loadAsset(named:bundle:into:) with the app bundle.
Sources/LavaUI/LavaApp.swift:82
static func resolveEngineAssetsRoot(_ override: String? = nil) -> String
Engine assets root: override, else CANVAS_ASSETS_ROOT, else the
CanvasResources SwiftPM bundle (checked-in SPIR-V under shaders/).
Sources/LavaUI/LavaApp.swift:75
static func run<V>(editor: Editor, menu: (() -> MenuBar)? = nil, onRawKey: ((InputEvent) -> Bool)? = nil, makeRoot: @escaping () -> V) where V : View
Runs the full input/invalidation/render/agent-server loop until the window closes.
Drives every open window, not just this one: openWindow adds a
second tree to the same loop, and one GLFW wait serves all of them, so
N windows cost N draw arenas rather than N event loops. The app ends
when the window opened here closes; secondary windows come and go under
it. See LavaWindow for the per-window half and WindowScope for what
each window owns privately.
makeRoot: rebuilds the view tree from scratch. Called on the first frame and on any invalidation that can't be satisfied per-node (seeViewInvalidation.consumeDirtyBodyNodes) — keep it cheap, an app's own one-time setup belongs before this call, against theEditoropenalready returned.menu: optional application menubar. When a global-menu registrar is available (Vala Panel / Plasma appmenu / …), the tree is exported via DBusMenu and no in-window strip is drawn. OtherwiseMenuChromeRootdraws it with Vulkan. Override withLAVA_MENU=vulkanordbus. Rebuilt on every full body pass so labels/isEnabledstay in sync. Menu shortcuts are matched afteronRawKey(both backends).onRawKey: first look at every key event, ahead of focus/overlay/ content-scale handling. Returntrueto consume it.
Sources/LavaUI/LavaApp.swift:109
Types
LavaApp.SurfaceAnchor struct
A rectangle in the parent surface's own coordinates. A popup hangs just below it; the compositor turns that into a position on screen, because the client does not know where its window is.