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 mut 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 args.scale_factor = c.scale_factor;
177 args.refresh_rate = c.refresh_rate;
178 RAW_WINDOW_CHANGED_EVENT.notify(args);
179 }
180 Event::DragHovered { window, data, allowed } => {
181 let args = RawDragHoveredArgs::now(window_id(window), data, allowed);
182 RAW_DRAG_HOVERED_EVENT.notify(args);
183 }
184 Event::DragMoved {
185 window,
186 coalesced_pos,
187 position,
188 } => {
189 let args = RawDragMovedArgs::now(window_id(window), coalesced_pos, position);
190 RAW_DRAG_MOVED_EVENT.notify(args);
191 }
192 Event::DragDropped {
193 window,
194 data,
195 allowed,
196 drop_id,
197 } => {
198 let args = RawDragDroppedArgs::now(window_id(window), data, allowed, drop_id);
199 RAW_DRAG_DROPPED_EVENT.notify(args);
200 }
201 Event::DragCancelled { window } => {
202 let args = RawDragCancelledArgs::now(window_id(window));
203 RAW_DRAG_CANCELLED_EVENT.notify(args);
204 }
205 Event::AppDragEnded { window, drag, applied } => {
206 let args = RawAppDragEndedArgs::now(window_id(window), drag, applied);
207 RAW_APP_DRAG_ENDED_EVENT.notify(args);
208 }
209 Event::FocusChanged { prev, new } => {
210 let args = RawWindowFocusArgs::now(prev.map(window_id), new.map(window_id));
211 RAW_WINDOW_FOCUS_EVENT.notify(args);
212 }
213 Event::KeyboardInput {
214 window: w_id,
215 device: d_id,
216 key_code,
217 state,
218 key,
219 key_location,
220 key_modified,
221 text,
222 } => {
223 let args = RawKeyInputArgs::now(
224 window_id(w_id),
225 self.input_device_id(d_id),
226 key_code,
227 key_location,
228 state,
229 key,
230 key_modified,
231 text,
232 );
233 RAW_KEY_INPUT_EVENT.notify(args);
234 }
235 Event::Ime { window: w_id, ime } => {
236 let args = RawImeArgs::now(window_id(w_id), ime);
237 RAW_IME_EVENT.notify(args);
238 }
239
240 Event::MouseWheel {
241 window: w_id,
242 device: d_id,
243 delta,
244 phase,
245 } => {
246 let args = RawMouseWheelArgs::now(window_id(w_id), self.input_device_id(d_id), delta, phase);
247 RAW_MOUSE_WHEEL_EVENT.notify(args);
248 }
249 Event::MouseInput {
250 window: w_id,
251 device: d_id,
252 state,
253 button,
254 } => {
255 let args = RawMouseInputArgs::now(window_id(w_id), self.input_device_id(d_id), state, button);
256 RAW_MOUSE_INPUT_EVENT.notify(args);
257 }
258 Event::TouchpadPressure {
259 window: w_id,
260 device: d_id,
261 pressure,
262 stage,
263 } => {
264 let args = RawTouchpadPressureArgs::now(window_id(w_id), self.input_device_id(d_id), pressure, stage);
265 RAW_TOUCHPAD_PRESSURE_EVENT.notify(args);
266 }
267 Event::AxisMotion {
268 window: w_id,
269 device: d_id,
270 axis,
271 value,
272 } => {
273 let args = RawAxisMotionArgs::now(window_id(w_id), self.input_device_id(d_id), axis, value);
274 RAW_AXIS_MOTION_EVENT.notify(args);
275 }
276 Event::Touch {
277 window: w_id,
278 device: d_id,
279 touches,
280 } => {
281 let args = RawTouchArgs::now(window_id(w_id), self.input_device_id(d_id), touches);
282 RAW_TOUCH_EVENT.notify(args);
283 }
284 #[allow(deprecated)]
285 Event::ScaleFactorChanged {
286 monitor: id,
287 windows,
288 scale_factor,
289 } => {
290 let monitor_id = VIEW_PROCESS.monitor_id(id);
291 let windows: Vec<_> = windows.into_iter().map(window_id).collect();
292 let args = RawScaleFactorChangedArgs::now(monitor_id, windows, scale_factor);
293 RAW_SCALE_FACTOR_CHANGED_EVENT.notify(args);
294 }
295 Event::MonitorsChanged(monitors) => {
296 let monitors: Vec<_> = monitors.into_iter().map(|(id, info)| (VIEW_PROCESS.monitor_id(id), info)).collect();
297 let args = RawMonitorsChangedArgs::now(monitors);
298 RAW_MONITORS_CHANGED_EVENT.notify(args);
299 }
300 Event::AudioDevicesChanged(_audio_devices) => {}
301 Event::WindowCloseRequested(w_id) => {
302 let args = RawWindowCloseRequestedArgs::now(window_id(w_id));
303 RAW_WINDOW_CLOSE_REQUESTED_EVENT.notify(args);
304 }
305 Event::WindowOpened(w_id, data) => {
306 let w_id = window_id(w_id);
307 let (window, data) = VIEW_PROCESS.on_window_opened(w_id, data);
308 let args = RawWindowOpenArgs::now(w_id, window.downgrade(), data);
309 RAW_WINDOW_OPEN_EVENT.notify(args);
310 UPDATES.once_next_update("", move || {
311 let _hold_once = &window;
312 });
313 }
314 Event::HeadlessOpened(w_id, data) => {
315 let w_id = window_id(w_id);
316 let (surface, data) = VIEW_PROCESS.on_headless_opened(w_id, data);
317 let args = RawHeadlessOpenArgs::now(w_id, surface.downgrade(), data);
318 RAW_HEADLESS_OPEN_EVENT.notify(args);
319 UPDATES.once_next_update("", move || {
320 let _hold_once = &surface;
321 });
322 }
323 Event::WindowOrHeadlessOpenError { id: w_id, error } => {
324 let w_id = window_id(w_id);
325 let args = RawWindowOrHeadlessOpenErrorArgs::now(w_id, error);
326 RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT.notify(args);
327 }
328 Event::WindowClosed(w_id) => {
329 let args = RawWindowCloseArgs::now(window_id(w_id));
330 RAW_WINDOW_CLOSE_EVENT.notify(args);
331 }
332 Event::ImageMetadataDecoded(meta) => {
333 if let Some(handle) = VIEW_PROCESS.on_image_metadata(&meta) {
334 let args = RawImageMetadataDecodedArgs::now(handle.downgrade(), meta);
335 RAW_IMAGE_METADATA_DECODED_EVENT.notify(args);
336 UPDATES.once_next_update("", move || {
337 let _hold_once = &handle;
338 });
339 } else {
340 tracing::warn!("received unknown image metadata {:?} ({:?}), ignoring", meta.id, meta.size);
341 }
342 }
343 Event::ImageDecoded(img) => {
344 if let Some(handle) = VIEW_PROCESS.on_image_decoded(&img) {
345 let img = ArcEq::new(img);
346 let args = RawImageDecodedArgs::now(handle.downgrade(), ArcEq::downgrade(&img));
347 RAW_IMAGE_DECODED_EVENT.notify(args);
348 UPDATES.once_next_update("", move || {
349 let _hold_once = (&handle, &img);
350 });
351 } else {
352 tracing::warn!("received unknown image data {:?} ({:?}), ignoring", img.meta.id, img.meta.size);
353 }
354 }
355 Event::ImageDecodeError { image: id, error } => {
356 if let Some(handle) = VIEW_PROCESS.on_image_error(id) {
357 let args = RawImageDecodeErrorArgs::now(handle.downgrade(), error);
358 RAW_IMAGE_DECODE_ERROR_EVENT.notify(args);
359 UPDATES.once_next_update("", move || {
360 let _hold_once = &handle;
361 });
362 }
363 }
364 Event::ImageEncoded { task, data } => VIEW_PROCESS.on_image_encoded(task, data),
365 Event::ImageEncodeError { task, error } => {
366 VIEW_PROCESS.on_image_encode_error(task, error);
367 }
368
369 Event::AudioMetadataDecoded(meta) => {
370 if let Some(handle) = VIEW_PROCESS.on_audio_metadata(&meta) {
371 let args = RawAudioMetadataDecodedArgs::now(handle.downgrade(), meta);
372 RAW_AUDIO_METADATA_DECODED_EVENT.notify(args);
373 UPDATES.once_next_update("", move || {
374 let _hold_once = &handle;
375 });
376 } else {
377 tracing::warn!("received unknown audio metadata {:?}, ignoring", meta.id);
378 }
379 }
380 Event::AudioDecoded(audio) => {
381 if let Some(handle) = VIEW_PROCESS.on_audio_decoded(&audio) {
382 let audio = ArcEq::new(audio);
383 let args = RawAudioDecodedArgs::now(handle.downgrade(), ArcEq::downgrade(&audio));
384 RAW_AUDIO_DECODED_EVENT.notify(args);
385 UPDATES.once_next_update("", move || {
386 let _hold_once = (&handle, &audio);
387 });
388 } else {
389 tracing::warn!("received unknown audio metadata {:?}, ignoring", audio.id);
390 }
391 }
392 Event::AudioDecodeError { audio: id, error } => {
393 if let Some(handle) = VIEW_PROCESS.on_audio_error(id) {
394 let args = RawAudioDecodeErrorArgs::now(handle.downgrade(), error);
395 RAW_AUDIO_DECODE_ERROR_EVENT.notify(args);
396 UPDATES.once_next_update("", move || {
397 let _hold_once = &handle;
398 });
399 }
400 }
401
402 Event::AudioOutputOpened(id, data) => {
403 let a_id = audio_output_id(id);
404 let output = VIEW_PROCESS.on_audio_output_opened(a_id, data);
405
406 let args = RawAudioOutputOpenArgs::now(a_id, output.downgrade());
407 RAW_AUDIO_OUTPUT_OPEN_EVENT.notify(args);
408 UPDATES.once_next_update("", move || {
409 let _hold_once = &output;
410 });
411 }
412 Event::AudioOutputOpenError { id, error } => {
413 let a_id = audio_output_id(id);
414
415 let args = RawAudioOutputOpenErrorArgs::now(a_id, error);
416 RAW_AUDIO_OUTPUT_OPEN_ERROR_EVENT.notify(args);
417 }
418
419 Event::AccessInit { window: w_id } => {
420 crate::access::on_access_init(window_id(w_id));
421 }
422 Event::AccessCommand {
423 window: win_id,
424 target: wgt_id,
425 command,
426 } => {
427 crate::access::on_access_command(window_id(win_id), WidgetId::from_raw(wgt_id.0), command);
428 }
429 Event::AccessDeinit { window: w_id } => {
430 crate::access::on_access_deinit(window_id(w_id));
431 }
432
433 Event::MsgDialogResponse(id, response) => {
435 VIEW_PROCESS.on_message_dlg_response(id, response);
436 }
437 Event::FileDialogResponse(id, response) => {
438 VIEW_PROCESS.on_file_dlg_response(id, response);
439 }
440 Event::NotificationResponse(id, response) => {
441 VIEW_PROCESS.on_notification_dlg_response(id, response);
442 }
443
444 Event::MenuCommand { id } => {
445 let _ = id;
446 }
447
448 Event::ExtensionEvent(id, payload) => {
450 let args = RawExtensionEventArgs::now(id, payload);
451 RAW_EXTENSION_EVENT.notify(args);
452 }
453
454 Event::FontsChanged => {
456 let args = RawFontChangedArgs::now();
457 RAW_FONT_CHANGED_EVENT.notify(args);
458 }
459 Event::FontAaChanged(aa) => {
460 let args = RawFontAaChangedArgs::now(aa);
461 RAW_FONT_AA_CHANGED_EVENT.notify(args);
462 }
463 Event::MultiClickConfigChanged(cfg) => {
464 let args = RawMultiClickConfigChangedArgs::now(cfg);
465 RAW_MULTI_CLICK_CONFIG_CHANGED_EVENT.notify(args);
466 }
467 Event::AnimationsConfigChanged(cfg) => {
468 VARS_APP.set_sys_animations_enabled(cfg.enabled);
469 let args = RawAnimationsConfigChangedArgs::now(cfg);
470 RAW_ANIMATIONS_CONFIG_CHANGED_EVENT.notify(args);
471 }
472 Event::KeyRepeatConfigChanged(cfg) => {
473 let args = RawKeyRepeatConfigChangedArgs::now(cfg);
474 RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT.notify(args);
475 }
476 Event::TouchConfigChanged(cfg) => {
477 let args = RawTouchConfigChangedArgs::now(cfg);
478 RAW_TOUCH_CONFIG_CHANGED_EVENT.notify(args);
479 }
480 Event::LocaleChanged(cfg) => {
481 let args = RawLocaleChangedArgs::now(cfg);
482 RAW_LOCALE_CONFIG_CHANGED_EVENT.notify(args);
483 }
484 Event::ColorsConfigChanged(cfg) => {
485 let args = RawColorsConfigChangedArgs::now(cfg);
486 RAW_COLORS_CONFIG_CHANGED_EVENT.notify(args);
487 }
488
489 Event::InputDevicesChanged(devices) => {
491 let devices: HashMap<_, _> = devices.into_iter().map(|(d_id, info)| (self.input_device_id(d_id), info)).collect();
492 INPUT_DEVICES.update(devices.clone());
493 let args = InputDevicesChangedArgs::now(devices);
494 INPUT_DEVICES_CHANGED_EVENT.notify(args);
495 }
496 Event::InputDeviceEvent { device, event } => {
497 let d_id = self.input_device_id(device);
498 match event {
499 InputDeviceEvent::PointerMotion { delta } => {
500 let args = PointerMotionArgs::now(d_id, delta);
501 POINTER_MOTION_EVENT.notify(args);
502 }
503 InputDeviceEvent::ScrollMotion { delta } => {
504 let args = ScrollMotionArgs::now(d_id, delta);
505 SCROLL_MOTION_EVENT.notify(args);
506 }
507 InputDeviceEvent::AxisMotion { axis, value } => {
508 let args = AxisMotionArgs::now(d_id, axis, value);
509 AXIS_MOTION_EVENT.notify(args);
510 }
511 InputDeviceEvent::Button { button, state } => {
512 let args = ButtonArgs::now(d_id, button, state);
513 BUTTON_EVENT.notify(args);
514 }
515 InputDeviceEvent::Key { key_code, state } => {
516 let args = KeyArgs::now(d_id, key_code, state);
517 KEY_EVENT.notify(args);
518 }
519 _ => {}
520 }
521 }
522
523 Event::LowMemory => {
524 LOW_MEMORY_EVENT.notify(LowMemoryArgs::now());
525 }
526
527 Event::RecoveredFromComponentPanic { component, recover, panic } => {
528 tracing::error!(
529 "view-process recovered from internal component panic\n component: {component}\n recover: {recover}\n```panic\n{panic}\n```"
530 );
531 }
532
533 Event::Inited(zng_view_api::ViewProcessInfo { .. }) | Event::Suspended | Event::Disconnected(_) | Event::FrameRendered(_) => {
535 unreachable!()
536 } _ => {}
539 }
540 }
541
542 fn on_view_rendered_event(&mut self, ev: zng_view_api::window::EventFrameRendered) {
544 debug_assert!(ev.window != zng_view_api::window::WindowId::INVALID);
545 let window_id = WindowId::from_raw(ev.window.get());
546 let image = ev.frame_image.map(|img| (VIEW_PROCESS.on_frame_image(&img), img)).map(ArcEq::new);
548 let args = crate::view_process::raw_events::RawFrameRenderedArgs::now(window_id, ev.frame, image.as_ref().map(ArcEq::downgrade));
549 RAW_FRAME_RENDERED_EVENT.notify(args);
550 if image.is_some() {
551 UPDATES.once_next_update("", move || {
552 let _hold_once = ℑ
553 });
554 }
555 }
556
557 pub(crate) fn run_headed(mut self) {
558 self.apply_updates();
559 let mut wait = false;
560 loop {
561 wait = match self.poll(wait) {
562 AppControlFlow::Poll => false,
563 AppControlFlow::Wait => true,
564 AppControlFlow::Exit => break,
565 };
566 }
567 }
568
569 fn push_coalesce(&mut self, ev: AppEvent) {
570 match ev {
571 AppEvent::ViewEvent(ev) => match ev {
572 zng_view_api::Event::FrameRendered(ev) => {
573 if ev.window == zng_view_api::window::WindowId::INVALID {
574 tracing::error!("ignored rendered event for invalid window id, {ev:?}");
575 return;
576 }
577
578 let window = WindowId::from_raw(ev.window.get());
579
580 {
582 if VIEW_PROCESS.is_available() {
583 VIEW_PROCESS.on_frame_rendered(window);
584 }
585 }
586
587 self.pending_view_frame_events.push(ev);
588 }
589 zng_view_api::Event::Pong(count) => VIEW_PROCESS.on_pong(count),
590 zng_view_api::Event::Inited(inited) => {
591 if inited.is_respawn {
593 VIEW_PROCESS.on_respawned(inited.generation);
594 APP_PROCESS_SV.read().is_suspended.set(false);
595 }
596
597 VIEW_PROCESS.handle_inited(&inited);
598
599 let args = crate::view_process::ViewProcessInitedArgs::now(inited);
600 VIEW_PROCESS_INITED_EVENT.notify(args);
601 }
602 zng_view_api::Event::Suspended => {
603 VIEW_PROCESS.handle_suspended();
604 let args = crate::view_process::ViewProcessSuspendedArgs::now();
605 VIEW_PROCESS_SUSPENDED_EVENT.notify(args);
606 APP_PROCESS_SV.read().is_suspended.set(true);
607 }
608 zng_view_api::Event::Disconnected(vp_gen) => {
609 VIEW_PROCESS.handle_disconnect(vp_gen);
611 }
612 ev => {
613 if let Some(last) = self.pending_view_events.last_mut() {
614 match last.coalesce(ev) {
615 Ok(()) => {}
616 Err(ev) => self.pending_view_events.push(ev),
617 }
618 } else {
619 self.pending_view_events.push(ev);
620 }
621 }
622 },
623 AppEvent::Update(op, target) => {
624 UPDATES.update_op(op, target);
625 }
626 AppEvent::UpdateApp => {
627 UPDATES.update_app();
628 }
629 AppEvent::ResumeUnwind(p) => std::panic::resume_unwind(p),
630 }
631 }
632
633 fn has_pending_updates(&mut self) -> bool {
634 !self.pending_view_events.is_empty() || self.pending.has_updates() || UPDATES.has_pending_updates() || !self.receiver.is_empty()
635 }
636
637 pub(crate) fn poll(&mut self, wait_app_event: bool) -> AppControlFlow {
638 let mut disconnected = false;
639
640 if self.exited {
641 return AppControlFlow::Exit;
642 }
643
644 if wait_app_event {
645 const PING_TIMER: Duration = Duration::from_secs(2);
646
647 let ping_timer = Deadline::timeout(PING_TIMER);
648 let timer = if self.view_process_is_busy() {
649 None
650 } else {
651 self.loop_timer.deadline().map(|t| t.min(ping_timer))
652 };
653 match self.receiver.recv_deadline_blocking(timer.unwrap_or(ping_timer)) {
654 Ok(ev) => {
655 self.last_wait_event = Instant::now();
656 self.push_coalesce(ev)
657 }
658 Err(e) => match e {
659 ChannelError::Timeout => {
660 if VIEW_PROCESS.is_available()
661 && self.last_wait_event.elapsed() >= PING_TIMER
662 && !VIEW_PROCESS.is_same_process()
663 && VIEW_PROCESS.is_connected()
664 {
665 VIEW_PROCESS.ping();
666 }
667 }
668 ChannelError::Disconnected { .. } => disconnected = true,
669 },
670 }
671 }
672 loop {
673 match self.receiver.try_recv() {
674 Ok(ev) => match ev {
675 Some(ev) => self.push_coalesce(ev),
676 None => break,
677 },
678 Err(e) => match e {
679 ChannelError::Disconnected { .. } => {
680 disconnected = true;
681 break;
682 }
683 _ => unreachable!(),
684 },
685 }
686 }
687 if disconnected {
688 panic!("app events channel disconnected");
689 }
690
691 if self.view_process_is_busy() {
692 return AppControlFlow::Wait;
693 }
694
695 UPDATES.on_app_awake();
696
697 let updated_timers = self.loop_timer.awake();
699 if updated_timers {
700 UPDATES.update_timers(&mut self.loop_timer);
702 self.apply_updates();
703 }
704
705 let mut events = mem::take(&mut self.pending_view_events);
706 for ev in events.drain(..) {
707 self.on_view_event(ev);
708 self.apply_updates();
709 }
710 debug_assert!(self.pending_view_events.is_empty());
711 self.pending_view_events = events; let mut events = mem::take(&mut self.pending_view_frame_events);
714 for ev in events.drain(..) {
715 self.on_view_rendered_event(ev);
716 }
717 self.pending_view_frame_events = events;
718
719 if self.has_pending_updates() {
720 self.apply_updates();
721 }
722
723 self.finish_frame();
724
725 UPDATES.next_deadline(&mut self.loop_timer);
726
727 if APP_PROCESS_SV.read().exit {
728 UPDATES.on_app_sleep();
729 self.exited = true;
730 AppControlFlow::Exit
731 } else if self.has_pending_updates()
732 || UPDATES.has_pending_layout_or_render()
733 || matches!(self.loop_timer.deadline(), Some(t) if t.has_elapsed())
734 {
735 AppControlFlow::Poll
736 } else {
737 UPDATES.on_app_sleep();
738 AppControlFlow::Wait
739 }
740 }
741
742 fn apply_updates(&mut self) {
744 let _s = tracing::debug_span!("apply_updates").entered();
745
746 let mut run = true;
747 while run {
748 run = self.loop_monitor.update(|| {
749 let mut any = false;
750
751 self.pending |= UPDATES.apply_info();
752 if mem::take(&mut self.pending.info) {
753 any = true;
754 let _s = tracing::debug_span!("info").entered();
755
756 let mut info_widgets = mem::take(&mut self.pending.info_widgets);
757
758 let _t = INSTANT_APP.pause_for_update();
759
760 WINDOWS_APP.update_info(&mut info_widgets);
761 }
762
763 {
764 let _s = tracing::debug_span!("hooks").entered();
765 self.pending |= UPDATES.apply_updates();
766 }
767
768 TimersService::notify();
769 if mem::take(&mut self.pending.update) {
770 any = true;
771 let _s = tracing::debug_span!("update").entered();
772
773 let mut update_widgets = mem::take(&mut self.pending.update_widgets);
774
775 let _t = INSTANT_APP.pause_for_update();
776
777 UPDATES.on_pre_updates();
778
779 WINDOWS_APP.update_widgets(&mut update_widgets);
780
781 UPDATES.on_updates();
782 }
783
784 any
785 });
786 }
787 }
788
789 fn view_process_is_busy(&mut self) -> bool {
790 VIEW_PROCESS.is_available() && VIEW_PROCESS.is_busy()
791 }
792
793 fn finish_frame(&mut self) {
795 self.pending |= UPDATES.apply_layout_render();
796
797 while mem::take(&mut self.pending.layout) {
798 let _s = tracing::debug_span!("apply_layout").entered();
799
800 let mut layout_widgets = mem::take(&mut self.pending.layout_widgets);
801
802 self.loop_monitor.maybe_trace(|| {
803 let _t = INSTANT_APP.pause_for_update();
804
805 WINDOWS_APP.update_layout(&mut layout_widgets);
806 });
807
808 self.apply_updates();
809 self.pending |= UPDATES.apply_layout_render();
810 }
811
812 if mem::take(&mut self.pending.render) {
813 let _s = tracing::debug_span!("apply_render").entered();
814
815 let mut render_widgets = mem::take(&mut self.pending.render_widgets);
816 let mut render_update_widgets = mem::take(&mut self.pending.render_update_widgets);
817
818 let _t = INSTANT_APP.pause_for_update();
819
820 WINDOWS_APP.update_render(&mut render_widgets, &mut render_update_widgets);
821 }
822
823 self.loop_monitor.finish_frame();
824 }
825}
826
827#[derive(Clone, Debug)]
833#[non_exhaustive]
834pub struct AppInitArgs {
835 pub is_minimal: bool,
837}
838
839#[derive(Clone, Debug)]
845#[non_exhaustive]
846pub struct AppDeinitArgs {}
847
848impl APP {
849 pub fn on_init(&self, handler: crate::handler::Handler<AppInitArgs>) {
860 zng_unique_id::hot_static_ref!(ON_INIT).lock().push(handler);
861 }
862
863 pub fn on_deinit(&self, handler: impl FnOnce(&AppDeinitArgs) + Send + 'static) {
870 ON_DEINIT.write().get_mut().push(Box::new(handler));
871 }
872
873 fn call_init_handlers(&self, is_minimal: bool) {
874 #[cfg(feature = "multi_app")]
875 let _lock = zng_unique_id::hot_static_ref!(ON_INIT_CALL).lock();
876
877 let mut handlers = mem::take(&mut *zng_unique_id::hot_static_ref!(ON_INIT).lock());
878 let args = AppInitArgs { is_minimal };
879 handlers.retain_mut(|h| {
880 let (owner, handle) = zng_handle::Handle::new(());
881 h.app_event(Box::new(handle.downgrade()), true, &args);
882 !owner.is_dropped()
883 });
884
885 let mut s = zng_unique_id::hot_static_ref!(ON_INIT).lock();
886 handlers.extend(s.drain(..));
887 *s = handlers;
888 }
889
890 fn call_deinit_handlers(&self) {
891 let handlers = mem::take(&mut *ON_DEINIT.write().get_mut());
892 let args = AppDeinitArgs {};
893 for h in handlers {
894 h(&args);
895 }
896 }
897}
898zng_unique_id::hot_static! {
899 static ON_INIT: Mutex<Vec<crate::handler::Handler<AppInitArgs>>> = Mutex::new(vec![]);
900}
901#[cfg(feature = "multi_app")]
902zng_unique_id::hot_static! {
903 static ON_INIT_CALL: Mutex<()> = Mutex::new(());
904}
905app_local! {
906 static ON_DEINIT: Mutex<Vec<Box<dyn FnOnce(&AppDeinitArgs) + Send + 'static>>> = const { Mutex::new(vec![]) };
908}
909
910#[derive(Debug)]
912pub(crate) struct LoopTimer {
913 now: DInstant,
914 deadline: Option<Deadline>,
915}
916impl Default for LoopTimer {
917 fn default() -> Self {
918 Self {
919 now: INSTANT.now(),
920 deadline: None,
921 }
922 }
923}
924impl LoopTimer {
925 pub fn elapsed(&mut self, deadline: Deadline) -> bool {
928 if deadline.0 <= self.now {
929 true
930 } else {
931 self.register(deadline);
932 false
933 }
934 }
935
936 pub fn register(&mut self, deadline: Deadline) {
938 if let Some(d) = &mut self.deadline {
939 if deadline < *d {
940 *d = deadline;
941 }
942 } else {
943 self.deadline = Some(deadline)
944 }
945 }
946
947 pub(crate) fn deadline(&self) -> Option<Deadline> {
949 self.deadline
950 }
951
952 pub(crate) fn awake(&mut self) -> bool {
954 self.now = INSTANT.now();
955 if let Some(d) = self.deadline
956 && d.0 <= self.now
957 {
958 self.deadline = None;
959 return true;
960 }
961 false
962 }
963
964 pub fn now(&self) -> DInstant {
966 self.now
967 }
968}
969impl zng_var::animation::AnimationTimer for LoopTimer {
970 fn elapsed(&mut self, deadline: Deadline) -> bool {
971 self.elapsed(deadline)
972 }
973
974 fn register(&mut self, deadline: Deadline) {
975 self.register(deadline)
976 }
977
978 fn now(&self) -> DInstant {
979 self.now()
980 }
981}
982
983#[derive(Default)]
984struct LoopMonitor {
985 update_count: u16,
986 skipped: bool,
987 trace: Vec<UpdateTrace>,
988}
989impl LoopMonitor {
990 pub fn update(&mut self, update_once: impl FnOnce() -> bool) -> bool {
992 self.update_count += 1;
993
994 if self.update_count < 500 {
995 update_once()
996 } else if self.update_count < 1000 {
997 UpdatesTrace::collect_trace(&mut self.trace, update_once)
998 } else if self.update_count == 1000 {
999 self.skipped = true;
1000 let trace = UpdatesTrace::format_trace(mem::take(&mut self.trace));
1001 tracing::error!(
1002 "updated 1000 times without rendering, probably stuck in an infinite loop\n\
1003 will start skipping updates to render and poll system events\n\
1004 top 20 most frequent update requests (in 500 cycles):\n\
1005 {trace}\n\
1006 you can use `UpdatesTraceUiNodeExt` and `updates_trace_event` to refine the trace"
1007 );
1008 false
1009 } else if self.update_count == 1500 {
1010 self.update_count = 1001;
1011 false
1012 } else {
1013 update_once()
1014 }
1015 }
1016
1017 pub fn maybe_trace(&mut self, notify_once: impl FnOnce()) {
1018 if (500..1000).contains(&self.update_count) {
1019 UpdatesTrace::collect_trace(&mut self.trace, notify_once);
1020 } else {
1021 notify_once();
1022 }
1023 }
1024
1025 pub fn finish_frame(&mut self) {
1026 if !self.skipped {
1027 self.skipped = false;
1028 self.update_count = 0;
1029 self.trace = vec![];
1030 }
1031 }
1032}
1033
1034impl APP {
1035 pub(super) fn pre_init(&self, is_headed: bool, with_renderer: bool, view_process_exe: PathBuf, view_process_env: HashMap<Txt, Txt>) {
1037 let s = APP_PROCESS_SV.read();
1039 s.pause_time_for_updates
1040 .hook(|a| {
1041 if !matches!(INSTANT.mode(), zng_time::InstantMode::Manual) {
1042 if *a.value() {
1043 INSTANT_APP.set_mode(InstantMode::UpdatePaused);
1044 } else {
1045 INSTANT_APP.set_mode(InstantMode::Now);
1046 }
1047 }
1048 true
1049 })
1050 .perm();
1051
1052 VIEW_PROCESS_INITED_EVENT
1054 .hook(|_| {
1055 let filter = APP_PROCESS_SV.read().device_events_filter.get();
1056 if !filter.is_empty()
1057 && let Err(e) = VIEW_PROCESS.set_device_events_filter(filter)
1058 {
1059 tracing::error!("cannot set device events on the view-process, {e}");
1060 }
1061 true
1062 })
1063 .perm();
1064
1065 EXIT_CMD
1067 .on_event(
1068 true,
1069 true,
1070 false,
1071 crate::hn!(|a| {
1072 a.propagation.stop();
1073 APP.exit();
1074 }),
1075 )
1076 .perm();
1077
1078 s.device_events_filter
1080 .hook(|a| {
1081 if let Err(e) = VIEW_PROCESS.set_device_events_filter(a.value().clone()) {
1082 tracing::error!("cannot set device events on the view-process, {e}");
1083 }
1084 true
1085 })
1086 .perm();
1087
1088 if is_headed {
1090 debug_assert!(with_renderer);
1091
1092 let view_evs_sender = UPDATES.sender();
1093 VIEW_PROCESS.start(view_process_exe, view_process_env, false, move |ev| {
1094 let _ = view_evs_sender.send_view_event(ev);
1095 });
1096 } else if with_renderer {
1097 let view_evs_sender = UPDATES.sender();
1098 VIEW_PROCESS.start(view_process_exe, view_process_env, true, move |ev| {
1099 let _ = view_evs_sender.send_view_event(ev);
1100 });
1101 }
1102 }
1103}
1104
1105impl APP {
1106 pub fn exit(&self) -> ResponseVar<ExitCancelled> {
1115 let mut s = APP_PROCESS_SV.write();
1116 if let Some(r) = &s.exit_requests {
1117 r.response_var()
1118 } else {
1119 let (responder, response) = response_var();
1120 s.exit_requests = Some(responder);
1121 EXIT_REQUESTED_EVENT.notify(ExitRequestedArgs::now());
1122 EXIT_REQUESTED_EVENT
1123 .on_event(
1124 true,
1125 crate::hn_once!(|args: &ExitRequestedArgs| {
1126 let mut s = APP_PROCESS_SV.write();
1127 if !args.propagation.is_stopped() {
1128 s.exit = true;
1129 } else {
1130 s.exit_requests.take().unwrap().respond(ExitCancelled);
1131 }
1132 }),
1133 )
1134 .perm();
1135 response
1136 }
1137 }
1138
1139 pub fn is_suspended(&self) -> Var<bool> {
1147 expr_var! {
1148 let inited = #{VIEW_PROCESS_INITED_EVENT.var_latest()};
1149 let sus = #{VIEW_PROCESS_SUSPENDED_EVENT.var_latest()};
1150
1151 match (sus, inited) {
1152 (_, None) => true, (None, Some(_)) => false, (Some(s), Some(i)) => s.timestamp > i.timestamp, }
1156 }
1157 }
1158}
1159
1160impl APP {
1165 pub fn pause_time_for_update(&self) -> Var<bool> {
1171 APP_PROCESS_SV.read().pause_time_for_updates.clone()
1172 }
1173
1174 pub fn start_manual_time(&self) {
1182 INSTANT_APP.set_mode(InstantMode::Manual);
1183 INSTANT_APP.set_now(INSTANT.now());
1184 UPDATES.update_app();
1185 }
1186
1187 pub fn advance_manual_time(&self, advance: Duration) {
1198 INSTANT_APP.advance_now(advance);
1199 UPDATES.update_app();
1200 }
1201
1202 pub fn set_manual_time(&self, now: DInstant) {
1211 INSTANT_APP.set_now(now);
1212 UPDATES.update_app();
1213 }
1214
1215 pub fn end_manual_time(&self) {
1217 INSTANT_APP.set_mode(match APP.pause_time_for_update().get() {
1218 true => InstantMode::UpdatePaused,
1219 false => InstantMode::Now,
1220 });
1221 UPDATES.update_app();
1222 }
1223}
1224
1225command! {
1226 pub static EXIT_CMD {
1230 l10n!: true,
1231 name: "Exit",
1232 info: "Close all windows and exit",
1233 shortcut: shortcut!(Exit),
1234 };
1235}
1236
1237#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1241pub struct ExitCancelled;
1242impl fmt::Display for ExitCancelled {
1243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1244 write!(f, "exit request cancelled")
1245 }
1246}
1247
1248pub(crate) fn assert_not_view_process() {
1249 if zng_view_api::ViewConfig::from_env().is_some() {
1250 panic!("cannot start App in view-process");
1251 }
1252}
1253#[cfg(feature = "deadlock_detection")]
1258pub fn spawn_deadlock_detection() {
1259 use parking_lot::deadlock;
1260 use std::{
1261 sync::atomic::{self, AtomicBool},
1262 thread,
1263 time::*,
1264 };
1265
1266 static CHECK_RUNNING: AtomicBool = AtomicBool::new(false);
1267
1268 if CHECK_RUNNING.swap(true, atomic::Ordering::SeqCst) {
1269 return;
1270 }
1271
1272 thread::Builder::new()
1273 .name("deadlock_detection".into())
1274 .stack_size(256 * 1024)
1275 .spawn(|| {
1276 loop {
1277 thread::sleep(Duration::from_secs(10));
1278
1279 let deadlocks = deadlock::check_deadlock();
1280 if deadlocks.is_empty() {
1281 continue;
1282 }
1283
1284 use std::fmt::Write;
1285 let mut msg = String::new();
1286
1287 let _ = writeln!(&mut msg, "{} deadlocks detected", deadlocks.len());
1288 for (i, threads) in deadlocks.iter().enumerate() {
1289 let _ = writeln!(&mut msg, "Deadlock #{}, {} threads", i, threads.len());
1290 for t in threads {
1291 let _ = writeln!(&mut msg, "Thread Id {:#?}", t.thread_id());
1292 let _ = writeln!(&mut msg, "{:#?}", t.backtrace());
1293 }
1294 }
1295
1296 #[cfg(not(feature = "test_util"))]
1297 eprint!("{msg}");
1298
1299 #[cfg(feature = "test_util")]
1300 {
1301 use std::io::Write;
1304 let _ = write!(&mut std::io::stderr(), "{msg}");
1305 zng_env::exit(-1);
1306 }
1307 }
1308 })
1309 .expect("failed to spawn thread");
1310}
1311#[cfg(not(feature = "deadlock_detection"))]
1316pub fn spawn_deadlock_detection() {}
1317
1318app_local! {
1319 pub(super) static APP_PROCESS_SV: AppProcessService = AppProcessService {
1320 exit_requests: None,
1321 exit: false,
1322 device_events_filter: zng_var::var(Default::default()),
1323 pause_time_for_updates: zng_var::var(true),
1324 is_suspended: zng_var::var(false),
1325 };
1326}
1327
1328pub(super) struct AppProcessService {
1329 exit_requests: Option<ResponderVar<ExitCancelled>>,
1330 pub(crate) exit: bool,
1331 pub(crate) device_events_filter: Var<DeviceEventsFilter>,
1332 pause_time_for_updates: Var<bool>,
1333 is_suspended: Var<bool>,
1334}
1335
1336#[derive(Debug)]
1338#[allow(clippy::large_enum_variant)] pub(crate) enum AppEvent {
1340 ViewEvent(zng_view_api::Event),
1342 Update(UpdateOp, WidgetId),
1344 ResumeUnwind(PanicPayload),
1346 UpdateApp,
1348}
1349
1350#[derive(Clone)]
1356pub struct AppEventSender(channel::Sender<AppEvent>);
1357impl AppEventSender {
1358 pub(crate) fn new() -> (Self, channel::Receiver<AppEvent>) {
1359 let (sender, receiver) = channel::unbounded();
1360 (Self(sender), receiver)
1361 }
1362
1363 #[allow(clippy::result_large_err)] fn send_app_event(&self, event: AppEvent) -> Result<(), ChannelError> {
1365 self.0.send_blocking(event)
1366 }
1367
1368 #[allow(clippy::result_large_err)]
1369 fn send_view_event(&self, event: zng_view_api::Event) -> Result<(), ChannelError> {
1370 self.0.send_blocking(AppEvent::ViewEvent(event))
1371 }
1372
1373 pub fn send_update(&self, op: UpdateOp, target: WidgetId) -> Result<(), ChannelError> {
1375 UpdatesTrace::log_update();
1376 self.send_app_event(AppEvent::Update(op, target))
1377 }
1378
1379 pub fn send_update_app(&self) -> Result<(), ChannelError> {
1381 UpdatesTrace::log_update();
1382 self.send_app_event(AppEvent::UpdateApp)
1383 }
1384
1385 pub fn send_resume_unwind(&self, payload: PanicPayload) -> Result<(), ChannelError> {
1387 self.send_app_event(AppEvent::ResumeUnwind(payload))
1388 }
1389
1390 pub fn waker(&self, also_update: Option<WidgetId>) -> Waker {
1392 Arc::new(AppWaker(self.0.clone(), also_update)).into()
1393 }
1394}
1395
1396struct AppWaker(channel::Sender<AppEvent>, Option<WidgetId>);
1397impl std::task::Wake for AppWaker {
1398 fn wake(self: std::sync::Arc<Self>) {
1399 self.wake_by_ref()
1400 }
1401 fn wake_by_ref(self: &Arc<Self>) {
1402 match self.1 {
1403 Some(id) => {
1404 let _ = self.0.send_blocking(AppEvent::Update(UpdateOp::Update, id));
1405 }
1406 None => {
1407 let _ = self.0.send_blocking(AppEvent::UpdateApp);
1408 }
1409 }
1410 }
1411}
1412
1413type PanicPayload = Box<dyn std::any::Any + Send + 'static>;
1414
1415event_args! {
1416 pub struct ExitRequestedArgs {
1420
1421 ..
1422
1423 fn is_in_target(&self, _id: WidgetId) -> bool {
1425 true
1426 }
1427 }
1428}
1429
1430event! {
1431 pub static EXIT_REQUESTED_EVENT: ExitRequestedArgs;
1439}