Struct RuntimeHandle

Source
pub struct RuntimeHandle<A> { /* private fields */ }
Expand description

Cloneable handle to shared, UI-thread-local runtime state.

Clones share actions, tree-scoped dirty work, timers, clipboard/provider hooks, popup authority, and presentation queues. The Rc<RefCell<_>> backing means this type is neither Send nor Sync; ordinary APIs can panic on conflicting reentrant borrows. A standalone handle uses tree namespace zero until Runtime allocates scoped handles.

§Examples

use ailloli_ui_runtime::app::RuntimeHandle;
let handle = RuntimeHandle::<String>::new();
let clone = handle.clone();
clone.dispatch("save".into());
assert_eq!(handle.take_actions(), ["save"]);

Implementations§

Source§

impl<A> RuntimeHandle<A>

Runtime state and tree-scope operations.

Source

pub fn new() -> Self

Creates isolated runtime state in compatibility tree namespace zero.

Queues and diagnostics start empty, the clipboard contains available empty text, the URL opener is in-memory, and no wake is installed.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert_eq!(runtime.element_tree_id().get(), 0);
assert!(!runtime.has_dirty_elements());
Source

pub const fn element_tree_id(&self) -> ElementTreeId

Stable namespace of the retained element tree using this handle.

A newly-created standalone handle uses the compatibility namespace 0. Runtime::new reserves a unique namespace from the shared handle for every retained tree it creates.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
assert_eq!(RuntimeHandle::<()>::new().element_tree_id().get(), 0);
Source

pub fn set_presentation_scope( &self, logical_window_id: impl Into<LogicalWindowId>, presentation_generation: PresentationGeneration, )

Records the logical presentation currently hosting this retained tree.

Widgets that publish popup geometry during paint do not have an crate::input::EventMeta. This tree-scoped value lets them refresh popup ownership after suspend/resume without falling back to a synthetic headless owner. Hosts update it before routing or painting a tree. Replacing a scope discards pending popup intents for the same logical window whose generation is now stale.

§Examples
use ailloli_ui_runtime::app::{PresentationGeneration, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.set_presentation_scope("main", PresentationGeneration::new(4));
assert_eq!(runtime.presentation_scope().unwrap().0.as_str(), "main");
Source

pub fn presentation_scope( &self, ) -> Option<(LogicalWindowId, PresentationGeneration)>

Returns the last presentation scope installed for this retained tree.

None means no scope was installed or it was cleared/released. The logical-window string is cloned into the returned tuple.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
assert!(RuntimeHandle::<()>::new().presentation_scope().is_none());
Source

pub fn clear_presentation_scope(&self)

Removes the host presentation associated with this retained tree.

Matching pending popup intents for that logical window/tree are also removed. Calling it without a scope is a no-op.

§Examples
use ailloli_ui_runtime::app::{PresentationGeneration, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.set_presentation_scope("main", PresentationGeneration::INITIAL);
runtime.clear_presentation_scope();
assert!(runtime.presentation_scope().is_none());
Source

pub fn dispatch(&self, action: A)

Appends an application action to the shared FIFO action queue.

Dispatch does not wake a host or request a frame by itself.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::new();
runtime.dispatch(1);
runtime.dispatch(2);
assert_eq!(runtime.take_actions(), [1, 2]);
Source

pub fn invalidate(&self, element_id: ElementId, invalidation: Invalidation)

Requests the smallest retained unit of work required by element_id. Repeated requests are coalesced to the strongest invalidation. Requests are isolated by this handle’s tree namespace and recorded with InvalidationSource::Runtime provenance.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::{Invalidation, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.invalidate(ElementId(2), Invalidation::Paint);
runtime.invalidate(ElementId(2), Invalidation::Build);
assert!(runtime.frame_work_plan().needs_build());
Source

pub fn invalidate_from( &self, element_id: ElementId, invalidation: Invalidation, source: InvalidationSource, )

Requests retained work while preserving its diagnostic provenance.

Repeated requests for the same tree/element merge to the strongest invalidation, while every request still increments bounded diagnostics.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::{Invalidation, InvalidationSource, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.invalidate_from(ElementId(3), Invalidation::Layout, InvalidationSource::Host);
assert_eq!(runtime.invalidation_diagnostics().records[0].source(), InvalidationSource::Host);
Source

pub fn invalidation_diagnostics(&self) -> InvalidationDiagnosticsSnapshot

Returns an owned snapshot of global invalidation diagnostics.

Counters cover every tree sharing the handle, not only this namespace. Aggregate counters saturate and the provenance ring is bounded.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
assert_eq!(RuntimeHandle::<()>::new().invalidation_diagnostics().requests, 0);
Source

pub fn mark_dirty(&self, element_id: ElementId)

👎Deprecated: use invalidate(element_id, Invalidation::Build)

Compatibility alias for the historical rebuild invalidation.

§Examples
#![allow(deprecated)]
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.mark_dirty(ElementId(1));
assert!(runtime.frame_work_plan().needs_build());
Source

pub fn request_repaint(&self, element_id: ElementId)

Requests paint-only work for one tree-local element.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_repaint(ElementId(1));
assert!(runtime.frame_work_plan().needs_paint());
Source

pub fn request_layout(&self, element_id: ElementId)

Requests layout-and-paint work for one tree-local element.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_layout(ElementId(1));
assert!(runtime.frame_work_plan().needs_layout());
Source

pub fn request_build(&self, element_id: ElementId)

Requests component-build, layout, and paint work for one element.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_build(ElementId(1));
assert!(runtime.frame_work_plan().needs_build());
Source

pub fn install_ui_wake(&self, wake: Arc<dyn UiWake>)

Installs or replaces the payload-free host wake shared by UI services.

Installation does not invoke the callback. The Arc may be used from background threads even though this handle itself is UI-thread-local.

§Examples
use std::sync::Arc;
use ailloli_ui_runtime::app::{RuntimeHandle, UiWake, UiWakeError};
struct Wake;
impl UiWake for Wake { fn wake(&self) -> Result<(), UiWakeError> { Ok(()) } }
let runtime = RuntimeHandle::<()>::new();
runtime.install_ui_wake(Arc::new(Wake));
assert!(runtime.ui_wake().unwrap().wake().is_ok());
Source

pub fn ui_wake(&self) -> Option<Arc<dyn UiWake>>

Returns a clone of the installed thread-safe host wake.

None means none was installed. Removing the returned Arc does not uninstall the runtime’s copy.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
assert!(RuntimeHandle::<()>::new().ui_wake().is_none());
Source

pub fn register_ui_service( &self, service: &Rc<dyn Fn() -> bool>, ) -> UiServiceRegistration<A>

Registers low-level UI-thread work after a payload-free host wake. The registry owns only a weak target; the returned RAII guard and the caller own the callback lifetime. The boolean result is observational: this low-level registration does not infer an owner or enqueue retained work. Component code should prefer crate::component::Context::register_ui_service, whose changed result requests a build of that exact component owner. IDs start at one and wrap on overflow; the (tree, id) key means a theoretical wrap can replace an older still-live registration.

§Examples
use std::{cell::Cell, rc::Rc};
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
let calls = Rc::new(Cell::new(0));
let seen = calls.clone();
let service: Rc<dyn Fn() -> bool> = Rc::new(move || { seen.set(seen.get() + 1); true });
let _registration = runtime.register_ui_service(&service);
assert!(runtime.service_ui_sources());
assert_eq!(calls.get(), 1);
Source

pub fn service_ui_sources(&self) -> bool

Services every live UI-local worker target. Callbacks run outside the runtime borrow. A changed component-owned service requests Build for its exact owner and mount generation; low-level registrations must invalidate explicitly. Dead weak callbacks are pruned. Every live callback runs once in unspecified hash-map order; the return value ORs their boolean results.

§Panics

A callback panic propagates and later callbacks are not serviced.

§Examples
use std::rc::Rc;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
let service: Rc<dyn Fn() -> bool> = Rc::new(|| false);
let _registration = runtime.register_ui_service(&service);
assert!(!runtime.service_ui_sources());
Source

pub fn request_focus_key(&self, key: impl Into<String>)

Replaces the pending focus request for this tree with a view-key string.

Empty strings are valid keys. The request is not itself an invalidation and remains pending until taken or the tree scope is released.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_focus_key("search");
assert_eq!(runtime.take_focus_key_request().as_deref(), Some("search"));
Source

pub fn take_focus_key_request(&self) -> Option<String>

Takes this tree’s pending focus key, leaving no request.

None means no request is pending; Some("") is a real empty key.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert_eq!(runtime.take_focus_key_request(), None);
runtime.request_focus_key("");
assert_eq!(runtime.take_focus_key_request(), Some(String::new()));
Source

pub fn request_repaint_after(&self, element_id: ElementId, delay: Duration)

Schedules paint invalidation after a monotonic delay.

Equal tree/element/strength timers coalesce to their earliest deadline. A zero delay is due immediately but must still be promoted or taken.

§Examples
use std::time::{Duration, Instant};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_repaint_after(ElementId(1), Duration::ZERO);
assert_eq!(runtime.take_due_scheduled_repaints(Instant::now()), [ElementId(1)]);
Source

pub fn request_layout_after(&self, element_id: ElementId, delay: Duration)

Schedules layout invalidation after a monotonic delay.

§Examples
use std::time::{Duration, Instant};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_layout_after(ElementId(2), Duration::ZERO);
assert_eq!(runtime.promote_due_scheduled_repaints(Instant::now()), 1);
assert!(runtime.frame_work_plan().needs_layout());
Source

pub fn request_build_after(&self, element_id: ElementId, delay: Duration)

Schedules component-build invalidation after a monotonic delay.

§Examples
use std::time::{Duration, Instant};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_build_after(ElementId(3), Duration::ZERO);
runtime.promote_due_scheduled_repaints(Instant::now());
assert!(runtime.frame_work_plan().needs_build());
Source

pub fn invalidate_after( &self, element_id: ElementId, invalidation: Invalidation, delay: Duration, )

Schedules an exact invalidation strength for a monotonic deadline.

The deadline is computed as Instant::now() + delay. Entries coalesce only when tree, element, and invalidation strength all match; the earlier deadline wins. Different strengths remain separate timers and later merge when promoted.

§Panics

Instant addition can panic if delay exceeds the platform clock range.

§Examples
use std::time::{Duration, Instant};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::{Invalidation, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.invalidate_after(ElementId(4), Invalidation::Paint, Duration::ZERO);
assert_eq!(runtime.take_due_scheduled_repaints(Instant::now()), [ElementId(4)]);
Source

pub fn take_due_scheduled_repaints(&self, now: Instant) -> Vec<ElementId>

Removes and returns due timer element IDs for this tree only.

Despite the historical name, timers of every invalidation strength are removed, their strengths are discarded, and no dirty work is enqueued. Results preserve timer-vector order and may contain the same element more than once when different strengths were scheduled. Other trees and deadlines strictly later than now remain queued.

§Examples
use std::time::{Duration, Instant};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::{Invalidation, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.invalidate_after(ElementId(1), Invalidation::Paint, Duration::ZERO);
runtime.invalidate_after(ElementId(1), Invalidation::Layout, Duration::ZERO);
assert_eq!(runtime.take_due_scheduled_repaints(Instant::now()), [ElementId(1), ElementId(1)]);
assert!(!runtime.has_dirty_elements());
Source

pub fn promote_due_scheduled_repaints(&self, now: Instant) -> usize

Promotes all due repaint timers to their owning tree’s dirty queue.

Hosts with multiple windows use this at their global scheduling boundary. The return value is the number of promoted timer entries, including entries that coalesce into already-pending work. This operation spans all retained trees sharing the handle and records timer provenance.

§Examples
use std::time::{Duration, Instant};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_repaint_after(ElementId(5), Duration::ZERO);
assert_eq!(runtime.promote_due_scheduled_repaints(Instant::now()), 1);
assert!(runtime.has_dirty_elements());
Source

pub fn next_scheduled_repaint_due(&self) -> Option<Instant>

Returns this tree’s earliest timer deadline without removing it.

None means this tree has no scheduled invalidation of any strength.

§Examples
use std::time::Duration;
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert!(runtime.next_scheduled_repaint_due().is_none());
runtime.request_repaint_after(ElementId(1), Duration::from_secs(1));
assert!(runtime.next_scheduled_repaint_due().is_some());
Source

pub fn next_scheduled_repaint_due_global(&self) -> Option<Instant>

Returns the earliest scheduled invalidation across all retained trees.

None means the shared runtime has no timer of any invalidation strength.

§Examples
use std::time::Duration;
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_layout_after(ElementId(1), Duration::from_millis(2));
assert_eq!(runtime.next_scheduled_repaint_due_global(), runtime.next_scheduled_repaint_due());
Source

pub fn has_dirty_elements(&self) -> bool

Reports whether this tree has at least one pending invalidation.

Scheduled-but-unpromoted timers do not count.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert!(!runtime.has_dirty_elements());
runtime.request_repaint(ElementId(1));
assert!(runtime.has_dirty_elements());
Source

pub fn take_dirty_elements(&self) -> Vec<ElementId>

Drains this tree’s pending invalidations and returns sorted element IDs.

Invalidation strengths are discarded. Each element occurs once because its requests were previously coalesced; ascending numeric ID order makes the result deterministic. Other tree namespaces are untouched.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_repaint(ElementId(9));
runtime.request_layout(ElementId(2));
assert_eq!(runtime.take_dirty_elements(), [ElementId(2), ElementId(9)]);
assert!(!runtime.has_dirty_elements());
Source

pub fn frame_work_plan(&self) -> FrameWorkPlan

Aggregate work currently pending for this tree without draining it.

Empty queues return FrameWorkPlan::none. All element invalidations are merged to the strongest required frame stages.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert!(runtime.frame_work_plan().is_empty());
runtime.request_layout(ElementId(1));
assert!(runtime.frame_work_plan().needs_layout());
Source

pub fn take_actions(&self) -> Vec<A>

Drains and returns all shared application actions in FIFO order.

The action queue is global to clones/tree scopes; an empty queue returns an empty vector without allocation reuse guarantees.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::new();
runtime.dispatch("a");
runtime.dispatch("b");
assert_eq!(runtime.take_actions(), ["a", "b"]);
assert!(runtime.take_actions().is_empty());
Source

pub fn states(&self) -> Rc<RefCell<StateStore>>

Clones the shared retained state store handle.

Tree scoping is part of each internal state key. Holding the returned Rc can keep state alive after the runtime handle is dropped; conflicting RefCell borrows panic.

§Examples
use std::rc::Rc;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
let states = runtime.states();
assert!(Rc::ptr_eq(&states, &runtime.states()));
Source

pub fn set_clipboard_provider(&self, provider: Rc<dyn ClipboardProvider>)

Replaces the shared clipboard provider without migrating its contents.

§Examples
use std::rc::Rc;
use ailloli_ui_runtime::app::{MemoryClipboard, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.set_clipboard_provider(Rc::new(MemoryClipboard::new()));
assert_eq!(runtime.read_clipboard_text().as_deref(), Some(""));
Source

pub fn read_clipboard_text(&self) -> Option<String>

Reads text through the current provider.

None and Some("") retain the distinction defined by ClipboardProvider::read_text.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
assert_eq!(RuntimeHandle::<()>::new().read_clipboard_text(), Some(String::new()));
Source

pub fn write_clipboard_text(&self, text: &str) -> Result<(), String>

Writes UTF-8 text through the current provider.

Errors are returned verbatim and are not recorded by the runtime.

§Errors

Returns the provider-defined display string when the configured clipboard rejects or cannot complete the write.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.write_clipboard_text("hello")?;
assert_eq!(runtime.read_clipboard_text().as_deref(), Some("hello"));
Source

pub fn set_external_url_opener(&self, opener: Rc<dyn ExternalUrlOpener>)

Replaces the shared validated-URL opener.

Previously recorded errors remain queued and opener state is not migrated.

§Examples
use std::rc::Rc;
use ailloli_ui_runtime::app::{MemoryExternalUrlOpener, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
runtime.set_external_url_opener(Rc::new(MemoryExternalUrlOpener::new()));
assert!(runtime.take_open_url_errors().is_empty());
Source

pub fn open_external_url(&self, url: &ExternalUrl) -> Result<(), OpenUrlError>

Opens an already validated URL and records non-fatal provider errors.

Validation must have occurred through ExternalUrl::parse. Successful calls are not recorded here; failures are both returned and cloned into the FIFO error queue.

§Errors

Returns the active provider’s OpenUrlError.

§Examples
use ailloli_ui_runtime::app::{ExternalUrl, RuntimeHandle};
let runtime = RuntimeHandle::<()>::new();
let url = ExternalUrl::parse("https://example.com")?;
runtime.open_external_url(&url)?;
assert!(runtime.take_open_url_errors().is_empty());
Source

pub fn take_open_url_errors(&self) -> Vec<OpenUrlError>

Drains provider failures recorded by Self::open_external_url.

Errors preserve call order and successful opens add nothing.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert!(runtime.take_open_url_errors().is_empty());
Source

pub fn request_close(&self)

Requests application exit (like Command::Quit without a user action). The flag is idempotent and shared across all handle clones/tree scopes.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_close();
assert!(runtime.take_close_requested());
Source

pub fn take_close_requested(&self) -> bool

Returns and clears the shared close-request flag.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert!(!runtime.take_close_requested());
runtime.request_close();
assert!(runtime.take_close_requested());
assert!(!runtime.take_close_requested());
Source

pub fn request_window_minimize( &self, logical_window_id: impl Into<LogicalWindowId>, )

Queues a minimize request for one logical window.

Empty logical IDs are stored verbatim; the runtime does not check that a native presentation exists or coalesce duplicate operations.

§Examples
use ailloli_ui_runtime::app::{RuntimeHandle, WindowChromeOp};
let runtime = RuntimeHandle::<()>::new();
runtime.request_window_minimize("main");
assert_eq!(runtime.take_window_chrome_ops()[0].1, WindowChromeOp::Minimize);
Source

pub fn request_window_toggle_maximize( &self, logical_window_id: impl Into<LogicalWindowId>, )

Queues a maximize-toggle request for one logical window.

Repeated requests remain repeated and may cancel at the host depending on the native state observed when each is applied.

§Examples
use ailloli_ui_runtime::app::{RuntimeHandle, WindowChromeOp};
let runtime = RuntimeHandle::<()>::new();
runtime.request_window_toggle_maximize("main");
assert_eq!(runtime.take_window_chrome_ops()[0].1, WindowChromeOp::ToggleMaximize);
Source

pub fn take_window_chrome_ops(&self) -> Vec<(LogicalWindowId, WindowChromeOp)>

Drains all logical-window chrome operations in FIFO order.

This queue is shared globally rather than filtered by tree namespace.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
runtime.request_window_minimize("one");
runtime.request_window_toggle_maximize("two");
let operations = runtime.take_window_chrome_ops();
assert_eq!((operations[0].0.as_str(), operations[1].0.as_str()), ("one", "two"));
Source

pub fn popup_portal(&self) -> Rc<RefCell<PopupPortal<A>>>

Returns the UI-local popup authority shared by this runtime.

Prefer the typed helpers below when the resulting host intents or errors must remain observable. Direct access is primarily intended for provider-neutral hosts and deterministic inspection. The returned Rc<RefCell<_>> shares authority with every handle clone; conflicting borrows panic and callers must remain on the UI thread.

§Examples
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
assert_eq!(runtime.popup_portal().borrow().open_ids().count(), 0);
Source

pub fn popup_id_for_element( &self, owner: ElementId, ) -> Result<PopupId, PopupPortalError>

Returns the stable popup id reserved for one retained popup owner.

The mapping deliberately follows the owner element rather than a native presentation, so a popup keeps its identity across surface detach/reattach and component reconciliation. Equal element IDs in different tree namespaces do not alias. IDs are allocated lazily and a successful mapping remains until tree release.

§Errors

Returns and records PopupPortalError::IdExhausted if the portal’s u64 identifier space is exhausted.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::RuntimeHandle;
let runtime = RuntimeHandle::<()>::new();
let first = runtime.popup_id_for_element(ElementId(8))?;
assert_eq!(runtime.popup_id_for_element(ElementId(8))?, first);
Source

pub fn register_popup( &self, request: PopupRequest<A>, ) -> Result<(), PopupPortalError>

Registers a closed popup and records any portal error.

The request is moved into shared portal storage. Registration does not open, position, build, or emit presentation intents.

§Errors

Propagates duplicate-ID, parent, presentation, or identifier-exhaustion errors from PopupPortal::register and clones them into the error queue.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let request = PopupRequest::new(PopupId::new(1), PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(2)), PopupContent::new(View::empty));
runtime.register_popup(request)?;
assert!(!runtime.popup_is_open(PopupId::new(1)));
Source

pub fn set_popup_content( &self, popup_id: PopupId, content: PopupContent<A>, ) -> Result<(), PopupPortalError>

Refreshes retained popup content for an already registered owner.

Visibility, z-order, ownership, semantics, and resolved geometry remain unchanged. The new content factory is not called by this method.

§Errors

Returns and records PopupPortalError::UnknownPopup for an unregistered ID.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.set_popup_content(id, PopupContent::new(|| View::empty().key("updated")))?;
assert_eq!(runtime.popup_portal().borrow().build_content(id).unwrap().key_ref(), Some("updated"));
Source

pub fn open_popup( &self, popup_id: PopupId, anchor: Rect, bounds: Rect, ) -> Result<PopupPortalOutcome, PopupPortalError>

Updates procedural backend geometry and opens or raises a popup.

anchor and bounds are global logical-pixel rectangles. Both must be finite with non-negative dimensions. Anchor update, bounds update, and open occur in order but are not transactional: a later failure can leave an earlier update committed. Successful lifecycle intents are recorded.

§Errors

Returns and records portal validation, unknown-ID, or parent-open errors.

§Examples
use ailloli_ui_core::{ElementId, Rect};
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
assert!(runtime.open_popup(id, Rect::new(5.0, 5.0, 10.0, 4.0), Rect::new(5.0, 9.0, 40.0, 20.0))?.handled());
assert!(runtime.popup_is_open(id));
Source

pub fn open_popup_placed( &self, popup_id: PopupId, placement: PopupPlacementSpec, ) -> Result<PopupPortalOutcome, PopupPortalError>

Publishes semantic placement inputs and opens (or raises) a popup.

Unlike Self::open_popup, this path does not accept backend-resolved bounds. A changed request clears previous backend geometry so the active host resolves it against its current viewport; an identical repaint preserves geometry already resolved by that host. All dimensions use logical pixels.

§Errors

Returns and records invalid placement geometry, unknown-ID, or parent-open errors.

§Examples
use ailloli_ui_core::{ElementId, Rect, Size};
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupPlacementSpec, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
let spec = PopupPlacementSpec::new(Rect::new(0.0, 0.0, 10.0, 4.0), Size::new(30.0, 20.0));
runtime.open_popup_placed(id, spec)?;
assert_eq!(runtime.popup_portal().borrow().request(id).unwrap().desired_size(), Some(Size::new(30.0, 20.0)));
Source

pub fn open_popup_unpositioned( &self, popup_id: PopupId, ) -> Result<PopupPortalOutcome, PopupPortalError>

Opens a registered popup before its backend has committed geometry.

This is used for declarative default_open/bound-open state. The overlay backend supplies anchor and bounds at its next interaction or paint pass without delaying semantic visibility.

§Errors

Returns and records unknown-ID or parent-open errors.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup_unpositioned(id)?;
assert!(runtime.popup_is_open(id));
assert_eq!(runtime.popup_portal().borrow().bounds(id), None);
Source

pub fn close_popup( &self, popup_id: PopupId, reason: PopupDismissReason, ) -> PopupPortalOutcome

Closes an open popup subtree for a stated reason and records its intents.

Unknown or already-closed IDs produce an unhandled empty outcome rather than an error. Descendants close before their parent; focus restoration can add a final intent.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupDismissReason, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup_unpositioned(id)?;
assert!(runtime.close_popup(id, PopupDismissReason::Programmatic).handled());
assert!(!runtime.popup_is_open(id));
Source

pub fn unregister_popup(&self, popup_id: PopupId) -> PopupPortalOutcome

Closes and removes a popup registration, recording resulting intents.

An owner snapshot preserves focus-restoration data after the portal entry disappears. Unknown IDs return an unhandled outcome. Any element-to-ID reservation remains until its tree scope is released.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
assert!(runtime.unregister_popup(id).handled());
assert!(!runtime.popup_portal().borrow().contains(id));
Source

pub fn popup_is_open(&self, popup_id: PopupId) -> bool

Reports whether a registered popup is currently open.

Unknown IDs and registered-but-closed entries both return false.

§Examples
use ailloli_ui_runtime::{app::RuntimeHandle, popup::PopupId};
assert!(!RuntimeHandle::<()>::new().popup_is_open(PopupId::new(404)));
Source

pub fn route_popup_pointer_press( &self, logical_window_id: &LogicalWindowId, presentation_generation: PresentationGeneration, point: Point, ) -> PopupPortalOutcome

Routes a pointer press through the popup z-order authority.

The returned outcome is also recorded for backend processing. Input routers use it to prevent an outside-dismiss press from activating content behind the popup. point is in global logical pixels. Only popups belonging to the exact logical window and presentation generation participate.

§Examples
use ailloli_ui_core::{ElementId, LogicalWindowId, Point, Rect};
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let window = LogicalWindowId::new("main");
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new(window.clone(), PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup(id, Rect::new(0.0, 0.0, 1.0, 1.0), Rect::new(0.0, 0.0, 10.0, 10.0))?;
let outcome = runtime.route_popup_pointer_press(&window, PresentationGeneration::INITIAL, Point::new(20.0, 20.0));
assert!(outcome.handled() && !runtime.popup_is_open(id));
Source

pub fn route_popup_pointer_press_with_backend_hit( &self, logical_window_id: &LogicalWindowId, presentation_generation: PresentationGeneration, point: Point, backend_hit: Option<PopupId>, ) -> PopupPortalOutcome

Same as Self::route_popup_pointer_press, with a popup hit confirmed by the active presentation backend.

backend_hit is trusted only when it names an open popup in the exact presentation. None falls back to retained bounds; an unpositioned popup can therefore still be recognized by Some(id).

§Examples
use ailloli_ui_core::{ElementId, LogicalWindowId, Point};
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let window = LogicalWindowId::new("main");
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new(window.clone(), PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup_unpositioned(id)?;
assert!(runtime.route_popup_pointer_press_with_backend_hit(&window, PresentationGeneration::INITIAL, Point::new(500.0, 500.0), Some(id)).handled());
Source

pub fn route_popup_escape( &self, logical_window_id: &LogicalWindowId, presentation_generation: PresentationGeneration, ) -> PopupPortalOutcome

Routes Escape to the topmost eligible popup.

Only the exact logical window/generation participates. The returned outcome is recorded; an eligible popup may close and restore focus.

§Examples
use ailloli_ui_core::{ElementId, LogicalWindowId};
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let window = LogicalWindowId::new("main");
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new(window.clone(), PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup_unpositioned(id)?;
assert!(runtime.route_popup_escape(&window, PresentationGeneration::INITIAL).handled());
assert!(!runtime.popup_is_open(id));
Source

pub fn close_stale_popup_presentations( &self, logical_window_id: &LogicalWindowId, presentation_generation: PresentationGeneration, ) -> PopupPortalOutcome

Closes registrations attached to obsolete native presentation generations and records the resulting backend intents. Registrations for other logical windows or for the supplied current generation remain open.

§Examples
use ailloli_ui_core::{ElementId, LogicalWindowId};
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let window = LogicalWindowId::new("main");
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new(window.clone(), PresentationGeneration::new(1), ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup_unpositioned(id)?;
assert!(runtime.close_stale_popup_presentations(&window, PresentationGeneration::new(2)).handled());
assert!(!runtime.popup_is_open(id));
Source

pub fn prune_stale_popup_owners( &self, element_is_alive: impl FnMut(ElementId) -> bool, ) -> PopupPortalOutcome

Prunes missing popup owners in this handle’s retained-tree namespace.

The callback receives tree-local element IDs for registrations in this scope. Missing owners and their descendants are closed/unregistered; sibling tree namespaces are untouched. Resulting intents are recorded.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(9)), PopupContent::new(View::empty)))?;
let outcome = runtime.prune_stale_popup_owners(|element| element != ElementId(9));
assert!(outcome.handled());
assert!(!runtime.popup_portal().borrow().contains(id));
Source

pub fn take_popup_intents(&self) -> Vec<PopupIntent>

Drains all backend-facing popup intents in production order.

This queue is global across tree namespaces/presentations. It is distinct from the internally filtered pending-input queue, so draining it does not consume focus work awaited by an input router.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupIntent, PopupOwner, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let id = PopupId::new(1);
runtime.register_popup(PopupRequest::new(id, PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty)))?;
runtime.open_popup_unpositioned(id)?;
assert!(matches!(runtime.take_popup_intents().as_slice(), [PopupIntent::Present { popup_id }] if *popup_id == id));
Source

pub fn take_popup_errors(&self) -> Vec<PopupPortalError>

Drains popup-operation errors in occurrence order.

Only handle helpers record here; errors produced through direct Self::popup_portal access are not observed.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::{PresentationGeneration, RuntimeHandle}, component::View, popup::{ElementTreeId, PopupContent, PopupId, PopupOwner, PopupPortalError, PopupRequest}};
let runtime = RuntimeHandle::<()>::new();
let request = || PopupRequest::new(PopupId::new(1), PopupOwner::new("main", PresentationGeneration::INITIAL, ElementTreeId::new(0), ElementId(1)), PopupContent::new(View::empty));
runtime.register_popup(request())?;
assert_eq!(runtime.register_popup(request()), Err(PopupPortalError::DuplicateId));
assert_eq!(runtime.take_popup_errors(), [PopupPortalError::DuplicateId]);

Trait Implementations§

Source§

impl<A> Clone for RuntimeHandle<A>

Clones the shared storage and preserves the current tree namespace.

Source§

fn clone(&self) -> Self

Clones the Rc and copies the tree namespace.

1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A> Default for RuntimeHandle<A>

Creates the same isolated compatibility-scope state as RuntimeHandle::new.

Source§

fn default() -> Self

Auto Trait Implementations§

§

impl<A> Freeze for RuntimeHandle<A>

§

impl<A> !RefUnwindSafe for RuntimeHandle<A>

§

impl<A> !Send for RuntimeHandle<A>

§

impl<A> !Sync for RuntimeHandle<A>

§

impl<A> Unpin for RuntimeHandle<A>

§

impl<A> !UnwindSafe for RuntimeHandle<A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<A> IntoClickAction<A> for A
where A: Clone + 'static,

Source§

fn into_click_action(self) -> ClickAction<A>

Implements the into_click_action helper used by this module.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> Props for T
where T: Clone + 'static,