1use std::{any::Any, mem, sync::Arc};
2
3use parking_lot::Mutex;
4use zng_app::{
5 APP, AppEventSender, Deadline, EXIT_REQUESTED_EVENT, app_hn_once,
6 event::AnyEventArgs,
7 timer::{DeadlineHandle, TIMERS},
8 update::{EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, WidgetUpdates},
9 view_process::{
10 self, VIEW_PROCESS, VIEW_PROCESS_INITED_EVENT, ViewImage, ViewRenderer, ViewWindowOrHeadless,
11 raw_events::{
12 RAW_CHROME_CONFIG_CHANGED_EVENT, RAW_COLORS_CONFIG_CHANGED_EVENT, RAW_IMAGE_LOAD_ERROR_EVENT, RAW_IMAGE_LOADED_EVENT,
13 RAW_WINDOW_CLOSE_EVENT, RAW_WINDOW_CLOSE_REQUESTED_EVENT, RAW_WINDOW_FOCUS_EVENT,
14 },
15 },
16 widget::{
17 UiTaskWidget, WidgetId,
18 info::{InteractionPath, WidgetInfo, WidgetInfoTree},
19 node::{BoxedUiNode, NilUiNode, UiNode},
20 },
21 window::{WINDOW, WindowCtx, WindowId, WindowMode},
22};
23use zng_app_context::app_local;
24
25use zng_color::{COLOR_SCHEME_VAR, colors::ACCENT_COLOR_VAR};
26use zng_ext_image::{ImageRenderWindowRoot, ImageRenderWindowsService, ImageVar, Img};
27use zng_layout::unit::TimeUnits as _;
28use zng_layout::unit::{Factor, FactorUnits, LengthUnits, PxRect};
29use zng_task::{
30 ParallelIteratorExt, UiTask,
31 rayon::iter::{IntoParallelRefMutIterator, ParallelIterator},
32};
33use zng_txt::{ToTxt as _, Txt, formatx};
34use zng_unique_id::{IdMap, IdSet};
35use zng_var::{
36 AnyWeakVar, ArcVar, BoxedVar, LocalVar, ReadOnlyArcVar, ResponderVar, ResponseVar, Var, WeakVar, impl_from_and_into_var,
37 response_done_var, response_var, types::WeakArcVar, var,
38};
39use zng_view_api::{
40 DragDropId, ViewProcessOffline,
41 api_extension::{ApiExtensionId, ApiExtensionPayload},
42 config::{ChromeConfig, ColorsConfig},
43 drag_drop::{DragDropData, DragDropEffect, DragDropError},
44 image::ImageMaskMode,
45 window::{RenderMode, WindowState},
46};
47use zng_wgt::node::with_context_var;
48
49use crate::{
50 CloseWindowResult, FRAME_IMAGE_READY_EVENT, FrameCaptureMode, HeadlessMonitor, MONITORS, StartPosition, ViewExtensionError,
51 WINDOW_CLOSE_EVENT, WINDOW_CLOSE_REQUESTED_EVENT, WINDOW_FOCUS_CHANGED_EVENT, WINDOW_LOAD_EVENT, WINDOW_VARS_ID, WindowCloseArgs,
52 WindowCloseRequestedArgs, WindowFocusChangedArgs, WindowLoadingHandle, WindowNotFound, WindowOpenArgs, WindowRoot, WindowVars,
53 cmd::WindowCommands, control::WindowCtrl,
54};
55
56app_local! {
57 pub(super) static WINDOWS_SV: WindowsService = WindowsService::new();
58 static FOCUS_SV: BoxedVar<Option<InteractionPath>> = LocalVar(None).boxed();
59}
60pub(super) struct WindowsService {
61 exit_on_last_close: ArcVar<bool>,
62 default_render_mode: ArcVar<RenderMode>,
63 parallel: ArcVar<ParallelWin>,
64 system_chrome: ArcVar<ChromeConfig>,
65 root_extenders: Mutex<Vec<Box<dyn FnMut(WindowRootExtenderArgs) -> BoxedUiNode + Send>>>, open_nested_handlers: Mutex<Vec<Box<dyn FnMut(&mut crate::OpenNestedHandlerArgs) + Send>>>,
67
68 windows: IdMap<WindowId, AppWindow>,
69 windows_info: IdMap<WindowId, AppWindowInfo>,
70
71 open_loading: IdMap<WindowId, WindowLoading>,
72 open_requests: Vec<OpenWindowRequest>,
73 open_tasks: Vec<AppWindowTask>,
74
75 close_requests: Vec<CloseWindowRequest>,
76 close_responders: IdMap<WindowId, Vec<ResponderVar<CloseWindowResult>>>,
77 exit_on_close: bool,
78
79 focus_request: Option<WindowId>,
80 bring_to_top_requests: Vec<WindowId>,
81
82 frame_images: Vec<WeakArcVar<Img>>,
83
84 loading_deadline: Option<DeadlineHandle>,
85 latest_colors_cfg: ColorsConfig,
86
87 view_window_tasks: Vec<ViewWindowTask>,
88}
89impl WindowsService {
90 fn new() -> Self {
91 Self {
92 exit_on_last_close: var(true),
93 default_render_mode: var(RenderMode::default()),
94 root_extenders: Mutex::new(vec![]),
95 open_nested_handlers: Mutex::new(vec![]),
96 system_chrome: var(ChromeConfig::default()),
97 parallel: var(ParallelWin::default()),
98 windows: IdMap::default(),
99 windows_info: IdMap::default(),
100 open_loading: IdMap::new(),
101 open_tasks: vec![],
102 open_requests: Vec::with_capacity(1),
103 exit_on_close: false,
104 close_responders: IdMap::default(),
105 close_requests: vec![],
106 focus_request: None,
107 bring_to_top_requests: vec![],
108 frame_images: vec![],
109 loading_deadline: None,
110 latest_colors_cfg: ColorsConfig::default(),
111 view_window_tasks: vec![],
112 }
113 }
114
115 fn open_impl(&mut self, id: WindowId, new_window: UiTask<WindowRoot>, force_headless: Option<WindowMode>) -> ResponseVar<WindowId> {
116 let (responder, response) = response_var();
117 let request = OpenWindowRequest {
118 id,
119 new: Mutex::new(new_window),
120 force_headless,
121 responder,
122 };
123 self.open_requests.push(request);
124 self.open_loading.insert(id, WindowLoading::new());
125 UPDATES.update(None);
126
127 response
128 }
129
130 fn loading_handle_impl(&mut self, window_id: WindowId, deadline: Deadline) -> Option<WindowLoadingHandle> {
131 let mut handle = None;
132
133 if let Some(info) = self.windows_info.get_mut(&window_id) {
134 if !info.is_loaded {
136 handle = Some(info.loading_handle.new_handle(UPDATES.sender(), deadline))
137 }
138
139 self.loading_deadline = None;
141 } else if let Some(h) = self.open_loading.get_mut(&window_id) {
142 handle = Some(h.new_handle(UPDATES.sender(), deadline));
144 }
145
146 handle
147 }
148
149 fn close_together(&mut self, windows: impl IntoIterator<Item = WindowId>) -> Result<ResponseVar<CloseWindowResult>, WindowNotFound> {
150 let mut group = IdSet::default();
151
152 for w in windows {
153 if !self.windows_info.contains_key(&w) {
154 return Err(WindowNotFound(w));
155 }
156 group.insert(w);
157 }
158
159 if group.is_empty() {
160 return Ok(response_done_var(CloseWindowResult::Cancel));
161 }
162
163 let (responder, response) = response_var();
164 self.close_requests.push(CloseWindowRequest { responder, windows: group });
165 UPDATES.update(None);
166
167 Ok(response)
168 }
169
170 fn frame_image_impl(
171 &mut self,
172 window_id: WindowId,
173 action: impl FnOnce(&ViewRenderer) -> std::result::Result<ViewImage, ViewProcessOffline>,
174 ) -> ImageVar {
175 if let Some(w) = self.windows_info.get(&window_id) {
176 if let Some(r) = &w.view {
177 match action(&r.renderer()) {
178 Ok(img) => {
179 let img = Img::new(img);
180 let img = var(img);
181 self.frame_images.retain(|i| i.strong_count() > 0);
182 self.frame_images.push(img.downgrade());
183 img.read_only()
184 }
185 Err(_) => var(Img::dummy(Some(formatx!("{}", WindowNotFound(window_id))))).read_only(),
186 }
187 } else {
188 var(Img::dummy(Some(formatx!("window `{window_id}` is headless without renderer")))).read_only()
189 }
190 } else {
191 var(Img::dummy(Some(formatx!("{}", WindowNotFound(window_id))))).read_only()
192 }
193 }
194
195 fn view_window_task(&mut self, window_id: WindowId, task: impl FnOnce(Option<&view_process::ViewWindow>) + Send + 'static) {
196 self.view_window_tasks.push(ViewWindowTask {
197 window_id,
198 task: Mutex::new(Box::new(task)),
199 });
200 }
201
202 fn take_requests(
203 &mut self,
204 ) -> (
205 Vec<OpenWindowRequest>,
206 Vec<AppWindowTask>,
207 Vec<CloseWindowRequest>,
208 Option<WindowId>,
209 Vec<WindowId>,
210 Vec<ViewWindowTask>,
211 ) {
212 (
213 mem::take(&mut self.open_requests),
214 mem::take(&mut self.open_tasks),
215 mem::take(&mut self.close_requests),
216 self.focus_request.take(),
217 mem::take(&mut self.bring_to_top_requests),
218 mem::take(&mut self.view_window_tasks),
219 )
220 }
221}
222
223bitflags! {
224 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
230 #[serde(transparent)]
231 pub struct ParallelWin: u8 {
232 const UPDATE = 0b0001;
234 const EVENT = 0b0010;
236 const LAYOUT = 0b0100;
238 const RENDER = 0b1000;
240 }
241}
242impl Default for ParallelWin {
243 fn default() -> Self {
245 Self::all()
246 }
247}
248impl_from_and_into_var! {
249 fn from(all: bool) -> ParallelWin {
250 if all {
251 ParallelWin::all()
252 } else {
253 ParallelWin::empty()
254 }
255 }
256}
257
258pub struct WINDOWS;
266impl WINDOWS {
267 pub fn exit_on_last_close(&self) -> ArcVar<bool> {
275 WINDOWS_SV.read().exit_on_last_close.clone()
276 }
277
278 pub fn default_render_mode(&self) -> ArcVar<RenderMode> {
283 WINDOWS_SV.read().default_render_mode.clone()
284 }
285
286 pub fn parallel(&self) -> ArcVar<ParallelWin> {
293 WINDOWS_SV.read().parallel.clone()
294 }
295
296 pub fn open<F: Future<Output = WindowRoot> + Send + 'static>(
311 &self,
312 new_window: impl IntoFuture<IntoFuture = F>,
313 ) -> ResponseVar<WindowId> {
314 WINDOWS_SV
315 .write()
316 .open_impl(WindowId::new_unique(), UiTask::new(None, new_window), None)
317 }
318
319 pub fn open_id<F: Future<Output = WindowRoot> + Send + 'static>(
325 &self,
326 window_id: impl Into<WindowId>,
327 new_window: impl IntoFuture<IntoFuture = F>,
328 ) -> ResponseVar<WindowId> {
329 let window_id = window_id.into();
330 self.assert_id_unused(window_id);
331 WINDOWS_SV.write().open_impl(window_id, UiTask::new(None, new_window), None)
332 }
333
334 pub fn open_headless<F: Future<Output = WindowRoot> + Send + 'static>(
343 &self,
344 new_window: impl IntoFuture<IntoFuture = F>,
345 with_renderer: bool,
346 ) -> ResponseVar<WindowId> {
347 WINDOWS_SV.write().open_impl(
348 WindowId::new_unique(),
349 UiTask::new(None, new_window),
350 Some(if with_renderer {
351 WindowMode::HeadlessWithRenderer
352 } else {
353 WindowMode::Headless
354 }),
355 )
356 }
357
358 pub fn open_headless_id<F: Future<Output = WindowRoot> + Send + 'static>(
364 &self,
365 window_id: impl Into<WindowId>,
366 new_window: impl IntoFuture<IntoFuture = F>,
367 with_renderer: bool,
368 ) -> ResponseVar<WindowId> {
369 let window_id = window_id.into();
370 self.assert_id_unused(window_id);
371 WINDOWS_SV.write().open_impl(
372 window_id,
373 UiTask::new(None, new_window),
374 Some(if with_renderer {
375 WindowMode::HeadlessWithRenderer
376 } else {
377 WindowMode::Headless
378 }),
379 )
380 }
381
382 #[track_caller]
383 fn assert_id_unused(&self, id: WindowId) {
384 let w = WINDOWS_SV.read();
385 if w.windows_info.contains_key(&id) || w.open_loading.contains_key(&id) {
386 panic!("window id `{id:?}` is already in use")
387 }
388 }
389
390 pub fn loading_handle(&self, window_id: impl Into<WindowId>, deadline: impl Into<Deadline>) -> Option<WindowLoadingHandle> {
401 WINDOWS_SV.write().loading_handle_impl(window_id.into(), deadline.into())
402 }
403
404 pub fn close(&self, window_id: impl Into<WindowId>) -> Result<ResponseVar<CloseWindowResult>, WindowNotFound> {
411 self.close_together([window_id.into()])
412 }
413
414 pub fn close_together(&self, windows: impl IntoIterator<Item = WindowId>) -> Result<ResponseVar<CloseWindowResult>, WindowNotFound> {
425 WINDOWS_SV.write().close_together(windows)
426 }
427
428 pub fn close_all(&self) -> ResponseVar<CloseWindowResult> {
436 let set: Vec<_> = WINDOWS_SV.read().windows_info.keys().copied().collect();
437 self.close_together(set).unwrap()
438 }
439
440 pub fn mode(&self, window_id: impl Into<WindowId>) -> Result<WindowMode, WindowNotFound> {
448 let window_id = window_id.into();
449 WINDOWS_SV
450 .read()
451 .windows_info
452 .get(&window_id)
453 .map(|w| w.mode)
454 .ok_or(WindowNotFound(window_id))
455 }
456
457 pub fn widget_tree(&self, window_id: impl Into<WindowId>) -> Result<WidgetInfoTree, WindowNotFound> {
461 let window_id = window_id.into();
462 WINDOWS_SV
463 .read()
464 .windows_info
465 .get(&window_id)
466 .map(|w| w.widget_tree.clone())
467 .ok_or(WindowNotFound(window_id))
468 }
469
470 pub fn widget_info(&self, widget_id: impl Into<WidgetId>) -> Option<WidgetInfo> {
472 let widget_id = widget_id.into();
473 WINDOWS_SV.read().windows_info.values().find_map(|w| w.widget_tree.get(widget_id))
474 }
475
476 pub fn frame_image(&self, window_id: impl Into<WindowId>, mask: Option<ImageMaskMode>) -> ImageVar {
484 let window_id = window_id.into();
485 if let Some((win, wgt)) = self.nest_parent(window_id) {
486 if let Ok(tree) = self.widget_tree(win) {
487 if let Some(wgt) = tree.get(wgt) {
488 return WINDOWS_SV
489 .write()
490 .frame_image_impl(win, |vr| vr.frame_image_rect(wgt.inner_bounds(), mask));
491 }
492 }
493 tracing::error!("did not find nest parent {win:?}//.../{wgt:?}, will capture parent window frame")
494 }
495 WINDOWS_SV.write().frame_image_impl(window_id, move |vr| vr.frame_image(mask))
496 }
497
498 pub fn frame_image_rect(&self, window_id: impl Into<WindowId>, mut rect: PxRect, mask: Option<ImageMaskMode>) -> ImageVar {
506 let mut window_id = window_id.into();
507 if let Some((win, wgt)) = self.nest_parent(window_id) {
508 if let Ok(tree) = self.widget_tree(win) {
509 if let Some(wgt) = tree.get(wgt) {
510 window_id = win;
511 let bounds = wgt.inner_bounds();
512 rect.origin += bounds.origin.to_vector();
513 rect = rect.intersection(&bounds).unwrap_or_default();
514 }
515 }
516 if window_id != win {
517 tracing::error!("did not find nest parent {win:?}//.../{wgt:?}, will capture parent window frame")
518 }
519 }
520 WINDOWS_SV.write().frame_image_impl(window_id, |vr| vr.frame_image_rect(rect, mask))
521 }
522
523 pub fn vars(&self, window_id: impl Into<WindowId>) -> Result<WindowVars, WindowNotFound> {
527 let window_id = window_id.into();
528 WINDOWS_SV
529 .read()
530 .windows_info
531 .get(&window_id)
532 .map(|w| w.vars.clone())
533 .ok_or(WindowNotFound(window_id))
534 }
535
536 pub fn is_focused(&self, window_id: impl Into<WindowId>) -> Result<bool, WindowNotFound> {
541 let window_id = window_id.into();
542 let w = WINDOWS_SV.read();
543 if let Some(w) = w.windows_info.get(&window_id) {
544 Ok(w.is_focused)
545 } else if w.open_loading.contains_key(&window_id) {
546 Ok(false)
547 } else {
548 Err(WindowNotFound(window_id))
549 }
550 }
551
552 pub fn widget_trees(&self) -> Vec<WidgetInfoTree> {
554 WINDOWS_SV.read().windows_info.values().map(|w| w.widget_tree.clone()).collect()
555 }
556
557 pub fn focused_window_id(&self) -> Option<WindowId> {
559 WINDOWS_SV.read().windows_info.values().find(|w| w.is_focused).map(|w| w.id)
560 }
561
562 pub fn focused_info(&self) -> Option<WidgetInfoTree> {
564 WINDOWS_SV
565 .read()
566 .windows_info
567 .values()
568 .find(|w| w.is_focused)
569 .map(|w| w.widget_tree.clone())
570 }
571
572 pub fn is_open(&self, window_id: impl Into<WindowId>) -> bool {
574 WINDOWS_SV.read().windows_info.contains_key(&window_id.into())
575 }
576
577 pub fn is_opening(&self, window_id: impl Into<WindowId>) -> bool {
581 let window_id = window_id.into();
582 let sv = WINDOWS_SV.read();
583 sv.open_loading.contains_key(&window_id)
584 }
585
586 pub fn is_loading(&self, window_id: impl Into<WindowId>) -> bool {
588 let window_id = window_id.into();
589 let sv = WINDOWS_SV.read();
590 sv.open_loading.contains_key(&window_id) || sv.windows_info.get(&window_id).map(|i| !i.is_loaded).unwrap_or(false)
591 }
592
593 pub fn is_loaded(&self, window_id: impl Into<WindowId>) -> bool {
595 let window_id = window_id.into();
596 WINDOWS_SV.read().windows_info.get(&window_id).map(|i| i.is_loaded).unwrap_or(false)
597 }
598
599 pub fn wait_loaded(&self, window_id: impl Into<WindowId>, wait_event: bool) -> impl Future<Output = bool> + Send + Sync + 'static {
605 Self::wait_loaded_impl(window_id.into(), wait_event)
606 }
607 async fn wait_loaded_impl(window_id: WindowId, wait_event: bool) -> bool {
608 if Self.is_loaded(window_id) {
609 if wait_event {
610 zng_task::yield_now().await;
612 }
613 return true;
614 }
615
616 let recv = WINDOW_LOAD_EVENT.receiver();
618 while Self.is_loading(window_id) {
619 while let Ok(msg) = zng_task::with_deadline(recv.recv_async(), 1.secs()).await {
620 if let Ok(args) = msg {
621 if args.window_id == window_id {
622 if wait_event {
623 zng_task::yield_now().await;
624 }
625 return true;
626 }
627 }
628 }
629 }
631
632 if Self.is_loaded(window_id) {
633 if wait_event {
634 zng_task::yield_now().await;
635 }
636 return true;
637 }
638 false
639 }
640
641 pub fn focus(&self, window_id: impl Into<WindowId>) -> Result<(), WindowNotFound> {
651 let window_id = window_id.into();
652 if !self.is_focused(window_id)? {
653 let mut w = WINDOWS_SV.write();
654 w.focus_request = Some(window_id);
655 UPDATES.update(None);
656 }
657 Ok(())
658 }
659
660 pub fn focus_or_open(
662 &self,
663 window_id: impl Into<WindowId>,
664 open: impl Future<Output = WindowRoot> + Send + 'static,
665 ) -> Option<ResponseVar<WindowId>> {
666 let window_id = window_id.into();
667 if self.focus(window_id).is_ok() {
668 None
669 } else {
670 let r = self.open_id(window_id, async move {
671 let w = open.await;
672 WINDOWS.focus(WINDOW.id()).unwrap();
674 w
675 });
676 Some(r)
677 }
678 }
679
680 pub fn bring_to_top(&self, window_id: impl Into<WindowId>) -> Result<(), WindowNotFound> {
687 let window_id = window_id.into();
688 let mut w = WINDOWS_SV.write();
689 if w.windows_info.contains_key(&window_id) {
690 w.bring_to_top_requests.push(window_id);
691 UPDATES.update(None);
692 Ok(())
693 } else {
694 Err(WindowNotFound(window_id))
695 }
696 }
697
698 pub fn register_root_extender<E>(&self, mut extender: impl FnMut(WindowRootExtenderArgs) -> E + Send + 'static)
710 where
711 E: zng_app::widget::node::UiNode,
712 {
713 WINDOWS_SV
714 .write()
715 .root_extenders
716 .get_mut()
717 .push(Box::new(move |a| extender(a).boxed()))
718 }
719
720 pub fn system_chrome(&self) -> ReadOnlyArcVar<ChromeConfig> {
728 WINDOWS_SV.read().system_chrome.read_only()
729 }
730
731 pub fn register_open_nested_handler(&self, handler: impl FnMut(&mut crate::OpenNestedHandlerArgs) + Send + 'static) {
744 WINDOWS_SV.write().open_nested_handlers.get_mut().push(Box::new(handler))
745 }
746
747 pub fn nest_parent(&self, maybe_nested: impl Into<WindowId>) -> Option<(WindowId, WidgetId)> {
749 let vars = self.vars(maybe_nested.into()).ok()?;
750 let nest = vars.nest_parent().get()?;
751 let parent = vars.parent().get()?;
752 Some((parent, nest))
753 }
754
755 pub fn view_extensions_init(
766 &self,
767 window_id: impl Into<WindowId>,
768 extension_id: ApiExtensionId,
769 request: ApiExtensionPayload,
770 ) -> Result<(), WindowNotFound> {
771 let window_id = window_id.into();
772 match WINDOWS_SV.write().windows_info.get_mut(&window_id) {
773 Some(i) => {
774 i.extensions.push((extension_id, request));
775 Ok(())
776 }
777 None => Err(WindowNotFound(window_id)),
778 }
779 }
780
781 pub(super) fn system_colors_config(&self) -> ColorsConfig {
782 WINDOWS_SV.read().latest_colors_cfg
783 }
784
785 pub(super) fn take_view_extensions_init(&self, id: WindowId) -> Vec<(ApiExtensionId, ApiExtensionPayload)> {
786 std::mem::take(&mut WINDOWS_SV.write().windows_info.get_mut(&id).unwrap().extensions)
787 }
788
789 pub fn view_window_extension_raw(
793 &self,
794 window_id: impl Into<WindowId>,
795 extension_id: ApiExtensionId,
796 request: ApiExtensionPayload,
797 ) -> Result<ApiExtensionPayload, ViewExtensionError> {
798 let window_id = window_id.into();
799 let sv = WINDOWS_SV.read();
800 match WINDOWS_SV.read().windows_info.get(&window_id) {
801 Some(i) => match &i.view {
802 Some(r) => match r {
803 ViewWindowOrHeadless::Window(r) => {
804 let r = r.clone();
805 drop(sv);
806 r.window_extension_raw(extension_id, request)
807 .map_err(ViewExtensionError::ViewProcessOffline)
808 }
809 ViewWindowOrHeadless::Headless(_) => Err(ViewExtensionError::WindowNotHeaded(window_id)),
810 },
811 None => Err(ViewExtensionError::NotOpenInViewProcess(window_id)),
812 },
813 None => Err(ViewExtensionError::WindowNotFound(WindowNotFound(window_id))),
814 }
815 }
816
817 pub fn view_window_extension<I, O>(
821 &self,
822 window_id: impl Into<WindowId>,
823 extension_id: ApiExtensionId,
824 request: &I,
825 ) -> Result<O, ViewExtensionError>
826 where
827 I: serde::Serialize,
828 O: serde::de::DeserializeOwned,
829 {
830 let window_id = window_id.into();
831 let sv = WINDOWS_SV.read();
832 match sv.windows_info.get(&window_id) {
833 Some(i) => match &i.view {
834 Some(r) => match r {
835 ViewWindowOrHeadless::Window(r) => {
836 let r = r.clone();
837 drop(sv);
838 let r = r
839 .window_extension(extension_id, request)
840 .map_err(ViewExtensionError::ViewProcessOffline)?;
841 r.map_err(ViewExtensionError::Api)
842 }
843 ViewWindowOrHeadless::Headless(_) => Err(ViewExtensionError::WindowNotHeaded(window_id)),
844 },
845 None => Err(ViewExtensionError::NotOpenInViewProcess(window_id)),
846 },
847 None => Err(ViewExtensionError::WindowNotFound(WindowNotFound(window_id))),
848 }
849 }
850
851 pub fn view_render_extension_raw(
855 &self,
856 window_id: impl Into<WindowId>,
857 extension_id: ApiExtensionId,
858 request: ApiExtensionPayload,
859 ) -> Result<ApiExtensionPayload, ViewExtensionError> {
860 let window_id = window_id.into();
861 let sv = WINDOWS_SV.read();
862 match WINDOWS_SV.read().windows_info.get(&window_id) {
863 Some(i) => match &i.view {
864 Some(r) => {
865 let r = r.renderer();
866 drop(sv);
867 r.render_extension_raw(extension_id, request)
868 .map_err(ViewExtensionError::ViewProcessOffline)
869 }
870 None => Err(ViewExtensionError::NotOpenInViewProcess(window_id)),
871 },
872 None => Err(ViewExtensionError::WindowNotFound(WindowNotFound(window_id))),
873 }
874 }
875
876 pub fn view_render_extension<I, O>(
880 &self,
881 window_id: impl Into<WindowId>,
882 extension_id: ApiExtensionId,
883 request: &I,
884 ) -> Result<O, ViewExtensionError>
885 where
886 I: serde::Serialize,
887 O: serde::de::DeserializeOwned,
888 {
889 let window_id = window_id.into();
890 let sv = WINDOWS_SV.read();
891 match sv.windows_info.get(&window_id) {
892 Some(i) => match &i.view {
893 Some(r) => {
894 let r = r.renderer();
895 drop(sv);
896 let r = r
897 .render_extension(extension_id, request)
898 .map_err(ViewExtensionError::ViewProcessOffline)?;
899 r.map_err(ViewExtensionError::Api)
900 }
901 None => Err(ViewExtensionError::NotOpenInViewProcess(window_id)),
902 },
903 None => Err(ViewExtensionError::WindowNotFound(WindowNotFound(window_id))),
904 }
905 }
906
907 pub(super) fn set_view(&self, id: WindowId, view: ViewWindowOrHeadless) {
909 if let Some(info) = WINDOWS_SV.write().windows_info.get_mut(&id) {
910 info.view = Some(view);
911 }
912 }
913
914 pub(super) fn set_widget_tree(&self, info_tree: WidgetInfoTree) {
916 if let Some(info) = WINDOWS_SV.write().windows_info.get_mut(&info_tree.window_id()) {
917 info.widget_tree = info_tree;
918 }
919 }
920
921 pub(super) fn try_load(&self, window_id: WindowId) -> bool {
925 if let Some(info) = WINDOWS_SV.write().windows_info.get_mut(&window_id) {
926 info.is_loaded = info.loading_handle.try_load(window_id);
927
928 if info.is_loaded && !info.vars.0.is_loaded.get() {
929 info.vars.0.is_loaded.set(true);
930 WINDOW_LOAD_EVENT.notify(WindowOpenArgs::now(info.id));
931 }
932
933 info.is_loaded
934 } else {
935 unreachable!()
936 }
937 }
938
939 pub(super) fn on_pre_event(update: &EventUpdate) {
940 if let Some(args) = RAW_WINDOW_FOCUS_EVENT.on(update) {
941 let mut wns = WINDOWS_SV.write();
942
943 let mut prev = None;
944 let mut new = None;
945
946 if let Some(prev_focus) = args.prev_focus {
947 if let Some(window) = wns.windows_info.get_mut(&prev_focus) {
948 if window.is_focused {
949 window.is_focused = false;
950 prev = Some(prev_focus);
951 } else if args.new_focus.is_none() {
952 if let Some(focused) = wns.windows_info.values_mut().find(|w| w.is_focused) {
953 if focused.vars.nest_parent().get().is_some() && focused.vars.parent().get() == Some(prev_focus) {
954 focused.is_focused = false;
956 prev = Some(focused.id);
957 }
958 }
959 }
960 }
961 }
962 if let Some(new_focus) = args.new_focus {
963 if prev.is_none() {
964 if let Some((&id, window)) = wns.windows_info.iter_mut().find(|w| w.1.is_focused) {
965 if new_focus != id {
966 window.is_focused = false;
967 prev = Some(id);
968 }
969 }
970 }
971
972 if let Some(window) = wns.windows_info.get_mut(&new_focus) {
973 if !window.is_focused {
974 window.is_focused = true;
975 window.vars.focus_indicator().set(None);
976 new = Some(new_focus);
977 }
978 }
979 }
980
981 if prev.is_some() || new.is_some() {
982 let args = WindowFocusChangedArgs::new(args.timestamp, args.propagation().clone(), prev, new, false);
983 WINDOW_FOCUS_CHANGED_EVENT.notify(args);
984 }
985 } else if let Some(args) = RAW_WINDOW_CLOSE_REQUESTED_EVENT.on(update) {
986 let _ = WINDOWS.close(args.window_id);
987 } else if let Some(args) = RAW_WINDOW_CLOSE_EVENT.on(update) {
988 if WINDOWS_SV.read().windows.contains_key(&args.window_id) {
989 tracing::error!("view-process closed window without request");
990 let mut windows = IdSet::default();
991 windows.insert(args.window_id);
992 let args = WindowCloseArgs::new(args.timestamp, args.propagation().clone(), windows);
993 WINDOW_CLOSE_EVENT.notify(args);
994 }
995 } else if let Some(args) = RAW_COLORS_CONFIG_CHANGED_EVENT.on(update) {
996 WINDOWS_SV.write().latest_colors_cfg = args.config;
997 } else if let Some(args) = RAW_CHROME_CONFIG_CHANGED_EVENT.on(update) {
998 WINDOWS_SV.read().system_chrome.set(args.config);
999 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update) {
1000 let mut wns = WINDOWS_SV.write();
1001 wns.latest_colors_cfg = args.colors_config;
1002 wns.system_chrome.set(args.chrome_config);
1003
1004 UPDATES.update(None);
1006 } else if let Some(args) = RAW_IMAGE_LOADED_EVENT.on(update).or_else(|| RAW_IMAGE_LOAD_ERROR_EVENT.on(update)) {
1007 let mut sv = WINDOWS_SV.write();
1009 sv.frame_images.retain(|i| {
1010 if let Some(i) = i.upgrade() {
1011 if Some(&args.image) == i.get().view() {
1012 i.update();
1013 false
1014 } else {
1015 true
1016 }
1017 } else {
1018 false
1019 }
1020 });
1021 }
1022
1023 Self::with_detached_windows(|windows, parallel| {
1024 if windows.len() > 1 && parallel.contains(ParallelWin::EVENT) {
1025 windows.par_iter_mut().with_ctx().for_each(|(_, window)| {
1026 window.pre_event(update);
1027 });
1028 } else {
1029 for (_, window) in windows.iter_mut() {
1030 window.pre_event(update);
1031 }
1032 }
1033 })
1034 }
1035
1036 pub(super) fn on_ui_event(update: &mut EventUpdate) {
1037 if update.delivery_list_mut().has_pending_search() {
1038 update
1039 .delivery_list_mut()
1040 .fulfill_search(WINDOWS_SV.read().windows_info.values().map(|w| &w.widget_tree));
1041 }
1042 Self::with_detached_windows(|windows, parallel| {
1043 if windows.len() > 1 && parallel.contains(ParallelWin::EVENT) {
1044 windows.par_iter_mut().with_ctx().for_each(|(_, window)| {
1045 window.ui_event(update);
1046 });
1047 } else {
1048 for (_, window) in windows.iter_mut() {
1049 window.ui_event(update);
1050 }
1051 }
1052 });
1053 }
1054
1055 pub(super) fn on_event(update: &mut EventUpdate) {
1056 if let Some(args) = WINDOW_CLOSE_REQUESTED_EVENT.on(update) {
1057 let key = args.windows.iter().next().unwrap();
1058 let mut sv = WINDOWS_SV.write();
1059 if let Some(rsp) = sv.close_responders.remove(key) {
1060 if !args.propagation().is_stopped() {
1061 WINDOW_CLOSE_EVENT.notify(WindowCloseArgs::now(args.windows.clone()));
1063 for r in rsp {
1064 r.respond(CloseWindowResult::Closed);
1065 }
1066 } else {
1067 for r in rsp {
1068 r.respond(CloseWindowResult::Cancel);
1069 }
1070 sv.exit_on_close = false;
1072 }
1073 }
1074 } else if let Some(args) = WINDOW_CLOSE_EVENT.on(update) {
1075 for w in args.windows.iter() {
1079 let w = WINDOWS_SV.write().windows.remove(w);
1080 if let Some(w) = w {
1081 let id = w.ctx.id();
1082 w.close();
1083
1084 let info = WINDOWS_SV.write().windows_info.remove(&id).unwrap();
1085
1086 info.vars.0.is_open.set(false);
1087
1088 if info.is_focused {
1089 let args = WindowFocusChangedArgs::now(Some(info.id), None, true);
1090 WINDOW_FOCUS_CHANGED_EVENT.notify(args)
1091 }
1092 }
1093 }
1094
1095 let is_headless_app = zng_app::APP.window_mode().is_headless();
1096 let mut wns = WINDOWS_SV.write();
1097
1098 if mem::take(&mut wns.exit_on_close)
1103 || (wns.exit_on_last_close.get()
1104 && !is_headless_app
1105 && !wns.windows.values().any(|w| matches!(w.ctx.mode(), WindowMode::Headed))
1106 && !wns
1107 .open_requests
1108 .iter()
1109 .any(|w| matches!(w.force_headless, None | Some(WindowMode::Headed)))
1110 && !wns.open_tasks.iter().any(|t| matches!(t.mode, WindowMode::Headed)))
1111 {
1112 APP.exit();
1114 }
1115 } else if let Some(args) = EXIT_REQUESTED_EVENT.on(update) {
1116 if !args.propagation().is_stopped() {
1117 let mut windows = WINDOWS_SV.write();
1118 if !windows.windows_info.is_empty() {
1119 args.propagation().stop();
1120 windows.exit_on_close = true;
1121 drop(windows);
1122 WINDOWS.close_all();
1123 }
1124 }
1125 }
1126 }
1127
1128 pub(super) fn on_ui_update(update_widgets: &mut WidgetUpdates) {
1129 if update_widgets.delivery_list_mut().has_pending_search() {
1130 update_widgets
1131 .delivery_list_mut()
1132 .fulfill_search(WINDOWS_SV.read().windows_info.values().map(|w| &w.widget_tree));
1133 }
1134
1135 Self::with_detached_windows(|windows, parallel| {
1136 if windows.len() > 1 && parallel.contains(ParallelWin::UPDATE) {
1137 windows.par_iter_mut().with_ctx().for_each(|(_, window)| {
1138 window.update(update_widgets);
1139 });
1140 } else {
1141 for (_, window) in windows.iter_mut() {
1142 window.update(update_widgets);
1143 }
1144 }
1145 });
1146 }
1147
1148 pub(super) fn on_update() {
1149 Self::fulfill_requests();
1150 }
1151
1152 fn fulfill_requests() {
1153 if VIEW_PROCESS.is_available() && !VIEW_PROCESS.is_online() {
1154 return;
1156 }
1157
1158 let ((open, mut open_tasks, close, focus, bring_to_top, view_tasks), colors_cfg) = {
1159 let mut wns = WINDOWS_SV.write();
1160 (wns.take_requests(), wns.latest_colors_cfg)
1161 };
1162
1163 let window_mode = zng_app::APP.window_mode();
1164
1165 for r in open {
1167 let window_mode = match (window_mode, r.force_headless) {
1168 (WindowMode::Headed | WindowMode::HeadlessWithRenderer, Some(mode)) => {
1169 debug_assert!(!matches!(mode, WindowMode::Headed));
1170 mode
1171 }
1172 (mode, _) => mode,
1173 };
1174
1175 let colors_cfg = match window_mode {
1176 WindowMode::Headed => colors_cfg,
1177 WindowMode::Headless | WindowMode::HeadlessWithRenderer => ColorsConfig::default(),
1178 };
1179
1180 let task = AppWindowTask::new(r.id, window_mode, colors_cfg, r.new.into_inner(), r.responder);
1181 open_tasks.push(task);
1182 }
1183
1184 let mut any_ready = false;
1186 for task in &mut open_tasks {
1187 let ready = task.update();
1188 any_ready |= ready;
1189 }
1190 if any_ready {
1191 for mut task in open_tasks {
1192 if task.is_ready() {
1193 let window_id = task.ctx.id();
1194
1195 let mut wns = WINDOWS_SV.write();
1196 let loading = wns.open_loading.remove(&window_id).unwrap();
1197 let mut root_extenders = mem::take(&mut wns.root_extenders);
1198 let mut open_nested_handlers = mem::take(&mut wns.open_nested_handlers);
1199 drop(wns);
1200 let (window, info, responder) =
1201 task.finish(loading, &mut root_extenders.get_mut()[..], &mut open_nested_handlers.get_mut()[..]);
1202
1203 let mut wns = WINDOWS_SV.write();
1204 root_extenders.get_mut().append(wns.root_extenders.get_mut());
1205 open_nested_handlers.get_mut().append(wns.open_nested_handlers.get_mut());
1206 wns.root_extenders = root_extenders;
1207 wns.open_nested_handlers = open_nested_handlers;
1208
1209 if wns.windows.insert(window_id, window).is_some() {
1210 unreachable!();
1212 }
1213 wns.windows_info.insert(info.id, info);
1214
1215 responder.respond(window_id);
1216 } else {
1219 let mut wns = WINDOWS_SV.write();
1220 wns.open_tasks.push(task);
1221 }
1222 }
1223 } else {
1224 let mut wns = WINDOWS_SV.write();
1225 debug_assert!(wns.open_tasks.is_empty());
1226 wns.open_tasks = open_tasks;
1227 }
1228
1229 {
1233 let mut wns = WINDOWS_SV.write();
1234 let wns = &mut *wns;
1235
1236 let mut close_wns = IdSet::default();
1237
1238 for r in close {
1239 for w in r.windows {
1240 if let Some(info) = wns.windows_info.get(&w) {
1241 if close_wns.insert(w) {
1242 wns.close_responders
1243 .entry(w)
1244 .or_insert_with(Default::default)
1245 .push(r.responder.clone());
1246
1247 info.vars.0.children.with(|c| {
1248 for &c in c.iter() {
1249 if wns.windows_info.contains_key(&c) && close_wns.insert(c) {
1250 wns.close_responders
1251 .entry(c)
1252 .or_insert_with(Default::default)
1253 .push(r.responder.clone());
1254 }
1255 }
1256 });
1257 }
1258 }
1259 }
1260 }
1261 if !close_wns.is_empty() {
1262 let args = WindowCloseRequestedArgs::now(close_wns);
1263 WINDOW_CLOSE_REQUESTED_EVENT.notify(args);
1264 }
1265 }
1266
1267 if let Some(w_id) = focus {
1269 Self::with_detached_windows(|windows, _| {
1270 if let Some(w) = windows.get_mut(&w_id) {
1271 w.focus();
1272 }
1273 });
1274 }
1275
1276 for w_id in bring_to_top {
1277 Self::with_detached_windows(|windows, _| {
1278 if let Some(w) = windows.get_mut(&w_id) {
1279 w.bring_to_top();
1280 }
1281 });
1282 }
1283
1284 for view_task in view_tasks {
1285 let task = view_task.task.into_inner();
1286 Self::with_detached_windows(|windows, _| {
1287 if let Some(w) = windows.get_mut(&view_task.window_id) {
1288 w.view_task(task);
1289 } else {
1290 task(None);
1291 }
1292 })
1293 }
1294 }
1295
1296 pub(super) fn on_info(info_widgets: &mut InfoUpdates) {
1297 if info_widgets.delivery_list_mut().has_pending_search() {
1298 info_widgets
1299 .delivery_list_mut()
1300 .fulfill_search(WINDOWS_SV.read().windows_info.values().map(|w| &w.widget_tree));
1301 }
1302
1303 let info_widgets_arc = Arc::new(mem::take(info_widgets));
1304
1305 Self::with_detached_windows(|windows, parallel| {
1306 if windows.len() > 1 && parallel.contains(ParallelWin::LAYOUT) {
1307 windows.par_iter_mut().with_ctx().for_each(|(_, window)| {
1308 window.info(info_widgets_arc.clone());
1309 })
1310 } else {
1311 for (_, window) in windows.iter_mut() {
1312 window.info(info_widgets_arc.clone());
1313 }
1314 }
1315 });
1316
1317 match Arc::try_unwrap(info_widgets_arc) {
1318 Ok(w) => {
1319 *info_widgets = w;
1320 }
1321 Err(_) => {
1322 tracing::error!("info_widgets not released by window")
1323 }
1324 }
1325 }
1326
1327 pub(super) fn on_layout(layout_widgets: &mut LayoutUpdates) {
1328 if layout_widgets.delivery_list_mut().has_pending_search() {
1329 layout_widgets
1330 .delivery_list_mut()
1331 .fulfill_search(WINDOWS_SV.read().windows_info.values().map(|w| &w.widget_tree));
1332 }
1333
1334 let layout_widgets_arc = Arc::new(mem::take(layout_widgets));
1335
1336 Self::with_detached_windows(|windows, parallel| {
1337 if windows.len() > 1 && parallel.contains(ParallelWin::LAYOUT) {
1338 windows.par_iter_mut().with_ctx().for_each(|(_, window)| {
1339 window.layout(layout_widgets_arc.clone());
1340 })
1341 } else {
1342 for (_, window) in windows.iter_mut() {
1343 window.layout(layout_widgets_arc.clone());
1344 }
1345 }
1346 });
1347
1348 match Arc::try_unwrap(layout_widgets_arc) {
1349 Ok(w) => {
1350 *layout_widgets = w;
1351 }
1352 Err(_) => {
1353 tracing::debug!("layout_widgets not released by window")
1355 }
1356 }
1357 }
1358
1359 pub(super) fn on_render(render_widgets: &mut RenderUpdates, render_update_widgets: &mut RenderUpdates) {
1360 for list in [&mut *render_widgets, &mut *render_update_widgets] {
1361 if list.delivery_list_mut().has_pending_search() {
1362 list.delivery_list_mut()
1363 .fulfill_search(WINDOWS_SV.read().windows_info.values().map(|w| &w.widget_tree));
1364 }
1365 }
1366
1367 let render_widgets_arc = Arc::new(mem::take(render_widgets));
1368 let render_update_widgets_arc = Arc::new(mem::take(render_update_widgets));
1369
1370 Self::with_detached_windows(|windows, parallel| {
1371 if windows.len() > 1 && parallel.contains(ParallelWin::RENDER) {
1372 windows.par_iter_mut().with_ctx().for_each(|(_, window)| {
1373 window.render(render_widgets_arc.clone(), render_update_widgets_arc.clone());
1374 });
1375 } else {
1376 for (_, window) in windows.iter_mut() {
1377 window.render(render_widgets_arc.clone(), render_update_widgets_arc.clone());
1378 }
1379 }
1380 });
1381
1382 match Arc::try_unwrap(render_widgets_arc) {
1383 Ok(w) => {
1384 *render_widgets = w;
1385 }
1386 Err(_) => {
1387 tracing::debug!("render_widgets not released by window")
1389 }
1390 }
1391 match Arc::try_unwrap(render_update_widgets_arc) {
1392 Ok(w) => {
1393 *render_update_widgets = w;
1394 }
1395 Err(_) => {
1396 tracing::debug!("render_update_widgets not released by window")
1398 }
1399 }
1400 }
1401
1402 fn with_detached_windows(f: impl FnOnce(&mut IdMap<WindowId, AppWindow>, ParallelWin)) {
1407 let (mut windows, parallel) = {
1408 let mut w = WINDOWS_SV.write();
1409 (mem::take(&mut w.windows), w.parallel.get())
1410 };
1411 f(&mut windows, parallel);
1412 let mut wns = WINDOWS_SV.write();
1413 debug_assert!(wns.windows.is_empty());
1414 wns.windows = windows;
1415 }
1416}
1417
1418impl WINDOWS {
1420 pub fn native_message_dialog(
1427 &self,
1428 window_id: WindowId,
1429 dialog: zng_view_api::dialog::MsgDialog,
1430 ) -> ResponseVar<zng_view_api::dialog::MsgDialogResponse> {
1431 let (responder, rsp) = response_var();
1432 WINDOWS_SV.write().view_window_task(window_id, move |win| match win {
1433 Some(win) => {
1434 if let Err(e) = win.message_dialog(dialog, responder.clone()) {
1435 responder.respond(zng_view_api::dialog::MsgDialogResponse::Error(formatx!("{e}")))
1436 }
1437 }
1438 None => responder.respond(zng_view_api::dialog::MsgDialogResponse::Error(Txt::from_static(
1439 "native window not found",
1440 ))),
1441 });
1442 rsp
1443 }
1444
1445 pub fn native_file_dialog(
1452 &self,
1453 window_id: WindowId,
1454 dialog: zng_view_api::dialog::FileDialog,
1455 ) -> ResponseVar<zng_view_api::dialog::FileDialogResponse> {
1456 let (responder, rsp) = response_var();
1457 WINDOWS_SV.write().view_window_task(window_id, move |win| match win {
1458 Some(win) => {
1459 if let Err(e) = win.file_dialog(dialog, responder.clone()) {
1460 responder.respond(zng_view_api::dialog::FileDialogResponse::Error(formatx!("{e}")))
1461 }
1462 }
1463 None => responder.respond(zng_view_api::dialog::FileDialogResponse::Error(Txt::from_static(
1464 "native window not found",
1465 ))),
1466 });
1467 rsp
1468 }
1469}
1470
1471#[allow(non_camel_case_types)]
1473pub struct WINDOWS_DRAG_DROP;
1474impl WINDOWS_DRAG_DROP {
1475 pub fn start_drag_drop(
1477 &self,
1478 window_id: WindowId,
1479 data: Vec<DragDropData>,
1480 allowed_effects: DragDropEffect,
1481 ) -> Result<DragDropId, DragDropError> {
1482 match WINDOWS_SV.write().windows.get_mut(&window_id) {
1483 Some(w) => w.start_drag_drop(data, allowed_effects),
1484 None => Err(DragDropError::CannotStart(WindowNotFound(window_id).to_txt())),
1485 }
1486 }
1487
1488 pub fn drag_dropped(&self, window_id: WindowId, drop_id: DragDropId, applied: DragDropEffect) -> Result<(), WindowNotFound> {
1490 match WINDOWS_SV.write().windows.get_mut(&window_id) {
1491 Some(w) => {
1492 w.drag_dropped(drop_id, applied);
1493 Ok(())
1494 }
1495 None => Err(WindowNotFound(window_id)),
1496 }
1497 }
1498}
1499
1500struct AppWindowInfo {
1502 id: WindowId,
1503 mode: WindowMode,
1504 view: Option<ViewWindowOrHeadless>,
1505 extensions: Vec<(ApiExtensionId, ApiExtensionPayload)>,
1506 vars: WindowVars,
1507
1508 widget_tree: WidgetInfoTree,
1509 is_focused: bool,
1511
1512 loading_handle: WindowLoading,
1513 is_loaded: bool,
1514}
1515impl AppWindowInfo {
1516 pub fn new(id: WindowId, root_id: WidgetId, mode: WindowMode, vars: WindowVars, loading_handle: WindowLoading) -> Self {
1517 Self {
1518 id,
1519 mode,
1520 view: None,
1521 extensions: vec![],
1522 vars,
1523 widget_tree: WidgetInfoTree::wgt(id, root_id),
1524 is_focused: false,
1525 loading_handle,
1526 is_loaded: false,
1527 }
1528 }
1529}
1530struct OpenWindowRequest {
1531 id: WindowId,
1532 new: Mutex<UiTask<WindowRoot>>, force_headless: Option<WindowMode>,
1534 responder: ResponderVar<WindowId>,
1535}
1536struct CloseWindowRequest {
1537 responder: ResponderVar<CloseWindowResult>,
1538 windows: IdSet<WindowId>,
1539}
1540
1541struct AppWindowTask {
1542 ctx: WindowCtx,
1543 mode: WindowMode,
1544 task: Mutex<UiTask<WindowRoot>>, responder: ResponderVar<WindowId>,
1546}
1547impl AppWindowTask {
1548 fn new(id: WindowId, mode: WindowMode, colors_cfg: ColorsConfig, new: UiTask<WindowRoot>, responder: ResponderVar<WindowId>) -> Self {
1549 let primary_scale_factor = match mode {
1550 WindowMode::Headed => MONITORS
1551 .primary_monitor()
1552 .map(|m| m.scale_factor().get())
1553 .unwrap_or_else(|| 1.fct()),
1554 WindowMode::Headless | WindowMode::HeadlessWithRenderer => 1.fct(),
1555 };
1556
1557 let mut ctx = WindowCtx::new(id, mode);
1558
1559 let vars = WindowVars::new(WINDOWS_SV.read().default_render_mode.get(), primary_scale_factor, colors_cfg);
1560 ctx.with_state(|s| s.borrow_mut().set(*WINDOW_VARS_ID, vars.clone()));
1561
1562 Self {
1563 ctx,
1564 mode,
1565 responder,
1566 task: Mutex::new(new),
1567 }
1568 }
1569
1570 fn is_ready(&mut self) -> bool {
1571 self.task.get_mut().is_ready()
1572 }
1573
1574 fn update(&mut self) -> bool {
1575 WINDOW.with_context(&mut self.ctx, || {
1576 self.task.get_mut().update();
1577 });
1578 self.task.get_mut().is_ready()
1579 }
1580
1581 fn finish(
1582 self,
1583 loading: WindowLoading,
1584 extenders: &mut [Box<dyn FnMut(WindowRootExtenderArgs) -> BoxedUiNode + Send>],
1585 open_nested_handlers: &mut [Box<dyn FnMut(&mut crate::OpenNestedHandlerArgs) + Send>],
1586 ) -> (AppWindow, AppWindowInfo, ResponderVar<WindowId>) {
1587 let mut window = self.task.into_inner().into_result().unwrap_or_else(|_| panic!());
1588 let mut ctx = self.ctx;
1589
1590 WINDOW.with_context(&mut ctx, || {
1591 for ext in extenders.iter_mut().rev() {
1592 let root = mem::replace(&mut window.child, NilUiNode.boxed());
1593 window.child = ext(WindowRootExtenderArgs { root });
1594 }
1595 let child = mem::replace(&mut window.child, NilUiNode.boxed());
1596 let vars = WINDOW.vars();
1597 let child = with_context_var(child, ACCENT_COLOR_VAR, vars.actual_accent_color());
1598 let child = with_context_var(child, COLOR_SCHEME_VAR, vars.actual_color_scheme());
1599 window.child = child.boxed();
1600 });
1601
1602 let mode = self.mode;
1603 let id = ctx.id();
1604
1605 ctx.set_widget_tree(WidgetInfoTree::wgt(id, window.id));
1606
1607 let vars = ctx.with_state(|s| s.borrow().get_clone(*WINDOW_VARS_ID)).unwrap();
1608
1609 if window.kiosk {
1610 vars.chrome().set(false);
1611 vars.visible().set(true);
1612 if !vars.state().get().is_fullscreen() {
1613 vars.state().set(WindowState::Exclusive);
1614 }
1615 }
1616
1617 let commands = WindowCommands::new(id);
1618
1619 let root_id = window.id;
1620
1621 let mut args = crate::OpenNestedHandlerArgs::new(ctx, vars.clone(), commands, window);
1622 for h in open_nested_handlers.iter_mut().rev() {
1623 h(&mut args);
1624 if args.has_nested() {
1625 break;
1626 }
1627 }
1628
1629 let (ctx, ctrl) = match args.take_normal() {
1630 Ok((ctx, vars, commands, window)) => (ctx, WindowCtrl::new(&vars, commands, mode, window)),
1631 Err((ctx, node)) => (ctx, WindowCtrl::new_nested(node)),
1632 };
1633
1634 let window = AppWindow {
1635 ctrl: Mutex::new(ctrl),
1636 ctx,
1637 };
1638 let info = AppWindowInfo::new(id, root_id, mode, vars, loading);
1639
1640 (window, info, self.responder)
1641 }
1642}
1643
1644struct ViewWindowTask {
1645 window_id: WindowId,
1646 task: Mutex<Box<dyn FnOnce(Option<&view_process::ViewWindow>) + Send>>, }
1648
1649struct AppWindow {
1651 ctrl: Mutex<WindowCtrl>, ctx: WindowCtx,
1653}
1654impl AppWindow {
1655 fn ctrl_in_ctx<R>(&mut self, action: impl FnOnce(&mut WindowCtrl) -> R) -> R {
1656 WINDOW.with_context(&mut self.ctx, || action(self.ctrl.get_mut()))
1657 }
1658
1659 pub fn pre_event(&mut self, update: &EventUpdate) {
1660 self.ctrl_in_ctx(|ctrl| ctrl.pre_event(update))
1661 }
1662
1663 pub fn ui_event(&mut self, update: &EventUpdate) {
1664 self.ctrl_in_ctx(|ctrl| ctrl.ui_event(update))
1665 }
1666
1667 pub fn update(&mut self, update_widgets: &WidgetUpdates) {
1668 self.ctrl_in_ctx(|ctrl| ctrl.update(update_widgets));
1669 }
1670
1671 pub fn info(&mut self, info_widgets: Arc<InfoUpdates>) {
1672 let info_update = self.ctrl_in_ctx(|ctrl| ctrl.info(info_widgets));
1673 if let Some(new) = info_update {
1674 self.ctx.set_widget_tree(new);
1675 }
1676 }
1677
1678 pub fn layout(&mut self, layout_widgets: Arc<LayoutUpdates>) {
1679 self.ctrl_in_ctx(|ctrl| ctrl.layout(layout_widgets));
1680 }
1681
1682 pub fn render(&mut self, render_widgets: Arc<RenderUpdates>, render_update_widgets: Arc<RenderUpdates>) {
1683 self.ctrl_in_ctx(|ctrl| ctrl.render(render_widgets, render_update_widgets));
1684 }
1685
1686 pub fn focus(&mut self) {
1687 self.ctrl_in_ctx(|ctrl| ctrl.focus());
1688 }
1689
1690 pub fn start_drag_drop(&mut self, data: Vec<DragDropData>, allowed_effects: DragDropEffect) -> Result<DragDropId, DragDropError> {
1691 self.ctrl_in_ctx(|ctx| ctx.start_drag_drop(data, allowed_effects))
1692 }
1693
1694 pub fn drag_dropped(&mut self, drop_id: DragDropId, applied: DragDropEffect) {
1695 self.ctrl_in_ctx(|ctx| ctx.drag_dropped(drop_id, applied))
1696 }
1697
1698 pub fn bring_to_top(&mut self) {
1699 self.ctrl_in_ctx(|ctrl| ctrl.bring_to_top());
1700 }
1701
1702 pub fn close(mut self) {
1703 self.ctrl_in_ctx(|ctrl| ctrl.close());
1704 }
1705
1706 fn view_task(&mut self, task: Box<dyn FnOnce(Option<&view_process::ViewWindow>) + Send>) {
1707 self.ctrl_in_ctx(|ctrl| ctrl.view_task(task));
1708 }
1709}
1710
1711struct WindowLoading {
1712 handles: Vec<std::sync::Weak<crate::WindowLoadingHandleData>>,
1713 timer: Option<DeadlineHandle>,
1714}
1715impl WindowLoading {
1716 pub fn new() -> Self {
1717 WindowLoading {
1718 handles: vec![],
1719 timer: None,
1720 }
1721 }
1722
1723 pub fn try_load(&mut self, window_id: WindowId) -> bool {
1725 let mut deadline = Deadline::MAX;
1726 self.handles.retain(|h| match h.upgrade() {
1727 Some(h) => {
1728 if h.deadline.has_elapsed() {
1729 false
1730 } else {
1731 deadline = deadline.min(h.deadline);
1732 true
1733 }
1734 }
1735 None => false,
1736 });
1737
1738 if self.handles.is_empty() {
1739 self.timer = None;
1740 true
1741 } else {
1742 if let Some(t) = &self.timer {
1743 if t.deadline() != deadline {
1744 self.timer = None;
1745 }
1746 }
1747 if self.timer.is_none() {
1748 let t = TIMERS.on_deadline(
1749 deadline,
1750 app_hn_once!(|_| {
1751 UPDATES.update_window(window_id).layout_window(window_id).render_window(window_id);
1752 }),
1753 );
1754 self.timer = Some(t);
1755 }
1756
1757 false
1758 }
1759 }
1760
1761 pub fn new_handle(&mut self, update: AppEventSender, deadline: Deadline) -> WindowLoadingHandle {
1762 let h = Arc::new(crate::WindowLoadingHandleData { update, deadline });
1763 self.handles.push(Arc::downgrade(&h));
1764 WindowLoadingHandle(h)
1765 }
1766}
1767
1768#[expect(non_camel_case_types)]
1772pub trait WINDOW_Ext {
1773 fn vars(&self) -> super::WindowVars {
1775 WindowVars::req()
1776 }
1777
1778 fn is_open(&self) -> bool {
1780 WINDOWS.is_open(WINDOW.id())
1781 }
1782
1783 fn is_loaded(&self) -> bool {
1785 WINDOWS.is_loaded(WINDOW.id())
1786 }
1787
1788 fn enable_access(&self) {
1792 let vars = WINDOW.vars();
1793 let access_enabled = &vars.0.access_enabled;
1794 if access_enabled.get().is_disabled() {
1795 access_enabled.modify(|e| *e.to_mut() |= zng_app::widget::info::access::AccessEnabled::APP);
1796 }
1797 }
1798
1799 fn loading_handle(&self, deadline: impl Into<Deadline>) -> Option<WindowLoadingHandle> {
1810 WINDOWS.loading_handle(WINDOW.id(), deadline)
1811 }
1812
1813 fn frame_image(&self, mask: Option<ImageMaskMode>) -> ImageVar {
1817 WINDOWS.frame_image(WINDOW.id(), mask)
1818 }
1819
1820 fn frame_image_rect(&self, rect: PxRect, mask: Option<ImageMaskMode>) -> ImageVar {
1826 WINDOWS.frame_image_rect(WINDOW.id(), rect, mask)
1827 }
1828
1829 fn bring_to_top(&self) {
1835 WINDOWS.bring_to_top(WINDOW.id()).ok();
1836 }
1837
1838 fn close(&self) -> ResponseVar<CloseWindowResult> {
1847 WINDOWS.close(WINDOW.id()).unwrap()
1848 }
1849}
1850impl WINDOW_Ext for WINDOW {}
1851
1852pub struct WindowRootExtenderArgs {
1856 pub root: BoxedUiNode,
1859}
1860
1861impl ImageRenderWindowRoot for WindowRoot {
1862 fn into_any(self: Box<Self>) -> Box<dyn Any> {
1863 self
1864 }
1865}
1866
1867#[doc(hidden)]
1868impl ImageRenderWindowsService for WINDOWS {
1869 fn new_window_root(&self, node: BoxedUiNode, render_mode: RenderMode, scale_factor: Option<Factor>) -> Box<dyn ImageRenderWindowRoot> {
1870 Box::new(WindowRoot::new_container(
1871 WidgetId::new_unique(),
1872 StartPosition::Default,
1873 false,
1874 true,
1875 Some(render_mode),
1876 scale_factor.map(HeadlessMonitor::new_scale).unwrap_or_default(),
1877 false,
1878 node,
1879 ))
1880 }
1881
1882 fn enable_frame_capture_in_window_context(&self, mask: Option<ImageMaskMode>) {
1883 let mode = if let Some(mask) = mask {
1884 FrameCaptureMode::AllMask(mask)
1885 } else {
1886 FrameCaptureMode::All
1887 };
1888 WINDOW.vars().frame_capture_mode().set(mode);
1889 }
1890
1891 fn set_parent_in_window_context(&self, parent_id: WindowId) {
1892 let vars = WINDOW.vars();
1893 vars.parent().set(parent_id);
1894 }
1895
1896 fn open_headless_window(&self, new_window_root: Box<dyn FnOnce() -> Box<dyn ImageRenderWindowRoot> + Send>) {
1897 WINDOWS.open_headless(
1898 async move {
1899 let w = *new_window_root()
1900 .into_any()
1901 .downcast::<WindowRoot>()
1902 .expect("expected `WindowRoot` in image render window");
1903 let vars = WINDOW.vars();
1904 vars.auto_size().set(true);
1905 vars.min_size().set((1.px(), 1.px()));
1906 w
1907 },
1908 true,
1909 );
1910 }
1911
1912 fn on_frame_image_ready(&self, update: &EventUpdate) -> Option<(WindowId, Img)> {
1913 if let Some(args) = FRAME_IMAGE_READY_EVENT.on(update) {
1914 if let Some(img) = &args.frame_image {
1915 return Some((args.window_id, img.clone()));
1916 }
1917 }
1918 None
1919 }
1920
1921 fn close_window(&self, window_id: WindowId) {
1922 let _ = WINDOWS.close(window_id);
1923 }
1924
1925 fn clone_boxed(&self) -> Box<dyn ImageRenderWindowsService> {
1926 Box::new(WINDOWS)
1927 }
1928}
1929
1930#[expect(non_camel_case_types)]
1932pub struct WINDOW_FOCUS;
1933impl WINDOW_FOCUS {
1934 pub fn hook_focus_service(&self, focused: BoxedVar<Option<InteractionPath>>) {
1938 *FOCUS_SV.write() = focused;
1939 }
1940
1941 pub(crate) fn focused(&self) -> BoxedVar<Option<InteractionPath>> {
1942 FOCUS_SV.get()
1943 }
1944}