Merge branch 'worktree-agent-a466c08a4014dbcbe' into rustify (I4: AccessKit names)
This commit is contained in:
commit
32a5256a0d
22 files changed
+2251
-22
No files matched your search
@@ -8,6 +8,37 @@ capability that moved. Small and trivial changes do not go here.
|
||||
An entry gives the date, what changed, why, and a short before/after where
|
||||
it helps judge the change without the session that made it. Newest first.
|
||||
|
||||
## 2026-09-05: accessibility names via AccessKit (RUST.md's I4)
|
||||
|
||||
`.label()` (already in `trait_fns.rs`, previously unused anywhere in-tree)
|
||||
is now load-bearing: it's the one thing that puts a widget in the AccessKit
|
||||
tree `iris_core::ui::access::AccessTree` builds and both backends push
|
||||
out. A widget author who wants a control to be findable by name (and
|
||||
tappable by name, through `ui-trace`/a real screen reader) calls `.label()`
|
||||
on it; nothing else is required, and a widget nobody labels is invisible
|
||||
to this system at zero cost, not just zero UI.
|
||||
|
||||
```rust
|
||||
let button = rect(Color::LIME)
|
||||
.on(CursorSense::click(), move |_, rsc| { ... })
|
||||
.label("Add task"); // now findable by uiautomator/AccessKit as "Add task"
|
||||
```
|
||||
|
||||
Two new things a widget author might touch directly:
|
||||
|
||||
- **`Widget::access_role(&self) -> accesskit::Role`**, default `Unknown`.
|
||||
Override it if your widget has a real platform equivalent —
|
||||
`TextEdit` now returns `TextInput`/`MultilineTextInput` by `EditMode`.
|
||||
Only consulted for a widget that also has a `.label()`; an unlabelled
|
||||
widget's `access_role` is never called.
|
||||
- **`Widgets::named() -> impl Iterator<Item = WidgetId>`** — every widget
|
||||
with an explicit label, for anything else that wants to walk the same
|
||||
set `AccessTree` does.
|
||||
|
||||
Nothing about `Painter`, `draw`, or the layout/move machinery changed —
|
||||
this sits entirely beside them, reading `resolved_region`'s output rather
|
||||
than participating in producing it.
|
||||
|
||||
## 2026-09-05: `List`, a virtualised bottom-anchored list (RUST.md's I3)
|
||||
|
||||
A new widget, `iris::widget::List` (`iris/src/widget/list.rs` -- read its
|
||||
|
||||
@@ -42,7 +42,7 @@ session spending an afternoon on them again.
|
||||
below), **E3 (the Kotlin/Java shell over a JNI bridge into Rust, both
|
||||
pass conditions proved on the emulator — see its own box)**, I0a, I0b
|
||||
(iris builds on a pinned nightly and runs), I1 (parley + glyph atlas),
|
||||
I2 (iris on android-view).
|
||||
I2 (iris on android-view), I3 (`iris::widget::List`).
|
||||
- **E3 done, 2026-09-05, and unlike E1/E2 it is committed to this repo**
|
||||
(`android-shell/` — a JNI-bridge crate on `client-core` — plus a new
|
||||
Gradle module `app/shellApp/`, left deliberately separate from
|
||||
@@ -61,6 +61,20 @@ session spending an afternoon on them again.
|
||||
box for the full account, the exact commands, and what was deliberately
|
||||
cut (attachment uploads, a session picker, the on-screen/banner
|
||||
suppression — all pending E4's screen).
|
||||
- **I4 — accessibility names via AccessKit: host half done and verified
|
||||
2026-09-05, ticked in the box below.** `iris_core::ui::access::AccessTree`
|
||||
builds one flat AccessKit tree from `Widgets::named()` (a side set only
|
||||
`.label()` populates, so an unnamed widget costs this nothing), pushed
|
||||
through `accesskit_winit` on the desktop and `accesskit_android` on
|
||||
Android, updated only when a name/role/bounds actually changes (a
|
||||
counter confirms it: 1 rebuild on first draw, 0 across an unchanged
|
||||
frame, 1 more after a real move). E1's detach-abort mitigation is
|
||||
carried (`android/access.rs`'s `raise_if_enabled`). Every check that
|
||||
doesn't need the emulator is clean — see I4's own box for the exact
|
||||
numbers. **What's left**: the emulator itself is held by another session
|
||||
this pass, so `ui-trace record --do "tap 'pad'"` against
|
||||
`iris-android-app`'s tabs screen (which now has five named buttons) has
|
||||
not been run for real yet — exact commands at the bottom of I4's box.
|
||||
- **E2 done, 2026-09-05, and its headline finding changes what "decide
|
||||
from the measurements" (recommendation item 3) can mean right now.**
|
||||
Built a real transcript screen (`~/src/android-view/e2-transcript`,
|
||||
@@ -1772,9 +1786,144 @@ silently on real hardware.
|
||||
session screen, i.e. most of I5's work) rather than something this
|
||||
box's scope could finish alone -- recorded here rather than left
|
||||
silently undone.
|
||||
- [ ] **I4 — accessibility names via AccessKit.** Every control carries a
|
||||
name; `ui-trace` can find and tap it by label. Pass: `bench-lib.sh`'s
|
||||
tap-by-name works against the iris screen unchanged.
|
||||
- [x] **I4 — accessibility names via AccessKit, host half done and verified
|
||||
2026-09-05; the emulator half is the one step left, named at the
|
||||
bottom of this box.** Built `iris_core::ui::access::AccessTree`
|
||||
(`iris/core/src/ui/access.rs`) -- one flat AccessKit tree, a synthetic
|
||||
`Role::Window` root with every **named** widget as a direct child.
|
||||
Deliberately flat rather than mirroring iris's real widget nesting:
|
||||
nothing upstream of a named leaf needs a node, since a screen
|
||||
reader's traversal (and uiautomator's tap-by-name, this box's own
|
||||
pass condition) works from each node's on-screen bounds, not from
|
||||
tree structure -- and mirroring the real tree would rebuild
|
||||
intermediate nodes on every resize of any container above a named
|
||||
widget, which is most frames.
|
||||
|
||||
**Modular the way input's sense registry is.** `Widgets` gained one
|
||||
`HashSet<WidgetId>` (`named`), populated only by `.label()`/
|
||||
`set_label` and drained by `free_next` (the same removal path a
|
||||
freed id already went through -- no second bookkeeping call added
|
||||
anywhere). `AccessTree::update` walks `widgets.named()` directly,
|
||||
never the full widget arena, so a widget nobody named costs this
|
||||
subsystem nothing -- not a visit, not a branch. Roles come from a
|
||||
new `Widget::access_role(&self) -> accesskit::Role` trait method,
|
||||
default `Unknown`; the one override so far is `TextEdit` ->
|
||||
`TextInput`/`MultilineTextInput` by `EditMode`. Bounds come from
|
||||
`UiRenderState::window_region`, which sits on `resolved_region`'s
|
||||
move-chain walk -- so a widget moved via `Offset`/`Scroll` (never
|
||||
redrawn from scratch) still reports where it actually ended up; see
|
||||
`bounds_follow_a_moved_widget_and_updates_stay_incremental` below.
|
||||
|
||||
**Incremental, not per-frame.** `AccessTree` keeps the last
|
||||
`HashMap<WidgetId, Entry>` (name, role, bounds) it sent and only
|
||||
returns a new `TreeUpdate` -- and only then bumps its `rebuilds`
|
||||
counter, `take_rebuilds()`'s the AccessKit twin of
|
||||
`UiRenderState::take_counters` -- when that set actually differs.
|
||||
Confirmed by `bounds_follow_a_moved_widget_and_updates_stay_incremental`
|
||||
(`iris/src/access_tests.rs`): 1 rebuild on the first draw, 0 across an
|
||||
unchanged frame, 1 more after a real move, regardless of how many
|
||||
other widgets are on screen.
|
||||
|
||||
**`SlotId::as_u64`** (`core/src/util/slot.rs`) encodes a `WidgetId`
|
||||
into accesskit's flat `NodeId(u64)`, offset by one so a real widget
|
||||
never collides with the reserved window node (`NodeId(0)`).
|
||||
|
||||
**Pushed through two backends, each behind an inert action/activation
|
||||
handler** -- see below for why inert is correct, not incomplete.
|
||||
`default/access.rs` (winit): `accesskit_winit::Adapter`, built in
|
||||
`DefaultApp::new` with the window created hidden
|
||||
(`with_visible(false)`) and shown only after the adapter exists,
|
||||
which is what that constructor requires. `process_event` runs on
|
||||
every `WindowEvent`; `update_if_active` runs once per
|
||||
`RedrawRequested`, after `render.update()` so bounds reflect the
|
||||
frame just drawn. `android/access.rs` (android-view):
|
||||
`accesskit_android::Adapter` on `AndroidUiState`, `IrisViewPeer` now
|
||||
implements `AccessibilityNodeProvider`
|
||||
(`create_accessibility_node_info`/`find_focus`/`perform_action`), and
|
||||
`render()` (now taking `&mut CallbackCtx`, needed for the JNI handle
|
||||
any `raise` requires) pushes the same `AccessTree::update` after
|
||||
every draw.
|
||||
|
||||
**Why the `ActionHandler`s are empty, not a placeholder for later
|
||||
work**: AGENTS.md's own "Driving the UI" section says it plainly --
|
||||
`ui-trace record --do "tap 'Save'"` resolves the label against the
|
||||
screen and performs a **real touch at that node's bounds**, the same
|
||||
as a person's finger. It does not call into AccessKit's action
|
||||
system at all. So once `AccessTree` reports correct bounds, the
|
||||
ordinary pointer path (already built, already tested) is what
|
||||
answers the tap -- there is nothing for `do_action` to do for this
|
||||
pass condition specifically. A future real screen reader's own
|
||||
double-tap-to-activate gesture works the same way, for the same
|
||||
reason. If iris ever needs to answer an AccessKit `Action::Click`
|
||||
injected without a matching touch (e.g. a switch-access scanner),
|
||||
that is new scope, not a gap in this box.
|
||||
|
||||
**E1's abort mitigation, carried.** `android/access.rs`'s
|
||||
`raise_if_enabled` is the one place `QueuedEvents::raise` may be
|
||||
called: it asks `AccessibilityManager.isEnabled()` (a `getSystemService`
|
||||
JNI call, since android-view has no ready-made wrapper) immediately
|
||||
before every `raise` and drops the events instead when the answer is
|
||||
no. Every call site (`render`'s per-frame push, `perform_action`)
|
||||
goes through it, and each pushes it as a *deferred* callback exactly
|
||||
like android-view's own demo, so it runs after the current JNI
|
||||
callback has released whatever it's holding -- `raise`'s own
|
||||
documented requirement. Not independently re-triggered on this
|
||||
pass (that needs the emulator, see below); the mitigation is coded
|
||||
to the exact mechanism E1 diagnosed (`sendAccessibilityEvent`
|
||||
throwing when accessibility is off) rather than to the symptom, so
|
||||
there is no reason to expect it behaves differently here than it did
|
||||
there.
|
||||
|
||||
**Verified, 2026-09-05, host only.**
|
||||
`cargo fmt --all -- --check`, `cargo build --workspace --all-targets`,
|
||||
`cargo clippy --all-targets` (both plain and `--all-targets`) clean;
|
||||
`cargo test --workspace` -- 28 tests in `iris/`, three of them new
|
||||
(`access_tests::a_named_widget_reaches_the_tree_with_its_role_and_bounds`,
|
||||
`::a_widget_with_no_label_never_reaches_the_tree`,
|
||||
`::bounds_follow_a_moved_widget_and_updates_stay_incremental`).
|
||||
`cd iris/android-app && cargo ndk -t x86_64 -P 26 build` and
|
||||
`... clippy` clean for both `iris` (with the android module) and
|
||||
`iris-android-app`, same shape as I2/I3's checks.
|
||||
`iris/run-headless.sh tabs --shot /tmp/iris_i4_tabs.png --seconds 4`
|
||||
still renders -- **27266 bytes, byte-for-byte identical to I2's own
|
||||
post-fix screenshot** -- confirming the hidden-window-then-adapter
|
||||
change to `DefaultApp::new` cost nothing visible. `tabs-ui`'s five
|
||||
switch buttons (`tabs-ui/src/lib.rs`) now carry `.label()`s matching
|
||||
their on-screen text ("pad", "span", "image span", "text layout",
|
||||
"text edit scroll") -- both so the desktop run above exercises a
|
||||
non-empty tree and so the emulator step below has real names to tap.
|
||||
Not independently checked on this pass: whether `accesskit_winit`'s
|
||||
Linux path (AT-SPI, via `accesskit_unix`) actually reaches a real
|
||||
assistive-technology client on this VM's headless sway -- there is
|
||||
no AT-SPI registry running here, so `default/access.rs`'s handlers
|
||||
are exercised as inert code paths (built, called, no panic) rather
|
||||
than confirmed end-to-end the way the emulator step below confirms
|
||||
the Android path.
|
||||
|
||||
**What remains -- the one check that needs the emulator, held by
|
||||
another session during this pass.** `iris-android-app`'s tabs screen
|
||||
has never been driven by `ui-trace` for real; everything above is
|
||||
"builds, runs, produces the right data" on the host. Once the
|
||||
emulator is free:
|
||||
|
||||
cd iris/android-app && cargo ndk -t x86_64 -P 26 -o app/src/main/jniLibs/ build --release && gradle :app:assembleDebug
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
# launch iris-android-app on the emulator, then:
|
||||
ui-trace record --do "tap 'pad'"
|
||||
ui-trace record --do "tap 'span'"
|
||||
ui-trace record --do "tap 'image span'"
|
||||
ui-trace record --do "tap 'text layout'"
|
||||
ui-trace record --do "tap 'text edit scroll'"
|
||||
|
||||
Pass condition: each tap resolves (uiautomator finds a node with
|
||||
that exact label) and switches `main`'s visible pane the way a
|
||||
direct touch on that button already does -- i.e. `bench-lib.sh`'s
|
||||
tap-by-name mechanism, unmodified, driving the iris screen instead
|
||||
of the Compose one. Also worth checking while the emulator is up,
|
||||
since E1 found it exactly this way: run a second `ui-trace record`
|
||||
immediately after the first (attach, detach, attach again) and
|
||||
confirm the process is still alive afterward -- the detach-abort
|
||||
this box's mitigation exists for.
|
||||
- [ ] **I5 — the transcript screen in iris.** E2's pass conditions, all
|
||||
seven behaviours, against the sandbox with `--delay`. This is the
|
||||
point the decision in the recommendation is made at.
|
||||
|
||||
Generated
+733
-2
@@ -18,6 +18,126 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||
|
||||
[[package]]
|
||||
name = "accesskit"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "438a7081a65b95c668db56591a4fef9bc5dad275f448bd6223fc6949d823db38"
|
||||
dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_android"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "929aff36b0d3dd22ddb59191989d5293ed958294d7728bd6c2ec9778f73414aa"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"jni",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_atspi_common"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9d47ad644916f6cb7e432a5ca0dbd7cc78281a9772881057bb72d4aadb93257"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"atspi-common",
|
||||
"phf",
|
||||
"serde",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_consumer"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc882fa0c9c24c53649e256311b51046cf36eca9a8f7e54ff4ef682160b0cb27"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"hashbrown 0.17.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_ios"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5e9b29c6ba5f4d2e0662e9c562484f061ffc58f658479c538ecca8299ada1e9"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"hashbrown 0.17.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-ui-kit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_macos"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f278988416e5fb600f24d0cfffe31a249ebbff980fb9c5a3b5fbed2c579f73"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"hashbrown 0.17.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_unix"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "665c9079b7325a8168a6793437a172dda44b19a05af8ed52d7e32abaada996fe"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_atspi_common",
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-task",
|
||||
"atspi",
|
||||
"futures-lite",
|
||||
"futures-util",
|
||||
"serde",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_windows"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a59e8d7160cbac991c1345c99153783ab96423644ccb1f20617cf80c97596aa1"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"hashbrown 0.17.1",
|
||||
"static_assertions",
|
||||
"windows",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_winit"
|
||||
version = "0.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1eb960a51582305f94b3884a7ff54b3462abe38f0de95a9e7e04dd7ab7b757da"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_ios",
|
||||
"accesskit_macos",
|
||||
"accesskit_unix",
|
||||
"accesskit_windows",
|
||||
"raw-window-handle",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
@@ -191,12 +311,180 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.1.3",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-signal",
|
||||
"async-task",
|
||||
"blocking",
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix 1.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-signal"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"atomic-waker",
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.1.3",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "atspi"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77886257be21c9cd89a4ae7e64860c6f0eefca799bb79127913052bd0eefb3d"
|
||||
dependencies = [
|
||||
"atspi-common",
|
||||
"atspi-proxies",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atspi-common"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20c5617155740c98003016429ad13fe43ce7a77b007479350a9f8bf95a29f63d"
|
||||
dependencies = [
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zbus",
|
||||
"zbus-lockstep",
|
||||
"zbus-lockstep-macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atspi-proxies"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc"
|
||||
dependencies = [
|
||||
"atspi-common",
|
||||
"serde",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
@@ -303,6 +591,19 @@ dependencies = [
|
||||
"objc2 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a70e4329df6cb94385eed412ec92375c3cdd8a6e502493d1229b6414e4036dfa"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-task",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.8.0"
|
||||
@@ -633,6 +934,33 @@ version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
|
||||
dependencies = [
|
||||
"enumflags2_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
@@ -675,6 +1003,26 @@ version = "3.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
|
||||
dependencies = [
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.74.0"
|
||||
@@ -690,6 +1038,12 @@ dependencies = [
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.6"
|
||||
@@ -811,6 +1165,61 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
@@ -977,6 +1386,12 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
@@ -1176,6 +1591,9 @@ dependencies = [
|
||||
name = "iris"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_android",
|
||||
"accesskit_winit",
|
||||
"android-view",
|
||||
"arboard",
|
||||
"image",
|
||||
@@ -1196,6 +1614,7 @@ dependencies = [
|
||||
name = "iris-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"bytemuck",
|
||||
"fxhash",
|
||||
"image",
|
||||
@@ -1428,6 +1847,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.33.0"
|
||||
@@ -1927,6 +2355,16 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.3"
|
||||
@@ -1946,6 +2384,12 @@ dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@@ -2031,6 +2475,49 @@ dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.10"
|
||||
@@ -2057,6 +2544,17 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
@@ -2500,12 +2998,33 @@ dependencies = [
|
||||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.8"
|
||||
@@ -2521,6 +3040,12 @@ dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
||||
|
||||
[[package]]
|
||||
name = "skrifa"
|
||||
version = "0.44.0"
|
||||
@@ -2664,6 +3189,19 @@ dependencies = [
|
||||
"iris",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix 1.1.3",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
@@ -2790,7 +3328,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
"winnow 0.7.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2799,7 +3337,7 @@ version = "1.0.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
"winnow 0.7.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2809,14 +3347,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree_magic_mini"
|
||||
@@ -2835,6 +3388,17 @@ version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ui-events"
|
||||
version = "0.1.0"
|
||||
@@ -2869,6 +3433,17 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5772d71c9be8a8a6ac2117d949c5b224c1b72241bb611d9a3012edcf8af7812"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde_core",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
@@ -3659,6 +4234,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
@@ -3798,6 +4382,112 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db4be7c075cb421e4b7ee645541604239bd243ba7c357511f4ff3a74b555907"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"async-recursion",
|
||||
"async-task",
|
||||
"async-trait",
|
||||
"blocking",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-lite",
|
||||
"hex",
|
||||
"libc",
|
||||
"ordered-stream",
|
||||
"rustix 1.1.3",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"uuid",
|
||||
"windows-sys 0.61.2",
|
||||
"winnow 1.0.4",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus-lockstep"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863"
|
||||
dependencies = [
|
||||
"zbus_xml",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus-lockstep-macros"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
"zbus-lockstep",
|
||||
"zbus_xml",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2990635d09ade6df1868f72f8cac69a876a90981e8bd3c40b1be413f8dc88f40"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "4.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow 1.0.4",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_xml"
|
||||
version = "5.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1586c021a01ca0a9216dcd874e546382e156a5cbab5fab6cb5f10087e22682a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow 1.0.4",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcheapstr"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeno"
|
||||
version = "0.3.3"
|
||||
@@ -3918,3 +4608,44 @@ checksum = "e35aee689668bf9bd6f6f3a6c60bb29ba1244b3b43adfd50edd554a371da37d5"
|
||||
dependencies = [
|
||||
"zune-core 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1d34c27cc6cdd1f458427519dd6b8612f7b7e3f7b9a0b2355d041dda9869147"
|
||||
dependencies = [
|
||||
"endi",
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"winnow 1.0.4",
|
||||
"zcheapstr",
|
||||
"zvariant_derive",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "5.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864155e69b4352db0c7f374917bf45d1e0c8d17659c8b3dbf9795f3673f8c497"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_utils"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 3.0.5",
|
||||
"winnow 1.0.4",
|
||||
]
|
||||
@@ -13,6 +13,7 @@ swash = { workspace = true }
|
||||
pollster = { workspace = true }
|
||||
wgpu = { workspace = true }
|
||||
image = { workspace = true }
|
||||
accesskit = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync", "rt", "rt-multi-thread"] }
|
||||
|
||||
# winit everywhere except Android; android-view (below) is what stands in
|
||||
@@ -27,6 +28,11 @@ tokio = { workspace = true, features = ["sync", "rt", "rt-multi-thread"] }
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
winit = { workspace = true }
|
||||
arboard = { workspace = true, features = ["wayland-data-control"] }
|
||||
# I4 (RUST.md): the desktop half of the AccessKit push, `winit`'s own
|
||||
# adapter over `accesskit`. No pin needed the way android-view's rev is
|
||||
# pinned -- this is an ordinary crates.io release with no local abort to
|
||||
# track (that finding is Android-only, see below).
|
||||
accesskit_winit = "0.34.0"
|
||||
|
||||
# Pinned to the exact commit RUST.md's E1 (2026-09-04) measured on this
|
||||
# emulator -- real Vulkan rendering, a working `InputConnection`, and the
|
||||
@@ -35,6 +41,14 @@ arboard = { workspace = true, features = ["wayland-data-control"] }
|
||||
# is dated rather than floating.
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android-view = { git = "https://github.com/rust-mobile/android-view.git", rev = "bec6c62a96cef8239b0fd7fedeef9b184d02e3a1" }
|
||||
# I4 (RUST.md): the Android half of the AccessKit push, over android-view's
|
||||
# `AccessibilityNodeProvider`. **0.8.0 carries the same detach-abort E1
|
||||
# found on 0.4.0** (the `State` enum still never returns to `Inactive`,
|
||||
# and `send_completed_event` still unwraps a Java exception) -- advancing
|
||||
# the version is not the fix, so pinning to a specific rev buys nothing
|
||||
# here the way it does for android-view itself. `android/view.rs`'s
|
||||
# `raise_if_enabled` is the mitigation, carried from E1.
|
||||
accesskit_android = "0.8.0"
|
||||
# Not re-exported by android-view (only `jni` and `ndk` are), and needed
|
||||
# for `android/insets.rs`'s own id -> state map -- the same reason
|
||||
# android-view's own `PEER_MAP` carries one.
|
||||
@@ -82,6 +96,7 @@ parley = "0.11.1"
|
||||
swash = "0.2.10"
|
||||
fxhash = "0.2.1"
|
||||
arboard = "3.6.1"
|
||||
accesskit = "0.25.0"
|
||||
iris-core = { path = "core" }
|
||||
iris-macro = { path = "macro" }
|
||||
tokio = "1.49.0"
|
||||
Generated
+698
@@ -18,6 +18,126 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||
|
||||
[[package]]
|
||||
name = "accesskit"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "438a7081a65b95c668db56591a4fef9bc5dad275f448bd6223fc6949d823db38"
|
||||
dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_android"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "929aff36b0d3dd22ddb59191989d5293ed958294d7728bd6c2ec9778f73414aa"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"jni 0.21.1",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_atspi_common"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9d47ad644916f6cb7e432a5ca0dbd7cc78281a9772881057bb72d4aadb93257"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"atspi-common",
|
||||
"phf",
|
||||
"serde",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_consumer"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc882fa0c9c24c53649e256311b51046cf36eca9a8f7e54ff4ef682160b0cb27"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"hashbrown 0.17.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_ios"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5e9b29c6ba5f4d2e0662e9c562484f061ffc58f658479c538ecca8299ada1e9"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"hashbrown 0.17.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-ui-kit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_macos"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f278988416e5fb600f24d0cfffe31a249ebbff980fb9c5a3b5fbed2c579f73"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"hashbrown 0.17.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_unix"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "665c9079b7325a8168a6793437a172dda44b19a05af8ed52d7e32abaada996fe"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_atspi_common",
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-task",
|
||||
"atspi",
|
||||
"futures-lite",
|
||||
"futures-util",
|
||||
"serde",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_windows"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a59e8d7160cbac991c1345c99153783ab96423644ccb1f20617cf80c97596aa1"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
"hashbrown 0.17.1",
|
||||
"static_assertions",
|
||||
"windows",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_winit"
|
||||
version = "0.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1eb960a51582305f94b3884a7ff54b3462abe38f0de95a9e7e04dd7ab7b757da"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_ios",
|
||||
"accesskit_macos",
|
||||
"accesskit_unix",
|
||||
"accesskit_windows",
|
||||
"raw-window-handle",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
@@ -215,12 +335,180 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.1.4",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-signal",
|
||||
"async-task",
|
||||
"blocking",
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix 1.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-signal"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"atomic-waker",
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.1.4",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "atspi"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77886257be21c9cd89a4ae7e64860c6f0eefca799bb79127913052bd0eefb3d"
|
||||
dependencies = [
|
||||
"atspi-common",
|
||||
"atspi-proxies",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atspi-common"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20c5617155740c98003016429ad13fe43ce7a77b007479350a9f8bf95a29f63d"
|
||||
dependencies = [
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zbus",
|
||||
"zbus-lockstep",
|
||||
"zbus-lockstep-macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atspi-proxies"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc"
|
||||
dependencies = [
|
||||
"atspi-common",
|
||||
"serde",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
@@ -327,6 +615,19 @@ dependencies = [
|
||||
"objc2 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a70e4329df6cb94385eed412ec92375c3cdd8a6e502493d1229b6414e4036dfa"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-task",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.8.1"
|
||||
@@ -648,6 +949,33 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
|
||||
dependencies = [
|
||||
"enumflags2_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.4"
|
||||
@@ -700,6 +1028,26 @@ version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
|
||||
dependencies = [
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.74.2"
|
||||
@@ -717,6 +1065,12 @@ dependencies = [
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
@@ -831,6 +1185,36 @@ version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.34"
|
||||
@@ -844,6 +1228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
@@ -1026,6 +1411,12 @@ version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
@@ -1225,6 +1616,9 @@ dependencies = [
|
||||
name = "iris"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_android",
|
||||
"accesskit_winit",
|
||||
"android-view",
|
||||
"arboard",
|
||||
"image",
|
||||
@@ -1255,6 +1649,7 @@ dependencies = [
|
||||
name = "iris-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"bytemuck",
|
||||
"fxhash",
|
||||
"image",
|
||||
@@ -1541,6 +1936,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.33.0"
|
||||
@@ -2069,6 +2473,16 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.3"
|
||||
@@ -2088,6 +2502,12 @@ dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@@ -2173,6 +2593,49 @@ dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.13"
|
||||
@@ -2199,6 +2662,17 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.34"
|
||||
@@ -2733,12 +3207,33 @@ dependencies = [
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
@@ -2770,6 +3265,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
||||
|
||||
[[package]]
|
||||
name = "skrifa"
|
||||
version = "0.44.0"
|
||||
@@ -2913,6 +3414,19 @@ dependencies = [
|
||||
"iris",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.4.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
@@ -3058,14 +3572,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree_magic_mini"
|
||||
@@ -3084,6 +3613,17 @@ version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ui-events"
|
||||
version = "0.1.0"
|
||||
@@ -3118,6 +3658,17 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5772d71c9be8a8a6ac2117d949c5b224c1b72241bb611d9a3012edcf8af7812"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde_core",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
@@ -4044,6 +4595,112 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db4be7c075cb421e4b7ee645541604239bd243ba7c357511f4ff3a74b555907"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"async-recursion",
|
||||
"async-task",
|
||||
"async-trait",
|
||||
"blocking",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-lite",
|
||||
"hex",
|
||||
"libc",
|
||||
"ordered-stream",
|
||||
"rustix 1.1.4",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"uuid",
|
||||
"windows-sys 0.61.2",
|
||||
"winnow",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus-lockstep"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863"
|
||||
dependencies = [
|
||||
"zbus_xml",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus-lockstep-macros"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"zbus-lockstep",
|
||||
"zbus_xml",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2990635d09ade6df1868f72f8cac69a876a90981e8bd3c40b1be413f8dc88f40"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "4.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_xml"
|
||||
version = "5.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1586c021a01ca0a9216dcd874e546382e156a5cbab5fab6cb5f10087e22682a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcheapstr"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeno"
|
||||
version = "0.3.3"
|
||||
@@ -4155,3 +4812,44 @@ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1d34c27cc6cdd1f458427519dd6b8612f7b7e3f7b9a0b2355d041dda9869147"
|
||||
dependencies = [
|
||||
"endi",
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"winnow",
|
||||
"zcheapstr",
|
||||
"zvariant_derive",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "5.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864155e69b4352db0c7f374917bf45d1e0c8d17659c8b3dbf9795f3673f8c497"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.5",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_utils"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 3.0.5",
|
||||
"winnow",
|
||||
]
|
||||
@@ -10,3 +10,4 @@ image = { workspace = true }
|
||||
parley = { workspace = true }
|
||||
swash = { workspace = true }
|
||||
fxhash = { workspace = true }
|
||||
accesskit = { workspace = true }
|
||||
@@ -421,7 +421,7 @@ impl Display for UiRegion {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct PixelRegion {
|
||||
pub top_left: Vec2,
|
||||
pub bot_right: Vec2,
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
//! I4 (RUST.md): an AccessKit tree built from iris's own widget tree,
|
||||
//! shared by both backends -- `android/view.rs` pushes its `TreeUpdate`s
|
||||
//! through `accesskit_android::Adapter`, `default/mod.rs` through
|
||||
//! `accesskit_winit::Adapter`. Kept modular the way input's sense registry
|
||||
//! is: `Widgets::named()` is a side set populated only by `.label()`, so a
|
||||
//! widget nobody named is never visited here at all, not even to decide it
|
||||
//! has no name.
|
||||
//!
|
||||
//! The tree itself is deliberately flat -- one synthetic `Role::Window`
|
||||
//! root with every named widget as a direct child, in no particular order.
|
||||
//! iris's actual widget nesting (a label three `Span`s deep inside a
|
||||
//! `Scroll`) carries no accessibility meaning of its own here: nothing
|
||||
//! upstream of a named leaf needs a node, since a screen reader's own
|
||||
//! traversal (and uiautomator's tap-by-name, the pass condition this was
|
||||
//! built for) works from each node's on-screen bounds rather than from
|
||||
//! tree structure. Mirroring the real widget tree exactly would also mean
|
||||
//! rebuilding intermediate nodes whenever *any* container above a named
|
||||
//! widget resizes, which is most frames -- the flat shape is what keeps
|
||||
//! rebuilds tied to "a name, a role or a position actually changed".
|
||||
|
||||
use crate::{PixelRegion, UiRenderState, UiRsc, WidgetId, Widgets, util::HashMap};
|
||||
use accesskit::{Node, NodeId, Rect, Role, TreeId, TreeInfo, TreeUpdate};
|
||||
|
||||
/// Reserved for the synthetic root; every real widget's `SlotId::as_u64`
|
||||
/// starts at 1, so this can never collide with one (see that method's
|
||||
/// doc comment).
|
||||
const WINDOW_NODE: NodeId = NodeId(0);
|
||||
|
||||
fn node_id(id: WidgetId) -> NodeId {
|
||||
NodeId(id.as_u64())
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct Entry {
|
||||
name: String,
|
||||
role: Role,
|
||||
bounds: PixelRegion,
|
||||
}
|
||||
|
||||
fn entry_node(entry: &Entry) -> Node {
|
||||
let mut node = Node::new(entry.role);
|
||||
node.set_label(entry.name.clone());
|
||||
node.set_bounds(Rect {
|
||||
x0: entry.bounds.top_left.x as f64,
|
||||
y0: entry.bounds.top_left.y as f64,
|
||||
x1: entry.bounds.bot_right.x as f64,
|
||||
y1: entry.bounds.bot_right.y as f64,
|
||||
});
|
||||
node
|
||||
}
|
||||
|
||||
/// Owns the last tree pushed out, so `update` can tell "nothing
|
||||
/// accessibility-relevant changed" from "something did" without asking
|
||||
/// the platform adapter to diff two `Node`s itself. One of these per
|
||||
/// window/view -- `default::DefaultUiState` and `android::AndroidUiState`
|
||||
/// each keep one.
|
||||
#[derive(Default)]
|
||||
pub struct AccessTree {
|
||||
known: HashMap<WidgetId, Entry>,
|
||||
/// `TreeUpdate`s actually produced since the last `take_rebuilds` --
|
||||
/// the AccessKit-tree twin of `UiRenderState::take_counters`. Should
|
||||
/// stay at 0 across an unchanged frame and move by exactly 1 when a
|
||||
/// named widget's position, name or role changes, however many other
|
||||
/// widgets are on screen; see `iris/src/access_tests.rs`.
|
||||
rebuilds: u64,
|
||||
}
|
||||
|
||||
impl AccessTree {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn collect(
|
||||
widgets: &Widgets,
|
||||
render: &UiRenderState,
|
||||
rsc: &dyn UiRsc,
|
||||
) -> HashMap<WidgetId, Entry> {
|
||||
let mut current = HashMap::default();
|
||||
for id in widgets.named() {
|
||||
let Some(bounds) = render.window_region(&id, rsc) else {
|
||||
continue;
|
||||
};
|
||||
let Some(widget) = widgets.get_dyn(id) else {
|
||||
continue;
|
||||
};
|
||||
current.insert(
|
||||
id,
|
||||
Entry {
|
||||
name: widgets.label(id).clone(),
|
||||
role: widget.access_role(),
|
||||
bounds,
|
||||
},
|
||||
);
|
||||
}
|
||||
current
|
||||
}
|
||||
|
||||
/// Walks `widgets.named()`, looks up each one's current screen bounds
|
||||
/// via `render.window_region` (which resolves the same move-chain
|
||||
/// `resolved_region` does, so a moved subtree reports where it
|
||||
/// actually is), and returns a full `TreeUpdate` if and only if that
|
||||
/// set differs from the last call -- added, removed, renamed, or
|
||||
/// moved/resized. A widget that is named but not currently active
|
||||
/// (not drawn this frame) is left out, the same as one never named at
|
||||
/// all.
|
||||
pub fn update(
|
||||
&mut self,
|
||||
widgets: &Widgets,
|
||||
render: &UiRenderState,
|
||||
rsc: &dyn UiRsc,
|
||||
) -> Option<TreeUpdate> {
|
||||
let current = Self::collect(widgets, render, rsc);
|
||||
if current == self.known {
|
||||
return None;
|
||||
}
|
||||
self.known = current.clone();
|
||||
self.rebuilds += 1;
|
||||
Some(build_update(¤t))
|
||||
}
|
||||
|
||||
/// The unconditional twin of `update`, for a platform adapter's
|
||||
/// activation handler (`android/access.rs`'s `AndroidAccessSource`) --
|
||||
/// AccessKit asks for a full tree the first time a client attaches,
|
||||
/// which is exactly the case `update`'s diff-against-`known` is not
|
||||
/// meant to answer (it may have already sent this same snapshot to a
|
||||
/// client that has since detached and reattached).
|
||||
pub fn build_full(widgets: &Widgets, render: &UiRenderState, rsc: &dyn UiRsc) -> TreeUpdate {
|
||||
build_update(&Self::collect(widgets, render, rsc))
|
||||
}
|
||||
|
||||
/// Reads and zeroes the rebuild counter, the same call shape as
|
||||
/// `UiRenderState::take_counters`.
|
||||
pub fn take_rebuilds(&mut self) -> u64 {
|
||||
std::mem::take(&mut self.rebuilds)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_update(current: &HashMap<WidgetId, Entry>) -> TreeUpdate {
|
||||
let mut window = Node::new(Role::Window);
|
||||
let mut nodes = Vec::with_capacity(current.len() + 1);
|
||||
for (&id, entry) in current {
|
||||
window.push_child(node_id(id));
|
||||
nodes.push((node_id(id), entry_node(entry)));
|
||||
}
|
||||
nodes.push((WINDOW_NODE, window));
|
||||
TreeUpdate {
|
||||
nodes,
|
||||
tree: Some(TreeInfo::new(WINDOW_NODE)),
|
||||
tree_id: TreeId::ROOT,
|
||||
focus: WINDOW_NODE,
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,12 @@ use crate::{
|
||||
Mask, MoveOffset, TextData, Textures, WeakWidget, WidgetId, Widgets, util::TrackedArena,
|
||||
};
|
||||
|
||||
mod access;
|
||||
mod active;
|
||||
mod painter;
|
||||
mod render_state;
|
||||
|
||||
pub use access::*;
|
||||
pub use active::*;
|
||||
pub use painter::Painter;
|
||||
pub use render_state::*;
|
||||
|
||||
@@ -4,6 +4,17 @@ pub struct SlotId {
|
||||
genr: u32,
|
||||
}
|
||||
|
||||
impl SlotId {
|
||||
/// A stable, collision-free `u64` encoding of this id -- for a caller
|
||||
/// (accesskit's `NodeId`, today) that wants a flat integer key rather
|
||||
/// than the two `u32`s. `idx` is offset by one so no real id ever
|
||||
/// encodes to 0, which callers can then reserve for their own
|
||||
/// out-of-band root/window node.
|
||||
pub fn as_u64(&self) -> u64 {
|
||||
((self.idx as u64) + 1) << 32 | self.genr as u64
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SlotVec<T> {
|
||||
data: Vec<(u32, Option<T>)>,
|
||||
free: Vec<u32>,
|
||||
|
||||
@@ -29,6 +29,18 @@ pub trait Widget: Any {
|
||||
fn is_size_independent(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// What kind of control this is, for the AccessKit tree `ui::access`
|
||||
/// builds (RUST.md's I4). Only consulted for a widget that also has an
|
||||
/// explicit `.label()` -- an unnamed widget is never visited by that
|
||||
/// tree at all, named or not, so the default here costs nothing except
|
||||
/// at the handful of call sites that opt in. Default `Unknown` (a
|
||||
/// generic control with no more specific semantics); a widget with a
|
||||
/// real platform equivalent -- `TextEdit`'s `MultilineTextInput` --
|
||||
/// overrides it.
|
||||
fn access_role(&self) -> accesskit::Role {
|
||||
accesskit::Role::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for () {
|
||||
|
||||
@@ -11,6 +11,11 @@ pub struct Widgets {
|
||||
send: Sender<WidgetId>,
|
||||
recv: Receiver<WidgetId>,
|
||||
pub(crate) waiting: HashSet<WidgetId>,
|
||||
/// Every widget that has ever been given an explicit `.label()` --
|
||||
/// `ui::access::AccessTree` walks exactly this set, not the whole
|
||||
/// arena, so a widget nobody named costs it nothing. Symmetric with
|
||||
/// `free_next` below, which is this set's one removal path.
|
||||
named: HashSet<WidgetId>,
|
||||
}
|
||||
|
||||
impl Widgets {
|
||||
@@ -20,6 +25,7 @@ impl Widgets {
|
||||
needs_redraw: Default::default(),
|
||||
vec: Default::default(),
|
||||
waiting: Default::default(),
|
||||
named: Default::default(),
|
||||
send,
|
||||
recv,
|
||||
}
|
||||
@@ -95,9 +101,20 @@ impl Widgets {
|
||||
&self.data(id.id()).unwrap().label
|
||||
}
|
||||
|
||||
/// useful for debugging
|
||||
/// Also the one place a widget opts into `ui::access`'s AccessKit tree
|
||||
/// (RUST.md's I4) -- see `named`'s doc comment.
|
||||
pub fn set_label(&mut self, id: impl IdLike, label: String) {
|
||||
self.data_mut(id.id()).unwrap().label = label;
|
||||
let id = id.id();
|
||||
self.data_mut(id).unwrap().label = label;
|
||||
self.named.insert(id);
|
||||
}
|
||||
|
||||
/// Every widget with an explicit name, for `ui::access::AccessTree` to
|
||||
/// walk. Order is unspecified; `AccessTree` doesn't need one; a screen
|
||||
/// reader's own traversal is worked out by uiautomator from each
|
||||
/// node's on-screen bounds instead.
|
||||
pub fn named(&self) -> impl Iterator<Item = WidgetId> + '_ {
|
||||
self.named.iter().copied()
|
||||
}
|
||||
|
||||
pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> {
|
||||
@@ -107,6 +124,7 @@ impl Widgets {
|
||||
pub fn free_next(&mut self) -> Option<WidgetId> {
|
||||
let next = self.recv.try_recv().ok()?;
|
||||
self.vec.free(next);
|
||||
self.named.remove(&next);
|
||||
Some(next)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
//! Pass conditions for RUST.md's I4, exercised the same way
|
||||
//! `layout_tests.rs` exercises LAYOUT.md's: `AccessTree` only touches
|
||||
//! `Widgets`/`UiRenderState`, neither of which needs a GPU or a window, so
|
||||
//! it can be driven directly against `layout_tests::TestRsc`.
|
||||
|
||||
use crate::layout_tests::TestRsc;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn a_named_widget_reaches_the_tree_with_its_role_and_bounds() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let leaf: WeakWidget<Rect> = rect(UiColor::WHITE).label("Add task").add(&mut rsc);
|
||||
let root = leaf.upgrade(&mut rsc).any();
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 600.0));
|
||||
render.update(&root, &mut rsc);
|
||||
|
||||
let mut access = AccessTree::new();
|
||||
let update = access
|
||||
.update(rsc.widgets(), &render, &rsc)
|
||||
.expect("a first draw with a named widget must produce a tree");
|
||||
|
||||
// One node for the widget, one for the synthetic window root.
|
||||
assert_eq!(update.nodes.len(), 2);
|
||||
let (_, node) = update
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|(_, n)| n.role() != accesskit::Role::Window)
|
||||
.expect("the named widget's own node");
|
||||
assert_eq!(node.label(), Some("Add task"));
|
||||
assert_eq!(node.role(), accesskit::Role::Unknown);
|
||||
let bounds = node.bounds().expect("a drawn widget reports its bounds");
|
||||
let region = render
|
||||
.window_region(&leaf, &rsc)
|
||||
.expect("the widget is active after render.update");
|
||||
assert_eq!(bounds.x0, region.top_left.x as f64);
|
||||
assert_eq!(bounds.y0, region.top_left.y as f64);
|
||||
assert_eq!(bounds.x1, region.bot_right.x as f64);
|
||||
assert_eq!(bounds.y1, region.bot_right.y as f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_widget_with_no_label_never_reaches_the_tree() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let root = rsc.ui.widgets.add_strong(rect(UiColor::WHITE));
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 600.0));
|
||||
render.update(&root.any(), &mut rsc);
|
||||
|
||||
let mut access = AccessTree::new();
|
||||
assert!(
|
||||
access.update(rsc.widgets(), &render, &rsc).is_none(),
|
||||
"no widget was ever `.label()`ed, so there is nothing to report -- \
|
||||
not even an empty tree change"
|
||||
);
|
||||
}
|
||||
|
||||
/// LAYOUT.md's "a moved subtree" lesson applies here too: `resolved_region`
|
||||
/// (which `window_region` sits on) walks the move-offset chain, so a
|
||||
/// widget moved via `Offset` -- not redrawn from scratch -- must still
|
||||
/// report where it actually ended up.
|
||||
#[test]
|
||||
fn bounds_follow_a_moved_widget_and_updates_stay_incremental() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let leaf: WeakWidget<Rect> = rect(UiColor::WHITE).label("thing").add(&mut rsc);
|
||||
let leaf_strong = leaf.upgrade(&mut rsc).any();
|
||||
let offset = rsc.ui.widgets.add_strong(Offset {
|
||||
inner: leaf_strong,
|
||||
amt: UiVec2::ZERO,
|
||||
});
|
||||
let offset_id = offset.weak();
|
||||
let root = offset.any();
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 600.0));
|
||||
render.update(&root, &mut rsc);
|
||||
|
||||
let mut access = AccessTree::new();
|
||||
access
|
||||
.update(rsc.widgets(), &render, &rsc)
|
||||
.expect("the first draw is always a change");
|
||||
assert_eq!(access.take_rebuilds(), 1);
|
||||
|
||||
// Unchanged frame: nothing moved, nothing renamed -- `update` must
|
||||
// report no change, and the rebuild counter (I4's twin of
|
||||
// `take_counters`) must stay at 0.
|
||||
render.update(&root, &mut rsc);
|
||||
assert!(access.update(rsc.widgets(), &render, &rsc).is_none());
|
||||
assert_eq!(access.take_rebuilds(), 0);
|
||||
|
||||
// Move the child via `Offset` (a move-offset write, not necessarily a
|
||||
// full redraw of the leaf -- see `resolve_move_chain`) and confirm the
|
||||
// reported bounds shifted by exactly that amount, in exactly one more
|
||||
// rebuild.
|
||||
let before = render
|
||||
.window_region(&leaf, &rsc)
|
||||
.expect("active before the move");
|
||||
rsc.ui.widgets.get_mut(&offset_id).unwrap().amt = UiVec2::abs(Vec2::new(50.0, 0.0));
|
||||
render.update(&root, &mut rsc);
|
||||
let update = access
|
||||
.update(rsc.widgets(), &render, &rsc)
|
||||
.expect("a moved named widget is a change");
|
||||
assert_eq!(access.take_rebuilds(), 1);
|
||||
|
||||
let after = render
|
||||
.window_region(&leaf, &rsc)
|
||||
.expect("still active after the move");
|
||||
// Not asserting the exact delta: `Offset`'s own `amt` -> pixel mapping
|
||||
// is that widget's business, not this tree's. What I4 owns is that
|
||||
// `AccessTree` reports whatever `window_region` says *now* -- so the
|
||||
// node must have moved, and in the direction the offset moved it.
|
||||
assert!(
|
||||
after.top_left.x > before.top_left.x,
|
||||
"the leaf's reported bounds must move right along with its offset"
|
||||
);
|
||||
|
||||
let (_, node) = update
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|(_, n)| n.role() != accesskit::Role::Window)
|
||||
.unwrap();
|
||||
let bounds = node.bounds().unwrap();
|
||||
assert_eq!(bounds.x0, after.top_left.x as f64);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
//! I4 (RUST.md): the Android half of the AccessKit push, over
|
||||
//! `accesskit_android::Adapter` and android-view's
|
||||
//! `AccessibilityNodeProvider`. Carries E1's mitigation for the adapter's
|
||||
//! reproducible abort: `accesskit_android`'s `State` (0.4.0 and 0.8.0
|
||||
//! alike) never moves back to `Inactive` once a client attaches, so once
|
||||
//! one has, every later `QueuedEvents::raise` reaches
|
||||
//! `AccessibilityManager.sendAccessibilityEvent` -- which throws if
|
||||
//! accessibility has since been switched off (or the client detached),
|
||||
//! and android-view's `panic = "abort"` turns that Java exception into a
|
||||
//! process kill. `raise_if_enabled` is the gate: ask
|
||||
//! `AccessibilityManager.isEnabled()` immediately before every `raise`
|
||||
//! and drop the events instead of calling it when the answer is no. See
|
||||
//! RUST.md's E1 box for the full repro.
|
||||
use accesskit::{ActionHandler, ActionRequest, ActivationHandler, TreeUpdate};
|
||||
use accesskit_android::QueuedEvents;
|
||||
use android_view::{
|
||||
View,
|
||||
jni::{JNIEnv, objects::JObject},
|
||||
};
|
||||
use iris_core::{AccessTree, UiRenderState, UiRsc, Widgets};
|
||||
|
||||
/// The `ActivationHandler` `accesskit_android::Adapter` asks for its
|
||||
/// initial tree from -- unlike `accesskit_winit`'s handlers (see
|
||||
/// `default/access.rs`), this one is only ever invoked synchronously from
|
||||
/// inside a JNI callback that already holds everything it needs, so it can
|
||||
/// just borrow `IrisViewPeer`'s own fields for the length of one call
|
||||
/// rather than going through a channel.
|
||||
pub(super) struct AndroidAccessSource<'a> {
|
||||
pub widgets: &'a Widgets,
|
||||
pub render: &'a UiRenderState,
|
||||
pub rsc: &'a dyn UiRsc,
|
||||
}
|
||||
|
||||
impl ActivationHandler for AndroidAccessSource<'_> {
|
||||
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
|
||||
Some(AccessTree::build_full(self.widgets, self.render, self.rsc))
|
||||
}
|
||||
}
|
||||
|
||||
/// Every AccessKit action request is inert here -- see this module's doc
|
||||
/// comment and `default/access.rs`'s matching handler for why: a screen
|
||||
/// reader's tap on a named node is a real touch delivered at that node's
|
||||
/// bounds, which the ordinary pointer path already handles once the
|
||||
/// bounds `AccessTree` reports are right.
|
||||
pub(super) struct NullActionHandler;
|
||||
impl ActionHandler for NullActionHandler {
|
||||
fn do_action(&mut self, _request: ActionRequest) {}
|
||||
}
|
||||
|
||||
fn is_accessibility_enabled<'local>(env: &mut JNIEnv<'local>, view: &View<'local>) -> bool {
|
||||
let context = view.context(env);
|
||||
let name = env.new_string("accessibility").unwrap();
|
||||
let manager: JObject = env
|
||||
.call_method(
|
||||
&context.0,
|
||||
"getSystemService",
|
||||
"(Ljava/lang/String;)Ljava/lang/Object;",
|
||||
&[(&name).into()],
|
||||
)
|
||||
.unwrap()
|
||||
.l()
|
||||
.unwrap();
|
||||
if manager.is_null() {
|
||||
return false;
|
||||
}
|
||||
env.call_method(&manager, "isEnabled", "()Z", &[])
|
||||
.unwrap()
|
||||
.z()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// The one place `QueuedEvents::raise` may be called -- see this module's
|
||||
/// doc comment. Every call site pushes this as a deferred callback rather
|
||||
/// than calling it inline, matching android-view's own demo: `raise`
|
||||
/// itself asks not to be called while the caller holds locks a framework
|
||||
/// callback might, and a deferred callback runs after the current one has
|
||||
/// returned them.
|
||||
pub(super) fn raise_if_enabled<'local>(
|
||||
env: &mut JNIEnv<'local>,
|
||||
view: &View<'local>,
|
||||
events: QueuedEvents,
|
||||
) {
|
||||
if is_accessibility_enabled(env, view) {
|
||||
events.raise(env, &view.0);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
//! counterpart: winit cannot drive an IME beyond `Ime::Preedit`/`Commit`
|
||||
//! (RUST.md's E1) and has no concept of Android's window insets at all.
|
||||
|
||||
mod access;
|
||||
mod attr;
|
||||
mod ime;
|
||||
mod input;
|
||||
|
||||
+108
-6
@@ -1,8 +1,10 @@
|
||||
use crate::prelude::*;
|
||||
use crate::task::RequestRedraw;
|
||||
use accesskit_android::Adapter as AccessAdapter;
|
||||
use android_view::{
|
||||
CallbackCtx, Context, InputConnection, KeyEvent, MotionEvent, Rect, View, ViewPeer,
|
||||
jni::JNIEnv,
|
||||
AccessibilityNodeInfo, AccessibilityNodeProvider, Bundle, CallbackCtx, Context,
|
||||
InputConnection, KeyEvent, MotionEvent, Rect, View, ViewPeer,
|
||||
jni::{JNIEnv, sys::jint},
|
||||
ndk::event::{Keycode, MotionAction},
|
||||
};
|
||||
// `marker::Sized` explicitly: `crate::prelude::*` below also brings in the
|
||||
@@ -18,6 +20,7 @@ use std::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
access::{AndroidAccessSource, NullActionHandler, raise_if_enabled},
|
||||
insets::{Insets, Shared},
|
||||
render::{AndroidRedrawHandle, AndroidRenderer},
|
||||
};
|
||||
@@ -47,6 +50,13 @@ pub struct AndroidUiState {
|
||||
/// path -- see `android/insets.rs` for why they need a registry of
|
||||
/// their own.
|
||||
shared: Rc<RefCell<Shared>>,
|
||||
/// I4 (RUST.md): pushed from `IrisViewPeer::render` and consulted by
|
||||
/// the `AccessibilityNodeProvider` impl below; see `android/access.rs`
|
||||
/// for the abort mitigation every `raise` on it goes through.
|
||||
pub access_adapter: AccessAdapter,
|
||||
/// The AccessKit tree itself -- see `iris_core::AccessTree`'s doc
|
||||
/// comment.
|
||||
pub access: AccessTree,
|
||||
}
|
||||
|
||||
impl AndroidUiState {
|
||||
@@ -60,6 +70,8 @@ impl AndroidUiState {
|
||||
compose_len: 0,
|
||||
pending_show_keyboard: false,
|
||||
shared,
|
||||
access_adapter: Default::default(),
|
||||
access: AccessTree::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +246,7 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
/// it -- on both the Vulkan/SwiftShader and GLES/virgl backends. Leave
|
||||
/// these in until that is root-caused; removing them loses the exact
|
||||
/// evidence a `logcat` capture needs to reproduce the state.
|
||||
fn render(&mut self) {
|
||||
fn render(&mut self, ctx: &mut CallbackCtx) {
|
||||
let ui_state = self.state.android_state();
|
||||
if ui_state.renderer.is_none() {
|
||||
return;
|
||||
@@ -267,6 +279,26 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
.as_ref()
|
||||
.and_then(|r| self.render.window_region(r, &self.rsc)),
|
||||
);
|
||||
|
||||
// I4 (RUST.md): only produces a `TreeUpdate` -- and so only queues
|
||||
// anything to raise -- when the named set actually changed this
|
||||
// frame; see `AccessTree`'s doc comment. Deferred rather than
|
||||
// raised inline so it runs after this callback releases whatever
|
||||
// it's holding, matching android-view's own demo and `raise`'s own
|
||||
// contract.
|
||||
let ui_state = self.state.android_state_mut();
|
||||
if let Some(tree_update) =
|
||||
ui_state
|
||||
.access
|
||||
.update(self.rsc.widgets(), &self.render, &self.rsc)
|
||||
{
|
||||
let ui_state = self.state.android_state_mut();
|
||||
if let Some(events) = ui_state.access_adapter.update_if_active(|| tree_update) {
|
||||
ctx.push_dynamic_deferred_callback(move |env, view| {
|
||||
raise_if_enabled(env, view, events);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +416,7 @@ impl<State: AndroidAppState> ViewPeer for IrisViewPeer<State> {
|
||||
let ui_state = self.state.android_state_mut();
|
||||
ui_state.renderer = None;
|
||||
ui_state.renderer = Some(AndroidRenderer::new(window, width as u32, height as u32));
|
||||
self.render();
|
||||
self.render(ctx);
|
||||
}
|
||||
|
||||
fn surface_destroyed<'local>(
|
||||
@@ -395,14 +427,84 @@ impl<State: AndroidAppState> ViewPeer for IrisViewPeer<State> {
|
||||
self.state.android_state_mut().renderer = None;
|
||||
}
|
||||
|
||||
fn do_frame(&mut self, _ctx: &mut CallbackCtx, _frame_time_nanos: i64) {
|
||||
fn do_frame(&mut self, ctx: &mut CallbackCtx, _frame_time_nanos: i64) {
|
||||
self.drain_tasks();
|
||||
self.render();
|
||||
self.render(ctx);
|
||||
}
|
||||
|
||||
fn as_input_connection(&mut self) -> Option<&mut dyn InputConnection> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn as_accessibility_node_provider(&mut self) -> Option<&mut dyn AccessibilityNodeProvider> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<State: AndroidAppState> AccessibilityNodeProvider for IrisViewPeer<State> {
|
||||
fn create_accessibility_node_info<'local>(
|
||||
&mut self,
|
||||
ctx: &mut CallbackCtx<'local>,
|
||||
virtual_view_id: jint,
|
||||
) -> AccessibilityNodeInfo<'local> {
|
||||
let mut source = AndroidAccessSource {
|
||||
widgets: self.rsc.widgets(),
|
||||
render: &self.render,
|
||||
rsc: &self.rsc,
|
||||
};
|
||||
let ui_state = self.state.android_state_mut();
|
||||
AccessibilityNodeInfo(ui_state.access_adapter.create_accessibility_node_info(
|
||||
&mut source,
|
||||
&mut ctx.env,
|
||||
&ctx.view.0,
|
||||
virtual_view_id,
|
||||
))
|
||||
}
|
||||
|
||||
fn find_focus<'local>(
|
||||
&mut self,
|
||||
ctx: &mut CallbackCtx<'local>,
|
||||
focus_type: jint,
|
||||
) -> AccessibilityNodeInfo<'local> {
|
||||
let mut source = AndroidAccessSource {
|
||||
widgets: self.rsc.widgets(),
|
||||
render: &self.render,
|
||||
rsc: &self.rsc,
|
||||
};
|
||||
let ui_state = self.state.android_state_mut();
|
||||
AccessibilityNodeInfo(ui_state.access_adapter.find_focus(
|
||||
&mut source,
|
||||
&mut ctx.env,
|
||||
&ctx.view.0,
|
||||
focus_type,
|
||||
))
|
||||
}
|
||||
|
||||
fn perform_action<'local>(
|
||||
&mut self,
|
||||
ctx: &mut CallbackCtx<'local>,
|
||||
virtual_view_id: jint,
|
||||
action: jint,
|
||||
arguments: &Bundle<'local>,
|
||||
) -> bool {
|
||||
let Some(action) =
|
||||
accesskit_android::PlatformAction::from_java(&mut ctx.env, action, &arguments.0)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let ui_state = self.state.android_state_mut();
|
||||
let Some(events) = ui_state.access_adapter.perform_action(
|
||||
&mut NullActionHandler,
|
||||
virtual_view_id,
|
||||
&action,
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
ctx.push_dynamic_deferred_callback(move |env, view| {
|
||||
raise_if_enabled(env, view, events);
|
||||
});
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers `IrisViewPeer<State>`'s native methods and builds one on every
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
//! I4 (RUST.md): the desktop half of the AccessKit push, over
|
||||
//! `accesskit_winit`. `bench-lib.sh`'s tap-by-name goes through the
|
||||
//! platform's real accessibility tree, so this crate only has to keep that
|
||||
//! tree in sync with `ui::access::AccessTree`'s output -- nothing here
|
||||
//! reacts to an AccessKit action request, which is why the three handlers
|
||||
//! below are inert. See RUST.md's I4 box for why: on Android (and, by the
|
||||
//! same platform convention, everywhere else) a screen reader's element tap
|
||||
//! is a real touch delivered at the node's own bounds, not an action
|
||||
//! request synthesised in-process -- so the ordinary pointer path already
|
||||
//! handles it once the bounds are right.
|
||||
use accesskit::{ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, TreeUpdate};
|
||||
|
||||
pub struct NullActivationHandler;
|
||||
impl ActivationHandler for NullActivationHandler {
|
||||
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NullActionHandler;
|
||||
impl ActionHandler for NullActionHandler {
|
||||
fn do_action(&mut self, _request: ActionRequest) {}
|
||||
}
|
||||
|
||||
pub struct NullDeactivationHandler;
|
||||
impl DeactivationHandler for NullDeactivationHandler {
|
||||
fn deactivate_accessibility(&mut self) {}
|
||||
}
|
||||
+46
-3
@@ -11,11 +11,13 @@ use winit::{
|
||||
window::{Window, WindowAttributes},
|
||||
};
|
||||
|
||||
mod access;
|
||||
mod app;
|
||||
mod attr;
|
||||
mod input;
|
||||
mod render;
|
||||
|
||||
pub use access::*;
|
||||
pub use app::*;
|
||||
pub use input::*;
|
||||
pub use render::*;
|
||||
@@ -31,6 +33,17 @@ pub struct DefaultUiState {
|
||||
pub window: Arc<Window>,
|
||||
pub ime: usize,
|
||||
pub last_click: Instant,
|
||||
/// I4 (RUST.md): pushed through in `DefaultApp::window_event`'s
|
||||
/// `RedrawRequested` arm, from `access`'s output. Built in
|
||||
/// `DefaultApp::new`, which is the only place with the
|
||||
/// `&ActiveEventLoop` `accesskit_winit::Adapter::with_direct_handlers`
|
||||
/// needs -- see that constructor's doc comment on why the window must
|
||||
/// still be invisible when it is called.
|
||||
pub access_adapter: accesskit_winit::Adapter,
|
||||
/// The AccessKit tree itself -- see `iris_core::AccessTree`'s doc
|
||||
/// comment for the flat shape and why it only rebuilds on a real
|
||||
/// change.
|
||||
pub access: AccessTree,
|
||||
}
|
||||
|
||||
impl HasRoot for DefaultUiState {
|
||||
@@ -40,7 +53,7 @@ impl HasRoot for DefaultUiState {
|
||||
}
|
||||
|
||||
impl DefaultUiState {
|
||||
pub fn new(window: impl Into<Arc<Window>>) -> Self {
|
||||
pub fn new(window: impl Into<Arc<Window>>, access_adapter: accesskit_winit::Adapter) -> Self {
|
||||
let window = window.into();
|
||||
Self {
|
||||
root: None,
|
||||
@@ -51,6 +64,8 @@ impl DefaultUiState {
|
||||
ime: 0,
|
||||
last_click: Instant::now(),
|
||||
focus: None,
|
||||
access_adapter,
|
||||
access: AccessTree::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,10 +194,24 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
type Event = State::Event;
|
||||
|
||||
fn new(event_loop: &ActiveEventLoop, proxy: EventLoopProxy<Self::Event>) -> Self {
|
||||
// `accesskit_winit::Adapter::with_direct_handlers` panics if the
|
||||
// window is already visible when it's built, so the window is
|
||||
// created hidden and only shown once the adapter exists -- the one
|
||||
// extra step I4 (RUST.md) needs here. The three handlers are inert
|
||||
// (see `access.rs`): a screen reader's tap is a real touch at the
|
||||
// node's bounds, not an action request this process has to answer.
|
||||
let window = event_loop
|
||||
.create_window(State::window_attributes())
|
||||
.create_window(State::window_attributes().with_visible(false))
|
||||
.unwrap();
|
||||
let default_state = DefaultUiState::new(window);
|
||||
let access_adapter = accesskit_winit::Adapter::with_direct_handlers(
|
||||
event_loop,
|
||||
&window,
|
||||
NullActivationHandler,
|
||||
NullActionHandler,
|
||||
NullDeactivationHandler,
|
||||
);
|
||||
window.set_visible(true);
|
||||
let default_state = DefaultUiState::new(window, access_adapter);
|
||||
let (mut rsc, task_recv) = DefaultRsc::init(default_state.window.clone());
|
||||
let state = State::new(default_state, &mut rsc, proxy);
|
||||
let render = UiRenderState::new();
|
||||
@@ -211,6 +240,12 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
}
|
||||
|
||||
let ui_state = state.default_state_mut();
|
||||
// Required by `accesskit_winit` on every window event, not just the
|
||||
// ones this backend otherwise cares about -- some platform adapters
|
||||
// rely on it to notice activation (a screen reader turning on).
|
||||
ui_state
|
||||
.access_adapter
|
||||
.process_event(&ui_state.window, &event);
|
||||
let input_changed = ui_state.input.event(&event);
|
||||
let cursor_state = ui_state.cursor_state().clone();
|
||||
let old = ui_state.focus;
|
||||
@@ -233,6 +268,14 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
render.update(&ui_state.root, rsc);
|
||||
ui_state.renderer.update(&mut rsc.ui, render);
|
||||
ui_state.renderer.draw();
|
||||
// I4 (RUST.md): only produces a `TreeUpdate` when the named
|
||||
// set actually changed this frame -- see `AccessTree`'s doc
|
||||
// comment. `render` reflects the draw that just happened,
|
||||
// so `resolved_region`/`window_region` inside it report a
|
||||
// moved subtree's *new* position, not last frame's.
|
||||
if let Some(tree_update) = ui_state.access.update(rsc.widgets(), render, rsc) {
|
||||
ui_state.access_adapter.update_if_active(|| tree_update);
|
||||
}
|
||||
}
|
||||
WindowEvent::Resized(size) => {
|
||||
render.resize((size.width, size.height));
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// The minimal `UiRsc` a test needs: just the shared `UiData`, none of the
|
||||
/// event/window/state plumbing `DefaultRsc` carries.
|
||||
struct TestRsc {
|
||||
ui: UiData,
|
||||
/// event/window/state plumbing `DefaultRsc` carries. `pub(crate)` so
|
||||
/// `access_tests.rs` (I4, RUST.md) can reuse it rather than keeping a
|
||||
/// second copy of the same harness.
|
||||
pub(crate) struct TestRsc {
|
||||
pub(crate) ui: UiData,
|
||||
}
|
||||
|
||||
impl UiRsc for TestRsc {
|
||||
|
||||
@@ -26,6 +26,8 @@ pub mod state;
|
||||
pub mod task;
|
||||
pub mod widget;
|
||||
|
||||
#[cfg(test)]
|
||||
mod access_tests;
|
||||
#[cfg(test)]
|
||||
mod layout_tests;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -114,6 +114,15 @@ impl Widget for TextEdit {
|
||||
);
|
||||
used
|
||||
}
|
||||
|
||||
/// I4 (RUST.md): the one override that exists so far -- everything
|
||||
/// else falls back to `Widget::access_role`'s default `Unknown`.
|
||||
fn access_role(&self) -> accesskit::Role {
|
||||
match self.mode {
|
||||
EditMode::SingleLine => accesskit::Role::TextInput,
|
||||
EditMode::MultiLine => accesskit::Role::MultilineTextInput,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CARET_WIDTH: f32 = 1.0;
|
||||
|
||||
@@ -177,7 +177,14 @@ where
|
||||
)
|
||||
.on(CursorSense::HoverEnd, move |ctx, rsc| {
|
||||
ctx.widget(rsc).color = color;
|
||||
});
|
||||
})
|
||||
// I4 (RUST.md): the tabs screen's only named controls, and the
|
||||
// ones the emulator step at the bottom of that box taps by
|
||||
// name -- `ui-trace record --do "tap 'pad'"` and so on. `.label`
|
||||
// slots into this chain like any other widget combinator
|
||||
// (`RefFnTag` in `core/src/widget/tag.rs`); it does not have to
|
||||
// be the last thing before `.add`.
|
||||
.label(label);
|
||||
(rect, wtext(label).size(30).text_align(Align::CENTER)).stack()
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user