1use std::{
2 collections::HashMap,
3 fmt, mem,
4 path::PathBuf,
5 sync::Arc,
6 task::Waker,
7 time::{Duration, Instant},
8};
9
10use crate::{Deadline, handler::HandlerExt as _, view_process::raw_events::RAW_FRAME_RENDERED_EVENT, window::WINDOWS_APP};
11use parking_lot::Mutex;
12use zng_app_context::{AppScope, app_local};
13use zng_task::DEADLINE_APP;
14use zng_task::channel::{self, ChannelError};
15use zng_time::{INSTANT_APP, InstantMode};
16use zng_txt::Txt;
17use zng_var::{ArcEq, ResponderVar, ResponseVar, VARS_APP, Var, expr_var, response_var};
18use zng_view_api::{DeviceEventsFilter, raw_input::InputDeviceEvent};
19
20use crate::{
21 APP, AppControlFlow, DInstant, INSTANT,
22 event::{CommandInfoExt, CommandNameExt, command, event},
23 event_args,
24 shortcut::CommandShortcutExt,
25 shortcut::shortcut,
26 timer::TimersService,
27 update::{ContextUpdates, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, UpdateOp, UpdateTrace, UpdatesTrace, WidgetUpdates},
28 view_process::{raw_device_events::InputDeviceId, *},
29 widget::WidgetId,
30 window::WindowId,
31};
32
33pub(crate) struct RunningApp {
35 receiver: channel::Receiver<AppEvent>,
36
37 loop_timer: LoopTimer,
38 loop_monitor: LoopMonitor,
39 last_wait_event: Instant,
40
41 pending_view_events: Vec<zng_view_api::Event>,
42 pending_view_frame_events: Vec<zng_view_api::window::EventFrameRendered>,
43 pending: ContextUpdates,
44
45 exited: bool,
46
47 _scope: AppScope,
49}
50impl Drop for RunningApp {
51 fn drop(&mut self) {
52 let _s = tracing::debug_span!("RunningApp::drop").entered();
53 APP.call_deinit_handlers();
54 VIEW_PROCESS.exit();
55 }
56}
57impl RunningApp {
58 pub(crate) fn start(
59 scope: AppScope,
60 is_headed: bool,
61 with_renderer: bool,
62 view_process_exe: Option<PathBuf>,
63 view_process_env: HashMap<Txt, Txt>,
64 is_minimal: bool,
65 ) -> Self {
66 let _s = tracing::debug_span!("APP::start").entered();
67
68 let (sender, receiver) = AppEventSender::new();
69
70 UPDATES.init(sender);
71
72 fn app_waker() {
73 UPDATES.update_app();
74 }
75 VARS_APP.init_app_waker(app_waker);
76 VARS_APP.init_modify_trace(UpdatesTrace::log_var);
77 DEADLINE_APP.init_deadline_service(crate::timer::deadline_service);
78 zng_var::animation::TRANSITIONABLE_APP.init_rgba_lerp(zng_color::lerp_rgba);
79
80 if with_renderer && view_process_exe.is_none() {
81 zng_env::assert_inited();
82 }
83
84 #[cfg(not(target_arch = "wasm32"))]
85 let view_process_exe = view_process_exe.unwrap_or_else(|| std::env::current_exe().expect("current_exe"));
86 #[cfg(target_arch = "wasm32")]
87 let view_process_exe = std::path::PathBuf::from("<wasm>");
88
89 APP.pre_init(is_headed, with_renderer, view_process_exe, view_process_env);
90
91 APP.call_init_handlers(is_minimal);
92
93 RunningApp {
94 receiver,
95
96 loop_timer: LoopTimer::default(),
97 loop_monitor: LoopMonitor::default(),
98 last_wait_event: Instant::now(),
99
100 pending_view_events: Vec::with_capacity(100),
101 pending_view_frame_events: Vec::with_capacity(5),
102 pending: ContextUpdates {
103 update: false,
104 info: false,
105 layout: false,
106 render: false,
107 update_widgets: WidgetUpdates::default(),
108 info_widgets: InfoUpdates::default(),
109 layout_widgets: LayoutUpdates::default(),
110 render_widgets: RenderUpdates::default(),
111 render_update_widgets: RenderUpdates::default(),
112 },
113 exited: false,
114
115 _scope: scope,
116 }
117 }
118
119 pub fn has_exited(&self) -> bool {
120 self.exited
121 }
122
123 fn input_device_id(&mut self, id: zng_view_api::raw_input::InputDeviceId) -> InputDeviceId {
124 VIEW_PROCESS.input_device_id(id)
125 }
126
127 fn on_view_event(&mut self, ev: zng_view_api::Event) {
129 use crate::view_process::raw_device_events::*;
130 use crate::view_process::raw_events::*;
131 use zng_view_api::Event;
132
133 fn window_id(id: zng_view_api::window::WindowId) -> WindowId {
134 WindowId::from_raw(id.get())
135 }
136 fn audio_output_id(id: zng_view_api::audio::AudioOutputId) -> AudioOutputId {
137 AudioOutputId::from_raw(id.get())
138 }
139
140 match ev {
141 Event::MouseMoved {
142 window: w_id,
143 device: d_id,
144 coalesced_pos,
145 position,
146 } => {
147 let args = RawMouseMovedArgs::now(window_id(w_id), self.input_device_id(d_id), coalesced_pos, position);
148 RAW_MOUSE_MOVED_EVENT.notify(args);
149 }
150 Event::MouseEntered {
151 window: w_id,
152 device: d_id,
153 } => {
154 let args = RawMouseArgs::now(window_id(w_id), self.input_device_id(d_id));
155 RAW_MOUSE_ENTERED_EVENT.notify(args);
156 }
157 Event::MouseLeft {
158 window: w_id,
159 device: d_id,
160 } => {
161 let args = RawMouseArgs::now(window_id(w_id), self.input_device_id(d_id));
162 RAW_MOUSE_LEFT_EVENT.notify(args);
163 }
164 Event::WindowChanged(c) => {
165 let monitor_id = c.monitor.map(|id| VIEW_PROCESS.monitor_id(id));
166 let args = RawWindowChangedArgs::now(
167 window_id(c.window),
168 c.state,
169 c.position,
170 monitor_id,
171 c.size,
172 c.safe_padding,
173 c.cause,
174 c.frame_wait_id,
175 );
176 RAW_WINDOW_CHANGED_EVENT.notify(args);
177 }
178 Event::DragHovered { window, data, allowed } => {
179 let args = RawDragHoveredArgs::now(window_id(window), data, allowed);
180 RAW_DRAG_HOVERED_EVENT.notify(args);
181 }
182 Event::DragMoved {
183 window,
184 coalesced_pos,
185 position,
186 } => {
187 let args = RawDragMovedArgs::now(window_id(window), coalesced_pos, position);
188 RAW_DRAG_MOVED_EVENT.notify(args);
189 }
190 Event::DragDropped {
191 window,
192 data,
193 allowed,
194 drop_id,
195 } => {
196 let args = RawDragDroppedArgs::now(window_id(window), data, allowed, drop_id);
197 RAW_DRAG_DROPPED_EVENT.notify(args);
198 }
199 Event::DragCancelled { window } => {
200 let args = RawDragCancelledArgs::now(window_id(window));
201 RAW_DRAG_CANCELLED_EVENT.notify(args);
202 }
203 Event::AppDragEnded { window, drag, applied } => {
204 let args = RawAppDragEndedArgs::now(window_id(window), drag, applied);
205 RAW_APP_DRAG_ENDED_EVENT.notify(args);
206 }
207 Event::FocusChanged { prev, new } => {
208 let args = RawWindowFocusArgs::now(prev.map(window_id), new.map(window_id));
209 RAW_WINDOW_FOCUS_EVENT.notify(args);
210 }
211 Event::KeyboardInput {
212 window: w_id,
213 device: d_id,
214 key_code,
215 state,
216 key,
217 key_location,
218 key_modified,
219 text,
220 } => {
221 let args = RawKeyInputArgs::now(
222 window_id(w_id),
223 self.input_device_id(d_id),
224 key_code,
225 key_location,
226 state,
227 key,
228 key_modified,
229 text,
230 );
231 RAW_KEY_INPUT_EVENT.notify(args);
232 }
233 Event::Ime { window: w_id, ime } => {
234 let args = RawImeArgs::now(window_id(w_id), ime);
235 RAW_IME_EVENT.notify(args);
236 }
237
238 Event::MouseWheel {
239 window: w_id,
240 device: d_id,
241 delta,
242 phase,
243 } => {
244 let args = RawMouseWheelArgs::now(window_id(w_id), self.input_device_id(d_id), delta, phase);
245 RAW_MOUSE_WHEEL_EVENT.notify(args);
246 }
247 Event::MouseInput {
248 window: w_id,
249 device: d_id,
250 state,
251 button,
252 } => {
253 let args = RawMouseInputArgs::now(window_id(w_id), self.input_device_id(d_id), state, button);
254 RAW_MOUSE_INPUT_EVENT.notify(args);
255 }
256 Event::TouchpadPressure {
257 window: w_id,
258 device: d_id,
259 pressure,
260 stage,
261 } => {
262 let args = RawTouchpadPressureArgs::now(window_id(w_id), self.input_device_id(d_id), pressure, stage);
263 RAW_TOUCHPAD_PRESSURE_EVENT.notify(args);
264 }
265 Event::AxisMotion {
266 window: w_id,
267 device: d_id,
268 axis,
269 value,
270 } => {
271 let args = RawAxisMotionArgs::now(window_id(w_id), self.input_device_id(d_id), axis, value);
272 RAW_AXIS_MOTION_EVENT.notify(args);
273 }
274 Event::Touch {
275 window: w_id,
276 device: d_id,
277 touches,
278 } => {
279 let args = RawTouchArgs::now(window_id(w_id), self.input_device_id(d_id), touches);
280 RAW_TOUCH_EVENT.notify(args);
281 }
282 Event::ScaleFactorChanged {
283 monitor: id,
284 windows,
285 scale_factor,
286 } => {
287 let monitor_id = VIEW_PROCESS.monitor_id(id);
288 let windows: Vec<_> = windows.into_iter().map(window_id).collect();
289 let args = RawScaleFactorChangedArgs::now(monitor_id, windows, scale_factor);
290 RAW_SCALE_FACTOR_CHANGED_EVENT.notify(args);
291 }
292 Event::MonitorsChanged(monitors) => {
293 let monitors: Vec<_> = monitors.into_iter().map(|(id, info)| (VIEW_PROCESS.monitor_id(id), info)).collect();
294 let args = RawMonitorsChangedArgs::now(monitors);
295 RAW_MONITORS_CHANGED_EVENT.notify(args);
296 }
297 Event::AudioDevicesChanged(_audio_devices) => {}
298 Event::WindowCloseRequested(w_id) => {
299 let args = RawWindowCloseRequestedArgs::now(window_id(w_id));
300 RAW_WINDOW_CLOSE_REQUESTED_EVENT.notify(args);
301 }
302 Event::WindowOpened(w_id, data) => {
303 let w_id = window_id(w_id);
304 let (window, data) = VIEW_PROCESS.on_window_opened(w_id, data);
305 let args = RawWindowOpenArgs::now(w_id, window.downgrade(), data);
306 RAW_WINDOW_OPEN_EVENT.notify(args);
307 UPDATES.once_next_update("", move || {
308 let _hold_once = &window;
309 });
310 }
311 Event::HeadlessOpened(w_id, data) => {
312 let w_id = window_id(w_id);
313 let (surface, data) = VIEW_PROCESS.on_headless_opened(w_id, data);
314 let args = RawHeadlessOpenArgs::now(w_id, surface.downgrade(), data);
315 RAW_HEADLESS_OPEN_EVENT.notify(args);
316 UPDATES.once_next_update("", move || {
317 let _hold_once = &surface;
318 });
319 }
320 Event::WindowOrHeadlessOpenError { id: w_id, error } => {
321 let w_id = window_id(w_id);
322 let args = RawWindowOrHeadlessOpenErrorArgs::now(w_id, error);
323 RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT.notify(args);
324 }
325 Event::WindowClosed(w_id) => {
326 let args = RawWindowCloseArgs::now(window_id(w_id));
327 RAW_WINDOW_CLOSE_EVENT.notify(args);
328 }
329 Event::ImageMetadataDecoded(meta) => {
330 if let Some(handle) = VIEW_PROCESS.on_image_metadata(&meta) {
331 let args = RawImageMetadataDecodedArgs::now(handle.downgrade(), meta);
332 RAW_IMAGE_METADATA_DECODED_EVENT.notify(args);
333 UPDATES.once_next_update("", move || {
334 let _hold_once = &handle;
335 });
336 } else {
337 tracing::warn!("received unknown image metadata {:?} ({:?}), ignoring", meta.id, meta.size);
338 }
339 }
340 Event::ImageDecoded(img) => {
341 if let Some(handle) = VIEW_PROCESS.on_image_decoded(&img) {
342 let img = ArcEq::new(img);
343 let args = RawImageDecodedArgs::now(handle.downgrade(), ArcEq::downgrade(&img));
344 RAW_IMAGE_DECODED_EVENT.notify(args);
345 UPDATES.once_next_update("", move || {
346 let _hold_once = (&handle, &img);
347 });
348 } else {
349 tracing::warn!("received unknown image data {:?} ({:?}), ignoring", img.meta.id, img.meta.size);
350 }
351 }
352 Event::ImageDecodeError { image: id, error } => {
353 if let Some(handle) = VIEW_PROCESS.on_image_error(id) {
354 let args = RawImageDecodeErrorArgs::now(handle.downgrade(), error);
355 RAW_IMAGE_DECODE_ERROR_EVENT.notify(args);
356 UPDATES.once_next_update("", move || {
357 let _hold_once = &handle;
358 });
359 }
360 }
361 Event::ImageEncoded { task, data } => VIEW_PROCESS.on_image_encoded(task, data),
362 Event::ImageEncodeError { task, error } => {
363 VIEW_PROCESS.on_image_encode_error(task, error);
364 }
365
366 Event::AudioMetadataDecoded(meta) => {
367 if let Some(handle) = VIEW_PROCESS.on_audio_metadata(&meta) {
368 let args = RawAudioMetadataDecodedArgs::now(handle.downgrade(), meta);
369 RAW_AUDIO_METADATA_DECODED_EVENT.notify(args);
370 UPDATES.once_next_update("", move || {
371 let _hold_once = &handle;
372 });
373 } else {
374 tracing::warn!("received unknown audio metadata {:?}, ignoring", meta.id);
375 }
376 }
377 Event::AudioDecoded(audio) => {
378 if let Some(handle) = VIEW_PROCESS.on_audio_decoded(&audio) {
379 let audio = ArcEq::new(audio);
380 let args = RawAudioDecodedArgs::now(handle.downgrade(), ArcEq::downgrade(&audio));
381 RAW_AUDIO_DECODED_EVENT.notify(args);
382 UPDATES.once_next_update("", move || {
383 let _hold_once = (&handle, &audio);
384 });
385 } else {
386 tracing::warn!("received unknown audio metadata {:?}, ignoring", audio.id);
387 }
388 }
389 Event::AudioDecodeError { audio: id, error } => {
390 if let Some(handle) = VIEW_PROCESS.on_audio_error(id) {
391 let args = RawAudioDecodeErrorArgs::now(handle.downgrade(), error);
392 RAW_AUDIO_DECODE_ERROR_EVENT.notify(args);
393 UPDATES.once_next_update("", move || {
394 let _hold_once = &handle;
395 });
396 }
397 }
398
399 Event::AudioOutputOpened(id, data) => {
400 let a_id = audio_output_id(id);
401 let output = VIEW_PROCESS.on_audio_output_opened(a_id, data);
402
403 let args = RawAudioOutputOpenArgs::now(a_id, output.downgrade());
404 RAW_AUDIO_OUTPUT_OPEN_EVENT.notify(args);
405 UPDATES.once_next_update("", move || {
406 let _hold_once = &output;
407 });
408 }
409 Event::AudioOutputOpenError { id, error } => {
410 let a_id = audio_output_id(id);
411
412 let args = RawAudioOutputOpenErrorArgs::now(a_id, error);
413 RAW_AUDIO_OUTPUT_OPEN_ERROR_EVENT.notify(args);
414 }
415
416 Event::AccessInit { window: w_id } => {
417 crate::access::on_access_init(window_id(w_id));
418 }
419 Event::AccessCommand {
420 window: win_id,
421 target: wgt_id,
422 command,
423 } => {
424 crate::access::on_access_command(window_id(win_id), WidgetId::from_raw(wgt_id.0), command);
425 }
426 Event::AccessDeinit { window: w_id } => {
427 crate::access::on_access_deinit(window_id(w_id));
428 }
429
430 Event::MsgDialogResponse(id, response) => {
432 VIEW_PROCESS.on_message_dlg_response(id, response);
433 }
434 Event::FileDialogResponse(id, response) => {
435 VIEW_PROCESS.on_file_dlg_response(id, response);
436 }
437 Event::NotificationResponse(id, response) => {
438 VIEW_PROCESS.on_notification_dlg_response(id, response);
439 }
440
441 Event::MenuCommand { id } => {
442 let _ = id;
443 }
444
445 Event::ExtensionEvent(id, payload) => {
447 let args = RawExtensionEventArgs::now(id, payload);
448 RAW_EXTENSION_EVENT.notify(args);
449 }
450
451 Event::FontsChanged => {
453 let args = RawFontChangedArgs::now();
454 RAW_FONT_CHANGED_EVENT.notify(args);
455 }
456 Event::FontAaChanged(aa) => {
457 let args = RawFontAaChangedArgs::now(aa);
458 RAW_FONT_AA_CHANGED_EVENT.notify(args);
459 }
460 Event::MultiClickConfigChanged(cfg) => {
461 let args = RawMultiClickConfigChangedArgs::now(cfg);
462 RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT.notify(args);
463 }
464 Event::AnimationsConfigChanged(cfg) => {
465 VARS_APP.set_sys_animations_enabled(cfg.enabled);
466 let args = RawAnimationsConfigChangedArgs::now(cfg);
467 RAW_ANIMATIONS_CONFIG_CHANGED_EVENT.notify(args);
468 }
469 Event::KeyRepeatConfigChanged(cfg) => {
470 let args = RawKeyRepeatConfigChangedArgs::now(cfg);
471 RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT.notify(args);
472 }
473 Event::TouchConfigChanged(cfg) => {
474 let args = RawTouchConfigChangedArgs::now(cfg);
475 RAW_TOUCH_CONFIG_CHANGED_EVENT.notify(args);
476 }
477 Event::LocaleChanged(cfg) => {
478 let args = RawLocaleChangedArgs::now(cfg);
479 RAW_LOCALE_CONFIG_CHANGED_EVENT.notify(args);
480 }
481 Event::ColorsConfigChanged(cfg) => {
482 let args = RawColorsConfigChangedArgs::now(cfg);
483 RAW_COLORS_CONFIG_CHANGED_EVENT.notify(args);
484 }
485
486 Event::InputDevicesChanged(devices) => {
488 let devices: HashMap<_, _> = devices.into_iter().map(|(d_id, info)| (self.input_device_id(d_id), info)).collect();
489 INPUT_DEVICES.update(devices.clone());
490 let args = InputDevicesChangedArgs::now(devices);
491 INPUT_DEVICES_CHANGED_EVENT.notify(args);
492 }
493 Event::InputDeviceEvent { device, event } => {
494 let d_id = self.input_device_id(device);
495 match event {
496 InputDeviceEvent::PointerMotion { delta } => {
497 let args = PointerMotionArgs::now(d_id, delta);
498 POINTER_MOTION_EVENT.notify(args);
499 }
500 InputDeviceEvent::ScrollMotion { delta } => {
501 let args = ScrollMotionArgs::now(d_id, delta);
502 SCROLL_MOTION_EVENT.notify(args);
503 }
504 InputDeviceEvent::AxisMotion { axis, value } => {
505 let args = AxisMotionArgs::now(d_id, axis, value);
506 AXIS_MOTION_EVENT.notify(args);
507 }
508 InputDeviceEvent::Button { button, state } => {
509 let args = ButtonArgs::now(d_id, button, state);
510 BUTTON_EVENT.notify(args);
511 }
512 InputDeviceEvent::Key { key_code, state } => {
513 let args = KeyArgs::now(d_id, key_code, state);
514 KEY_EVENT.notify(args);
515 }
516 _ => {}
517 }
518 }
519
520 Event::LowMemory => {
521 LOW_MEMORY_EVENT.notify(LowMemoryArgs::now());
522 }
523
524 Event::RecoveredFromComponentPanic { component, recover, panic } => {
525 tracing::error!(
526 "view-process recovered from internal component panic\n component: {component}\n recover: {recover}\n```panic\n{panic}\n```"
527 );
528 }
529
530 Event::Inited(zng_view_api::ViewProcessInfo { .. }) | Event::Suspended | Event::Disconnected(_) | Event::FrameRendered(_) => {
532 unreachable!()
533 } _ => {}
536 }
537 }
538
539 fn on_view_rendered_event(&mut self, ev: zng_view_api::window::EventFrameRendered) {
541 debug_assert!(ev.window != zng_view_api::window::WindowId::INVALID);
542 let window_id = WindowId::from_raw(ev.window.get());
543 let image = ev.frame_image.map(|img| (VIEW_PROCESS.on_frame_image(&img), img)).map(ArcEq::new);
545 let args = crate::view_process::raw_events::RawFrameRenderedArgs::now(window_id, ev.frame, image.as_ref().map(ArcEq::downgrade));
546 RAW_FRAME_RENDERED_EVENT.notify(args);
547 if image.is_some() {
548 UPDATES.once_next_update("", move || {
549 let _hold_once = ℑ
550 });
551 }
552 }
553
554 pub(crate) fn run_headed(mut self) {
555 self.apply_updates();
556 let mut wait = false;
557 loop {
558 wait = match self.poll(wait) {
559 AppControlFlow::Poll => false,
560 AppControlFlow::Wait => true,
561 AppControlFlow::Exit => break,
562 };
563 }
564 }
565
566 fn push_coalesce(&mut self, ev: AppEvent) {
567 match ev {
568 AppEvent::ViewEvent(ev) => match ev {
569 zng_view_api::Event::FrameRendered(ev) => {
570 if ev.window == zng_view_api::window::WindowId::INVALID {
571 tracing::error!("ignored rendered event for invalid window id, {ev:?}");
572 return;
573 }
574
575 let window = WindowId::from_raw(ev.window.get());
576
577 {
579 if VIEW_PROCESS.is_available() {
580 VIEW_PROCESS.on_frame_rendered(window);
581 }
582 }
583
584 #[cfg(debug_assertions)]
585 if self.pending_view_frame_events.iter().any(|e| e.window == ev.window) {
586 tracing::warn!("window `{window:?}` probably sent a frame request without awaiting renderer idle");
587 }
588
589 self.pending_view_frame_events.push(ev);
590 }
591 zng_view_api::Event::Pong(count) => VIEW_PROCESS.on_pong(count),
592 zng_view_api::Event::Inited(inited) => {
593 if inited.is_respawn {
595 VIEW_PROCESS.on_respawned(inited.generation);
596 APP_PROCESS_SV.read().is_suspended.set(false);
597 }
598
599 VIEW_PROCESS.handle_inited(&inited);
600
601 let args = crate::view_process::ViewProcessInitedArgs::now(inited);
602 VIEW_PROCESS_INITED_EVENT.notify(args);
603 }
604 zng_view_api::Event::Suspended => {
605 VIEW_PROCESS.handle_suspended();
606 let args = crate::view_process::ViewProcessSuspendedArgs::now();
607 VIEW_PROCESS_SUSPENDED_EVENT.notify(args);
608 APP_PROCESS_SV.read().is_suspended.set(true);
609 }
610 zng_view_api::Event::Disconnected(vp_gen) => {
611 VIEW_PROCESS.handle_disconnect(vp_gen);
613 }
614 ev => {
615 if let Some(last) = self.pending_view_events.last_mut() {
616 match last.coalesce(ev) {
617 Ok(()) => {}
618 Err(ev) => self.pending_view_events.push(ev),
619 }
620 } else {
621 self.pending_view_events.push(ev);
622 }
623 }
624 },
625 AppEvent::Update(op, target) => {
626 UPDATES.update_op(op, target);
627 }
628 AppEvent::UpdateApp => {
629 UPDATES.update_app();
630 }
631 AppEvent::ResumeUnwind(p) => std::panic::resume_unwind(p),
632 }
633 }
634
635 fn has_pending_updates(&mut self) -> bool {
636 !self.pending_view_events.is_empty() || self.pending.has_updates() || UPDATES.has_pending_updates() || !self.receiver.is_empty()
637 }
638
639 pub(crate) fn poll(&mut self, wait_app_event: bool) -> AppControlFlow {
640 let mut disconnected = false;
641
642 if self.exited {
643 return AppControlFlow::Exit;
644 }
645
646 if wait_app_event {
647 const PING_TIMER: Duration = Duration::from_secs(2);
648
649 let ping_timer = Deadline::timeout(PING_TIMER);
650 let timer = if self.view_is_busy() {
651 None
652 } else {
653 self.loop_timer.deadline().map(|t| t.min(ping_timer))
654 };
655 match self.receiver.recv_deadline_blocking(timer.unwrap_or(ping_timer)) {
656 Ok(ev) => {
657 self.last_wait_event = Instant::now();
658 self.push_coalesce(ev)
659 }
660 Err(e) => match e {
661 ChannelError::Timeout => {
662 if VIEW_PROCESS.is_available()
663 && self.last_wait_event.elapsed() >= PING_TIMER
664 && !VIEW_PROCESS.is_same_process()
665 && VIEW_PROCESS.is_connected()
666 {
667 VIEW_PROCESS.ping();
668 }
669 }
670 ChannelError::Disconnected { .. } => disconnected = true,
671 },
672 }
673 }
674 loop {
675 match self.receiver.try_recv() {
676 Ok(ev) => match ev {
677 Some(ev) => self.push_coalesce(ev),
678 None => break,
679 },
680 Err(e) => match e {
681 ChannelError::Disconnected { .. } => {
682 disconnected = true;
683 break;
684 }
685 _ => unreachable!(),
686 },
687 }
688 }
689 if disconnected {
690 panic!("app events channel disconnected");
691 }
692
693 if self.view_is_busy() {
694 return AppControlFlow::Wait;
695 }
696
697 UPDATES.on_app_awake();
698
699 let updated_timers = self.loop_timer.awake();
701 if updated_timers {
702 UPDATES.update_timers(&mut self.loop_timer);
704 self.apply_updates();
705 }
706
707 let mut events = mem::take(&mut self.pending_view_events);
708 for ev in events.drain(..) {
709 self.on_view_event(ev);
710 self.apply_updates();
711 }
712 debug_assert!(self.pending_view_events.is_empty());
713 self.pending_view_events = events; let mut events = mem::take(&mut self.pending_view_frame_events);
716 for ev in events.drain(..) {
717 self.on_view_rendered_event(ev);
718 }
719 self.pending_view_frame_events = events;
720
721 if self.has_pending_updates() {
722 self.apply_updates();
723 }
724
725 if self.view_is_busy() {
726 return AppControlFlow::Wait;
727 }
728
729 self.finish_frame();
730
731 UPDATES.next_deadline(&mut self.loop_timer);
732
733 if APP_PROCESS_SV.read().exit {
734 UPDATES.on_app_sleep();
735 self.exited = true;
736 AppControlFlow::Exit
737 } else if self.has_pending_updates()
738 || UPDATES.has_pending_layout_or_render()
739 || matches!(self.loop_timer.deadline(), Some(t) if t.has_elapsed())
740 {
741 AppControlFlow::Poll
742 } else {
743 UPDATES.on_app_sleep();
744 AppControlFlow::Wait
745 }
746 }
747
748 fn apply_updates(&mut self) {
750 let _s = tracing::debug_span!("apply_updates").entered();
751
752 let mut run = true;
753 while run {
754 run = self.loop_monitor.update(|| {
755 let mut any = false;
756
757 self.pending |= UPDATES.apply_info();
758 if mem::take(&mut self.pending.info) {
759 any = true;
760 let _s = tracing::debug_span!("info").entered();
761
762 let mut info_widgets = mem::take(&mut self.pending.info_widgets);
763
764 let _t = INSTANT_APP.pause_for_update();
765
766 WINDOWS_APP.update_info(&mut info_widgets);
767 }
768
769 {
770 let _s = tracing::debug_span!("hooks").entered();
771 self.pending |= UPDATES.apply_updates();
772 }
773
774 TimersService::notify();
775 if mem::take(&mut self.pending.update) {
776 any = true;
777 let _s = tracing::debug_span!("update").entered();
778
779 let mut update_widgets = mem::take(&mut self.pending.update_widgets);
780
781 let _t = INSTANT_APP.pause_for_update();
782
783 UPDATES.on_pre_updates();
784
785 WINDOWS_APP.update_widgets(&mut update_widgets);
786
787 UPDATES.on_updates();
788 }
789
790 any
791 });
792 }
793 }
794
795 fn view_is_busy(&mut self) -> bool {
796 VIEW_PROCESS.is_available() && VIEW_PROCESS.pending_frames() > 0
797 }
798
799 fn finish_frame(&mut self) {
801 debug_assert!(!self.view_is_busy());
802
803 self.pending |= UPDATES.apply_layout_render();
804
805 while mem::take(&mut self.pending.layout) {
806 let _s = tracing::debug_span!("apply_layout").entered();
807
808 let mut layout_widgets = mem::take(&mut self.pending.layout_widgets);
809
810 self.loop_monitor.maybe_trace(|| {
811 let _t = INSTANT_APP.pause_for_update();
812
813 WINDOWS_APP.update_layout(&mut layout_widgets);
814 });
815
816 self.apply_updates();
817 self.pending |= UPDATES.apply_layout_render();
818 }
819
820 if mem::take(&mut self.pending.render) {
821 let _s = tracing::debug_span!("apply_render").entered();
822
823 let mut render_widgets = mem::take(&mut self.pending.render_widgets);
824 let mut render_update_widgets = mem::take(&mut self.pending.render_update_widgets);
825
826 let _t = INSTANT_APP.pause_for_update();
827
828 WINDOWS_APP.update_render(&mut render_widgets, &mut render_update_widgets);
829 }
830
831 self.loop_monitor.finish_frame();
832 }
833}
834
835#[derive(Clone, Debug)]
841#[non_exhaustive]
842pub struct AppInitArgs {
843 pub is_minimal: bool,
845}
846
847#[derive(Clone, Debug)]
853#[non_exhaustive]
854pub struct AppDeinitArgs {}
855
856impl APP {
857 pub fn on_init(&self, handler: crate::handler::Handler<AppInitArgs>) {
868 zng_unique_id::hot_static_ref!(ON_INIT).lock().push(handler);
869 }
870
871 pub fn on_deinit(&self, handler: impl FnOnce(&AppDeinitArgs) + Send + 'static) {
878 ON_DEINIT.write().get_mut().push(Box::new(handler));
879 }
880
881 fn call_init_handlers(&self, is_minimal: bool) {
882 #[cfg(feature = "multi_app")]
883 let _lock = zng_unique_id::hot_static_ref!(ON_INIT_CALL).lock();
884
885 let mut handlers = mem::take(&mut *zng_unique_id::hot_static_ref!(ON_INIT).lock());
886 let args = AppInitArgs { is_minimal };
887 handlers.retain_mut(|h| {
888 let (owner, handle) = zng_handle::Handle::new(());
889 h.app_event(Box::new(handle.downgrade()), true, &args);
890 !owner.is_dropped()
891 });
892
893 let mut s = zng_unique_id::hot_static_ref!(ON_INIT).lock();
894 handlers.extend(s.drain(..));
895 *s = handlers;
896 }
897
898 fn call_deinit_handlers(&self) {
899 let handlers = mem::take(&mut *ON_DEINIT.write().get_mut());
900 let args = AppDeinitArgs {};
901 for h in handlers {
902 h(&args);
903 }
904 }
905}
906zng_unique_id::hot_static! {
907 static ON_INIT: Mutex<Vec<crate::handler::Handler<AppInitArgs>>> = Mutex::new(vec![]);
908}
909#[cfg(feature = "multi_app")]
910zng_unique_id::hot_static! {
911 static ON_INIT_CALL: Mutex<()> = Mutex::new(());
912}
913app_local! {
914 static ON_DEINIT: Mutex<Vec<Box<dyn FnOnce(&AppDeinitArgs) + Send + 'static>>> = const { Mutex::new(vec![]) };
916}
917
918#[derive(Debug)]
920pub(crate) struct LoopTimer {
921 now: DInstant,
922 deadline: Option<Deadline>,
923}
924impl Default for LoopTimer {
925 fn default() -> Self {
926 Self {
927 now: INSTANT.now(),
928 deadline: None,
929 }
930 }
931}
932impl LoopTimer {
933 pub fn elapsed(&mut self, deadline: Deadline) -> bool {
936 if deadline.0 <= self.now {
937 true
938 } else {
939 self.register(deadline);
940 false
941 }
942 }
943
944 pub fn register(&mut self, deadline: Deadline) {
946 if let Some(d) = &mut self.deadline {
947 if deadline < *d {
948 *d = deadline;
949 }
950 } else {
951 self.deadline = Some(deadline)
952 }
953 }
954
955 pub(crate) fn deadline(&self) -> Option<Deadline> {
957 self.deadline
958 }
959
960 pub(crate) fn awake(&mut self) -> bool {
962 self.now = INSTANT.now();
963 if let Some(d) = self.deadline
964 && d.0 <= self.now
965 {
966 self.deadline = None;
967 return true;
968 }
969 false
970 }
971
972 pub fn now(&self) -> DInstant {
974 self.now
975 }
976}
977impl zng_var::animation::AnimationTimer for LoopTimer {
978 fn elapsed(&mut self, deadline: Deadline) -> bool {
979 self.elapsed(deadline)
980 }
981
982 fn register(&mut self, deadline: Deadline) {
983 self.register(deadline)
984 }
985
986 fn now(&self) -> DInstant {
987 self.now()
988 }
989}
990
991#[derive(Default)]
992struct LoopMonitor {
993 update_count: u16,
994 skipped: bool,
995 trace: Vec<UpdateTrace>,
996}
997impl LoopMonitor {
998 pub fn update(&mut self, update_once: impl FnOnce() -> bool) -> bool {
1000 self.update_count += 1;
1001
1002 if self.update_count < 500 {
1003 update_once()
1004 } else if self.update_count < 1000 {
1005 UpdatesTrace::collect_trace(&mut self.trace, update_once)
1006 } else if self.update_count == 1000 {
1007 self.skipped = true;
1008 let trace = UpdatesTrace::format_trace(mem::take(&mut self.trace));
1009 tracing::error!(
1010 "updated 1000 times without rendering, probably stuck in an infinite loop\n\
1011 will start skipping updates to render and poll system events\n\
1012 top 20 most frequent update requests (in 500 cycles):\n\
1013 {trace}\n\
1014 you can use `UpdatesTraceUiNodeExt` and `updates_trace_event` to refine the trace"
1015 );
1016 false
1017 } else if self.update_count == 1500 {
1018 self.update_count = 1001;
1019 false
1020 } else {
1021 update_once()
1022 }
1023 }
1024
1025 pub fn maybe_trace(&mut self, notify_once: impl FnOnce()) {
1026 if (500..1000).contains(&self.update_count) {
1027 UpdatesTrace::collect_trace(&mut self.trace, notify_once);
1028 } else {
1029 notify_once();
1030 }
1031 }
1032
1033 pub fn finish_frame(&mut self) {
1034 if !self.skipped {
1035 self.skipped = false;
1036 self.update_count = 0;
1037 self.trace = vec![];
1038 }
1039 }
1040}
1041
1042impl APP {
1043 pub(super) fn pre_init(&self, is_headed: bool, with_renderer: bool, view_process_exe: PathBuf, view_process_env: HashMap<Txt, Txt>) {
1045 let s = APP_PROCESS_SV.read();
1047 s.pause_time_for_updates
1048 .hook(|a| {
1049 if !matches!(INSTANT.mode(), zng_time::InstantMode::Manual) {
1050 if *a.value() {
1051 INSTANT_APP.set_mode(InstantMode::UpdatePaused);
1052 } else {
1053 INSTANT_APP.set_mode(InstantMode::Now);
1054 }
1055 }
1056 true
1057 })
1058 .perm();
1059
1060 VIEW_PROCESS_INITED_EVENT
1062 .hook(|_| {
1063 let filter = APP_PROCESS_SV.read().device_events_filter.get();
1064 if !filter.is_empty()
1065 && let Err(e) = VIEW_PROCESS.set_device_events_filter(filter)
1066 {
1067 tracing::error!("cannot set device events on the view-process, {e}");
1068 }
1069 true
1070 })
1071 .perm();
1072
1073 EXIT_CMD
1075 .on_event(
1076 true,
1077 true,
1078 false,
1079 crate::hn!(|a| {
1080 a.propagation.stop();
1081 APP.exit();
1082 }),
1083 )
1084 .perm();
1085
1086 s.device_events_filter
1088 .hook(|a| {
1089 if let Err(e) = VIEW_PROCESS.set_device_events_filter(a.value().clone()) {
1090 tracing::error!("cannot set device events on the view-process, {e}");
1091 }
1092 true
1093 })
1094 .perm();
1095
1096 if is_headed {
1098 debug_assert!(with_renderer);
1099
1100 let view_evs_sender = UPDATES.sender();
1101 VIEW_PROCESS.start(view_process_exe, view_process_env, false, move |ev| {
1102 let _ = view_evs_sender.send_view_event(ev);
1103 });
1104 } else if with_renderer {
1105 let view_evs_sender = UPDATES.sender();
1106 VIEW_PROCESS.start(view_process_exe, view_process_env, true, move |ev| {
1107 let _ = view_evs_sender.send_view_event(ev);
1108 });
1109 }
1110 }
1111}
1112
1113impl APP {
1114 pub fn exit(&self) -> ResponseVar<ExitCancelled> {
1123 let mut s = APP_PROCESS_SV.write();
1124 if let Some(r) = &s.exit_requests {
1125 r.response_var()
1126 } else {
1127 let (responder, response) = response_var();
1128 s.exit_requests = Some(responder);
1129 EXIT_REQUESTED_EVENT.notify(ExitRequestedArgs::now());
1130 EXIT_REQUESTED_EVENT
1131 .on_event(
1132 true,
1133 crate::hn_once!(|args: &ExitRequestedArgs| {
1134 let mut s = APP_PROCESS_SV.write();
1135 if !args.propagation.is_stopped() {
1136 s.exit = true;
1137 } else {
1138 s.exit_requests.take().unwrap().respond(ExitCancelled);
1139 }
1140 }),
1141 )
1142 .perm();
1143 response
1144 }
1145 }
1146
1147 pub fn is_suspended(&self) -> Var<bool> {
1155 expr_var! {
1156 let inited = #{VIEW_PROCESS_INITED_EVENT.var_latest()};
1157 let sus = #{VIEW_PROCESS_SUSPENDED_EVENT.var_latest()};
1158
1159 match (sus, inited) {
1160 (_, None) => true, (None, Some(_)) => false, (Some(s), Some(i)) => s.timestamp > i.timestamp, }
1164 }
1165 }
1166}
1167
1168impl APP {
1173 pub fn pause_time_for_update(&self) -> Var<bool> {
1179 APP_PROCESS_SV.read().pause_time_for_updates.clone()
1180 }
1181
1182 pub fn start_manual_time(&self) {
1190 INSTANT_APP.set_mode(InstantMode::Manual);
1191 INSTANT_APP.set_now(INSTANT.now());
1192 UPDATES.update_app();
1193 }
1194
1195 pub fn advance_manual_time(&self, advance: Duration) {
1206 INSTANT_APP.advance_now(advance);
1207 UPDATES.update_app();
1208 }
1209
1210 pub fn set_manual_time(&self, now: DInstant) {
1219 INSTANT_APP.set_now(now);
1220 UPDATES.update_app();
1221 }
1222
1223 pub fn end_manual_time(&self) {
1225 INSTANT_APP.set_mode(match APP.pause_time_for_update().get() {
1226 true => InstantMode::UpdatePaused,
1227 false => InstantMode::Now,
1228 });
1229 UPDATES.update_app();
1230 }
1231}
1232
1233command! {
1234 pub static EXIT_CMD {
1238 l10n!: true,
1239 name: "Exit",
1240 info: "Close all windows and exit",
1241 shortcut: shortcut!(Exit),
1242 };
1243}
1244
1245#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1249pub struct ExitCancelled;
1250impl fmt::Display for ExitCancelled {
1251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1252 write!(f, "exit request cancelled")
1253 }
1254}
1255
1256pub(crate) fn assert_not_view_process() {
1257 if zng_view_api::ViewConfig::from_env().is_some() {
1258 panic!("cannot start App in view-process");
1259 }
1260}
1261#[cfg(feature = "deadlock_detection")]
1266pub fn spawn_deadlock_detection() {
1267 use parking_lot::deadlock;
1268 use std::{
1269 sync::atomic::{self, AtomicBool},
1270 thread,
1271 time::*,
1272 };
1273
1274 static CHECK_RUNNING: AtomicBool = AtomicBool::new(false);
1275
1276 if CHECK_RUNNING.swap(true, atomic::Ordering::SeqCst) {
1277 return;
1278 }
1279
1280 thread::Builder::new()
1281 .name("deadlock_detection".into())
1282 .stack_size(256 * 1024)
1283 .spawn(|| {
1284 loop {
1285 thread::sleep(Duration::from_secs(10));
1286
1287 let deadlocks = deadlock::check_deadlock();
1288 if deadlocks.is_empty() {
1289 continue;
1290 }
1291
1292 use std::fmt::Write;
1293 let mut msg = String::new();
1294
1295 let _ = writeln!(&mut msg, "{} deadlocks detected", deadlocks.len());
1296 for (i, threads) in deadlocks.iter().enumerate() {
1297 let _ = writeln!(&mut msg, "Deadlock #{}, {} threads", i, threads.len());
1298 for t in threads {
1299 let _ = writeln!(&mut msg, "Thread Id {:#?}", t.thread_id());
1300 let _ = writeln!(&mut msg, "{:#?}", t.backtrace());
1301 }
1302 }
1303
1304 #[cfg(not(feature = "test_util"))]
1305 eprint!("{msg}");
1306
1307 #[cfg(feature = "test_util")]
1308 {
1309 use std::io::Write;
1312 let _ = write!(&mut std::io::stderr(), "{msg}");
1313 zng_env::exit(-1);
1314 }
1315 }
1316 })
1317 .expect("failed to spawn thread");
1318}
1319#[cfg(not(feature = "deadlock_detection"))]
1324pub fn spawn_deadlock_detection() {}
1325
1326app_local! {
1327 pub(super) static APP_PROCESS_SV: AppProcessService = AppProcessService {
1328 exit_requests: None,
1329 exit: false,
1330 device_events_filter: zng_var::var(Default::default()),
1331 pause_time_for_updates: zng_var::var(true),
1332 is_suspended: zng_var::var(false),
1333 };
1334}
1335
1336pub(super) struct AppProcessService {
1337 exit_requests: Option<ResponderVar<ExitCancelled>>,
1338 pub(crate) exit: bool,
1339 pub(crate) device_events_filter: Var<DeviceEventsFilter>,
1340 pause_time_for_updates: Var<bool>,
1341 is_suspended: Var<bool>,
1342}
1343
1344#[derive(Debug)]
1346#[allow(clippy::large_enum_variant)] pub(crate) enum AppEvent {
1348 ViewEvent(zng_view_api::Event),
1350 Update(UpdateOp, WidgetId),
1352 ResumeUnwind(PanicPayload),
1354 UpdateApp,
1356}
1357
1358#[derive(Clone)]
1364pub struct AppEventSender(channel::Sender<AppEvent>);
1365impl AppEventSender {
1366 pub(crate) fn new() -> (Self, channel::Receiver<AppEvent>) {
1367 let (sender, receiver) = channel::unbounded();
1368 (Self(sender), receiver)
1369 }
1370
1371 #[allow(clippy::result_large_err)] fn send_app_event(&self, event: AppEvent) -> Result<(), ChannelError> {
1373 self.0.send_blocking(event)
1374 }
1375
1376 #[allow(clippy::result_large_err)]
1377 fn send_view_event(&self, event: zng_view_api::Event) -> Result<(), ChannelError> {
1378 self.0.send_blocking(AppEvent::ViewEvent(event))
1379 }
1380
1381 pub fn send_update(&self, op: UpdateOp, target: WidgetId) -> Result<(), ChannelError> {
1383 UpdatesTrace::log_update();
1384 self.send_app_event(AppEvent::Update(op, target))
1385 }
1386
1387 pub fn send_update_app(&self) -> Result<(), ChannelError> {
1389 UpdatesTrace::log_update();
1390 self.send_app_event(AppEvent::UpdateApp)
1391 }
1392
1393 pub fn send_resume_unwind(&self, payload: PanicPayload) -> Result<(), ChannelError> {
1395 self.send_app_event(AppEvent::ResumeUnwind(payload))
1396 }
1397
1398 pub fn waker(&self, also_update: Option<WidgetId>) -> Waker {
1400 Arc::new(AppWaker(self.0.clone(), also_update)).into()
1401 }
1402}
1403
1404struct AppWaker(channel::Sender<AppEvent>, Option<WidgetId>);
1405impl std::task::Wake for AppWaker {
1406 fn wake(self: std::sync::Arc<Self>) {
1407 self.wake_by_ref()
1408 }
1409 fn wake_by_ref(self: &Arc<Self>) {
1410 match self.1 {
1411 Some(id) => {
1412 let _ = self.0.send_blocking(AppEvent::Update(UpdateOp::Update, id));
1413 }
1414 None => {
1415 let _ = self.0.send_blocking(AppEvent::UpdateApp);
1416 }
1417 }
1418 }
1419}
1420
1421type PanicPayload = Box<dyn std::any::Any + Send + 'static>;
1422
1423event_args! {
1424 pub struct ExitRequestedArgs {
1428
1429 ..
1430
1431 fn is_in_target(&self, _id: WidgetId) -> bool {
1433 true
1434 }
1435 }
1436}
1437
1438event! {
1439 pub static EXIT_REQUESTED_EVENT: ExitRequestedArgs;
1447}