Skip to main content

AppTree

Trait AppTree 

Source
pub trait AppTree {
Show 27 methods // Required methods fn rebuild(&mut self); fn take_change_flags(&mut self) -> ChangeFlags; fn has_pending_change_flags(&self) -> bool; fn is_pointer_captured(&self) -> bool; fn is_focus_active(&self) -> bool; fn focus_ime_generation(&self) -> u64; fn focus_epoch(&self) -> u64; fn layout(&mut self, logical: Size, text_ctx: &mut dyn Any); fn paint( &mut self, scene: &mut dyn PaintScene, frame_time: FrameTime, ) -> PaintOutcome; fn event(&mut self, event: &InputEvent) -> EventOutcome; fn ime_apply(&mut self, state: EditingState) -> EventOutcome; fn ime_state(&self) -> Option<ImeState>; fn take_clipboard_write(&mut self) -> Option<String>; fn take_paste_request(&mut self) -> bool; fn set_theme(&mut self, theme: Box<dyn Any>); fn semantics(&mut self) -> SemanticsUpdate; fn semantics_generation(&self) -> u64; fn semantics_if_changed( &mut self, last_seen: u64, ) -> Option<SemanticsUpdate>; fn perform_accessibility_action( &mut self, node_id: u64, action: Action, ) -> EventOutcome; // Provided methods fn selection_toolbar(&self) -> Option<SelectionToolbarRequest> { ... } fn selection_toolbar_generation(&self) -> u64 { ... } fn set_insets(&mut self, _insets: WindowInsets) { ... } fn set_presented_frames(&mut self, _presented: u64) { ... } fn set_surface_translucent(&mut self, _translucent: bool) { ... } fn platform_view_frames(&self) -> &[PlatformViewFrame] { ... } fn input_shields(&self) -> &[Rect] { ... } fn take_retired_platform_views(&mut self) -> Vec<u64> { ... }
}
Expand description

Type-erased app tree: the one seam that lets a shell’s native handle stay non-generic while still driving a concrete State/app_logic/View.

Mirrors the desktop facade’s erasure approach (a stored generic behind a non-generic driver): a platform shell’s generated extern entry points can’t be generic, so the shell’s app-binding macro instantiates new_boxed_app with the app’s types and stores the result as a Box<dyn AppTree> inside the handle.

Required Methods§

Source

fn rebuild(&mut self)

Re-run app_logic and reconcile the retained tree.

Source

fn take_change_flags(&mut self) -> ChangeFlags

Take (and clear) the layout/paint dirtiness accumulated since the last call (delegates to RenderRoot::take_change_flags).

The frame-gate seam: a shell drives the layout-skip decision off this — run AppTree::rebuild, then run AppTree::layout only if the drained flags ChangeFlags::needs_layout (or it’s the first frame, or the surface resized), then always AppTree::paint. The set_theme ⇒ LAYOUT|PAINT contract keeps Text’s layout-baked theme color correct across a bare theme swap (see crate::frame_gate’s module docs). Draining is the caller’s commitment to act on the flags this frame; use AppTree::has_pending_change_flags to peek without draining when gathering crate::FrameInputs for a frame that may be skipped.

Source

fn has_pending_change_flags(&self) -> bool

Non-draining peek at whether any layout/paint dirtiness is pending (delegates to RenderRoot::has_pending_change_flags).

The frame gate reads this as its change_flags_pending crate::FrameInputs entry before deciding, so a frame it skips leaves the flags intact for the next frame that runs to drain via AppTree::take_change_flags.

Source

fn is_pointer_captured(&self) -> bool

Whether a captured pointer gesture is currently in flight (delegates to RenderRoot::is_pointer_captured).

A frame-gate input: a mid-drag captured widget may track/animate the pointer, so the mobile shells feed this into crate::FrameInputs::pointer_capture_active to keep producing frames while a gesture is live rather than skipping it.

Source

fn is_focus_active(&self) -> bool

Whether some widget in the tree currently holds keyboard/IME focus (delegates to RenderRoot::is_focus_active).

A level read, used by a shell that needs the current state (an IME reconcile, a caret decision). It is deliberately not what the mobile frame gate consults any more — a focus session that lasts forces a frame forever — see AppTree::focus_ime_generation.

Source

fn focus_ime_generation(&self) -> u64

The focus/IME session generation, bumped on every actual change of the root’s focus flag or published IME surface (delegates to RenderRoot::focus_ime_generation).

The frame gate’s edge input: a shell caches the value it last saw and feeds last != now into crate::FrameInputs::focus_or_ime_changed, so a focus/IME transition forces exactly one frame while a steady focus session (a caret blinking in an otherwise-idle field) leaves the gate free to skip or pace. The same cheap compare-a-generation shape as AppTree::semantics_generation.

Deliberately not defaulted, unlike AppTree::set_insets and the other additive methods below: any constant default (0 included) would report “nothing ever changed” and silently strand a focus transition, against the frame gate’s default-to-run rule.

This is not the session’s identity, and the distinction is the whole reason AppTree::focus_epoch sits beside it — read that one’s doc before using this counter to decide whether focus is still where it was.

Source

fn focus_epoch(&self) -> u64

The live focus session’s identity, advanced once per honoured focus claim and once per session release (delegates to RenderRoot::focus_epoch).

Two adjacent generation counters invite exactly one mistake, so: the neighbour above counts changes to the published surface, this one counts sessions, and neither substitutes for the other.

  • Focus moving from one field to another moves this one and can leave the neighbour completely still. Claiming focus while some field is already focused writes true over true, and ImeState is {active, editing, caret, content_type} — it names no widget, so two fields can publish equal surfaces, and a field that takes focus and publishes nothing leaves the previous field’s surface standing.
  • An edit, a caret move, or the field being repositioned under the user moves the neighbour and leaves this one still. The session is the same session throughout.

So a shell that must run a frame or re-sync the platform IME reads the neighbour; a shell binding an answer it will receive later to the session that asked for it — an off-thread clipboard read, say — reads this one and compares it again on arrival.

Never 0, whatever a shell’s own FFI layer may use 0 to mean: the counter is built at 1 and steps past 0 on wrap.

Not defaulted, for a sharper reason than its neighbour’s: a constant default would report “still the same session” forever, so every stale answer would compare equal and be accepted. A wrong default here delivers text into the wrong field rather than costing a frame.

Source

fn layout(&mut self, logical: Size, text_ctx: &mut dyn Any)

Lay the tree out against a logical (density-independent) size, threading the shell-owned TextContext down type-erased.

Source

fn paint( &mut self, scene: &mut dyn PaintScene, frame_time: FrameTime, ) -> PaintOutcome

Paint the tree into a scene builder at the shell-provided frame_time.

frame_time is the shell’s shared monotonic clock for this frame, threaded through to every animating widget as frust_core::widget::PaintCtx::frame_time (time enters from the shell, never Instant::now() inside the framework).

Returns a PaintOutcome whose needs_frame is set when a widget advanced animation state during paint and wants another frame, the framework’s animation seam. The desktop shell honors it with window.request_redraw(); the mobile shells’ continuous Choreographer/CADisplayLink loops already produce the next frame and may ignore it.

Source

fn event(&mut self, event: &InputEvent) -> EventOutcome

Deliver one platform input event to the retained tree.

Delegates to RenderRoot::event, threading the erased State the same way AppTree::rebuild does. The returned EventOutcome carries needs_redraw, which the shell honours by scheduling a frame: the desktop shell calls window.request_redraw(), while the mobile shells’ continuous Choreographer/CADisplayLink loops already produce the next frame. The event pass itself never rebuilds or repaints (see RenderRoot::event).

Source

fn ime_apply(&mut self, state: EditingState) -> EventOutcome

Apply a whole editing state pushed by the platform IME (the mobile state-sync path), routed to the focused widget as an InputEvent::Ime(ImeEvent::ApplyEditingState).

state’s selection/composing indices are UTF-16 code-unit based (the platform-native unit); the focused widget / frust-text converts them to Rust byte offsets. Returns the same EventOutcome as AppTree::event.

Source

fn ime_state(&self) -> Option<ImeState>

The IME surface the focused widget published, for the shell to drive the platform input method. Delegates to RenderRoot::ime_state; None when nothing is focused or no IME surface was published.

Source

fn take_clipboard_write(&mut self) -> Option<String>

Take (and clear) the text a widget asked to put on the host clipboard (delegates to RenderRoot::take_clipboard_write).

The shell half of the clipboard channel: a focused editable answers a copy/cut by writing its selection into the pass’s clipboard slot (frust_core::EventCtx::write_clipboard), and the shell — the only side with a host clipboard to talk to — drains it here immediately after every AppTree::event/AppTree::ime_apply, beside AppTree::ime_state. None means no widget copied, and a shell with no clipboard wired yet may simply not call this.

Destructive, unlike the level reads around it: a clipboard write is an edge, so a caller that drains and drops the result loses that write.

Source

fn take_paste_request(&mut self) -> bool

Take (and clear) whether a widget asked the shell to read the host clipboard back to it (delegates to RenderRoot::take_paste_request).

The inverse direction, drained in the same place: on true the shell reads its host clipboard and dispatches InputEvent::EditCommand(EditCommand::Paste(text)) back through AppTree::event — a new dispatch, since the read may be asynchronous. That answer is focus-routed and therefore self-cancelling: if focus moved or was released while the read was in flight it reaches no widget and is dropped, so the shell never has to track who asked.

Destructive, for AppTree::take_clipboard_write’s reason.

Source

fn set_theme(&mut self, theme: Box<dyn Any>)

Store the app’s active theme, threaded into every subsequent layout/paint pass (delegates to RenderRoot::set_theme).

The theme is type-erased (Box<dyn Any>) so frust-shell-common stays free of a frust-theme dependency (it compiles everywhere with no unsafe/FFI — see docs/ARCHITECTURE.md). The concrete Theme is boxed by the shell that owns the appearance state; each mobile shell wires this into its own appearance-change handling. Re-boxing on a live appearance change replaces the stored theme.

Source

fn semantics(&mut self) -> SemanticsUpdate

Collect the accessibility tree for the current frame, for a shell to push into its platform accesskit_* adapter. Delegates to RenderRoot::semantics; must run after AppTree::layout so node bounds are valid.

Source

fn semantics_generation(&self) -> u64

The current semantics generation, bumped whenever a rebuild/theme swap could have changed the tree (delegates to RenderRoot::semantics_generation). A shell compares it to skip re-pushing an unchanged tree — see AppTree::semantics_if_changed.

Source

fn semantics_if_changed(&mut self, last_seen: u64) -> Option<SemanticsUpdate>

Pull a fresh SemanticsUpdate only if the tree may have changed since generation last_seen (delegates to RenderRoot::semantics_if_changed), so a shell’s adapter push runs only when something changed.

Source

fn perform_accessibility_action( &mut self, node_id: u64, action: Action, ) -> EventOutcome

Perform a platform accessibility action delivered by the shell’s accesskit_* adapter (an ActionRequest), threading the erased State the same way AppTree::event does (delegates to RenderRoot::perform_accessibility_action).

node_id is the raw accesskit id the adapter reported; action is the requested accesskit::Action. Returns the same EventOutcome as AppTree::event — its needs_redraw tells the shell whether to schedule a frame. An unknown node or unmodelled action is a benign no-op.

Provided Methods§

Source

fn selection_toolbar(&self) -> Option<SelectionToolbarRequest>

The selection-toolbar request the focused field published during the most recent AppTree::paint (delegates to RenderRoot::selection_toolbar); None when no field has a selection worth a toolbar.

The shell half of the platform edit-menu route: on a host with a system edit menu (iOS UIEditMenuInteraction), a shell reads this beside AppTree::ime_state and presents the host menu at the request’s anchor rect, converting the logical rect to the platform’s own units itself. A level, not an edge — pair it with AppTree::selection_toolbar_generation to notice changes cheaply.

A field drawing its own toolbar publishes this too (one code path for both routes), so a shell must gate on frust_core::selection_toolbar::selection_toolbar_policy(), not on the presence of a request.

Some means a field is FOCUSED, not that it has a selection. The verbs are a level a platform responder chain reads at any moment, so they are published on every paint of a focused field; None means no field is focused. Whether a menu should be presented is the request’s own flag, not the presence of the request.

Defaulted to None like the getters below, so an AppTree impl that predates this channel still compiles and reads an empty one.

Source

fn selection_toolbar_generation(&self) -> u64

A monotonically-increasing generation bumped when the menu-significant part of AppTree::selection_toolbar actually changes — the present flag and the verb set, its clearing included — and NOT when the anchor alone moves (delegates to RenderRoot::selection_toolbar_generation).

The anchor exclusion is deliberate: the anchor is recomputed every painted frame and follows a dragging selection, so moving the generation with it would ask the host to re-present its menu on every touch sample. Re-read the anchor as a level for the menu’s target rect; do not treat it as a reason to present.

The AppTree::focus_ime_generation contract one channel over: a shell caches the last value it acted on and re-presents the host menu only when it moves, which is what keeps a standing selection — republished every frame it stands — from re-presenting the menu on every vsync.

Defaulted to 0, the same additive shape as its neighbour above.

Source

fn set_insets(&mut self, _insets: WindowInsets)

Store the window’s insets (WindowInsets), threaded into every subsequent layout/paint pass (delegates to RenderRoot::set_insets).

A shell reads the platform’s per-edge occlusion (Android WindowInsets, iOS safeAreaInsets + keyboard frame), converts device px to logical px at the FFI boundary (see crate::ffi_support::logical_insets), and pushes the result here; a SafeArea widget then insets by WindowInsets::padding. WindowInsets is a concrete core-owned type (only f64 scalars), so this needs no Box<dyn Any> erasure — unlike AppTree::set_theme.

Defaulted to a no-op so existing AppTree impls compile unchanged; the concrete tree overrides it to forward to RenderRoot::set_insets. The set_insets ⇒ LAYOUT | PAINT dirty contract keeps a SafeArea’s layout-time inset resolution correct under the mobile layout-skip gate, exactly like set_theme (see crate::frame_gate’s module docs).

Source

fn set_presented_frames(&mut self, _presented: u64)

Store the shell’s running count of frames the render thread has actually presented, threaded into every subsequent paint pass (delegates to RenderRoot::set_presented_frames).

A shell loads the atomic its render side increments (once per presented frame) and pushes it here once per UI frame, before AppTree::paint, so a widget measuring FPS reports the presented rate rather than its own paint cadence (which, under the render-thread split, runs faster).

Unlike AppTree::set_theme/AppTree::set_insets, this dirties nothing — RenderRoot::set_presented_frames marks no ChangeFlags, so a monotonically ticking counter never forces a relayout and — the subtle one — never keeps the mobile frame_gate’s pending-flags input perpetually true, so the menu still idles. Defaulted to a no-op so existing AppTree impls compile unchanged; the concrete tree overrides it.

Source

fn set_surface_translucent(&mut self, _translucent: bool)

Store whether the shell’s GPU surface is translucent (alpha-channel, “Mode B”), threaded into every subsequent paint pass (delegates to RenderRoot::set_surface_translucent).

A shell pushes the surface’s resolved translucency here — what frust_render::SurfaceRenderer::surface_resolved_translucent reports after an install, NOT the crate::SurfaceModeWatcher request latch (a translucency request the platform refuses must degrade to the opaque Mode A contract, or the punch presents black rectangles). Both mobile shells re-read it every frame, so a render-thread fallback downgrades within one frame. The platform-view hole-punch then clears each slot’s rect on a genuinely translucent surface so an opaque app backdrop doesn’t seal the hole (see RenderRoot::set_surface_translucent). Desktop leaves the default (opaque). Defaulted to a no-op so existing AppTree impls compile unchanged; the concrete tree overrides it — mirrors AppTree::set_insets’s default-no-op precedent.

Source

fn platform_view_frames(&self) -> &[PlatformViewFrame]

The PlatformViewFrames the tree published during the most recent paint pass (delegates to RenderRoot::platform_view_frames). A shell’s peek-getter path feeds this into a crate::platform_view::PlatformViewState’s ingest after each RUN frame’s paint (never on a gate-Skip, per that method’s skip-safety contract).

Defaulted to an empty slice so existing AppTree impls compile unchanged; the concrete tree overrides it — mirrors AppTree::set_insets’s default-no-op precedent.

Source

fn input_shields(&self) -> &[Rect]

The z-shield rects the tree reported during the most recent paint pass (delegates to RenderRoot::input_shields) — the second argument of the same ingest call AppTree::platform_view_frames feeds.

Defaulted to an empty slice like the frames getter above, so an AppTree impl that predates the shield channel still compiles (and simply ships no auto-collected shields).

Source

fn take_retired_platform_views(&mut self) -> Vec<u64>

Drain the slot ids whose platform_view widgets were torn down since the last call (delegates to RenderRoot::take_retired_platform_views).

A shell calls this right after AppTree::rebuild and retires each id in its PlatformViewState, so a disposed slot’s native view goes away on the next frame instead of waiting out the differ’s missing-streak heuristic. Draining is destructive — an id is reported exactly once.

Defaulted to an empty Vec, mirroring the two getters above.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§