mod a11y_rt;
mod helpers;
mod input;
mod redraw;
mod secondary;
use super::*;
pub(crate) fn build_window_attributes<A: App>() -> WindowAttributes {
let (w, h) = A::initial_size();
let attrs = WindowAttributes::default()
.with_title(A::title())
.with_inner_size(LogicalSize::new(w, h));
#[cfg(all(target_os = "linux", not(target_os = "android")))]
{
if let Some(id) = A::app_id() {
use llimphi_hal::winit::platform::wayland::WindowAttributesExtWayland;
return attrs.with_name(id, "");
}
}
attrs
}
fn push_a11y_tree<A: App>(state: &mut RuntimeState<A>) {
let Some(cache) = state.last_render.as_ref() else {
return;
};
let focused_idx = state.focused.and_then(|fid| {
cache
.mounted
.nodes
.iter()
.position(|n| n.focusable == Some(fid))
});
let app_name = A::window_title(state.model.as_ref().expect("model"))
.unwrap_or_else(|| String::from("Llimphi"));
let tree_id = state.a11y_tree_id;
state.a11y_adapter.update_if_active(|| {
crate::a11y::build_tree(&cache.mounted, &cache.computed, focused_idx, &app_name, tree_id)
});
}
impl<A: App> ApplicationHandler<UserEvent<A::Msg>> for Runtime<A> {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if self.state.is_some() {
return;
}
let window = event_loop
.create_window(build_window_attributes::<A>())
.expect("create window");
let window = Arc::new(window);
if A::ime_allowed() {
window.set_ime_allowed(true);
}
let a11y_proxy: EventLoopProxy<UserEvent<A::Msg>> =
match &self.handle.inner {
HandleInner::Real(p) => p.clone(),
HandleInner::Test => unreachable!("resumed sin event loop real"),
HandleInner::Lifted(_) => unreachable!("el runtime nunca corre con un handle lifteado"),
};
let a11y_adapter =
accesskit_winit::Adapter::with_event_loop_proxy(event_loop, &window, a11y_proxy);
let a11y_tree_id = accesskit::TreeId(uuid::Uuid::new_v4());
let hal = pollster::block_on(Hal::new(None)).expect("hal");
let surface = WinitSurface::new(&hal, window.clone()).expect("surface");
let renderer = Renderer::new(&hal).expect("renderer");
let overlay_compositor = llimphi_hal::OverlayCompositor::new(&hal.device);
let blur_compositor = llimphi_hal::BlurCompositor::new(&hal.device);
let color_filter_compositor = llimphi_hal::ColorFilterCompositor::new(&hal.device);
let typesetter = llimphi_text::Typesetter::new();
window.request_redraw();
self.state = Some(RuntimeState {
window,
hal,
surface,
renderer,
scene: vello::Scene::new(),
overlay_compositor,
blur_compositor,
color_filter_compositor,
model: Some(A::init(&self.handle)),
cursor: PhysicalPosition::new(0.0, 0.0),
modifiers: Modifiers::default(),
typesetter,
layout: LayoutTree::new(),
overlay_layout: LayoutTree::new(),
last_render: None,
hovered: None,
drag: None,
focused: None,
last_title: None,
anim_registry: llimphi_compositor::AnimRegistry::new(),
size_anim_registry: llimphi_compositor::SizeAnimRegistry::new(),
hero_registry: llimphi_compositor::HeroRegistry::new(),
ripple_registry: llimphi_compositor::RippleRegistry::new(),
last_tap: None,
pending_long_press: None,
retained: None,
selection: None,
a11y_adapter,
a11y_tree_id,
});
if let Some(state) = self.state.as_mut() {
let scale = state.window.scale_factor();
if let Some(msg) = A::on_scale_factor(state.model.as_ref().expect("model"), scale) {
let model = state.model.take().expect("model");
state.model = Some(A::update(model, msg, &self.handle));
state.last_render = None;
}
}
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent<A::Msg>) {
match event {
UserEvent::Quit => event_loop.exit(),
UserEvent::Msg(msg) => {
self.dispatch_model(msg);
}
UserEvent::OpenWindow { key, title, width, height } => {
self.open_secondary(event_loop, key, title, width, height);
}
UserEvent::CloseWindow { key } => {
if let Some(pos) = self.secondaries.iter().position(|s| s.key == key) {
self.secondaries.remove(pos);
}
}
UserEvent::A11y(ev) => {
self.handle_a11y_event(ev);
}
}
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
_id: WindowId,
event: WindowEvent,
) {
if let Some(idx) = self.secondaries.iter().position(|s| s.window.id() == _id) {
self.handle_secondary_event(idx, event);
return;
}
self.handle_primary_window_event(event_loop, event);
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
let Some(state) = self.state.as_mut() else {
return;
};
match state.pending_long_press.as_ref() {
Some(p) => {
if std::time::Instant::now() >= p.deadline {
let handler = state.pending_long_press.take().expect("pending").handler;
event_loop.set_control_flow(ControlFlow::Wait);
if let Some(msg) = handler.invoke() {
let model = state.model.take().expect("model");
state.model = Some(A::update(model, msg, &self.handle));
state.last_render = None;
state.window.request_redraw();
}
} else {
event_loop.set_control_flow(ControlFlow::WaitUntil(p.deadline));
}
}
None => event_loop.set_control_flow(ControlFlow::Wait),
}
}
}