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.
impl<A> RuntimeHandle<A>
Runtime state and tree-scope operations.
Sourcepub fn new() -> Self
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());Sourcepub const fn element_tree_id(&self) -> ElementTreeId
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);Sourcepub fn set_presentation_scope(
&self,
logical_window_id: impl Into<LogicalWindowId>,
presentation_generation: PresentationGeneration,
)
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");Sourcepub fn presentation_scope(
&self,
) -> Option<(LogicalWindowId, PresentationGeneration)>
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());Sourcepub fn clear_presentation_scope(&self)
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());Sourcepub fn dispatch(&self, action: A)
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]);Sourcepub fn invalidate(&self, element_id: ElementId, invalidation: Invalidation)
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());Sourcepub fn invalidate_from(
&self,
element_id: ElementId,
invalidation: Invalidation,
source: InvalidationSource,
)
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);Sourcepub fn invalidation_diagnostics(&self) -> InvalidationDiagnosticsSnapshot
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);Sourcepub fn mark_dirty(&self, element_id: ElementId)
👎Deprecated: use invalidate(element_id, Invalidation::Build)
pub fn mark_dirty(&self, element_id: ElementId)
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());Sourcepub fn request_repaint(&self, element_id: ElementId)
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());Sourcepub fn request_layout(&self, element_id: ElementId)
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());Sourcepub fn request_build(&self, element_id: ElementId)
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());Sourcepub fn install_ui_wake(&self, wake: Arc<dyn UiWake>)
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());Sourcepub fn ui_wake(&self) -> Option<Arc<dyn UiWake>>
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());Sourcepub fn register_ui_service(
&self,
service: &Rc<dyn Fn() -> bool>,
) -> UiServiceRegistration<A>
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);Sourcepub fn service_ui_sources(&self) -> bool
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());Sourcepub fn request_focus_key(&self, key: impl Into<String>)
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"));Sourcepub fn take_focus_key_request(&self) -> Option<String>
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()));Sourcepub fn request_repaint_after(&self, element_id: ElementId, delay: Duration)
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)]);Sourcepub fn request_layout_after(&self, element_id: ElementId, delay: Duration)
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());Sourcepub fn request_build_after(&self, element_id: ElementId, delay: Duration)
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());Sourcepub fn invalidate_after(
&self,
element_id: ElementId,
invalidation: Invalidation,
delay: Duration,
)
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)]);Sourcepub fn take_due_scheduled_repaints(&self, now: Instant) -> Vec<ElementId>
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());Sourcepub fn promote_due_scheduled_repaints(&self, now: Instant) -> usize
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());Sourcepub fn next_scheduled_repaint_due(&self) -> Option<Instant>
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());Sourcepub fn next_scheduled_repaint_due_global(&self) -> Option<Instant>
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());Sourcepub fn has_dirty_elements(&self) -> bool
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());Sourcepub fn take_dirty_elements(&self) -> Vec<ElementId>
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());Sourcepub fn frame_work_plan(&self) -> FrameWorkPlan
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());Sourcepub fn take_actions(&self) -> Vec<A>
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());Sourcepub fn states(&self) -> Rc<RefCell<StateStore>>
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()));Sourcepub fn set_clipboard_provider(&self, provider: Rc<dyn ClipboardProvider>)
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(""));Sourcepub fn read_clipboard_text(&self) -> Option<String>
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()));Sourcepub fn write_clipboard_text(&self, text: &str) -> Result<(), String>
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"));Sourcepub fn set_external_url_opener(&self, opener: Rc<dyn ExternalUrlOpener>)
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());Sourcepub fn open_external_url(&self, url: &ExternalUrl) -> Result<(), OpenUrlError>
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());Sourcepub fn take_open_url_errors(&self) -> Vec<OpenUrlError>
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());Sourcepub fn request_close(&self)
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());Sourcepub fn take_close_requested(&self) -> bool
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());Sourcepub fn request_window_minimize(
&self,
logical_window_id: impl Into<LogicalWindowId>,
)
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);Sourcepub fn request_window_toggle_maximize(
&self,
logical_window_id: impl Into<LogicalWindowId>,
)
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);Sourcepub fn take_window_chrome_ops(&self) -> Vec<(LogicalWindowId, WindowChromeOp)>
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"));Sourcepub fn popup_portal(&self) -> Rc<RefCell<PopupPortal<A>>>
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);Sourcepub fn popup_id_for_element(
&self,
owner: ElementId,
) -> Result<PopupId, PopupPortalError>
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);Sourcepub fn register_popup(
&self,
request: PopupRequest<A>,
) -> Result<(), PopupPortalError>
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)));Sourcepub fn set_popup_content(
&self,
popup_id: PopupId,
content: PopupContent<A>,
) -> Result<(), PopupPortalError>
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"));Sourcepub fn open_popup(
&self,
popup_id: PopupId,
anchor: Rect,
bounds: Rect,
) -> Result<PopupPortalOutcome, PopupPortalError>
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));Sourcepub fn open_popup_placed(
&self,
popup_id: PopupId,
placement: PopupPlacementSpec,
) -> Result<PopupPortalOutcome, PopupPortalError>
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)));Sourcepub fn open_popup_unpositioned(
&self,
popup_id: PopupId,
) -> Result<PopupPortalOutcome, PopupPortalError>
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);Sourcepub fn close_popup(
&self,
popup_id: PopupId,
reason: PopupDismissReason,
) -> PopupPortalOutcome
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));Sourcepub fn unregister_popup(&self, popup_id: PopupId) -> PopupPortalOutcome
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));Sourcepub fn popup_is_open(&self, popup_id: PopupId) -> bool
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)));Sourcepub fn route_popup_pointer_press(
&self,
logical_window_id: &LogicalWindowId,
presentation_generation: PresentationGeneration,
point: Point,
) -> PopupPortalOutcome
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));Sourcepub fn route_popup_pointer_press_with_backend_hit(
&self,
logical_window_id: &LogicalWindowId,
presentation_generation: PresentationGeneration,
point: Point,
backend_hit: Option<PopupId>,
) -> PopupPortalOutcome
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());Sourcepub fn route_popup_escape(
&self,
logical_window_id: &LogicalWindowId,
presentation_generation: PresentationGeneration,
) -> PopupPortalOutcome
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));Sourcepub fn close_stale_popup_presentations(
&self,
logical_window_id: &LogicalWindowId,
presentation_generation: PresentationGeneration,
) -> PopupPortalOutcome
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));Sourcepub fn prune_stale_popup_owners(
&self,
element_is_alive: impl FnMut(ElementId) -> bool,
) -> PopupPortalOutcome
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));Sourcepub fn take_popup_intents(&self) -> Vec<PopupIntent>
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));Sourcepub fn take_popup_errors(&self) -> Vec<PopupPortalError>
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.
impl<A> Clone for RuntimeHandle<A>
Clones the shared storage and preserves the current tree namespace.
Source§impl<A> Default for RuntimeHandle<A>
Creates the same isolated compatibility-scope state as RuntimeHandle::new.
impl<A> Default for RuntimeHandle<A>
Creates the same isolated compatibility-scope state as RuntimeHandle::new.
Source§fn default() -> Self
fn default() -> Self
Returns RuntimeHandle::new.
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<A> IntoClickAction<A> for Awhere
A: Clone + 'static,
impl<A> IntoClickAction<A> for Awhere
A: Clone + 'static,
Source§fn into_click_action(self) -> ClickAction<A>
fn into_click_action(self) -> ClickAction<A>
Implements the into_click_action helper used by this module.