ltk ran on Wayland and Android only. Running crustace and its apps in a browser needs, first, ltk apps running there; a window manager for the page is the next step. The runtime was already split from Wayland by the platform layer, so what kept it out of a browser was what the core and the runtime took from the operating system: calloop's epoll loop, EGL, a monotonic clock, a file system, threads and environment variables. The core builds for wasm32-unknown-unknown. `ltk::ChannelSender` is ltk's own type instead of a re-export of calloop's `Sender`, with the same `send` and `Clone`, so apps that only send and clone it build unchanged. The runtime arms its timers and channels through `event_loop/sources.rs` instead of a calloop `LoopHandle`: calloop's natively, and in a browser a queue the backend runs, which takes the due timers out, runs them on `AppData` and hands them back, and does not arm again one removed meanwhile. calloop, khronos-egl and raw-window-handle are dependencies off wasm32 only, where `egl_context.rs`, `UiSurface::try_new_gles` and `from_current_gles_loader` and the native GL names of `BorrowedGlesTexture` are left out; `sub_canvas` clones the uniform locations, which are `Copy` natively and only `Clone` on wasm. The monotonic clock is `crate::time::Instant`, `web_time`'s on wasm32, where `chrono` takes its `wasmbind` feature; the one subtraction that could go below the clock's origin, a surface's first `last_draw`, saturates. Themes, fonts, keyboard layouts and images are read through `vfs.rs`, the file system natively and on wasm32 files held in memory, so a wallpaper or an `Image::from_path` is now decoded from the file's bytes and its format told from its contents rather than its extension. The text-scale watcher, which runs gsettings on a thread, is left out on wasm32, and the built-in keyboard takes its language from `platform::language()`, `LANG` or the page's. criterion is a dev-dependency off wasm32 only, since rayon does not build there. The browser backend is the `web` feature, `platform/web/`, with wasm-bindgen, wasm-bindgen-futures, js-sys and web-sys. `build.rs` refuses it with another backend or for another target. A page's main thread must not block, so `ltk::run` sets the app up and returns, and the browser drives the loop: `AppData` lives in a closure a thread-local loop holds, which a `setTimeout` runs for messages, timers and page events and a `requestAnimationFrame` runs to draw. Event listeners and `ChannelSender::send` only queue and schedule, never touching `AppData`, so nothing they set off runs inside an iteration. The app draws on a canvas laid over the whole page, or the one `ltk::web::set_canvas` gives, through WebGL2 with the GLES canvas unchanged, its frame kept in its FBO, or without WebGL2 through `putImageData`. A lost context drops the GPU canvases and draws nothing until it is restored on a new `glow::Context`, so the glyph atlas and the caches of the old one are not reused. The main surface's logical size is the canvas's CSS size; the window's `resize` refits it, and on ltk's own canvas a hidden element padded by `env( safe-area-inset-* )` gives the insets. Input comes from Pointer Events, a mouse as the pointer and fingers and pens as touches, the wheel, in detents when it scrolls lines, and keys, whose keysym comes from `KeyboardEvent.key` and code from `.code` as the Linux input code Wayland reports; keys repeat on the browser's clock, AltGr types its character, and on macOS Command is Ctrl. ltk takes every key the browser lets a page have, and while fullscreen those `navigator.keyboard.lock()` adds in Chromium. Copies go to `navigator.clipboard.writeText`; a page reads the clipboard only from a `paste` event, so Ctrl+V is let through to the browser and held until its `paste` has put the text in `AppData::clipboard`, and a paste from the browser's menu comes with a Ctrl+V of its own. The cursor's shape is the canvas's CSS `cursor`. The built-in keyboard serves text where the page is used by touch. Panics go to the browser's console. When the app exits, the listeners are removed, the canvas receives an `ltk-exit` event and the app is dropped. The new `RunError::NoDocument` is returned where there is no page, as in a worker. Resources are the tree an Android package carries. `scripts/web-assets.sh` builds it through `android-assets.sh`, and `ltk::web::load_resources( base ).await` fetches its `MANIFEST` and every file it lists, with the manifest's hash in their URLs so a changed tree is not served from the browser's cache, into memory under `/ltk`, which becomes the resource directory. The per-script fallback fonts are read through `resources::read_font`, so a path that does not exist is found by file name in the resource directory's `fonts/`, where a page bundles them. A surface's scale may be fractional. `SurfaceState::scale_factor` is an `f32`, which `Platform::prepare_canvas`, `Presentation::scale` and the paint path take as it is; a surface's physical size is its logical size times the scale, rounded once, and `buffer_scale()` gives the whole number Wayland's buffer scale and regions need. Wayland and Android still set whole scales, so nothing changes there; the browser backend sets the page's `devicePixelRatio`, so the canvas holds the display's own pixels at any zoom. `App::on_scale_changed` keeps its `u32`, the scale rounded, and `App::on_resize` gives the exact physical size. The fallback-theme banner placed its text as if `draw_text` took the top of the line rather than its baseline, so most of the text fell above the banner, out of the surface; it is now centred as the title bar's is. Building. `make web-check` typechecks the backend. `make web-deps` installs Debian's std for wasm32 and wasm-bindgen-cli, whose version must be the one of the wasm-bindgen crate in `Cargo.lock`: the crate is pinned to 0.2.117, the last whose CLI builds with Debian's rustc 1.85, and since the lock the CLI was published with needs a newer rustc and `cargo install` ignores rust-version when it resolves, the CLI is built from its sources with a lock resolved for the rust-version it declares, into `target/tools`, where the Makefile finds it. `make web-assets` builds the resources with the in-tree default theme and the fallback fonts `WEB_FONTS` names. `examples/web_hello.rs`, a counter and a text field, and `web/index.html` are the smoke test: `make web-example` builds them into `target/web/` and `make web-serve` serves them. `make install` now copies `web/` into the registry. `README.md`, `docs/architecture.md` and `CHANGELOG.md` describe the backend, and `docs/cookbook.md` points to `ChannelSender`'s new home. Not done. In a browser there are no overlays, secondary surfaces or subsurfaces, no dead keys or input methods, no accessibility tree and no primary selection, and a canvas that changes size while the window does not is not refitted. Pasting relies on the browser sending `paste` to a focused canvas, which Chrome and Firefox do. The page fetches its whole resource tree, about 7 MB, before the app starts. There are no tests for the browser backend, `Sources`' queue or `vfs.rs`'s in-memory files, and fractional scales may leave one-pixel artefacts where edges fall between pixels.
167 lines
7.9 KiB
Makefile
167 lines
7.9 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
|
|
# 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 --example web_hello $(WEB_CARGO)
|
|
$(WASM_BINDGEN) --target web --no-typescript --out-dir $(WEB_OUT)/pkg target/$(WEB_TARGET)/release/examples/web_hello.wasm
|
|
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
|