The browser backend ran an app alone on a canvas over the page. An Eydos desktop in a browser needs crustace as its shell and other ltk apps as its windows on one page, managed by forge/web (forge's web/ directory), which publishes `globalThis.forgeWeb` and stacks, places and focuses the surfaces its clients ask for (forge/web/DESIGN.md). The desktop's client. On a page where `globalThis.forgeWeb` exists and `set_canvas` named no canvas, `platform/web/desktop.rs` connects as the app's `app_id` and asks for the main surface in the role the app's hooks give, as a Wayland compositor reads them: `shell_mode`, and for a layer `layer_anchor`, `layer_size`, `exclusive_zone` and `keyboard_exclusive`, for a window `app_id` and `window_size_hint`, and for `SessionLock` a full overlay that holds the keyboard. The app draws into the canvas forge/web gives and listens on the input element above it, takes its size and scale from forge/web's `configure` rather than from the window's `resize`, sends its input region in logical pixels when it changes, and leaves the keyboard focus to the desktop, which honours the surfaces that hold it exclusively. A `close` of the main surface reaches `App::on_close_requested`; on exit the surface is destroyed and the connection closed. The new `RunError::Desktop` says forge/web refused the main surface. Fullscreen inside a desktop does nothing yet. A page without a desktop, or one that named a canvas, runs the app as before. One WebGL context. A page holds few WebGL contexts, and the browser loses the oldest beyond them, while a shell has many surfaces. Every surface of an app now paints through one WebGL2 context on an `OffscreenCanvas`: the surface's FBO is blitted onto it, taken as an `ImageBitmap` and handed to the surface's own canvas, a `bitmaprenderer`, without a copy. Without WebGL2 each surface draws in software on a 2D context of its own. The context's loss is heard on the `OffscreenCanvas`, and now drops the GPU canvases of every surface, not only the main one's. Overlays. `platform/web/overlays.rs` keeps the app's overlays in step with `App::overlays()`, as the Wayland backend's `overlays_reconcile.rs` does with layer-shell: a new one becomes a layer surface or, for `Layer::Window`, a window, with its size and exclusive zone in logical pixels; a changed one gets an `update_role`; one that went is destroyed; forge/web's `close` of one delivers its `on_dismiss`. Popups anchored to a widget and the tooltip wait for a popup role forge/web does not have, and without a desktop an app still shows no overlays. What every backend does as overlays come and go, resolving an `OverlaySpec::size` and moving a drag and the focuses off an overlay that goes, moved out of the Wayland backend into `event_loop/overlays.rs` (`AppData::overlay_size`, `AppData::remove_overlay`); Wayland's behaviour is unchanged. Subsurfaces. `platform/web/subsurfaces.rs` makes each of `App::subsurfaces()` a surface of the desktop sized to its parent with an empty input region, painted on one shared GPU canvas only when it appears, its size changes or its `content_version` does, its frame then staying on its own canvas, and otherwise moved with an `update_role`, which the browser composes without painting. `App::on_subsurface_committed` follows each paint. A subsurface whose parent overlay was destroyed and made again is made again, since forge/web destroys a subsurface with its parent. `frame_presented` now knows whether a surface hosts subsurfaces, so while the app animates by subsurface motion only its frames keep coming without painting the parent, as Wayland keeps a parent's frame callbacks. Painting a view with no focus, hover or press on a canvas of its own, which both backends' subsurfaces do, moved out of the Wayland backend into `draw::paint_detached`. Input per surface. `input::listen` takes the surface's `SurfaceFocus`, which pointer, touch and keyboard focus events carry; a surface's blur no longer takes the keyboard from the surface focused after it. Listeners remove themselves when dropped, and a surface's live in its `WebSurfaceState`, so they go with it. The frames owed at the next animation frame are a list of surfaces instead of one, which with several surfaces left the main one waiting on a frame that never came. `examples/web_shell.rs` is a shell for the desktop: a background, a bar in the top layer with an exclusive zone, a panel that takes the keyboard, and a card on a subsurface that slides. `make web-example` builds it with web_hello (`WEB_EXAMPLES`); forge/web's `make hello` serves both at /shell.html. web-sys gains `OffscreenCanvas`, `ImageBitmap` and `ImageBitmapRenderingContext`. `CHANGELOG.md` describes the change. Not done. Popups and the tooltip in a desktop, overlays and subsurfaces without one, fullscreen and window moves through forge/web, and the cursor's shape over an overlay, which is still set on the main surface's element. The offscreen canvas is resized for each surface it paints, which reallocates its drawing buffer when the surfaces differ in size. There are no tests for the browser backend.
171 lines
8.1 KiB
Makefile
171 lines
8.1 KiB
Makefile
REGISTRY ?= /usr/share/cargo/registry/ltk
|
|
DOCDIR ?= /usr/share/doc/libltk-doc/html
|
|
|
|
# The Android build uses Debian's own packages: rustc and rust-src of the
|
|
# same version, whose std `-Zbuild-std` compiles for the target, and the NDK
|
|
# that google-android-ndk-r27c-installer (non-free) unpacks.
|
|
NDK ?= /usr/lib/android-sdk/ndk/27.2.12479018
|
|
ANDROID_API ?= 26
|
|
ANDROID_TARGET ?= aarch64-linux-android
|
|
NDK_BIN = $(NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin
|
|
NDK_CC = $(NDK_BIN)/$(ANDROID_TARGET)$(ANDROID_API)-clang
|
|
ANDROID_ENV = RUSTC_BOOTSTRAP=1 \
|
|
CC_$(subst -,_,$(ANDROID_TARGET))=$(NDK_CC) \
|
|
CXX_$(subst -,_,$(ANDROID_TARGET))=$(NDK_CC)++ \
|
|
AR_$(subst -,_,$(ANDROID_TARGET))=$(NDK_BIN)/llvm-ar \
|
|
CARGO_TARGET_$(shell echo $(ANDROID_TARGET) | tr a-z- A-Z_)_LINKER=$(NDK_CC)
|
|
ANDROID_CARGO = -Zbuild-std=std,panic_abort --target $(ANDROID_TARGET) --no-default-features --features android
|
|
# Where `android-assets` writes the `ltk/` tree an APK carries under `assets/`.
|
|
ANDROID_ASSETS ?= target/android/assets
|
|
# The example APK, packaged with aapt, zipalign, apksigner and
|
|
# android-framework-res, and installed with adb (android-sdk-platform-tools).
|
|
ANDROID_ABI ?= arm64-v8a
|
|
ANDROID_APK ?= target/android/ltk-hello.apk
|
|
|
|
# The browser build uses Debian's std for wasm32 (libstd-rust-dev-wasm32) and
|
|
# wasm-bindgen-cli, which Debian does not package and whose version must be
|
|
# the one of the wasm-bindgen crate in Cargo.lock.
|
|
WEB_TARGET = wasm32-unknown-unknown
|
|
WEB_CARGO = --target $(WEB_TARGET) --no-default-features --features web
|
|
WEB_OUT ?= target/web
|
|
# web_hello runs alone on a page; web_shell needs forge/web, whose `make hello` serves both.
|
|
WEB_EXAMPLES = web_hello web_shell
|
|
# Fallback fonts a page bundles beyond the theme's, for text Sora does not
|
|
# cover: Cyrillic, Greek and extended Latin, symbols, arrows and box drawing.
|
|
WEB_FONTS ?= $(wildcard /usr/share/fonts/truetype/noto/NotoSans-Regular.ttf /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf /usr/share/fonts/truetype/noto/NotoSansSymbols2-Regular.ttf)
|
|
WASM_BINDGEN_SRC = target/wasm-bindgen-cli
|
|
# Where web-deps installs wasm-bindgen-cli, so nothing needs to be on PATH;
|
|
# one already on PATH is used when there is none here.
|
|
WEB_TOOLS = target/tools
|
|
WASM_BINDGEN ?= $(or $(wildcard $(WEB_TOOLS)/bin/wasm-bindgen),$(shell command -v wasm-bindgen 2>/dev/null))
|
|
|
|
# Targets are recipes, not files. Listing them as PHONY tells make to
|
|
# ignore filesystem entries with the same name — without this `examples`
|
|
# silently no-ops because the `examples/` directory exists, and `doc`
|
|
# would do the same once `target/doc` is around.
|
|
.PHONY: all deps android-deps test doctest-md stylecheck clippy audit doc install examples clean distclean android-check android-assets android-apk android-install web-deps web-check web-assets web-example web-serve
|
|
|
|
all:
|
|
cargo build --release
|
|
|
|
# What building, testing and linting need, from Debian.
|
|
deps:
|
|
sudo apt-get install -y cargo rustc rust-clippy pkg-config libwayland-dev libegl-dev libxkbcommon-dev
|
|
|
|
# What the android-* targets need, from Debian: std's sources for -Zbuild-std,
|
|
# the NDK installer (non-free), the APK tools, rsvg-convert for SVG icons, javac, dx and
|
|
# android.jar (non-free) for the keep-alive service, and adb.
|
|
android-deps:
|
|
sudo apt-get install -y rust-src google-android-ndk-r27c-installer aapt zipalign apksigner android-framework-res librsvg2-bin default-jdk-headless art-standalone google-android-platform-34-installer android-sdk-platform-tools
|
|
|
|
test:
|
|
cargo test --features test-support
|
|
|
|
# Typecheck the `no_run` snippets in docs/*.md by feeding each markdown
|
|
# file to `rustdoc --test`. Catches API drift in cookbook + widget
|
|
# reference: drops a renamed builder, removed function, etc. surface
|
|
# here just like `cargo test --doc` does for in-source doctests.
|
|
doctest-md:
|
|
./scripts/doctest-md.sh
|
|
|
|
# Mechanical style checks (tabs, attribute-bracket spacing) — the
|
|
# grep-verifiable subset of code_style_guide.md.
|
|
stylecheck:
|
|
./scripts/style-check.sh
|
|
|
|
# Semantic lints, mirroring the CI invocation. Warnings are errors so a
|
|
# local run predicts the CI verdict.
|
|
clippy:
|
|
cargo clippy --workspace --all-targets --features test-support -- -D warnings
|
|
|
|
# Typecheck the Android backend. Needs rust-src and the NDK (see NDK above).
|
|
android-check:
|
|
@test -x $(NDK_CC) || { echo "No NDK compiler at $(NDK_CC); install google-android-ndk-r27c-installer or set NDK="; exit 1; }
|
|
$(ANDROID_ENV) cargo check $(ANDROID_CARGO)
|
|
|
|
# The in-tree default theme and the fonts it names, as an APK carries them.
|
|
android-assets:
|
|
./scripts/android-assets.sh $(ANDROID_ASSETS) themes default
|
|
|
|
# examples/android_hello.rs as an APK, with the in-tree default theme.
|
|
android-apk: android-assets
|
|
@test -x $(NDK_CC) || { echo "No NDK compiler at $(NDK_CC); install google-android-ndk-r27c-installer or set NDK="; exit 1; }
|
|
$(ANDROID_ENV) cargo build --release --example android_hello $(ANDROID_CARGO)
|
|
ANDROID_ABI=$(ANDROID_ABI) MIN_SDK=$(ANDROID_API) ./scripts/android-apk.sh $(ANDROID_APK) \
|
|
target/$(ANDROID_TARGET)/release/examples/libandroid_hello.so net.liberux.ltk.Hello "ltk hello" $(ANDROID_ASSETS)
|
|
|
|
android-install: android-apk
|
|
adb install -r $(ANDROID_APK)
|
|
|
|
# What the web-* targets need: Debian's std for wasm32, and wasm-bindgen-cli
|
|
# from crates.io at the version Cargo.lock holds. The lock it was published
|
|
# with needs a newer rustc, and `cargo install` ignores rust-version when it
|
|
# resolves, so its sources get a lock resolved for the rust-version it
|
|
# declares and are installed from there.
|
|
web-deps:
|
|
sudo apt-get install -y libstd-rust-dev-wasm32 curl
|
|
cargo metadata --format-version 1 >/dev/null
|
|
version="$$(sed -n '/^name = "wasm-bindgen"$$/{n;s/^version = "\(.*\)"$$/\1/p}' Cargo.lock)" && \
|
|
rm -rf $(WASM_BINDGEN_SRC) && mkdir -p $(WASM_BINDGEN_SRC) && \
|
|
curl -sSfL "https://static.crates.io/crates/wasm-bindgen-cli/wasm-bindgen-cli-$$version.crate" | tar -xz -C $(WASM_BINDGEN_SRC) --strip-components=1 && \
|
|
cd $(WASM_BINDGEN_SRC) && \
|
|
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS=fallback cargo generate-lockfile && \
|
|
cargo install --path . --locked --root $(CURDIR)/$(WEB_TOOLS)
|
|
|
|
# Typecheck the browser backend.
|
|
web-check:
|
|
cargo check $(WEB_CARGO)
|
|
|
|
# The in-tree default theme, the fonts it names and $(WEB_FONTS), as a page serves them.
|
|
web-assets:
|
|
EXTRA_FONTS="$(WEB_FONTS)" ./scripts/web-assets.sh $(WEB_OUT) themes default
|
|
|
|
# examples/web_hello.rs as a page under $(WEB_OUT), with its resources.
|
|
web-example: web-assets
|
|
@test -n "$(WASM_BINDGEN)" || { echo "No wasm-bindgen in $(WEB_TOOLS)/bin or on PATH; run make web-deps"; exit 1; }
|
|
cargo build --release $(addprefix --example ,$(WEB_EXAMPLES)) $(WEB_CARGO)
|
|
for example in $(WEB_EXAMPLES); do \
|
|
$(WASM_BINDGEN) --target web --no-typescript --out-dir $(WEB_OUT)/pkg target/$(WEB_TARGET)/release/examples/$$example.wasm || exit 1; \
|
|
done
|
|
cp web/index.html $(WEB_OUT)/
|
|
|
|
web-serve: web-example
|
|
cd $(WEB_OUT) && python3 -m http.server 8000
|
|
|
|
audit:
|
|
@command -v cargo-audit >/dev/null 2>&1 || cargo install cargo-audit --locked
|
|
cargo audit
|
|
|
|
doc:
|
|
cargo doc --no-deps
|
|
|
|
install: doc
|
|
install -d $(REGISTRY)
|
|
cp -r src benches examples locales protocols keyboards scripts java web build.rs Cargo.toml liberux.toml $(REGISTRY)/
|
|
cp debian/cargo-checksum.json $(REGISTRY)/.cargo-checksum.json
|
|
install -d $(DOCDIR)
|
|
cp -r target/doc/* $(DOCDIR)/
|
|
|
|
examples:
|
|
LTK_THEMES_DIR=themes cargo run --release --example showcase
|
|
LTK_THEMES_DIR=themes cargo run --release --example responsive
|
|
LTK_THEMES_DIR=themes cargo run --release --example inputs
|
|
LTK_THEMES_DIR=themes cargo run --release --example scroll
|
|
LTK_THEMES_DIR=themes cargo run --release --example sliders
|
|
LTK_THEMES_DIR=themes cargo run --release --example combo
|
|
LTK_THEMES_DIR=themes cargo run --release --example mini_shell
|
|
LTK_THEMES_DIR=themes cargo run --release --example widgets
|
|
LTK_THEMES_DIR=themes cargo run --release --example pickers
|
|
LTK_THEMES_DIR=themes cargo run --release --example dialog
|
|
LTK_THEMES_DIR=themes cargo run --release --example carousel
|
|
LTK_THEMES_DIR=themes cargo run --release --example clip_path
|
|
LTK_THEMES_DIR=themes cargo run --release --example tab_strip
|
|
|
|
clean:
|
|
dh_clean
|
|
cargo clean
|
|
rm -rf target
|
|
|
|
distclean: clean
|
|
rm -f Cargo.lock
|