Make the Rust client the sole app

This commit is contained in:
iris committed 2026-09-11 01:18:24 -04:00
1 parent 5ca244528f
commit 6dbc800739
27 files changed
+59 -42

No files matched your search

+3 -7
View File
@@ -18,11 +18,8 @@
# Needs python3 and network access; fontTools is fetched into a temporary # Needs python3 and network access; fontTools is fetched into a temporary
# venv, so nothing has to be installed on the machine. # venv, so nothing has to be installed on the machine.
# #
# The same arrangement as the Compose app's `app/build-icon-font.sh`, which # The Mono face makes icon metrics stable; the Material Design family keeps
# this is copied from -- including the Mono face and the Material Design # their meanings conventional.
# family, so an icon means the same thing in both apps. Copied rather than
# shared because most of it is the GLYPHS list, which has to differ: the
# point of subsetting is to ship only the codepoints one app draws.
set -euo pipefail set -euo pipefail
GLYPHS=( GLYPHS=(
@@ -48,8 +45,7 @@ unicodes="$(IFS=,; echo "${GLYPHS[*]}")"
mkdir -p "$(dirname "$out")" mkdir -p "$(dirname "$out")"
# The Mono face, where every glyph is one em wide and one em tall, so two # The Mono face, where every glyph is one em wide and one em tall, so two
# icons at the same font size are the same size without either being given # icons at the same font size are the same size without either being given
# one -- the same reason the Compose app's script takes it. It is also what # one, which makes an icon's box predictable beside a line of text.
# makes an icon's box predictable beside a line of text.
"$work/venv/bin/pyftsubset" "$work/SymbolsNerdFontMono-Regular.ttf" \ "$work/venv/bin/pyftsubset" "$work/SymbolsNerdFontMono-Regular.ttf" \
--unicodes="$unicodes" \ --unicodes="$unicodes" \
--layout-features= \ --layout-features= \
+5 -5
View File
@@ -3,14 +3,14 @@
# #
# ./run-headless.sh tabs [-- cargo args] # ./run-headless.sh tabs [-- cargo args]
# ./run-headless.sh tabs --shot /tmp/tabs.png --seconds 4 # ./run-headless.sh tabs --shot /tmp/tabs.png --seconds 4
# ./run-headless.sh phone --phone --dir ../app-rust --shot /tmp/p.png # ./run-headless.sh phone --phone --dir ../app --shot /tmp/p.png
# ./run-headless.sh phone --phone --dir ../app-rust \ # ./run-headless.sh phone --phone --dir ../app \
# --replay ../app-rust/touch/flick-120hz.touch --shot /tmp/p.png # --replay ../app/touch/flick-120hz.touch --shot /tmp/p.png
# #
# `--dir DIR` names the workspace to build in, defaulting to `iris/` (this # `--dir DIR` names the workspace to build in, defaulting to `iris/` (this
# script's own directory). The app's examples -- the phone-sized transcript # script's own directory). The app's examples -- the phone-sized transcript
# screen and everything else that is about *this product* -- live in # screen and everything else that is about *this product* -- live in
# `app-rust/`, which is a workspace of its own; `replay-touch` is still # `app/`, which is a workspace of its own; `replay-touch` is still
# built from iris, since it is part of the rig rather than of either app. # built from iris, since it is part of the rig rather than of either app.
# #
# `--phone` is layer 2 of docs/RUST.md's "Three test layers": the output # `--phone` is layer 2 of docs/RUST.md's "Three test layers": the output
@@ -24,7 +24,7 @@
# shaped, which is what every other example wants. # shaped, which is what every other example wants.
# #
# `--replay FILE` drives one of the `.touch` recordings the headless # `--replay FILE` drives one of the `.touch` recordings the headless
# tests use (`app-rust/touch/`) into the window through # tests use (`app/touch/`) into the window through
# `rig-input`'s `replay-touch` -- one recording, both layers. With # `rig-input`'s `replay-touch` -- one recording, both layers. With
# `--shot` it also writes `<shot>-before.png` from just before the # `--shot` it also writes `<shot>-before.png` from just before the
# gesture, since "the list moved" is a claim about two pictures. # gesture, since "the list moved" is a claim about two pictures.
+1 -1
View File
@@ -8,7 +8,7 @@ use iris_core::{AccessTree, UiRenderState, UiRsc, Widgets};
/// The `ActivationHandler` `accesskit_android::Adapter` asks for its /// The `ActivationHandler` `accesskit_android::Adapter` asks for its
/// initial tree from -- unlike `accesskit_winit`'s handlers (see /// initial tree from -- unlike `accesskit_winit`'s handlers (see
/// `default/access.rs`), this one is only ever invoked synchronously from /// `desktop/access.rs`), this one is only ever invoked synchronously from
/// inside a JNI callback that already holds everything it needs, so it can /// 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 /// just borrow `IrisViewPeer`'s own fields for the length of one call
/// rather than going through a channel. /// rather than going through a channel.
+19 -6
View File
@@ -217,7 +217,11 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
.get_or_insert_with(|| DeviceClock::anchored(Instant::now(), event_time, oldest)) .get_or_insert_with(|| DeviceClock::anchored(Instant::now(), event_time, oldest))
} }
fn generic_motion(&mut self, ctx: &mut CallbackCtx, event: &MotionEvent<'_>) -> bool { fn generic_motion<'local>(
&mut self,
ctx: &mut CallbackCtx<'local>,
event: &MotionEvent<'local>,
) -> bool {
let action = event.action_masked(&mut ctx.env); let action = event.action_masked(&mut ctx.env);
let event_time = event.event_time_nanos(&mut ctx.env); let event_time = event.event_time_nanos(&mut ctx.env);
let mut clock = self.device_clock(event_time, event_time); let mut clock = self.device_clock(event_time, event_time);
@@ -539,11 +543,20 @@ impl<State: AndroidAppState> ViewPeer for IrisViewPeer<State> {
let action = event.action(&mut ctx.env); let action = event.action(&mut ctx.env);
let x = event.x(&mut ctx.env); let x = event.x(&mut ctx.env);
let y = event.y(&mut ctx.env); let y = event.y(&mut ctx.env);
let ui = self.state.android_state_mut(); let access_events = {
if let Some(events) = ui let render_handle = self.rsc.ui.render_state();
.access_adapter let render_state = render_handle.get();
.on_hover_event(&mut NullActionHandler, action, x, y) let mut source = AndroidAccessSource {
{ widgets: self.rsc.widgets(),
render: &render_state,
rsc: &self.rsc,
};
self.state
.android_state_mut()
.access_adapter
.on_hover_event(&mut source, action, x, y)
};
if let Some(events) = access_events {
ctx.push_dynamic_deferred_callback(move |env, view| { ctx.push_dynamic_deferred_callback(move |env, view| {
raise_if_enabled(env, view, events); raise_if_enabled(env, view, events);
}); });
+6 -16
View File
@@ -12,24 +12,20 @@ pub mod android;
#[cfg(not(target_os = "android"))] #[cfg(not(target_os = "android"))]
pub mod desktop; pub mod desktop;
pub mod attr;
pub mod diagnostics; pub mod diagnostics;
pub mod event;
pub mod harness; pub mod harness;
pub mod overlay;
pub mod platform; pub mod platform;
pub mod runtime; pub mod rsc;
pub mod sense;
pub mod state;
pub mod task;
pub mod widget; pub mod widget;
// Preserve concise public paths while implementation files stay grouped.
pub use rsc::attr;
pub use rsc::{event, overlay, sense, state, task};
#[cfg(test)] #[cfg(test)]
mod access_tests; mod access_tests;
#[cfg(test)] #[cfg(test)]
mod layout_tests; mod layout_tests;
#[cfg(test)]
mod sense_tests;
pub use iris_core as core; pub use iris_core as core;
pub use iris_macro as macros; pub use iris_macro as macros;
@@ -41,16 +37,10 @@ pub mod prelude {
#[cfg(not(target_os = "android"))] #[cfg(not(target_os = "android"))]
pub use desktop::*; pub use desktop::*;
pub use attr::*;
pub use event::*;
pub use iris_core::*; pub use iris_core::*;
pub use iris_macro::*; pub use iris_macro::*;
pub use overlay::*;
pub use platform::*; pub use platform::*;
pub use runtime::*; pub use rsc::*;
pub use sense::*;
pub use state::*;
pub use task::*;
pub use widget::*; pub use widget::*;
pub use iris_core::util::Vec2; pub use iris_core::util::Vec2;
View File
File renamed without changes.
+1 -1
View File
@@ -2,7 +2,7 @@ use iris_core::*;
use iris_macro::*; use iris_macro::*;
use std::sync::Arc; use std::sync::Arc;
use crate::task::{TaskCtx, TaskUpdate, Tasks}; use super::task::{TaskCtx, TaskUpdate, Tasks};
#[derive(Eq, PartialEq, Hash, Clone)] #[derive(Eq, PartialEq, Hash, Clone)]
pub struct Submit; pub struct Submit;
+19
View File
@@ -1,3 +1,22 @@
//! Host-independent resources carried by [`AppRsc`].
pub mod attr;
pub mod event;
pub mod overlay;
pub mod sense;
pub mod state;
pub mod task;
#[cfg(test)]
mod sense_tests;
pub use attr::*;
pub use event::*;
pub use overlay::*;
pub use sense::*;
pub use state::*;
pub use task::*;
use crate::prelude::*; use crate::prelude::*;
use std::sync::Arc; use std::sync::Arc;
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
+2 -3
View File
@@ -78,9 +78,8 @@ impl<'a, T: 'static> FnOnce<(&'a mut WidgetState,)> for WeakState<T> {
/// What `Rsc[weak_handle]` indexes through -- one impl per kind of handle /// What `Rsc[weak_handle]` indexes through -- one impl per kind of handle
/// (a widget, a piece of per-widget state), shared by both backends' `Rsc` /// (a widget, a piece of per-widget state), shared by both backends' `Rsc`
/// types since indexing a widget tree has nothing to do with windowing. /// types since indexing a widget tree has nothing to do with windowing.
/// Each backend still needs its own `Index`/`IndexMut for ItsRsc<State>` /// `AppRsc` supplies the shared `Index`/`IndexMut` implementation; a blanket
/// (`default/mod.rs`, `android/view.rs`), because a blanket impl over every /// implementation over every possible resource type would conflict.
/// `I: RscIdx<Rsc>` for every possible `Rsc` would conflict between crates.
pub trait RscIdx<Rsc> { pub trait RscIdx<Rsc> {
type Output; type Output;
fn get(self, rsc: &Rsc) -> &Self::Output; fn get(self, rsc: &Rsc) -> &Self::Output;
+1 -1
View File
@@ -19,7 +19,7 @@ use tokio::{
/// android-view has no `Window` at all, and the redraw request there is a /// android-view has no `Window` at all, and the redraw request there is a
/// JNI call (`View::post_frame_callback`) rather than a method call on a /// JNI call (`View::post_frame_callback`) rather than a method call on a
/// value this crate owns. Each backend supplies its own implementation -- /// value this crate owns. Each backend supplies its own implementation --
/// `default/render.rs` for winit, `android/render.rs` for android-view -- /// `desktop/render.rs` for winit, `android/render.rs` for android-view --
/// and this module never needs to know which one it is holding. /// and this module never needs to know which one it is holding.
pub trait RequestRedraw: Send + Sync + 'static { pub trait RequestRedraw: Send + Sync + 'static {
fn request_redraw(&self); fn request_redraw(&self);
View File
Whitespace-only changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2 -2
View File
@@ -1,14 +1,14 @@
mod image; mod image;
mod layout;
mod mask; mod mask;
mod position;
mod ptr; mod ptr;
mod rect; mod rect;
mod text; mod text;
mod trait_fns; mod trait_fns;
pub use image::*; pub use image::*;
pub use layout::*;
pub use mask::*; pub use mask::*;
pub use position::*;
pub use ptr::*; pub use ptr::*;
pub use rect::*; pub use rect::*;
pub use text::*; pub use text::*;