biglinux-webapps ships a GTK4/libadwaita stack for creating, managing, and
launching site-specific browser instances ("WebApps") on BigLinux. It generates
isolated browser profiles per webapp, persists a JSON catalog under XDG dirs,
emits .desktop files, and ships its own WebKit viewer for sites that should
not pull in a full browser. The workspace is a four-crate split between a
toolkit-free core, two GUI binaries, and a small exec launcher.
crates/webapps-core/— toolkit-free domain:models/(webapp, browser, permissions),templates/registry.rs(curated catalog),browsers.rs(whitelist + flatpak detection),desktop/{builder,paths,sanitize,wm_class, icon}.rs,config.rs,i18n.rs. No GTK. Used by every other crate.crates/webapps-exec/— binarybig-webapps-exec: minimal launcher invoked from generated.desktopfiles. Modules:launch.rs(Firefox viaexec(), Chromium viaspawn()),wayland.rs(icon-swap workaround),icon.rs.crates/webapps-manager/— binarybig-webapps-gui+ lib: Relm4 + classic GTK manager UI.service/(CRUD, repository with flock, migration, icons, browser detect, welcome),relm4_window/(typed list + factory rows),window/(legacy imperative shell),webapp_dialog/,template_gallery.rs,welcome_dialog.rs,favicon/,ui_async.rs.crates/webapps-viewer/— binarybig-webapps-viewer: WebKit6 viewer.window/{chrome,session,settings,navigation,permissions,downloads, shortcuts,geometry,context_menu,loading,startup}.rs.
Dependency direction: core ← exec, manager, viewer. No cycles.
manager and viewer never link to each other.
Webapp lifecycle (manager):
Welcome? --no--> List(load) --create--> Dialog(new) --validate+save--> List
| ^ Dialog(edit) --validate+save--> List
| | Dialog(delete)--confirm--------> List
v |
Empty<--+
service::repository::load_webappsholds anflock(LOCK_EX)WebappsLockfor every write transaction;Dropunlocks even on panic (INVARIANTS).- Relm4 surface:
WebAppListController(FactoryVecDeque) ownsWebAppRowFactoryitems. Inputs:Reload,Add(Webapp),Remove(id),Update(Webapp). Outputs forwarded to the main window component. - Imperative
window/shell is being migrated torelm4_window/; both coexist behind the sameservicefacade — single source of truth. - Viewer state per process: window geometry (
geometry.rspersists), session cookies (per-app_idWebKit data manager), permissions (atomictmp + renamewrite inwindow/permissions/).
- Manager
ui_async.rswrapsglib::MainContext::spawn_localfor favicon fetches, browser detection, and icon resolution. favicon/performs capped blocking HTTP throughbig_os_kit::http_clientinsideglibIO threads to avoid blocking the GTK main loop.- All Relm4 components run on the main context; no background tokio runtime.
- Viewer downloads/permissions hook into WebKit asynchronous callbacks; user
consent is awaited via
adw::AlertDialogfutures. glib::SourceIddebounces (dialog text entries) are.remove()d before replacement (INVARIANTS — lifecycle).
| Site | Argv invariant |
|---|---|
webapps-exec/launch.rs:37 Command::new(<browser>) then .exec() |
Firefox-family. Replaces process image. Browser binary resolved from webapps-core::browsers whitelist; profile path argv-quoted, never shell-expanded. Env: XAPP_FORCE_GTKWINDOW_ICON, MOZ_APP_REMOTINGNAME. |
webapps-exec/launch.rs:61 Command::new(<browser>).spawn() |
Chromium-family. Same whitelist gate. --class= / --user-data-dir= constructed from sanitized app_id. |
webapps-exec/launch.rs:80 Command::new("flatpak").args(["override","--user","--filesystem=…",app_id]) |
Flatpak grant only. --filesystem value is the runtime profile dir; never user-controlled. |
webapps-core/desktop/paths.rs:122 Command::new("update-desktop-database") |
Refresh xdg DB after install/remove. No user argv. |
webapps-core/desktop/paths.rs:145 Command::new("dconf").args(*args) |
args is a &'static [&str] literal (write / read). No user input on argv. |
webapps-manager/service/browser.rs:26 Command::new("flatpak").args(["list","--app","--columns=application"]) |
Static argv. Stdout parsed for app IDs. |
webapps-manager/service/browser.rs:62 Command::new("xdg-settings").args(["get","default-web-browser"]) |
Static argv. |
webapps-manager/service/browser.rs:71 Command::new("xdg-mime").args(…) |
Static argv only; no user strings. |
Invariant: every browser path passed to Command::new must resolve through
webapps-core::browsers::BrowserDef (whitelist). Direct user-supplied
executables are rejected at validation time (INVARIANTS — security).
- Browser whitelist:
webapps-execrefuses any browser not declared inwebapps-core::browsers. No shell, nosystem(). - Desktop file safety:
desktop::sanitize::sanitize_exec_argquotes every field interpolated intoExec=(6 unit cases insanitize.rs). - Persisted data: catalog JSON write is
tmp + rename; permissions store follows the same pattern (window/permissions/mod.rs::save_permissions). - Inter-process locking:
WebappsLock(flock(LOCK_EX)) protects every write transaction; unlocked onDropeven under panic. - Profile isolation: each WebApp gets its own browser profile dir under
~/.local/share/biglinux-webapps/profiles/<browser>/<slug>/. - Flatpak: only
flatpak override --user --filesystem=issued; no--talk-name, no socket grants beyond the profile data dir. - Viewer permissions: camera/mic/geolocation prompts route through
adw::AlertDialog; default response is non-destructive (INVARIANTS — a11y).
- Unit:
webapps-corefor sanitize, paths, browsers, templates. - Integration:
crates/webapps-manager/tests/crud_integration.rsdrives the CRUD pipeline against a sandboxed$XDG_DATA_HOME(usestempfile+serial_test). - Property: planned for desktop-file builder; today covered by sanitize cases.
- i18n:
po/biglinux-webapps.potround-trip enforced inrust-quality.yml. - a11y: AT-SPI walk deferred to VM job; static review in
INVARIANTS.md. - Performance budget: each binary
--help< 200 ms (manual, tracked).
packaging/arch/PKGBUILD: declares pkgname=biglinux-webapps, depends on
gtk4, libadwaita, webkitgtk-6.0, xdg-utils, desktop-file-utils;
makedepends on rust, cargo, gettext. Local-source detection prefers
the workspace checkout (BIGLINUX_WEBAPPS_LOCAL_SOURCE env, or Cargo.toml + crates/ + biglinux-webapps/ next to the PKGBUILD) over the git fallback.
Installs three binaries (big-webapps-exec, big-webapps-gui,
big-webapps-viewer), the biglinux-webapps/ resource tree
(profile CSS/JS, icons, desktop templates), and compiled .mo catalogs.
Flatpak manifest under packaging/flatpak/ mirrors the Arch package.