diff options
| author | Adam Malczewski <[email protected]> | 2026-06-13 22:50:59 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-13 22:50:59 +0900 |
| commit | 6b67ae6ac1b8d0d272ddb50e6ef10d08f4fd6628 (patch) | |
| tree | 1e7233e046e2cb20555bf8d4a0fa22d4be4f9d68 /packages/kernel/src/server.cpp | |
| parent | f65b446cabe3da6f8afff34e127e247dd0d03e5c (diff) | |
| download | unbox-6b67ae6ac1b8d0d272ddb50e6ef10d08f4fd6628.tar.gz unbox-6b67ae6ac1b8d0d272ddb50e6ef10d08f4fd6628.zip | |
kernel: load ui surfaces from RML asset files + dev hot-reload
Externalize UI documents so RML/RCSS design changes need no C++ recompile — and,
in dev, no restart.
- UiSurfaceSpec::rml_path now actually loads the document from a file (path wins
over rml_inline, as documented). Resolution: absolute path as-is; relative path
against $UNBOX_ASSET_DIR, else the compile-time UNBOX_ASSET_DIR_DEFAULT (the
install data dir), else cwd. The document URL is set so its <link> RCSS / asset
refs resolve relative to the doc's own dir. Missing/unreadable file -> nullptr
(degrade, never throw).
- Dev hot-reload (gated by $UNBOX_DEV): an inotify watcher integrated into the
wl_event_loop (never blocks) watches the asset DIRS (dir-watch for IN_CLOSE_WRITE
/ IN_MOVED_TO, since editors save via temp+rename), coalesces events, and on a
change to a surface's backing .rml/.rcss reloads the document IN PLACE:
ClearStyleSheetCache + UnloadDocument + reload, preserving the surface's RmlUi
context, data model and the extension's registered bind_*/bind_list* getters
(the extension does NOT re-register), and its geometry/visibility; preview
textures are kept. A malformed file on reload is ERROR-ISOLATED — the previous
good document keeps rendering, one warning is logged, and a later good save
recovers; the session never dies.
- Test seam Server::ui_reload_surface() drives reload deterministically.
ui.hpp documents rml_path + the dev hot-reload behavior. kernel 54 cases/232
assertions green on build + build-asan (incl. the UNBOX_DEV inotify path), no new
suppressions. Edits confined to packages/kernel/.
Diffstat (limited to 'packages/kernel/src/server.cpp')
| -rw-r--r-- | packages/kernel/src/server.cpp | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/packages/kernel/src/server.cpp b/packages/kernel/src/server.cpp index d97104e..5d78b70 100644 --- a/packages/kernel/src/server.cpp +++ b/packages/kernel/src/server.cpp @@ -105,6 +105,10 @@ auto Server::ui_click_element(const char* tag, int index) -> bool { return impl_->substrate != nullptr && impl_->substrate->click_element(tag, index); } +auto Server::ui_reload_surface() -> bool { + return impl_->substrate != nullptr && impl_->substrate->reload_first_surface(); +} + void Server::ui_set_touch_override(UiTouchOverride ov) { if (impl_->substrate == nullptr) { return; @@ -371,8 +375,11 @@ void Server::Impl::start_substrate() { wlr_log(WLR_INFO, "ui-substrate: renderer is not gles2; substrate unavailable"); } // A data-event/getter throw disables the owning extension via the same - // isolation path the bus uses (Server::Impl is the DisableSink). + // isolation path the bus uses (Server::Impl is the DisableSink). The + // wl_event_loop lets the substrate poll the dev hot-reload inotify fd + // (UNBOX_DEV-gated) without ever blocking the loop. substrate = Substrate::create(display_egl, allocator, renderer, + wl_display_get_event_loop(display), [this](ExtensionId who) { disable(who); }); } |
