1use std::{mem, sync::Arc};
4
5use parking_lot::Mutex;
6use zng_app::{
7 access::{ACCESS_DEINITED_EVENT, ACCESS_INITED_EVENT},
8 event::{AnyEventArgs, CommandHandle},
9 hn_once,
10 render::{FrameBuilder, FrameUpdate},
11 static_id,
12 timer::TIMERS,
13 update::{EventUpdate, InfoUpdates, LayoutUpdates, RenderUpdates, UPDATES, WidgetUpdates},
14 view_process::{
15 VIEW_PROCESS, VIEW_PROCESS_INITED_EVENT, ViewHeadless, ViewRenderer, ViewWindow,
16 raw_events::{
17 RAW_COLORS_CONFIG_CHANGED_EVENT, RAW_HEADLESS_OPEN_EVENT, RAW_IME_EVENT, RAW_WINDOW_CHANGED_EVENT, RAW_WINDOW_FOCUS_EVENT,
18 RAW_WINDOW_OPEN_EVENT, RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT, RawWindowFocusArgs,
19 },
20 },
21 widget::{
22 VarLayout, WIDGET, WidgetCtx, WidgetId, WidgetUpdateMode,
23 info::{WidgetInfoBuilder, WidgetInfoTree, WidgetLayout, WidgetMeasure, WidgetPath, access::AccessEnabled},
24 node::{UiNode, UiNodeImpl, WidgetUiNodeImpl},
25 },
26 window::{WINDOW, WindowCtx, WindowId, WindowMode},
27};
28use zng_app_context::LocalContext;
29use zng_clone_move::clmv;
30use zng_color::{LightDark, Rgba, colors};
31use zng_layout::{
32 context::{DIRECTION_VAR, LAYOUT, LayoutMetrics, LayoutPassId},
33 unit::{
34 Dip, DipPoint, DipRect, DipSize, DipToPx, Factor, FactorUnits, Layout1d, Layout2d, Length, Px, PxConstraints, PxDensity, PxPoint,
35 PxRect, PxSize, PxToDip, PxVector, TimeUnits,
36 },
37};
38use zng_state_map::StateId;
39use zng_var::{Var, VarHandles};
40use zng_view_api::{
41 DragDropId, FocusResult, Ime,
42 config::{ColorScheme, FontAntiAliasing},
43 drag_drop::{DragDropData, DragDropEffect, DragDropError},
44 ipc::ViewChannelError,
45 window::{
46 EventCause, FrameCapture, FrameId, FrameRequest, FrameUpdateRequest, FrameWaitId, HeadlessRequest, RenderMode, WindowRequest,
47 WindowState, WindowStateAll,
48 },
49};
50use zng_wgt::prelude::WidgetInfo;
51
52use crate::{
53 AutoSize, HeadlessMonitor, MONITORS, MONITORS_CHANGED_EVENT, MonitorInfo, StartPosition, WINDOW_CHANGED_EVENT, WINDOW_Ext,
54 WINDOW_FOCUS, WINDOWS, WINDOWS_DRAG_DROP, WidgetInfoImeArea, WindowChangedArgs, WindowRoot, WindowVars,
55 cmd::{MINIMIZE_CMD, RESTORE_CMD, WindowCommands},
56};
57
58#[cfg(feature = "image")]
59use zng_app::{Deadline, view_process::raw_events::RAW_FRAME_RENDERED_EVENT};
60
61#[cfg(feature = "image")]
62use zng_ext_image::{IMAGES, ImageRenderArgs, ImageSource, ImageVar, Img};
63
64#[cfg(feature = "image")]
65use crate::{FRAME_IMAGE_READY_EVENT, FrameCaptureMode, FrameImageReadyArgs};
66
67#[cfg(feature = "image")]
68use zng_var::VarHandle;
69
70#[cfg(feature = "image")]
71use crate::WindowIcon;
72
73#[cfg(feature = "image")]
74struct ImageResources {
75 icon_var: Option<ImageVar>,
76 cursor_var: Option<ImageVar>,
77 icon_binding: VarHandle,
78 cursor_binding: VarHandle,
79 deadline: Deadline,
80}
81#[cfg(feature = "image")]
82impl Default for ImageResources {
83 fn default() -> Self {
84 Self {
85 icon_var: None,
86 cursor_var: None,
87 icon_binding: VarHandle::dummy(),
88 cursor_binding: VarHandle::dummy(),
89 deadline: Deadline::timeout(1.secs()),
90 }
91 }
92}
93
94struct ImeInfo {
95 target: WidgetPath,
96 has_preview: bool,
97 area: DipRect,
98}
99
100struct HeadedCtrl {
102 window: Option<ViewWindow>,
103 waiting_view: bool,
104 delayed_view_updates: Vec<Box<dyn FnOnce(&ViewWindow) + Send>>,
105 vars: WindowVars,
106 respawned: bool,
107
108 content: ContentCtrl,
109
110 start_position: StartPosition,
112 start_focused: bool,
113 kiosk: Option<WindowState>, transparent: bool,
115 render_mode: Option<RenderMode>,
116
117 state: Option<WindowStateAll>, monitor: Option<MonitorInfo>,
120 resize_wait_id: Option<FrameWaitId>,
121 #[cfg(feature = "image")]
122 img_res: ImageResources,
123 actual_state: Option<WindowState>, parent_color_scheme: Option<Var<ColorScheme>>,
125 parent_accent_color: Option<Var<LightDark>>,
126 actual_parent: Option<WindowId>,
127 root_font_size: Dip,
128 render_access_update: Option<WidgetInfoTree>, ime_info: Option<ImeInfo>,
130 cancel_ime_handle: CommandHandle,
131 open_title_menu_handle: CommandHandle,
132 drag_move_handle: CommandHandle,
133}
134impl HeadedCtrl {
135 pub fn new(vars: &WindowVars, commands: WindowCommands, content: WindowRoot) -> Self {
136 Self {
137 window: None,
138 waiting_view: false,
139 delayed_view_updates: vec![],
140
141 start_position: content.start_position,
142 start_focused: content.start_focused,
143 kiosk: if content.kiosk { Some(WindowState::Fullscreen) } else { None },
144 transparent: content.transparent,
145 render_mode: content.render_mode,
146
147 content: ContentCtrl::new(vars.clone(), commands, content),
148 vars: vars.clone(),
149 respawned: false,
150
151 state: None,
152 monitor: None,
153 resize_wait_id: None,
154 #[cfg(feature = "image")]
155 img_res: ImageResources::default(),
156 parent_color_scheme: None,
157 parent_accent_color: None,
158 actual_parent: None,
159 actual_state: None,
160 root_font_size: Dip::from_px(Length::pt_to_px(11.0, 1.fct()), 1.fct()),
161 render_access_update: None,
162 ime_info: None,
163 cancel_ime_handle: CommandHandle::dummy(),
164 open_title_menu_handle: CommandHandle::dummy(),
165 drag_move_handle: CommandHandle::dummy(),
166 }
167 }
168
169 fn update_gen(&mut self, update: impl FnOnce(&ViewWindow) + Send + 'static) {
170 if let Some(view) = &self.window {
171 update(view);
173 } else if self.waiting_view {
174 self.delayed_view_updates.push(Box::new(update));
177 } else {
178 }
180 }
181
182 pub fn update(&mut self, update_widgets: &WidgetUpdates) {
183 if self.window.is_none() && !self.waiting_view {
184 UPDATES.layout_window(WINDOW.id());
186
187 if let Some(enforced_fullscreen) = self.kiosk {
188 if !self.vars.state().get().is_fullscreen() {
191 self.vars.state().set(enforced_fullscreen);
192 }
193 }
194 }
195
196 if let Some(query) = self.vars.monitor().get_new() {
197 if self.monitor.is_none() {
198 let monitor = query.select_fallback();
199 let scale_factor = monitor.scale_factor().get();
200 self.vars.0.scale_factor.set(scale_factor);
201 self.monitor = Some(monitor);
202 UPDATES.layout_window(WINDOW.id());
203 } else if let Some(new) = query.select() {
204 let current = self.vars.0.actual_monitor.get();
205 if Some(new.id()) != current {
206 let scale_factor = new.scale_factor().get();
207 self.vars.0.scale_factor.set(scale_factor);
208 self.vars.0.actual_monitor.set(new.id());
209 self.monitor = Some(new);
210 UPDATES.layout_window(WINDOW.id());
211 }
212 }
213 }
214 if let Some(prev_state) = self.state.clone() {
215 debug_assert!(self.window.is_some() || self.waiting_view || self.respawned);
216
217 let mut new_state = prev_state.clone();
218
219 if self.vars.chrome().is_new() || WINDOWS.system_chrome().is_new() {
220 let mut chrome = self.vars.chrome().get();
221
222 if self.kiosk.is_some() && !chrome {
223 tracing::error!("window in `kiosk` mode can not show chrome");
224 chrome = false;
225 }
226
227 new_state.chrome_visible = chrome && !WINDOWS.system_chrome().get().needs_custom();
228 }
229
230 if let Some(mut req_state) = self.vars.state().get_new() {
231 if let Some(enforced_fullscreen) = &mut self.kiosk {
232 if !req_state.is_fullscreen() {
233 tracing::error!("window in `kiosk` mode can only be fullscreen");
234
235 req_state = *enforced_fullscreen;
236 } else {
237 *enforced_fullscreen = req_state;
238 }
239 }
240
241 new_state.set_state(req_state);
242 self.vars.0.restore_state.set(new_state.restore_state);
243 }
244
245 if (self.vars.min_size().is_new() || self.vars.max_size().is_new())
246 && let Some(m) = &self.monitor
247 {
248 let scale_factor = m.scale_factor().get();
249 let screen_density = m.density().get();
250 let screen_size = m.size().get();
251 let (min_size, max_size) = self.content.outer_layout(scale_factor, screen_density, screen_size, || {
252 let min_size = self.vars.min_size().layout_dft(default_min_size(scale_factor));
253 let max_size = self.vars.max_size().layout_dft(screen_size);
254
255 (min_size.to_dip(scale_factor), max_size.to_dip(scale_factor))
256 });
257
258 let size = new_state.restore_rect.size;
259
260 new_state.restore_rect.size = size.min(max_size).max(min_size);
261 new_state.min_size = min_size;
262 new_state.max_size = max_size;
263 }
264
265 if let Some(auto) = self.vars.auto_size().get_new()
266 && auto != AutoSize::DISABLED
267 {
268 UPDATES.layout_window(WINDOW.id());
269 }
270
271 if self.vars.size().is_new() {
272 let auto_size = self.vars.auto_size().get();
273
274 if auto_size != AutoSize::CONTENT
275 && let Some(m) = &self.monitor
276 {
277 let scale_factor = m.scale_factor().get();
278 let screen_density = m.density().get();
279 let screen_size = m.size().get();
280 let size = self.content.outer_layout(scale_factor, screen_density, screen_size, || {
281 self.vars.size().layout_dft(default_size(scale_factor)).to_dip(scale_factor)
282 });
283
284 let size = size.min(new_state.max_size).max(new_state.min_size);
285
286 if !auto_size.contains(AutoSize::CONTENT_WIDTH) {
287 new_state.restore_rect.size.width = size.width;
288 }
289 if !auto_size.contains(AutoSize::CONTENT_HEIGHT) {
290 new_state.restore_rect.size.height = size.height;
291 }
292 }
293 }
294
295 if let Some(pos) = self.vars.position().get_new()
296 && let Some(m) = &self.monitor
297 {
298 let scale_factor = m.scale_factor().get();
299 let screen_density = m.density().get();
300 let screen_size = m.size().get();
301 let pos = self.content.outer_layout(scale_factor, screen_density, screen_size, || {
302 pos.layout_dft(PxPoint::new(Px(50), Px(50)))
303 });
304 new_state.restore_rect.origin = pos.to_dip(scale_factor);
305 }
306
307 if let Some(mut visible) = self.vars.visible().get_new() {
308 if !visible && self.kiosk.is_some() {
309 tracing::error!("window in `kiosk` mode can not be hidden");
310 visible = true;
311 }
312
313 self.update_gen(move |view| {
314 let _: Ignore = view.set_visible(visible);
315 });
316 }
317
318 if let Some(movable) = self.vars.movable().get_new() {
319 self.update_gen(move |view| {
320 let _: Ignore = view.set_movable(movable);
321 });
322 }
323
324 if let Some(resizable) = self.vars.resizable().get_new() {
325 self.update_gen(move |view| {
326 let _: Ignore = view.set_resizable(resizable);
327 });
328 }
329
330 if let Some(buttons) = self.vars.enabled_buttons().get_new() {
331 self.update_gen(move |view| {
332 let _: Ignore = view.set_enabled_buttons(buttons);
333 })
334 }
335
336 if let Some(reason) = self.vars.system_shutdown_warn().get_new() {
337 self.update_gen(move |view| {
338 let _: Ignore = view.set_system_shutdown_warn(reason);
339 })
340 }
341
342 if prev_state != new_state {
343 self.update_gen(move |view| {
344 let _: Ignore = view.set_state(new_state);
345 })
346 }
347 }
348
349 if let Some(font_size) = self.vars.font_size().get_new()
350 && let Some(m) = &self.monitor
351 {
352 let scale_factor = m.scale_factor().get();
353 let screen_density = m.density().get();
354 let screen_size = m.size().get();
355 let mut font_size_px = self.content.outer_layout(scale_factor, screen_density, screen_size, || {
356 font_size.layout_dft_x(Length::pt_to_px(11.0, scale_factor))
357 });
358 if font_size_px < Px(0) {
359 tracing::error!("invalid font size {font_size:?} => {font_size_px:?}");
360 font_size_px = Length::pt_to_px(11.0, scale_factor);
361 }
362 let font_size_dip = font_size_px.to_dip(scale_factor);
363
364 if font_size_dip != self.root_font_size {
365 self.root_font_size = font_size_dip;
366 UPDATES.layout_window(WINDOW.id());
367 }
368 }
369
370 #[cfg(feature = "image")]
371 let mut img_res_loading = vec![];
372
373 #[cfg(feature = "image")]
375 let mut send_icon = false;
376 #[cfg(feature = "image")]
377 if let Some(ico) = self.vars.icon().get_new() {
378 self.img_res.icon_var = match ico {
379 WindowIcon::Default => None,
380 WindowIcon::Image(ImageSource::Render(ico, _)) => {
381 Some(IMAGES.cache(ImageSource::Render(ico.clone(), Some(ImageRenderArgs::new(WINDOW.id())))))
382 }
383 WindowIcon::Image(source) => Some(IMAGES.cache(source)),
384 };
385
386 if let Some(ico) = &self.img_res.icon_var {
387 self.img_res.icon_binding = ico.bind_map(&self.vars.0.actual_icon, |img| Some(img.clone()));
388
389 if ico.get().is_loading() && self.window.is_none() && !self.waiting_view {
390 img_res_loading.push(ico.clone());
391 }
392 } else {
393 self.vars.0.actual_icon.set(None);
394 self.img_res.icon_binding = VarHandle::dummy();
395 }
396
397 send_icon = true;
398 } else if self.img_res.icon_var.as_ref().map(|ico| ico.is_new()).unwrap_or(false) {
399 send_icon = true;
400 }
401 #[cfg(feature = "image")]
402 if send_icon {
403 let icon = self.img_res.icon_var.as_ref().and_then(|ico| ico.get().view().cloned());
404 self.update_gen(move |view| {
405 let _: Ignore = view.set_icon(icon.as_ref());
406 });
407 }
408
409 if let Some(cursor) = self.vars.cursor().get_new() {
411 match cursor {
412 crate::CursorSource::Icon(ico) => {
413 #[cfg(feature = "image")]
414 {
415 self.img_res.cursor_var = None;
416 }
417 self.update_gen(move |view| {
418 let _: Ignore = view.set_cursor(Some(ico));
419 #[cfg(feature = "image")]
420 let _: Ignore = view.set_cursor_image(None, PxPoint::zero());
421 });
422 }
423 #[cfg(feature = "image")]
424 crate::CursorSource::Img(img) => {
425 self.img_res.cursor_var = Some(match img.source {
426 ImageSource::Render(cur, _) => {
427 IMAGES.cache(ImageSource::Render(cur.clone(), Some(ImageRenderArgs::new(WINDOW.id()))))
428 }
429 source => IMAGES.cache(source),
430 });
431
432 self.update_gen(move |view| {
433 let _: Ignore = view.set_cursor(Some(img.fallback));
434 let _: Ignore = view.set_cursor_image(None, PxPoint::zero());
435 });
436 }
437 crate::CursorSource::Hidden => {
438 #[cfg(feature = "image")]
439 {
440 self.img_res.cursor_var = None;
441 }
442 self.update_gen(move |view| {
443 let _: Ignore = view.set_cursor(None);
444 #[cfg(feature = "image")]
445 let _: Ignore = view.set_cursor_image(None, PxPoint::zero());
446 });
447 }
448 }
449
450 #[cfg(feature = "image")]
451 if let Some(cur) = &self.img_res.cursor_var {
452 let hotspot = self.vars.cursor().with(|i| i.hotspot().cloned().unwrap_or_default());
453
454 let cursor_img_to_actual = move |img: &Img| -> Option<(Img, PxPoint)> {
455 let hotspot = if img.is_loaded() {
456 let mut metrics = LayoutMetrics::new(1.fct(), img.size(), Px(16));
457 if let Some(density) = img.density() {
458 metrics = metrics.with_screen_density(density.width);
459 }
460
461 LAYOUT.with_context(metrics, || hotspot.layout())
462 } else {
463 PxPoint::zero()
464 };
465
466 Some((img.clone(), hotspot))
467 };
468 self.vars.0.actual_cursor_img.set_from_map(cur, cursor_img_to_actual.clone());
469 self.img_res.cursor_binding = cur.bind_map(&self.vars.0.actual_cursor_img, cursor_img_to_actual);
470
471 if cur.get().is_loading() && self.window.is_none() && !self.waiting_view {
472 img_res_loading.push(cur.clone());
473 }
474 } else {
475 self.vars.0.actual_cursor_img.set(None);
476 self.img_res.cursor_binding = VarHandle::dummy();
477 }
478 }
479 #[cfg(feature = "image")]
480 if let Some(img_hotspot) = self.vars.0.actual_cursor_img.get_new() {
481 self.update_gen(move |view| match img_hotspot {
482 Some((img, hotspot)) => {
483 let _: Ignore = view.set_cursor_image(img.view(), hotspot);
484 }
485 None => {
486 let _: Ignore = view.set_cursor_image(None, PxPoint::zero());
487 }
488 })
489 }
490
491 #[cfg(feature = "image")]
493 if !img_res_loading.is_empty() {
494 if self.img_res.deadline.has_elapsed() {
495 UPDATES.layout_window(WINDOW.id());
496 } else {
497 let window_id = WINDOW.id();
498 TIMERS
499 .on_deadline(
500 self.img_res.deadline,
501 hn_once!(|_| {
502 if img_res_loading.iter().any(|i| i.get().is_loading()) {
503 UPDATES.layout_window(window_id);
505 }
506 }),
507 )
508 .perm();
509 }
510 }
511
512 if let Some(title) = self.vars.title().get_new() {
513 self.update_gen(move |view| {
514 let _: Ignore = view.set_title(title);
515 });
516 }
517
518 if let Some(mode) = self.vars.video_mode().get_new() {
519 self.update_gen(move |view| {
520 let _: Ignore = view.set_video_mode(mode);
521 });
522 }
523
524 if let Some(visible) = self.vars.taskbar_visible().get_new() {
525 self.update_gen(move |view| {
526 let _: Ignore = view.set_taskbar_visible(visible);
527 });
528 }
529
530 if let Some(top) = self.vars.always_on_top().get_new() {
531 self.update_gen(move |view| {
532 let _: Ignore = view.set_always_on_top(top);
533 });
534 }
535
536 #[cfg(feature = "image")]
537 if let Some(mode) = self.vars.frame_capture_mode().get_new() {
538 self.update_gen(move |view| {
539 let _: Ignore = view.set_capture_mode(matches!(mode, FrameCaptureMode::All));
540 });
541 }
542
543 if let Some(m) = &self.monitor {
544 if let Some(fct) = m.scale_factor().get_new() {
545 self.vars.0.scale_factor.set(fct);
546 }
547 if m.scale_factor().is_new() || m.size().is_new() || m.density().is_new() {
548 UPDATES.layout_window(WINDOW.id());
549 }
550 }
551
552 if let Some(indicator) = self.vars.focus_indicator().get_new() {
553 if WINDOWS.is_focused(WINDOW.id()).unwrap_or(false) {
554 self.vars.focus_indicator().set(None);
555 } else if let Some(view) = &self.window {
556 let _ = view.set_focus_indicator(indicator);
557 }
559 }
561
562 let mut update_colors = false;
563
564 if update_parent(&mut self.actual_parent, &self.vars) {
565 self.parent_color_scheme = self
566 .actual_parent
567 .and_then(|id| WINDOWS.vars(id).ok().map(|v| v.actual_color_scheme()));
568 self.parent_accent_color = self
569 .actual_parent
570 .and_then(|id| WINDOWS.vars(id).ok().map(|v| v.actual_accent_color()));
571 update_colors = true;
572 }
573
574 if update_colors || self.vars.color_scheme().is_new() || self.parent_color_scheme.as_ref().map(|t| t.is_new()).unwrap_or(false) {
575 let scheme = self
576 .vars
577 .color_scheme()
578 .get()
579 .or_else(|| self.parent_color_scheme.as_ref().map(|t| t.get()))
580 .unwrap_or_else(|| WINDOWS.system_colors_config().scheme);
581 self.vars.0.actual_color_scheme.set(scheme);
582 }
583 if update_colors || self.vars.accent_color().is_new() || self.parent_accent_color.as_ref().map(|t| t.is_new()).unwrap_or(false) {
584 let accent = self
585 .vars
586 .accent_color()
587 .get()
588 .or_else(|| self.parent_accent_color.as_ref().map(|t| t.get()))
589 .unwrap_or_else(|| WINDOWS.system_colors_config().accent.into());
590 self.vars.0.actual_accent_color.set(accent);
591 }
592
593 if self.vars.0.access_enabled.is_new() {
594 UPDATES.update_info_window(WINDOW.id());
595 } else if self.vars.0.access_enabled.get() == AccessEnabled::VIEW && WINDOW_FOCUS.focused().is_new() {
596 self.update_access_focused();
597 }
598
599 if super::IME_EVENT.has_subscribers() && WINDOW_FOCUS.focused().is_new() {
600 self.update_ime();
601 }
602
603 self.content.update(update_widgets);
604 }
605
606 pub fn pre_event(&mut self, update: &EventUpdate) {
607 if let Some(args) = RAW_WINDOW_CHANGED_EVENT.on(update) {
608 if args.window_id == WINDOW.id() {
609 let mut state_change = None;
610 let mut pos_change = None;
611 let mut size_change = None;
612
613 if let Some(monitor) = args.monitor
614 && self.vars.0.actual_monitor.get().map(|m| m != monitor).unwrap_or(true)
615 {
616 self.vars.0.actual_monitor.set(Some(monitor));
617 self.monitor = MONITORS.monitor(monitor);
618 if let Some(m) = &self.monitor {
619 let fct = m.scale_factor().get();
620 self.vars.0.scale_factor.set(fct);
621 }
622 UPDATES.layout_window(WINDOW.id());
623 }
624
625 if let Some(state) = args.state.clone() {
626 self.vars.state().set(state.state);
627 self.vars.0.restore_rect.set(state.restore_rect);
628 self.vars.0.restore_state.set(state.restore_state);
629
630 let new_state = state.state;
631 if self.actual_state != Some(new_state) {
632 let prev_state = self.actual_state.unwrap_or(WindowState::Normal);
633 state_change = Some((prev_state, new_state));
634 self.actual_state = Some(new_state);
635
636 match (prev_state, new_state) {
637 (_, WindowState::Minimized) => {
638 self.vars.0.children.with(|c| {
640 for &c in c.iter() {
641 MINIMIZE_CMD.scoped(c).notify();
642 }
643 });
644 }
645 (WindowState::Minimized, _) => {
646 self.vars.0.children.with(|c| {
648 for &c in c.iter() {
649 RESTORE_CMD.scoped(c).notify();
650 }
651 });
652
653 let w_id = WINDOW.id();
655 UPDATES.layout_window(w_id).render_window(w_id);
656 }
657 _ => {}
658 }
659 }
660
661 self.state = Some(state);
662 }
663
664 if let Some((global_pos, pos)) = args.position
665 && (self.vars.0.actual_position.get() != pos || self.vars.0.global_position.get() != global_pos)
666 {
667 self.vars.0.actual_position.set(pos);
668 self.vars.0.global_position.set(global_pos);
669 pos_change = Some((global_pos, pos));
670 }
671
672 if let Some(size) = args.size
673 && self.vars.0.actual_size.get() != size
674 {
675 self.vars.0.actual_size.set(size);
676 size_change = Some(size);
677
678 UPDATES.layout_window(WINDOW.id());
679
680 if args.cause == EventCause::System {
681 self.vars.auto_size().set(AutoSize::DISABLED);
683 }
684 }
685
686 if let Some(padding) = args.safe_padding {
687 self.vars.0.safe_padding.set(padding);
688 }
689
690 if let Some(id) = args.frame_wait_id {
691 self.resize_wait_id = Some(id);
692
693 UPDATES.render_update_window(WINDOW.id());
694 }
695
696 if state_change.is_some() || pos_change.is_some() || size_change.is_some() {
697 let args = WindowChangedArgs::new(
698 args.timestamp,
699 args.propagation().clone(),
700 args.window_id,
701 state_change,
702 pos_change,
703 size_change,
704 args.cause,
705 );
706 WINDOW_CHANGED_EVENT.notify(args);
707 }
708 } else if self.actual_state.unwrap_or(WindowState::Normal) == WindowState::Minimized
709 && args.state.as_ref().map(|s| s.state != WindowState::Minimized).unwrap_or(false)
710 && self.vars.0.children.with(|c| c.contains(&args.window_id))
711 {
712 RESTORE_CMD.scoped(WINDOW.id()).notify();
714 }
715 } else if let Some(args) = RAW_WINDOW_FOCUS_EVENT.on(update) {
716 if args.new_focus == Some(WINDOW.id()) {
717 self.vars.0.children.with(|c| {
718 for &c in c.iter() {
719 let _ = WINDOWS.bring_to_top(c);
720 }
721 });
722 } else if let Some(new_focus) = args.new_focus {
723 self.vars.0.children.with(|c| {
724 if c.contains(&new_focus) {
725 let _ = WINDOWS.bring_to_top(WINDOW.id());
726
727 for c in c.iter() {
728 if *c != new_focus {
729 let _ = WINDOWS.bring_to_top(WINDOW.id());
730 }
731 }
732
733 let _ = WINDOWS.bring_to_top(new_focus);
734 }
735 });
736 }
737 } else if let Some(args) = MONITORS_CHANGED_EVENT.on(update) {
738 if let Some(m) = &self.monitor
739 && args.removed.contains(&m.id())
740 {
741 self.monitor = None;
742 self.vars.0.actual_monitor.set(None);
743 }
744 self.vars.monitor().update();
745 } else if let Some(args) = RAW_WINDOW_OPEN_EVENT.on(update) {
746 if args.window_id == WINDOW.id() {
747 self.waiting_view = false;
748
749 WINDOWS.set_view(args.window_id, args.window.clone().into());
750
751 self.window = Some(args.window.clone());
752 self.cancel_ime_handle = super::cmd::CANCEL_IME_CMD.scoped(WINDOW.id()).subscribe(true);
753 self.open_title_menu_handle = super::cmd::OPEN_TITLE_BAR_CONTEXT_MENU_CMD.scoped(WINDOW.id()).subscribe(true);
754 self.drag_move_handle = super::cmd::DRAG_MOVE_RESIZE_CMD.scoped(WINDOW.id()).subscribe(true);
755
756 self.vars.0.render_mode.set(args.data.render_mode);
757 self.vars.state().set(args.data.state.state);
758 self.actual_state = Some(args.data.state.state);
759 self.vars.0.restore_state.set(args.data.state.restore_state);
760 self.vars.0.restore_rect.set(args.data.state.restore_rect);
761 self.vars.0.global_position.set(args.data.position.0);
762 self.vars.0.actual_position.set(args.data.position.1);
763 self.vars.0.actual_size.set(args.data.size);
764 self.vars.0.safe_padding.set(args.data.safe_padding);
765 self.vars.0.actual_monitor.set(args.data.monitor);
766 self.vars.0.scale_factor.set(args.data.scale_factor);
767
768 self.state = Some(args.data.state.clone());
769
770 let scheme = self
771 .vars
772 .color_scheme()
773 .get()
774 .or_else(|| self.parent_color_scheme.as_ref().map(|t| t.get()))
775 .unwrap_or_else(|| WINDOWS.system_colors_config().scheme);
776 self.vars.0.actual_color_scheme.set(scheme);
777 let accent = self
778 .vars
779 .accent_color()
780 .get()
781 .or_else(|| self.parent_accent_color.as_ref().map(|t| t.get()))
782 .unwrap_or_else(|| WINDOWS.system_colors_config().accent.into());
783 self.vars.0.actual_accent_color.set(accent);
784
785 UPDATES.layout_window(args.window_id).render_window(args.window_id);
786
787 for update in mem::take(&mut self.delayed_view_updates) {
788 update(&args.window);
789 }
790 }
791 } else if let Some(args) = RAW_COLORS_CONFIG_CHANGED_EVENT.on(update) {
792 let scheme = self
793 .vars
794 .color_scheme()
795 .get()
796 .or_else(|| self.parent_color_scheme.as_ref().map(|t| t.get()))
797 .unwrap_or(args.config.scheme);
798 self.vars.0.actual_color_scheme.set(scheme);
799 let color = self
800 .vars
801 .accent_color()
802 .get()
803 .or_else(|| self.parent_accent_color.as_ref().map(|t| t.get()))
804 .unwrap_or_else(|| args.config.accent.into());
805 self.vars.0.actual_accent_color.set(color);
806 } else if let Some(args) = RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT.on(update) {
807 let w_id = WINDOW.id();
808 if args.window_id == w_id && self.window.is_none() && self.waiting_view {
809 tracing::error!("view-process failed to open a window, {}", args.error);
810
811 self.waiting_view = false;
814 self.delayed_view_updates = vec![];
815 self.respawned = true;
816
817 UPDATES.layout_window(w_id).render_window(w_id);
818 }
819 } else if let Some(args) = RAW_IME_EVENT.on(update) {
820 let w_id = WINDOW.id();
821 if args.window_id == w_id {
822 match &args.ime {
823 Ime::Preview(s, c) => {
824 if let Some(info) = &mut self.ime_info {
825 info.has_preview = !s.is_empty();
826 let args = super::ImeArgs::now(info.target.clone(), s.clone(), *c);
827 super::IME_EVENT.notify(args);
828 }
829 }
830 Ime::Commit(s) => {
831 if let Some(info) = &mut self.ime_info {
832 info.has_preview = false;
833 let args = super::ImeArgs::now(info.target.clone(), s.clone(), None);
834 super::IME_EVENT.notify(args);
835 }
836 }
837 }
838 }
839 } else if let Some(args) = ACCESS_INITED_EVENT.on(update) {
840 if args.window_id == WINDOW.id() {
841 tracing::info!("accessibility info enabled in view for {:?}", args.window_id);
842 self.vars.0.access_enabled.set(AccessEnabled::VIEW);
843 }
844 } else if let Some(args) = ACCESS_DEINITED_EVENT.on(update) {
845 if args.window_id == WINDOW.id() {
846 tracing::info!("accessibility info disabled in view for {:?}", args.window_id);
847 self.vars.0.access_enabled.modify(|a| {
848 if a.is_enabled() {
849 **a = AccessEnabled::APP;
850 }
851 });
852 }
853 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update)
854 && self
855 .window
856 .as_ref()
857 .map(|w| w.renderer().generation() != Ok(args.generation))
858 .unwrap_or(args.is_respawn)
859 {
860 debug_assert!(args.is_respawn);
861
862 self.window = None;
863 self.cancel_ime_handle = CommandHandle::dummy();
864 self.open_title_menu_handle = CommandHandle::dummy();
865 self.drag_move_handle = CommandHandle::dummy();
866 self.waiting_view = false;
867 self.delayed_view_updates = vec![];
868 self.respawned = true;
869
870 let w_id = WINDOW.id();
871 UPDATES.layout_window(w_id).render_window(w_id);
872 }
873
874 self.content.pre_event(update);
875
876 if self.ime_info.is_some() && super::cmd::CANCEL_IME_CMD.scoped(WINDOW.id()).has(update) {
877 let prev = self.ime_info.take().unwrap();
878 if prev.has_preview {
879 let args = super::ImeArgs::now(prev.target, "", (0, 0));
880 super::IME_EVENT.notify(args);
881 }
882 if let Some(w) = &self.window {
883 let _ = w.set_ime_area(None);
884 }
885 } else if let Some(args) = super::cmd::DRAG_MOVE_RESIZE_CMD.scoped(WINDOW.id()).on(update) {
886 let r = args.handle_enabled(&self.drag_move_handle, |args| args.param::<crate::cmd::ResizeDirection>().copied());
887 if let Some(r) = r {
888 self.view_task(Box::new(move |w| {
889 let _ = if let Some(r) = r {
890 w.unwrap().drag_resize(r)
891 } else {
892 w.unwrap().drag_move()
893 };
894 }));
895 }
896 } else if let Some(args) = super::cmd::OPEN_TITLE_BAR_CONTEXT_MENU_CMD.scoped(WINDOW.id()).on(update) {
897 let pos = args.handle_enabled(&self.open_title_menu_handle, |args| {
898 if let Some(p) = args.param::<DipPoint>() {
899 *p
900 } else if let Some(p) = args.param::<PxPoint>() {
901 p.to_dip(self.vars.scale_factor().get())
902 } else {
903 DipPoint::splat(Dip::new(24))
904 }
905 });
906 if let Some(pos) = pos {
907 self.view_task(Box::new(move |w| {
908 let _ = w.unwrap().open_title_bar_context_menu(pos);
909 }));
910 }
911 };
912 }
913
914 pub fn ui_event(&mut self, update: &EventUpdate) {
915 self.content.ui_event(update);
916 }
917
918 #[must_use]
919 pub fn info(&mut self, info_widgets: Arc<InfoUpdates>) -> Option<WidgetInfoTree> {
920 let prev_tree = WINDOW.info();
921 let info = self.content.info(info_widgets);
922 if let Some(info) = &info
923 && self.window.is_some()
924 {
925 if info.access_enabled() == AccessEnabled::VIEW && self.render_access_update.is_none() {
927 self.render_access_update = Some(prev_tree);
929 UPDATES.render_window(WINDOW.id());
930 } else if self.ime_info.is_some() {
931 UPDATES.render_window(WINDOW.id());
932 }
933 }
934
935 info
936 }
937
938 fn accessible_focused(&self, info: &WidgetInfoTree) -> Option<WidgetId> {
939 if WINDOWS.is_focused(info.window_id()).unwrap_or(false) {
940 WINDOW_FOCUS.focused().with(|p| {
941 if let Some(p) = p
942 && p.window_id() == info.window_id()
943 && let Some(wgt) = info.get(p.widget_id())
944 && let Some(wgt) = wgt.access()
945 && wgt.is_accessible()
946 {
947 return Some(wgt.info().id());
949 }
950 None
951 })
952 } else {
953 None
954 }
955 }
956
957 fn update_access_focused(&mut self) {
958 if self.render_access_update.is_some() {
959 return;
961 }
962 if let Some(view) = &self.window {
963 let info = WINDOW.info();
964 if info.access_enabled().is_enabled() {
965 let _ = view.access_update(zng_view_api::access::AccessTreeUpdate::new(
966 vec![],
967 None,
968 self.accessible_focused(&info).unwrap_or(info.root().id()).into(),
969 ));
970 }
971 }
972 }
973
974 fn update_ime(&mut self) {
975 WINDOW_FOCUS.focused().with(|f| {
976 let mut ime_path = None;
977 if let Some(f) = f
978 && f.interactivity().is_enabled()
979 && f.window_id() == WINDOW.id()
980 && super::IME_EVENT.is_subscriber(f.widget_id())
981 {
982 ime_path = Some(f.as_path().clone());
983 }
984
985 if ime_path.as_ref() == self.ime_info.as_ref().map(|p| &p.target) {
986 return;
987 }
988
989 if let Some(p) = ime_path {
990 let info = WINDOW.info();
991 if let Some(w) = info.get(p.widget_id()) {
992 if let Some(prev) = self.ime_info.take()
993 && prev.has_preview
994 {
995 let args = super::ImeArgs::now(prev.target, "", (0, 0));
997 super::IME_EVENT.notify(args);
998 }
999
1000 self.ime_info = Some(ImeInfo {
1001 target: p.clone(),
1002 has_preview: false,
1003 area: DipRect::zero(),
1004 });
1005
1006 if let Some(win) = &self.window {
1007 let area = w.ime_area().to_dip(info.scale_factor());
1008 self.ime_info.as_mut().unwrap().area = area;
1009
1010 let _ = win.set_ime_area(None);
1013 let _ = win.set_ime_area(Some(area));
1014 }
1015 return;
1016 }
1017 }
1018
1019 if let Some(prev) = self.ime_info.take() {
1020 if let Some(w) = &self.window {
1021 let _ = w.set_ime_area(None);
1022 }
1023
1024 if prev.has_preview {
1025 let args = super::ImeArgs::now(prev.target, "", (0, 0));
1027 super::IME_EVENT.notify(args);
1028 }
1029 }
1030 });
1031 }
1032
1033 pub fn layout(&mut self, layout_widgets: Arc<LayoutUpdates>) {
1034 if !layout_widgets.delivery_list().enter_window(WINDOW.id()) {
1035 return;
1036 }
1037
1038 if self.window.is_some() {
1039 if matches!(self.state.as_ref().map(|s| s.state), Some(WindowState::Minimized)) {
1040 return;
1041 }
1042 self.layout_update(layout_widgets);
1043 } else if self.respawned && !self.waiting_view {
1044 self.layout_respawn();
1045 } else if !self.waiting_view {
1046 self.layout_init();
1047 }
1048 }
1049
1050 fn layout_init(&mut self) {
1052 #[cfg(feature = "image")]
1054 if self.img_res.deadline.has_elapsed() {
1055 if let Some(icon) = &self.img_res.icon_var
1056 && icon.get().is_loading()
1057 {
1058 return;
1059 }
1060 if let Some(cursor) = &self.img_res.cursor_var
1061 && cursor.get().is_loading()
1062 {
1063 return;
1064 }
1065 }
1066 if !WINDOWS.try_load(WINDOW.id()) {
1068 return;
1070 }
1071
1072 self.monitor = Some(self.vars.monitor().get().select_fallback());
1073 let m = self.monitor.as_ref().unwrap();
1074 self.vars.0.scale_factor.set(m.scale_factor().get());
1075
1076 let scale_factor = m.scale_factor().get();
1077 let screen_density = m.density().get();
1078 let screen_rect = m.px_rect();
1079
1080 let (min_size, max_size, mut size, root_font_size) =
1082 self.content.outer_layout(scale_factor, screen_density, screen_rect.size, || {
1083 let min_size = self.vars.min_size().layout_dft(default_min_size(scale_factor));
1084 let max_size = self.vars.max_size().layout_dft(screen_rect.size);
1085 let size = self.vars.size().layout_dft(default_size(scale_factor));
1086
1087 let font_size = self.vars.font_size().get();
1088 let mut root_font_size = font_size.layout_dft_x(Length::pt_to_px(11.0, scale_factor));
1089 if root_font_size < Px(0) {
1090 tracing::error!("invalid font size {font_size:?} => {root_font_size:?}");
1091 root_font_size = Length::pt_to_px(11.0, scale_factor);
1092 }
1093
1094 (min_size, max_size, size.min(max_size).max(min_size), root_font_size)
1095 });
1096
1097 self.root_font_size = root_font_size.to_dip(scale_factor);
1098
1099 let state = self.vars.state().get();
1100 if state == WindowState::Normal && self.vars.auto_size().get() != AutoSize::DISABLED {
1101 size = self.content.layout(
1103 Arc::default(),
1104 scale_factor,
1105 screen_density,
1106 min_size,
1107 max_size,
1108 size,
1109 root_font_size,
1110 false,
1111 );
1112 }
1113
1114 let mut system_pos = false;
1116 let position = match self.start_position {
1117 StartPosition::Default => {
1118 let pos = self.vars.position().get();
1119 if pos.x.is_default() || pos.y.is_default() {
1120 system_pos = true;
1121 screen_rect.origin + PxVector::splat(Px(40))
1122 } else {
1123 self.content.outer_layout(scale_factor, screen_density, screen_rect.size, || {
1124 pos.layout() + screen_rect.origin.to_vector()
1125 })
1126 }
1127 }
1128 StartPosition::CenterMonitor => {
1129 PxPoint::new(
1130 (screen_rect.size.width - size.width) / Px(2),
1131 (screen_rect.size.height - size.height) / Px(2),
1132 ) + screen_rect.origin.to_vector()
1133 }
1134 StartPosition::CenterParent => {
1135 let mut parent_rect = screen_rect;
1137
1138 if let Some(parent) = self.vars.parent().get()
1139 && let Ok(w) = WINDOWS.vars(parent)
1140 {
1141 let factor = w.scale_factor().get();
1142 let pos = w.actual_position().get().to_px(factor);
1143 let size = w.actual_size().get().to_px(factor);
1144
1145 parent_rect = PxRect::new(pos, size);
1146 }
1147
1148 PxPoint::new(
1149 (parent_rect.size.width - size.width) / Px(2),
1150 (parent_rect.size.height - size.height) / Px(2),
1151 ) + parent_rect.origin.to_vector()
1152 }
1153 };
1154
1155 let m_position = (position - screen_rect.origin.to_vector()).to_dip(scale_factor);
1158 let size = size.to_dip(scale_factor);
1159
1160 let state = WindowStateAll::new(
1161 state,
1162 position,
1163 DipRect::new(m_position, size),
1164 WindowState::Normal,
1165 min_size.to_dip(scale_factor),
1166 max_size.to_dip(scale_factor),
1167 self.vars.chrome().get() && !WINDOWS.system_chrome().get().needs_custom(),
1168 );
1169
1170 let window_id = WINDOW.id();
1171
1172 let request = WindowRequest::new(
1173 zng_view_api::window::WindowId::from_raw(window_id.get()),
1174 self.vars.title().get(),
1175 state.clone(),
1176 self.kiosk.is_some(),
1177 system_pos,
1178 self.vars.video_mode().get(),
1179 self.vars.visible().get(),
1180 self.vars.taskbar_visible().get(),
1181 self.vars.always_on_top().get(),
1182 self.vars.movable().get(),
1183 self.vars.resizable().get(),
1184 {
1185 #[cfg(feature = "image")]
1186 {
1187 self.img_res
1188 .icon_var
1189 .as_ref()
1190 .and_then(|ico| ico.get().view().map(|ico| ico.id()))
1191 .flatten()
1192 }
1193 #[cfg(not(feature = "image"))]
1194 None
1195 },
1196 self.vars.cursor().with(|c| c.icon()),
1197 {
1198 #[cfg(feature = "image")]
1199 {
1200 self.vars
1201 .actual_cursor_img()
1202 .get()
1203 .and_then(|(i, h)| i.view().and_then(|i| i.id()).map(|i| (i, h)))
1204 }
1205 #[cfg(not(feature = "image"))]
1206 None
1207 },
1208 self.transparent,
1209 {
1210 #[cfg(feature = "image")]
1211 {
1212 matches!(self.vars.frame_capture_mode().get(), FrameCaptureMode::All)
1213 }
1214
1215 #[cfg(not(feature = "image"))]
1216 false
1217 },
1218 self.render_mode.unwrap_or_else(|| WINDOWS.default_render_mode().get()),
1219 self.vars.focus_indicator().get(),
1220 self.start_focused,
1221 self.ime_info.as_ref().and_then(|a| {
1222 let area = WINDOW.info().get(a.target.widget_id())?.ime_area().to_dip(scale_factor);
1223 Some(area)
1224 }),
1225 self.vars.enabled_buttons().get(),
1226 self.vars.system_shutdown_warn().get(),
1227 WINDOWS.take_view_extensions_init(window_id),
1228 );
1229
1230 if let Ok(()) = VIEW_PROCESS.open_window(request) {
1231 self.state = Some(state);
1232 self.waiting_view = true;
1233 } }
1235
1236 fn layout_update(&mut self, layout_widgets: Arc<LayoutUpdates>) {
1238 let m = self.monitor.as_ref().unwrap();
1239 let scale_factor = m.scale_factor().get();
1240 let screen_density = m.density().get();
1241
1242 let mut state = self.state.clone().unwrap();
1243
1244 let current_size = self.vars.0.actual_size.get().to_px(scale_factor);
1245 let mut size = current_size;
1246 let min_size = state.min_size.to_px(scale_factor);
1247 let max_size = state.max_size.to_px(scale_factor);
1248 let root_font_size = self.root_font_size.to_px(scale_factor);
1249
1250 let skip_auto_size = !matches!(state.state, WindowState::Normal);
1251
1252 if !skip_auto_size {
1253 let auto_size = self.vars.auto_size().get();
1254
1255 if auto_size.contains(AutoSize::CONTENT_WIDTH) {
1256 size.width = max_size.width;
1257 }
1258 if auto_size.contains(AutoSize::CONTENT_HEIGHT) {
1259 size.height = max_size.height;
1260 }
1261 }
1262
1263 let size = self.content.layout(
1264 layout_widgets,
1265 scale_factor,
1266 screen_density,
1267 min_size,
1268 max_size,
1269 size,
1270 root_font_size,
1271 skip_auto_size,
1272 );
1273
1274 if size != current_size {
1275 assert!(!skip_auto_size);
1276
1277 let auto_size_origin = self.vars.auto_size_origin().get();
1278 let auto_size_origin = |size| {
1279 let metrics = LayoutMetrics::new(scale_factor, size, root_font_size)
1280 .with_screen_density(screen_density)
1281 .with_direction(DIRECTION_VAR.get());
1282 LAYOUT.with_context(metrics, || auto_size_origin.layout().to_dip(scale_factor))
1283 };
1284 let prev_origin = auto_size_origin(current_size);
1285 let new_origin = auto_size_origin(size);
1286
1287 let size = size.to_dip(scale_factor);
1288
1289 state.restore_rect.size = size;
1290 state.restore_rect.origin += prev_origin - new_origin;
1291
1292 if let Some(view) = &self.window {
1293 let _: Ignore = view.set_state(state);
1294 } else {
1295 debug_assert!(self.respawned);
1296 self.state = Some(state);
1297 }
1298 }
1299 }
1300
1301 fn layout_respawn(&mut self) {
1303 if self.monitor.is_none() {
1304 self.monitor = Some(self.vars.monitor().get().select_fallback());
1305 let m = self.monitor.as_ref().unwrap();
1306 self.vars.0.scale_factor.set(m.scale_factor().get());
1307 }
1308
1309 self.layout_update(Arc::default());
1310
1311 let window_id = WINDOW.id();
1312
1313 let request = WindowRequest::new(
1314 zng_view_api::window::WindowId::from_raw(window_id.get()),
1315 self.vars.title().get(),
1316 self.state.clone().unwrap(),
1317 self.kiosk.is_some(),
1318 false,
1319 self.vars.video_mode().get(),
1320 self.vars.visible().get(),
1321 self.vars.taskbar_visible().get(),
1322 self.vars.always_on_top().get(),
1323 self.vars.movable().get(),
1324 self.vars.resizable().get(),
1325 {
1326 #[cfg(feature = "image")]
1327 {
1328 self.img_res
1329 .icon_var
1330 .as_ref()
1331 .and_then(|ico| ico.get().view().map(|ico| ico.id()))
1332 .flatten()
1333 }
1334 #[cfg(not(feature = "image"))]
1335 None
1336 },
1337 self.vars.cursor().with(|c| c.icon()),
1338 {
1339 #[cfg(feature = "image")]
1340 {
1341 self.vars
1342 .actual_cursor_img()
1343 .get()
1344 .and_then(|(i, h)| i.view().and_then(|i| i.id()).map(|i| (i, h)))
1345 }
1346 #[cfg(not(feature = "image"))]
1347 None
1348 },
1349 self.transparent,
1350 {
1351 #[cfg(feature = "image")]
1352 {
1353 matches!(self.vars.frame_capture_mode().get(), FrameCaptureMode::All)
1354 }
1355 #[cfg(not(feature = "image"))]
1356 false
1357 },
1358 self.render_mode.unwrap_or_else(|| WINDOWS.default_render_mode().get()),
1359 self.vars.focus_indicator().get(),
1360 WINDOWS.is_focused(WINDOW.id()).unwrap_or(false),
1361 self.ime_info.as_ref().and_then(|a| {
1362 let info = WINDOW.info();
1363 let area = info.get(a.target.widget_id())?.ime_area().to_dip(info.scale_factor());
1364 Some(area)
1365 }),
1366 self.vars.enabled_buttons().get(),
1367 self.vars.system_shutdown_warn().get(),
1368 WINDOWS.take_view_extensions_init(window_id),
1369 );
1370
1371 if let Ok(()) = VIEW_PROCESS.open_window(request) {
1372 self.waiting_view = true
1373 }
1374 }
1375
1376 pub fn render(&mut self, render_widgets: Arc<RenderUpdates>, render_update_widgets: Arc<RenderUpdates>) {
1377 let w_id = WINDOW.id();
1378 if !render_widgets.delivery_list().enter_window(w_id) && !render_update_widgets.delivery_list().enter_window(w_id) {
1379 return;
1380 }
1381
1382 if let Some(view) = &self.window {
1383 if matches!(self.state.as_ref().map(|s| s.state), Some(WindowState::Minimized)) {
1384 return;
1385 }
1386
1387 let scale_factor = self.monitor.as_ref().unwrap().scale_factor().get();
1388 self.content.render(
1389 Some(view.renderer()),
1390 scale_factor,
1391 self.resize_wait_id.take(),
1392 render_widgets,
1393 render_update_widgets,
1394 );
1395
1396 if let Some(prev_tree) = self.render_access_update.take() {
1397 let info = WINDOW.info();
1398 if let Some(mut update) = info.to_access_updates(&prev_tree) {
1400 update.focused = self.accessible_focused(&info).unwrap_or_else(|| info.root().id()).into();
1402 let _ = view.access_update(update);
1403 }
1404 } else {
1405 let info = WINDOW.info();
1406 if info.access_enabled() == AccessEnabled::VIEW
1407 && let Some(mut update) = info.to_access_updates_bounds()
1408 {
1409 update.focused = self.accessible_focused(&info).unwrap_or_else(|| info.root().id()).into();
1411 let _ = view.access_update(update);
1412 }
1413 }
1414
1415 if let Some(ime) = &mut self.ime_info
1416 && let Some(w) = &self.window
1417 {
1418 let info = WINDOW.info();
1419 if let Some(wgt) = info.get(ime.target.widget_id()) {
1420 let area = wgt.ime_area().to_dip(scale_factor);
1421 if ime.area != area {
1422 ime.area = area;
1423 let _ = w.set_ime_area(Some(area));
1424 }
1425 }
1426 }
1427 }
1428 }
1429
1430 pub fn focus(&mut self) {
1431 self.update_gen(|view| {
1432 let r = view.focus();
1433 if let Ok(FocusResult::AlreadyFocused) = r {
1434 let prev = WINDOWS.focused_window_id();
1435 let new = Some(WINDOW.id());
1436 if prev != new {
1437 RAW_WINDOW_FOCUS_EVENT.notify(RawWindowFocusArgs::now(prev, new));
1439 }
1440 }
1441 });
1442 }
1443
1444 pub fn start_drag_drop(&mut self, data: Vec<DragDropData>, allowed_effects: DragDropEffect) -> Result<DragDropId, DragDropError> {
1445 if let Some(view) = &self.window
1446 && let Ok(r) = view.start_drag_drop(data, allowed_effects)
1447 {
1448 return r;
1449 }
1450 Err(DragDropError::CannotStart("view not available".into()))
1451 }
1452
1453 pub fn drag_dropped(&mut self, drop_id: DragDropId, applied: DragDropEffect) {
1454 if let Some(view) = &self.window {
1455 let _ = view.drag_dropped(drop_id, applied);
1456 }
1457 }
1458
1459 pub fn bring_to_top(&mut self) {
1460 self.update_gen(|view| {
1461 let _ = view.bring_to_top();
1462 });
1463 }
1464
1465 pub fn close(&mut self) {
1466 self.content.close();
1467 self.window = None;
1468 self.cancel_ime_handle = CommandHandle::dummy();
1469 self.cancel_ime_handle = CommandHandle::dummy();
1470 }
1471
1472 fn view_task(&mut self, task: Box<dyn FnOnce(Option<&ViewWindow>) + Send>) {
1473 if let Some(view) = &self.window {
1474 task(Some(view));
1475 } else if self.waiting_view {
1476 self.delayed_view_updates.push(Box::new(move |v| task(Some(v))));
1477 } else {
1478 task(None);
1479 }
1480 }
1481}
1482
1483fn update_parent(parent: &mut Option<WindowId>, vars: &WindowVars) -> bool {
1485 let parent_var = vars.parent();
1486 if let Some(parent_id) = parent_var.get_new() {
1487 if parent_id == *parent {
1488 return false;
1489 }
1490
1491 match parent_id {
1492 Some(mut parent_id) => {
1493 if parent_id == WINDOW.id() {
1494 tracing::error!("cannot set `{:?}` as it's own parent", parent_id);
1495 parent_var.set(*parent);
1496 return false;
1497 }
1498 if !vars.0.children.with(|c| c.is_empty()) {
1499 tracing::error!("cannot set parent for `{:?}` because it already has children", WINDOW.id());
1500 parent_var.set(*parent);
1501 return false;
1502 }
1503
1504 if let Ok(parent_vars) = WINDOWS.vars(parent_id) {
1505 if let Some(grand) = parent_vars.parent().get() {
1507 tracing::debug!("using `{grand:?}` as parent, because it is the parent of requested `{parent_id:?}`");
1508 parent_var.set(grand);
1509
1510 parent_id = grand;
1511 if Some(parent_id) == *parent {
1512 return false;
1513 }
1514 }
1515
1516 if let Some(parent_id) = parent.take()
1518 && let Ok(parent_vars) = WINDOWS.vars(parent_id)
1519 {
1520 let id = WINDOW.id();
1521 parent_vars.0.children.modify(move |c| {
1522 c.remove(&id);
1523 });
1524 }
1525
1526 *parent = Some(parent_id);
1528 let id = WINDOW.id();
1529 parent_vars.0.children.modify(move |c| {
1530 c.insert(id);
1531 });
1532
1533 true
1534 } else {
1535 tracing::error!("cannot use `{:?}` as a parent because it does not exist", parent_id);
1536 parent_var.set(*parent);
1537 false
1538 }
1539 }
1540 None => {
1541 if let Some(parent_id) = parent.take() {
1542 if let Ok(parent_vars) = WINDOWS.vars(parent_id) {
1543 let id = WINDOW.id();
1544 parent_vars.0.children.modify(move |c| {
1545 c.remove(&id);
1546 });
1547 }
1548 true
1549 } else {
1550 false
1551 }
1552 }
1553 }
1554 } else {
1555 false
1556 }
1557}
1558
1559struct HeadlessWithRendererCtrl {
1561 surface: Option<ViewHeadless>,
1562 waiting_view: bool,
1563 delayed_view_updates: Vec<Box<dyn FnOnce(&ViewHeadless) + Send>>,
1564 vars: WindowVars,
1565 content: ContentCtrl,
1566
1567 render_mode: Option<RenderMode>,
1569 headless_monitor: HeadlessMonitor,
1570 headless_simulator: HeadlessSimulator,
1571
1572 size: DipSize,
1574
1575 actual_parent: Option<WindowId>,
1576 var_bindings: VarHandles,
1578}
1579impl HeadlessWithRendererCtrl {
1580 pub fn new(vars: &WindowVars, commands: WindowCommands, content: WindowRoot) -> Self {
1581 Self {
1582 surface: None,
1583 waiting_view: false,
1584 delayed_view_updates: vec![],
1585 vars: vars.clone(),
1586
1587 render_mode: content.render_mode,
1588 headless_monitor: content.headless_monitor,
1589 headless_simulator: HeadlessSimulator::new(),
1590
1591 content: ContentCtrl::new(vars.clone(), commands, content),
1592
1593 actual_parent: None,
1594 size: DipSize::zero(),
1595 var_bindings: VarHandles::dummy(),
1596 }
1597 }
1598
1599 pub fn update(&mut self, update_widgets: &WidgetUpdates) {
1600 if self.vars.0.access_enabled.is_new() {
1601 UPDATES.update_info_window(WINDOW.id());
1602 }
1603
1604 if self.surface.is_some() {
1605 if self.vars.size().is_new()
1606 || self.vars.min_size().is_new()
1607 || self.vars.max_size().is_new()
1608 || self.vars.auto_size().is_new()
1609 || self.vars.font_size().is_new()
1610 {
1611 UPDATES.layout_window(WINDOW.id());
1612 }
1613 } else {
1614 UPDATES.layout_window(WINDOW.id());
1616 }
1617
1618 if update_parent(&mut self.actual_parent, &self.vars) || self.var_bindings.is_dummy() {
1619 self.var_bindings = update_headless_vars(self.headless_monitor.scale_factor, &self.vars);
1620 }
1621
1622 self.content.update(update_widgets);
1623 }
1624
1625 #[must_use]
1626 pub fn info(&mut self, info_widgets: Arc<InfoUpdates>) -> Option<WidgetInfoTree> {
1627 self.content.info(info_widgets)
1628 }
1629
1630 pub fn pre_event(&mut self, update: &EventUpdate) {
1631 if let Some(args) = RAW_HEADLESS_OPEN_EVENT.on(update) {
1632 if args.window_id == WINDOW.id() {
1633 self.waiting_view = false;
1634
1635 WINDOWS.set_view(args.window_id, args.surface.clone().into());
1636
1637 self.surface = Some(args.surface.clone());
1638 self.vars.0.render_mode.set(args.data.render_mode);
1639
1640 UPDATES.render_window(args.window_id);
1641
1642 for update in mem::take(&mut self.delayed_view_updates) {
1643 update(&args.surface);
1644 }
1645 }
1646 } else if let Some(args) = RAW_WINDOW_OR_HEADLESS_OPEN_ERROR_EVENT.on(update) {
1647 if args.window_id == WINDOW.id() && self.surface.is_none() && self.waiting_view {
1648 tracing::error!("view-process failed to open a headless surface, {}", args.error);
1649
1650 self.waiting_view = false;
1653 self.delayed_view_updates = vec![];
1654
1655 UPDATES.layout_window(args.window_id).render_window(args.window_id);
1656 }
1657 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update)
1658 && let Some(view) = &self.surface
1659 && view.renderer().generation() != Ok(args.generation)
1660 {
1661 debug_assert!(args.is_respawn);
1662
1663 self.surface = None;
1664
1665 let w_id = WINDOW.id();
1666 UPDATES.layout_window(w_id).render_window(w_id);
1667 }
1668
1669 self.content.pre_event(update);
1670
1671 self.headless_simulator.pre_event(update);
1672 }
1673
1674 pub fn ui_event(&mut self, update: &EventUpdate) {
1675 self.content.ui_event(update);
1676 }
1677
1678 pub fn layout(&mut self, layout_widgets: Arc<LayoutUpdates>) {
1679 if !layout_widgets.delivery_list().enter_window(WINDOW.id()) {
1680 return;
1681 }
1682
1683 let scale_factor = self.vars.0.scale_factor.get();
1684 let screen_density = self.headless_monitor.density;
1685 let screen_size = self.headless_monitor.size.to_px(scale_factor);
1686
1687 let (min_size, max_size, size, root_font_size) = self.content.outer_layout(scale_factor, screen_density, screen_size, || {
1688 let min_size = self.vars.min_size().layout_dft(default_min_size(scale_factor));
1689 let max_size = self.vars.max_size().layout_dft(screen_size);
1690 let size = self.vars.size().layout_dft(default_size(scale_factor));
1691 let root_font_size = self.vars.font_size().layout_dft_x(Length::pt_to_px(11.0, scale_factor));
1692
1693 (min_size, max_size, size.min(max_size).max(min_size), root_font_size)
1694 });
1695
1696 let size = self.content.layout(
1697 layout_widgets,
1698 scale_factor,
1699 screen_density,
1700 min_size,
1701 max_size,
1702 size,
1703 root_font_size,
1704 false,
1705 );
1706 let size = size.to_dip(scale_factor);
1707
1708 if let Some(view) = &self.surface {
1709 if self.size != size {
1711 self.size = size;
1712 let _: Ignore = view.set_size(size, scale_factor);
1713 }
1714 } else if !self.waiting_view {
1715 if !WINDOWS.try_load(WINDOW.id()) {
1718 return;
1719 }
1720
1721 let render_mode = self.render_mode.unwrap_or_else(|| WINDOWS.default_render_mode().get());
1722
1723 let window_id = WINDOW.id();
1724
1725 let r = VIEW_PROCESS.open_headless(HeadlessRequest::new(
1726 zng_view_api::window::WindowId::from_raw(window_id.get()),
1727 scale_factor,
1728 size,
1729 render_mode,
1730 WINDOWS.take_view_extensions_init(window_id),
1731 ));
1732
1733 if let Ok(()) = r {
1734 self.waiting_view = true
1735 }
1736 }
1737
1738 self.headless_simulator.layout();
1739 }
1740
1741 pub fn render(&mut self, render_widgets: Arc<RenderUpdates>, render_update_widgets: Arc<RenderUpdates>) {
1742 let w_id = WINDOW.id();
1743 if !render_widgets.delivery_list().enter_window(w_id) && !render_update_widgets.delivery_list().enter_window(w_id) {
1744 return;
1745 }
1746
1747 if let Some(view) = &self.surface {
1748 let fct = self.vars.0.scale_factor.get();
1749 self.content
1750 .render(Some(view.renderer()), fct, None, render_widgets, render_update_widgets);
1751 }
1752 }
1753
1754 pub fn focus(&mut self) {
1755 self.headless_simulator.focus();
1756 }
1757
1758 pub fn bring_to_top(&mut self) {
1759 self.headless_simulator.bring_to_top();
1760 }
1761
1762 pub fn close(&mut self) {
1763 self.content.close();
1764 self.surface = None;
1765 }
1766
1767 pub fn start_drag_drop(&mut self, data: Vec<DragDropData>, allowed_effects: DragDropEffect) -> Result<DragDropId, DragDropError> {
1768 let _ = (data, allowed_effects);
1769 Err(DragDropError::CannotStart("cannot start drag&drop from headless window".into()))
1770 }
1771
1772 pub fn drag_dropped(&mut self, drop_id: DragDropId, applied: DragDropEffect) {
1773 let _ = (drop_id, applied);
1774 }
1775
1776 fn view_task(&mut self, task: Box<dyn FnOnce(Option<&ViewWindow>) + Send>) {
1777 task(None)
1778 }
1779}
1780
1781fn update_headless_vars(m_factor: Option<Factor>, h_vars: &WindowVars) -> VarHandles {
1782 let mut handles = VarHandles::dummy();
1783
1784 if let Some(f) = m_factor {
1785 h_vars.0.scale_factor.set(f);
1786 }
1787
1788 if let Some(parent_vars) = h_vars.parent().get().and_then(|id| WINDOWS.vars(id).ok()) {
1789 if m_factor.is_none() {
1791 h_vars.0.scale_factor.set_from(&parent_vars.0.scale_factor);
1792 handles.push(parent_vars.0.scale_factor.bind(&h_vars.0.scale_factor));
1793 }
1794
1795 let user = h_vars.color_scheme();
1797 let parent = &parent_vars.0.actual_color_scheme;
1798 let actual = &h_vars.0.actual_color_scheme;
1799
1800 handles.push(user.hook(clmv!(parent, actual, |args| {
1801 let value = *args.value();
1802 let scheme = value.unwrap_or_else(|| parent.get());
1803 actual.set(scheme);
1804 true
1805 })));
1806
1807 handles.push(parent.hook(clmv!(user, actual, |args| {
1808 let scheme = user.get().unwrap_or_else(|| *args.value());
1809 actual.set(scheme);
1810 true
1811 })));
1812
1813 actual.modify(clmv!(user, parent, |a| {
1814 let value = user.get().unwrap_or_else(|| parent.get());
1815 a.set(value);
1816 }));
1817 } else {
1818 let from = h_vars.color_scheme();
1820 let to = &h_vars.0.actual_color_scheme;
1821
1822 to.set_from_map(&from, |&s| s.unwrap_or_default());
1823 handles.push(from.bind_map(to, |&s| s.unwrap_or_default()));
1824 }
1825
1826 handles
1827}
1828
1829struct HeadlessCtrl {
1831 vars: WindowVars,
1832 content: ContentCtrl,
1833
1834 headless_monitor: HeadlessMonitor,
1835 headless_simulator: HeadlessSimulator,
1836
1837 actual_parent: Option<WindowId>,
1838 var_bindings: VarHandles,
1840}
1841impl HeadlessCtrl {
1842 pub fn new(vars: &WindowVars, commands: WindowCommands, content: WindowRoot) -> Self {
1843 Self {
1844 vars: vars.clone(),
1845 headless_monitor: content.headless_monitor,
1846 content: ContentCtrl::new(vars.clone(), commands, content),
1847 headless_simulator: HeadlessSimulator::new(),
1848 actual_parent: None,
1849 var_bindings: VarHandles::dummy(),
1850 }
1851 }
1852
1853 pub fn update(&mut self, update_widgets: &WidgetUpdates) {
1854 if self.vars.0.access_enabled.is_new() {
1855 UPDATES.update_info_window(WINDOW.id());
1856 }
1857
1858 if self.vars.size().is_new() || self.vars.min_size().is_new() || self.vars.max_size().is_new() || self.vars.auto_size().is_new() {
1859 UPDATES.layout_window(WINDOW.id());
1860 }
1861
1862 if matches!(self.content.init_state, InitState::Init) {
1863 let w_id = WINDOW.id();
1864 UPDATES.layout_window(w_id).render_window(w_id);
1865 }
1866
1867 if update_parent(&mut self.actual_parent, &self.vars) || self.var_bindings.is_dummy() {
1868 self.var_bindings = update_headless_vars(self.headless_monitor.scale_factor, &self.vars);
1869 }
1870
1871 self.content.update(update_widgets);
1872 }
1873
1874 #[must_use]
1875 pub fn info(&mut self, info_widgets: Arc<InfoUpdates>) -> Option<WidgetInfoTree> {
1876 self.content.info(info_widgets)
1877 }
1878
1879 pub fn pre_event(&mut self, update: &EventUpdate) {
1880 self.content.pre_event(update);
1881 self.headless_simulator.pre_event(update);
1882 }
1883
1884 pub fn ui_event(&mut self, update: &EventUpdate) {
1885 self.content.ui_event(update);
1886 }
1887
1888 pub fn layout(&mut self, layout_widgets: Arc<LayoutUpdates>) {
1889 let w_id = WINDOW.id();
1890 if !layout_widgets.delivery_list().enter_window(w_id) {
1891 return;
1892 }
1893
1894 if !WINDOWS.try_load(w_id) {
1895 return;
1896 }
1897
1898 let scale_factor = self.vars.0.scale_factor.get();
1899 let screen_density = self.headless_monitor.density;
1900 let screen_size = self.headless_monitor.size.to_px(scale_factor);
1901
1902 let (min_size, max_size, size, root_font_size) = self.content.outer_layout(scale_factor, screen_density, screen_size, || {
1903 let min_size = self.vars.min_size().layout_dft(default_min_size(scale_factor));
1904 let max_size = self.vars.max_size().layout_dft(screen_size);
1905 let size = self.vars.size().layout_dft(default_size(scale_factor));
1906 let root_font_size = self.vars.font_size().layout_dft_x(Length::pt_to_px(11.0, scale_factor));
1907
1908 (min_size, max_size, size.min(max_size).max(min_size), root_font_size)
1909 });
1910
1911 let _surface_size = self.content.layout(
1912 layout_widgets,
1913 scale_factor,
1914 screen_density,
1915 min_size,
1916 max_size,
1917 size,
1918 root_font_size,
1919 false,
1920 );
1921
1922 self.headless_simulator.layout();
1923 }
1924
1925 pub fn render(&mut self, render_widgets: Arc<RenderUpdates>, render_update_widgets: Arc<RenderUpdates>) {
1926 let w_id = WINDOW.id();
1927 if !render_widgets.delivery_list().enter_window(w_id) && !render_update_widgets.delivery_list().enter_window(w_id) {
1928 return;
1929 }
1930
1931 if !WINDOWS.try_load(w_id) {
1933 return;
1934 }
1935
1936 let fct = self.vars.0.scale_factor.get();
1937 self.content.render(None, fct, None, render_widgets, render_update_widgets);
1938 }
1939
1940 pub fn focus(&mut self) {
1941 self.headless_simulator.focus();
1942 }
1943
1944 pub fn bring_to_top(&mut self) {
1945 self.headless_simulator.bring_to_top();
1946 }
1947
1948 pub fn close(&mut self) {
1949 self.content.close();
1950 }
1951
1952 pub fn start_drag_drop(&mut self, data: Vec<DragDropData>, allowed_effects: DragDropEffect) -> Result<DragDropId, DragDropError> {
1953 let _ = (data, allowed_effects);
1954 Err(DragDropError::CannotStart("cannot start drag&drop from headless window".into()))
1955 }
1956
1957 pub fn drag_dropped(&mut self, drop_id: DragDropId, applied: DragDropEffect) {
1958 let _ = (drop_id, applied);
1959 }
1960
1961 fn view_task(&mut self, task: Box<dyn FnOnce(Option<&ViewWindow>) + Send>) {
1962 task(None);
1963 }
1964}
1965
1966struct HeadlessSimulator {
1968 is_enabled: Option<bool>,
1969 is_open: bool,
1970}
1971impl HeadlessSimulator {
1972 fn new() -> Self {
1973 HeadlessSimulator {
1974 is_enabled: None,
1975 is_open: false,
1976 }
1977 }
1978
1979 fn enabled(&mut self) -> bool {
1980 *self.is_enabled.get_or_insert_with(|| zng_app::APP.window_mode().is_headless())
1981 }
1982
1983 pub fn pre_event(&mut self, update: &EventUpdate) {
1984 if self.enabled() && self.is_open && VIEW_PROCESS_INITED_EVENT.on(update).map(|a| a.is_respawn).unwrap_or(false) {
1985 self.is_open = false;
1986 }
1987 }
1988
1989 pub fn layout(&mut self) {
1990 if self.enabled() && !self.is_open {
1991 self.is_open = true;
1992 self.focus();
1993 }
1994 }
1995
1996 pub fn focus(&mut self) {
1997 let args = RawWindowFocusArgs::now(WINDOWS.focused_window_id(), Some(WINDOW.id()));
1998 RAW_WINDOW_FOCUS_EVENT.notify(args);
1999 }
2000
2001 pub fn bring_to_top(&mut self) {
2002 }
2004}
2005
2006#[derive(Clone, Copy)]
2007enum InitState {
2008 SkipOne,
2012 Init,
2013 Inited,
2014}
2015
2016struct ContentCtrl {
2018 vars: WindowVars,
2019 commands: WindowCommands,
2020
2021 root_ctx: WidgetCtx,
2022 root: UiNode,
2023 layout_pass: LayoutPassId,
2024
2025 init_state: InitState,
2026 frame_id: FrameId,
2027 clear_color: Rgba,
2028}
2029impl ContentCtrl {
2030 pub fn new(vars: WindowVars, commands: WindowCommands, window: WindowRoot) -> Self {
2031 Self {
2032 vars,
2033 commands,
2034
2035 root_ctx: WidgetCtx::new(window.id),
2036 root: window.child,
2037
2038 layout_pass: LayoutPassId::new(),
2039
2040 init_state: InitState::SkipOne,
2041 frame_id: FrameId::INVALID,
2042 clear_color: colors::BLACK,
2043 }
2044 }
2045
2046 pub fn update(&mut self, update_widgets: &WidgetUpdates) {
2047 match self.init_state {
2048 InitState::Inited => {
2049 self.commands.update(&self.vars);
2050
2051 update_widgets.with_window(|| {
2052 if self.root_ctx.take_reinit() {
2053 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2055 self.root.deinit();
2056 self.root.init();
2057 });
2058 let _ = self.root_ctx.take_reinit(); } else {
2060 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2062 update_widgets.with_widget(|| {
2063 self.root.update(update_widgets);
2064 });
2065 });
2066
2067 if self.root_ctx.take_reinit() {
2069 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2070 self.root.deinit();
2071 self.root.init();
2072 });
2073 }
2074 }
2075 });
2076 }
2077
2078 InitState::SkipOne => {
2079 UPDATES.update(None);
2080 self.init_state = InitState::Init;
2081 }
2082 InitState::Init => {
2083 self.commands.init(&self.vars);
2084 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2085 self.root.init();
2086 WIDGET.update_info().layout().render();
2088
2089 super::WINDOW_OPEN_EVENT.notify(super::WindowOpenArgs::now(WINDOW.id()));
2090 });
2091 self.init_state = InitState::Inited;
2092 self.root_ctx.take_reinit(); }
2094 }
2095 }
2096
2097 #[must_use]
2098 pub fn info(&mut self, info_widgets: Arc<InfoUpdates>) -> Option<WidgetInfoTree> {
2099 let win_id = WINDOW.id();
2100 if info_widgets.delivery_list().enter_window(win_id) && matches!(self.init_state, InitState::Inited) {
2101 let mut info = WidgetInfoBuilder::new(
2102 info_widgets,
2103 win_id,
2104 self.vars.0.access_enabled.get(),
2105 self.root_ctx.id(),
2106 self.root_ctx.bounds(),
2107 self.root_ctx.border(),
2108 self.vars.0.scale_factor.get(),
2109 );
2110
2111 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2112 self.root.info(&mut info);
2113 });
2114
2115 let info = info.finalize(Some(WINDOW.info()), true);
2116
2117 WINDOWS.set_widget_tree(info.clone());
2118
2119 if self.root_ctx.is_pending_reinit() {
2120 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
2121 }
2122
2123 Some(info)
2124 } else {
2125 None
2126 }
2127 }
2128
2129 pub fn pre_event(&mut self, update: &EventUpdate) {
2130 #[cfg(feature = "image")]
2131 if let Some(args) = RAW_FRAME_RENDERED_EVENT.on(update) {
2132 if args.window_id == WINDOW.id() {
2133 let image = args.frame_image.as_ref().cloned().map(Img::new);
2134
2135 let args = FrameImageReadyArgs::new(args.timestamp, args.propagation().clone(), args.window_id, args.frame_id, image);
2136 FRAME_IMAGE_READY_EVENT.notify(args);
2137 }
2138 return;
2139 }
2140
2141 self.commands.event(&self.vars, update);
2142 }
2143
2144 pub fn ui_event(&mut self, update: &EventUpdate) {
2145 update.with_window(|| {
2146 if !matches!(self.init_state, InitState::Inited) {
2147 tracing::error!("cannot deliver `{:?}`, window `{}` is not inited", update.event(), WINDOW.id());
2148 return;
2149 }
2150
2151 if self.root_ctx.take_reinit() {
2152 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2153 self.root.deinit();
2154 self.root.init();
2155 });
2156 let _ = self.root_ctx.take_reinit(); }
2158
2159 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2160 update.with_widget(|| {
2161 self.root.event(update);
2162 })
2163 });
2164
2165 if self.root_ctx.take_reinit() {
2166 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2167 self.root.deinit();
2168 self.root.init();
2169 });
2170 }
2171 });
2172 }
2173
2174 pub fn close(&mut self) {
2175 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2176 self.root.deinit();
2177 });
2178
2179 self.vars.0.is_open.set(false);
2180 self.root_ctx.deinit(false);
2181 }
2182
2183 pub fn outer_layout<R>(
2185 &mut self,
2186 scale_factor: Factor,
2187 screen_density: PxDensity,
2188 screen_size: PxSize,
2189 action: impl FnOnce() -> R,
2190 ) -> R {
2191 let metrics = LayoutMetrics::new(scale_factor, screen_size, Length::pt_to_px(11.0, scale_factor))
2192 .with_screen_density(screen_density)
2193 .with_direction(DIRECTION_VAR.get());
2194 LAYOUT.with_context(metrics, action)
2195 }
2196
2197 #[expect(clippy::too_many_arguments)]
2199 pub fn layout(
2200 &mut self,
2201 layout_widgets: Arc<LayoutUpdates>,
2202 scale_factor: Factor,
2203 screen_density: PxDensity,
2204 min_size: PxSize,
2205 max_size: PxSize,
2206 size: PxSize,
2207 root_font_size: Px,
2208 skip_auto_size: bool,
2209 ) -> PxSize {
2210 if !matches!(self.init_state, InitState::Inited) {
2211 return PxSize::zero();
2212 }
2213
2214 let _s = tracing::trace_span!("window.on_layout", window = %WINDOW.id().sequential()).entered();
2215
2216 let auto_size = self.vars.auto_size().get();
2217
2218 self.layout_pass = self.layout_pass.next();
2219
2220 let final_size = WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2221 let metrics = LayoutMetrics::new(scale_factor, size, root_font_size)
2222 .with_screen_density(screen_density)
2223 .with_direction(DIRECTION_VAR.get());
2224 LAYOUT.with_root_context(self.layout_pass, metrics, || {
2225 let mut root_cons = LAYOUT.constraints();
2226 if !skip_auto_size {
2227 if auto_size.contains(AutoSize::CONTENT_WIDTH) {
2228 root_cons.x = PxConstraints::new_range(min_size.width, max_size.width);
2229 }
2230 if auto_size.contains(AutoSize::CONTENT_HEIGHT) {
2231 root_cons.y = PxConstraints::new_range(min_size.height, max_size.height);
2232 }
2233 }
2234 let desired_size = LAYOUT.with_constraints(root_cons, || {
2235 WidgetLayout::with_root_widget(layout_widgets, |wl| self.root.layout(wl))
2236 });
2237
2238 let mut final_size = size;
2239 if !skip_auto_size {
2240 if auto_size.contains(AutoSize::CONTENT_WIDTH) {
2241 final_size.width = desired_size.width.max(min_size.width).min(max_size.width);
2242 }
2243 if auto_size.contains(AutoSize::CONTENT_HEIGHT) {
2244 final_size.height = desired_size.height.max(min_size.height).min(max_size.height);
2245 }
2246 }
2247
2248 final_size
2249 })
2250 });
2251
2252 if self.root_ctx.is_pending_reinit() {
2253 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
2254 }
2255
2256 final_size
2257 }
2258
2259 pub fn render(
2260 &mut self,
2261 renderer: Option<ViewRenderer>,
2262 scale_factor: Factor,
2263 wait_id: Option<FrameWaitId>,
2264 render_widgets: Arc<RenderUpdates>,
2265 render_update_widgets: Arc<RenderUpdates>,
2266 ) {
2267 if !matches!(self.init_state, InitState::Inited) {
2268 return;
2269 }
2270
2271 let w_id = WINDOW.id();
2272 if render_widgets.delivery_list().enter_window(w_id) {
2273 let _s = tracing::trace_span!("window.on_render", window = %WINDOW.id().sequential()).entered();
2275
2276 self.frame_id = self.frame_id.next();
2277
2278 let mut frame = FrameBuilder::new(
2279 render_widgets,
2280 render_update_widgets,
2281 self.frame_id,
2282 self.root_ctx.id(),
2283 &self.root_ctx.bounds(),
2284 &WINDOW.info(),
2285 renderer.clone(),
2286 scale_factor,
2287 FontAntiAliasing::Default,
2288 );
2289
2290 let frame = WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2291 self.root.render(&mut frame);
2292 frame.finalize(&WINDOW.info())
2293 });
2294
2295 if self.root_ctx.is_pending_reinit() {
2296 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
2297 }
2298
2299 self.clear_color = frame.clear_color;
2300
2301 #[cfg(feature = "image")]
2302 let capture = self.take_frame_capture();
2303 #[cfg(not(feature = "image"))]
2304 let capture = FrameCapture::None;
2305
2306 if let Some(renderer) = renderer {
2307 let _: Ignore = renderer.render(FrameRequest::new(
2308 self.frame_id,
2309 self.clear_color,
2310 frame.display_list,
2311 capture,
2312 wait_id,
2313 ));
2314 } else {
2315 #[cfg(feature = "image")]
2317 FRAME_IMAGE_READY_EVENT.notify(FrameImageReadyArgs::now(WINDOW.id(), self.frame_id, None));
2318 }
2319 } else if render_update_widgets.delivery_list().enter_window(w_id) {
2320 let _s = tracing::trace_span!("window.on_render_update", window = %WINDOW.id().sequential()).entered();
2322
2323 self.frame_id = self.frame_id.next_update();
2324
2325 let mut update = FrameUpdate::new(
2326 render_update_widgets,
2327 self.frame_id,
2328 self.root_ctx.id(),
2329 self.root_ctx.bounds(),
2330 self.clear_color,
2331 );
2332
2333 let update = WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || {
2334 self.root.render_update(&mut update);
2335 update.finalize(&WINDOW.info())
2336 });
2337
2338 if let Some(c) = update.clear_color {
2339 self.clear_color = c;
2340 }
2341
2342 if self.root_ctx.is_pending_reinit() {
2343 WIDGET.with_context(&mut self.root_ctx, WidgetUpdateMode::Bubble, || WIDGET.update());
2344 }
2345
2346 #[cfg(feature = "image")]
2347 let capture = self.take_frame_capture();
2348 #[cfg(not(feature = "image"))]
2349 let capture = FrameCapture::None;
2350
2351 if let Some(renderer) = renderer {
2352 let _: Ignore = renderer.render_update(FrameUpdateRequest::new(
2353 self.frame_id,
2354 update.transforms,
2355 update.floats,
2356 update.colors,
2357 update.clear_color,
2358 capture,
2359 wait_id,
2360 update.extensions,
2361 ));
2362 } else {
2363 #[cfg(feature = "image")]
2365 FRAME_IMAGE_READY_EVENT.notify(FrameImageReadyArgs::now(WINDOW.id(), self.frame_id, None));
2366 }
2367 }
2368 }
2369 #[cfg(feature = "image")]
2370 fn take_frame_capture(&self) -> FrameCapture {
2371 match self.vars.frame_capture_mode().get() {
2372 FrameCaptureMode::Sporadic => FrameCapture::None,
2373 FrameCaptureMode::Next => {
2374 self.vars.frame_capture_mode().set(FrameCaptureMode::Sporadic);
2375 FrameCapture::Full
2376 }
2377 FrameCaptureMode::All => FrameCapture::Full,
2378 FrameCaptureMode::NextMask(m) => {
2379 self.vars.frame_capture_mode().set(FrameCaptureMode::Sporadic);
2380 FrameCapture::Mask(m)
2381 }
2382 FrameCaptureMode::AllMask(m) => FrameCapture::Mask(m),
2383 }
2384 }
2385}
2386
2387pub(super) struct WindowCtrl(WindowCtrlMode);
2389#[allow(clippy::large_enum_variant)] enum WindowCtrlMode {
2391 Headed(HeadedCtrl),
2392 Headless(HeadlessCtrl),
2393 HeadlessWithRenderer(HeadlessWithRendererCtrl),
2394 Nested(NestedCtrl),
2395}
2396impl WindowCtrl {
2397 pub fn new(vars: &WindowVars, commands: WindowCommands, mode: WindowMode, content: WindowRoot) -> Self {
2398 WindowCtrl(match mode {
2399 WindowMode::Headed => WindowCtrlMode::Headed(HeadedCtrl::new(vars, commands, content)),
2400 WindowMode::Headless => WindowCtrlMode::Headless(HeadlessCtrl::new(vars, commands, content)),
2401 WindowMode::HeadlessWithRenderer => {
2402 WindowCtrlMode::HeadlessWithRenderer(HeadlessWithRendererCtrl::new(vars, commands, content))
2403 }
2404 })
2405 }
2406
2407 pub fn new_nested(c: Arc<Mutex<NestedContentCtrl>>) -> Self {
2408 WindowCtrl(WindowCtrlMode::Nested(NestedCtrl::new(c)))
2409 }
2410
2411 pub fn update(&mut self, update_widgets: &WidgetUpdates) {
2412 match &mut self.0 {
2413 WindowCtrlMode::Headed(c) => c.update(update_widgets),
2414 WindowCtrlMode::Headless(c) => c.update(update_widgets),
2415 WindowCtrlMode::HeadlessWithRenderer(c) => c.update(update_widgets),
2416 WindowCtrlMode::Nested(c) => c.update(update_widgets),
2417 }
2418 }
2419
2420 #[must_use]
2421 pub fn info(&mut self, info_widgets: Arc<InfoUpdates>) -> Option<WidgetInfoTree> {
2422 match &mut self.0 {
2423 WindowCtrlMode::Headed(c) => c.info(info_widgets),
2424 WindowCtrlMode::Headless(c) => c.info(info_widgets),
2425 WindowCtrlMode::HeadlessWithRenderer(c) => c.info(info_widgets),
2426 WindowCtrlMode::Nested(c) => c.info(info_widgets),
2427 }
2428 }
2429
2430 pub fn pre_event(&mut self, update: &EventUpdate) {
2431 match &mut self.0 {
2432 WindowCtrlMode::Headed(c) => c.pre_event(update),
2433 WindowCtrlMode::Headless(c) => c.pre_event(update),
2434 WindowCtrlMode::HeadlessWithRenderer(c) => c.pre_event(update),
2435 WindowCtrlMode::Nested(c) => c.pre_event(update),
2436 }
2437 }
2438
2439 pub fn ui_event(&mut self, update: &EventUpdate) {
2440 match &mut self.0 {
2441 WindowCtrlMode::Headed(c) => c.ui_event(update),
2442 WindowCtrlMode::Headless(c) => c.ui_event(update),
2443 WindowCtrlMode::HeadlessWithRenderer(c) => c.ui_event(update),
2444 WindowCtrlMode::Nested(c) => c.ui_event(update),
2445 }
2446 }
2447
2448 pub fn layout(&mut self, layout_widgets: Arc<LayoutUpdates>) {
2449 match &mut self.0 {
2450 WindowCtrlMode::Headed(c) => c.layout(layout_widgets),
2451 WindowCtrlMode::Headless(c) => c.layout(layout_widgets),
2452 WindowCtrlMode::HeadlessWithRenderer(c) => c.layout(layout_widgets),
2453 WindowCtrlMode::Nested(c) => c.layout(layout_widgets),
2454 }
2455 }
2456
2457 pub fn render(&mut self, render_widgets: Arc<RenderUpdates>, render_update_widgets: Arc<RenderUpdates>) {
2458 match &mut self.0 {
2459 WindowCtrlMode::Headed(c) => c.render(render_widgets, render_update_widgets),
2460 WindowCtrlMode::Headless(c) => c.render(render_widgets, render_update_widgets),
2461 WindowCtrlMode::HeadlessWithRenderer(c) => c.render(render_widgets, render_update_widgets),
2462 WindowCtrlMode::Nested(c) => c.render(render_widgets, render_update_widgets),
2463 }
2464 }
2465
2466 pub fn focus(&mut self) {
2467 match &mut self.0 {
2468 WindowCtrlMode::Headed(c) => c.focus(),
2469 WindowCtrlMode::Headless(c) => c.focus(),
2470 WindowCtrlMode::HeadlessWithRenderer(c) => c.focus(),
2471 WindowCtrlMode::Nested(c) => c.focus(),
2472 }
2473 }
2474
2475 pub fn start_drag_drop(&mut self, data: Vec<DragDropData>, allowed_effects: DragDropEffect) -> Result<DragDropId, DragDropError> {
2476 match &mut self.0 {
2477 WindowCtrlMode::Headed(c) => c.start_drag_drop(data, allowed_effects),
2478 WindowCtrlMode::Headless(c) => c.start_drag_drop(data, allowed_effects),
2479 WindowCtrlMode::HeadlessWithRenderer(c) => c.start_drag_drop(data, allowed_effects),
2480 WindowCtrlMode::Nested(c) => c.start_drag_drop(data, allowed_effects),
2481 }
2482 }
2483
2484 pub fn drag_dropped(&mut self, drop_id: DragDropId, applied: DragDropEffect) {
2485 match &mut self.0 {
2486 WindowCtrlMode::Headed(c) => c.drag_dropped(drop_id, applied),
2487 WindowCtrlMode::Headless(c) => c.drag_dropped(drop_id, applied),
2488 WindowCtrlMode::HeadlessWithRenderer(c) => c.drag_dropped(drop_id, applied),
2489 WindowCtrlMode::Nested(c) => c.drag_dropped(drop_id, applied),
2490 }
2491 }
2492
2493 pub fn bring_to_top(&mut self) {
2494 match &mut self.0 {
2495 WindowCtrlMode::Headed(c) => c.bring_to_top(),
2496 WindowCtrlMode::Headless(c) => c.bring_to_top(),
2497 WindowCtrlMode::HeadlessWithRenderer(c) => c.bring_to_top(),
2498 WindowCtrlMode::Nested(c) => c.bring_to_top(),
2499 }
2500 }
2501
2502 pub fn close(&mut self) {
2503 match &mut self.0 {
2504 WindowCtrlMode::Headed(c) => c.close(),
2505 WindowCtrlMode::Headless(c) => c.close(),
2506 WindowCtrlMode::HeadlessWithRenderer(c) => c.close(),
2507 WindowCtrlMode::Nested(c) => c.close(),
2508 }
2509 }
2510
2511 pub(crate) fn view_task(&mut self, task: Box<dyn FnOnce(Option<&ViewWindow>) + Send>) {
2512 match &mut self.0 {
2513 WindowCtrlMode::Headed(c) => c.view_task(task),
2514 WindowCtrlMode::Headless(c) => c.view_task(task),
2515 WindowCtrlMode::HeadlessWithRenderer(c) => c.view_task(task),
2516 WindowCtrlMode::Nested(c) => c.view_task(task),
2517 }
2518 }
2519}
2520
2521fn default_min_size(scale_factor: Factor) -> PxSize {
2522 DipSize::new(Dip::new(192), Dip::new(48)).to_px(scale_factor)
2523}
2524
2525fn default_size(scale_factor: Factor) -> PxSize {
2526 DipSize::new(Dip::new(800), Dip::new(600)).to_px(scale_factor)
2527}
2528
2529type Ignore = Result<(), ViewChannelError>;
2531
2532pub(crate) struct NestedContentCtrl {
2533 content: ContentCtrl,
2534 pending_layout: Option<Arc<LayoutUpdates>>,
2535 pending_render: Option<[Arc<RenderUpdates>; 2]>,
2536 ctx: WindowCtx,
2537 host: Option<(WindowId, WidgetId)>,
2538 #[cfg(feature = "image")]
2539 pending_frame_capture: FrameCapture,
2540}
2541
2542struct NestedCtrl {
2544 c: Arc<Mutex<NestedContentCtrl>>,
2545 actual_parent: Option<WindowId>,
2546 var_bindings: VarHandles,
2548}
2549impl NestedCtrl {
2550 pub fn new(c: Arc<Mutex<NestedContentCtrl>>) -> Self {
2551 Self {
2552 c,
2553 actual_parent: None,
2554 var_bindings: VarHandles::dummy(),
2555 }
2556 }
2557
2558 fn update(&mut self, update_widgets: &WidgetUpdates) {
2559 let mut c = self.c.lock();
2560 c.content.update(update_widgets);
2561
2562 let vars = &c.content.vars;
2563
2564 if update_parent(&mut self.actual_parent, vars) || self.var_bindings.is_dummy() {
2565 let m_scale_factor = if let Some(p) = self.actual_parent.and_then(|p| WINDOWS.vars(p).ok()) {
2566 p.actual_monitor()
2567 .get()
2568 .and_then(|m| MONITORS.monitor(m))
2569 .map(|m| m.scale_factor().get())
2570 } else {
2571 None
2572 };
2573 self.var_bindings = update_headless_vars(m_scale_factor, vars);
2574 }
2575 }
2576
2577 fn info(&mut self, info_widgets: Arc<InfoUpdates>) -> Option<WidgetInfoTree> {
2578 self.c.lock().content.info(info_widgets)
2579 }
2580
2581 fn pre_event(&mut self, update: &EventUpdate) {
2582 #[cfg(feature = "image")]
2583 if let Some(args) = RAW_FRAME_RENDERED_EVENT.on(update) {
2584 let mut c = self.c.lock();
2585 let c = &mut *c;
2586 if let Some((win, _)) = c.host
2587 && args.window_id == win
2588 {
2589 let image = match mem::take(&mut c.pending_frame_capture) {
2590 FrameCapture::None => None,
2591 FrameCapture::Full => Some(WINDOWS.frame_image(win, None).get()),
2592 FrameCapture::Mask(m) => Some(WINDOWS.frame_image(win, Some(m)).get()),
2593 _ => None,
2594 };
2595 let args = FrameImageReadyArgs::new(args.timestamp, args.propagation().clone(), win, args.frame_id, image);
2596 FRAME_IMAGE_READY_EVENT.notify(args);
2597 }
2598 return;
2599 }
2600 self.c.lock().content.pre_event(update)
2601 }
2602
2603 fn ui_event(&mut self, update: &EventUpdate) {
2604 self.c.lock().content.ui_event(update)
2605 }
2606
2607 fn layout(&self, layout_widgets: Arc<LayoutUpdates>) {
2608 if layout_widgets.delivery_list().enter_window(WINDOW.id()) {
2609 let mut c = self.c.lock();
2610 let c = &mut *c;
2611 if let Some((_, wgt_id)) = &c.host {
2612 c.pending_layout = Some(layout_widgets);
2613 UPDATES.layout(*wgt_id);
2614 }
2615 }
2616 }
2617
2618 fn render(&self, render_widgets: Arc<RenderUpdates>, render_update_widgets: Arc<RenderUpdates>) {
2619 let id = WINDOW.id();
2620 if render_widgets.delivery_list().enter_window(id) || render_update_widgets.delivery_list().enter_window(id) {
2621 let mut c = self.c.lock();
2622 let c = &mut *c;
2623 if let Some((_, wgt_id)) = &c.host {
2624 c.pending_render = Some([render_widgets, render_update_widgets]);
2625 UPDATES.render(*wgt_id);
2626 }
2627 }
2628 }
2629
2630 fn focus(&self) {
2631 self.bring_to_top();
2632 let args = RawWindowFocusArgs::now(WINDOWS.focused_window_id(), Some(WINDOW.id()));
2634 RAW_WINDOW_FOCUS_EVENT.notify(args);
2635 }
2636
2637 pub fn start_drag_drop(&mut self, data: Vec<DragDropData>, allowed_effects: DragDropEffect) -> Result<DragDropId, DragDropError> {
2638 if let Some((win_id, _)) = &self.c.lock().host {
2639 return WINDOWS_DRAG_DROP.start_drag_drop(*win_id, data, allowed_effects);
2640 }
2641 Err(DragDropError::CannotStart("nested window host unavailable".into()))
2642 }
2643
2644 pub fn drag_dropped(&mut self, drop_id: DragDropId, applied: DragDropEffect) {
2645 let _ = (drop_id, applied);
2646 }
2647
2648 fn bring_to_top(&self) {
2649 if let Some((win_id, _)) = &self.c.lock().host {
2650 let _ = WINDOWS.bring_to_top(*win_id);
2651 }
2652 }
2653
2654 fn close(&mut self) {
2655 let mut c = self.c.lock();
2656 c.content.close();
2657 c.pending_layout = None;
2658 c.pending_render = None;
2659 if let Some((_, wgt_id)) = &c.host {
2660 UPDATES.layout(*wgt_id);
2662 }
2663 }
2664
2665 fn view_task(&self, task: Box<dyn FnOnce(Option<&ViewWindow>)>) {
2666 task(None)
2667 }
2668}
2669
2670pub struct NestedWindowNode {
2672 c: Arc<Mutex<NestedContentCtrl>>,
2673}
2674impl NestedWindowNode {
2675 fn layout_impl(&mut self, is_measure: bool, measure_layout: impl FnOnce(&mut UiNode) -> PxSize) -> PxSize {
2676 let mut c = self.c.lock();
2677 let c = &mut *c;
2678
2679 if !c.content.vars.0.is_open.get() {
2680 return PxSize::zero();
2681 }
2682
2683 let auto_size = c.content.vars.auto_size().get();
2684 let constraints = LAYOUT.constraints();
2685
2686 let metrics = LayoutMetrics::new(LAYOUT.scale_factor(), PxSize::splat(Px::MAX), LAYOUT.root_font_size())
2687 .with_constraints(constraints)
2688 .with_screen_density(LAYOUT.screen_density())
2689 .with_direction(DIRECTION_VAR.get());
2690
2691 LocalContext::capture_filtered(zng_app_context::CaptureFilter::app_only()).with_context(|| {
2693 WINDOW.with_context(&mut c.ctx, || {
2694 WIDGET.with_context(&mut c.content.root_ctx, WidgetUpdateMode::Bubble, || {
2695 LAYOUT.with_root_context(c.content.layout_pass, metrics, || {
2696 let mut root_cons = LAYOUT.constraints();
2697
2698 let dft = root_cons.fill_size();
2700 let (min_size, max_size, pref_size) =
2701 LAYOUT.with_constraints(root_cons.with_fill_vector(root_cons.is_bounded()), || {
2702 let max = c.content.vars.max_size().layout_dft(dft);
2703 (c.content.vars.min_size().layout(), max, c.content.vars.size().layout_dft(max))
2704 });
2705
2706 let min_size = min_size.max(root_cons.min_size());
2707 let max_size = max_size.min(root_cons.max_size_or(PxSize::splat(Px::MAX)));
2708 let pref_size = pref_size.clamp(min_size, max_size);
2709
2710 if auto_size.contains(AutoSize::CONTENT_WIDTH) {
2711 root_cons.x = PxConstraints::new_range(min_size.width, max_size.width);
2712 } else {
2713 root_cons.x = PxConstraints::new_exact(pref_size.width);
2714 }
2715 if auto_size.contains(AutoSize::CONTENT_HEIGHT) {
2716 root_cons.y = PxConstraints::new_range(min_size.height, max_size.height);
2717 } else {
2718 root_cons.y = PxConstraints::new_exact(pref_size.height);
2719 }
2720
2721 if auto_size.is_empty() && is_measure {
2722 pref_size
2723 } else {
2724 LAYOUT.with_constraints(root_cons, || measure_layout(&mut c.content.root))
2725 }
2726 })
2727 })
2728 })
2729 })
2730 }
2731}
2732impl UiNodeImpl for NestedWindowNode {
2733 fn children_len(&self) -> usize {
2734 1
2735 }
2736
2737 fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
2738 if index == 0 {
2739 visitor(&mut self.c.lock().content.root)
2740 }
2741 }
2742
2743 fn init(&mut self) {
2744 let mut c = self.c.lock();
2745 let parent_id = WINDOW.id();
2746 c.content.vars.parent().set(parent_id);
2747 let nest_parent = WIDGET.id();
2748 c.content.vars.0.nest_parent.set(nest_parent);
2749 c.host = Some((parent_id, nest_parent));
2750 }
2752
2753 fn deinit(&mut self) {
2754 let mut c = self.c.lock();
2756 c.host = None;
2757 let c = &self.c;
2758 TIMERS
2759 .on_deadline(
2760 100.ms(),
2761 hn_once!(c, |_| {
2762 let c = c.lock();
2763 if c.host.is_none() {
2764 let _ = WINDOWS.close(c.ctx.id());
2765 }
2766 }),
2767 )
2768 .perm();
2769
2770 }
2772
2773 fn info(&mut self, info: &mut WidgetInfoBuilder) {
2774 info.set_meta(*NESTED_WINDOW_INFO_ID, self.c.lock().ctx.id());
2775 }
2776
2777 fn event(&mut self, _: &EventUpdate) {
2778 }
2780
2781 fn update(&mut self, _: &WidgetUpdates) {
2782 }
2784
2785 fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
2786 self.layout_impl(true, |r| wm.with_widget(|wm| r.measure(wm)))
2787 }
2788
2789 fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
2790 let pending = self.c.lock().pending_layout.take();
2791 let size = self.layout_impl(false, |r| {
2792 if let Some(p) = pending {
2793 wl.with_layout_updates(p, |wl| wl.with_widget(|wl| r.layout(wl)))
2794 } else {
2795 wl.with_widget(|wl| r.layout(wl))
2796 }
2797 });
2798 let c = self.c.lock();
2799 let factor = LAYOUT.scale_factor();
2800 c.content.vars.0.scale_factor.set(factor);
2801 c.content.vars.0.actual_size.set(size.to_dip(factor));
2802 size
2803 }
2804
2805 fn render(&mut self, frame: &mut FrameBuilder) {
2806 let mut c = self.c.lock();
2807 let c = &mut *c;
2808
2809 if !c.content.vars.0.is_open.get() {
2810 return;
2811 }
2812
2813 let [render_widgets, render_update_widgets] = c.pending_render.take().unwrap_or_default();
2814 LocalContext::capture_filtered(zng_app_context::CaptureFilter::app_only()).with_context(|| {
2816 WINDOW.with_context(&mut c.ctx, || {
2817 let root_id = c.content.root_ctx.id();
2818 let root_bounds = c.content.root_ctx.bounds();
2819 WIDGET.with_context(&mut c.content.root_ctx, WidgetUpdateMode::Bubble, || {
2820 frame.with_nested_window(
2821 render_widgets,
2822 render_update_widgets,
2823 root_id,
2824 &root_bounds,
2825 &WINDOW.info(),
2826 FontAntiAliasing::Default,
2827 |frame| {
2828 c.content.root.render(frame);
2829 },
2830 );
2831 });
2832 #[cfg(feature = "image")]
2833 {
2834 c.pending_frame_capture = c.content.take_frame_capture();
2835 }
2836 })
2837 })
2838 }
2839
2840 fn render_update(&mut self, update: &mut FrameUpdate) {
2841 let mut c = self.c.lock();
2842 let c = &mut *c;
2843
2844 if !c.content.vars.0.is_open.get() {
2845 return;
2846 }
2847
2848 let [_, render_update_widgets] = c.pending_render.take().unwrap_or_default();
2849 LocalContext::capture_filtered(zng_app_context::CaptureFilter::app_only()).with_context(|| {
2851 WINDOW.with_context(&mut c.ctx, || {
2852 WIDGET.with_context(&mut c.content.root_ctx, WidgetUpdateMode::Bubble, || {
2853 update.with_nested_window(render_update_widgets, WIDGET.id(), WIDGET.bounds(), |update| {
2854 c.content.root.render_update(update);
2855 })
2856 })
2857 })
2858 })
2859 }
2860
2861 fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
2862 if self.c.lock().content.root.as_widget().is_some() {
2863 Some(self)
2864 } else {
2865 None
2866 }
2867 }
2868}
2869impl WidgetUiNodeImpl for NestedWindowNode {
2870 fn with_context(&mut self, update_mode: WidgetUpdateMode, visitor: &mut dyn FnMut()) {
2871 let mut lock = self.c.lock();
2872 if let Some(mut w) = lock.content.root.as_widget() {
2873 w.with_context(update_mode, visitor)
2874 }
2875 }
2876}
2877
2878static_id! {
2879 static ref NESTED_WINDOW_INFO_ID: StateId<WindowId>;
2880}
2881
2882pub trait NestedWindowWidgetInfoExt {
2884 fn nested_window(&self) -> Option<WindowId>;
2886
2887 fn nested_window_tree(&self) -> Option<WidgetInfoTree> {
2889 WINDOWS.widget_tree(self.nested_window()?).ok()
2890 }
2891}
2892
2893impl NestedWindowWidgetInfoExt for WidgetInfo {
2894 fn nested_window(&self) -> Option<WindowId> {
2895 self.meta().get_clone(*NESTED_WINDOW_INFO_ID)
2896 }
2897}
2898
2899#[allow(clippy::large_enum_variant)] enum OpenNestedHandlerArgsValue {
2901 Normal {
2902 ctx: WindowCtx,
2903 vars: WindowVars,
2904 commands: WindowCommands,
2905 window: WindowRoot,
2906 },
2907 Nested {
2908 ctx: WindowCtx,
2909 node: Arc<Mutex<NestedContentCtrl>>,
2910 },
2911 TempNone,
2912}
2913
2914pub struct OpenNestedHandlerArgs {
2918 c: OpenNestedHandlerArgsValue,
2919}
2920impl OpenNestedHandlerArgs {
2921 pub(crate) fn new(ctx: WindowCtx, vars: WindowVars, commands: WindowCommands, window: WindowRoot) -> Self {
2922 Self {
2923 c: OpenNestedHandlerArgsValue::Normal {
2924 ctx,
2925 vars,
2926 commands,
2927 window,
2928 },
2929 }
2930 }
2931
2932 pub fn ctx(&self) -> &WindowCtx {
2934 match &self.c {
2935 OpenNestedHandlerArgsValue::Normal { ctx, .. } | OpenNestedHandlerArgsValue::Nested { ctx, .. } => ctx,
2936 OpenNestedHandlerArgsValue::TempNone => unreachable!(),
2937 }
2938 }
2939
2940 pub fn vars(&mut self) -> WindowVars {
2942 let ctx = match &mut self.c {
2943 OpenNestedHandlerArgsValue::Normal { ctx, .. } | OpenNestedHandlerArgsValue::Nested { ctx, .. } => ctx,
2944 OpenNestedHandlerArgsValue::TempNone => unreachable!(),
2945 };
2946 WINDOW.with_context(ctx, || WINDOW.vars())
2947 }
2948
2949 pub fn nest(&mut self) -> NestedWindowNode {
2956 match mem::replace(&mut self.c, OpenNestedHandlerArgsValue::TempNone) {
2957 OpenNestedHandlerArgsValue::Normal {
2958 mut ctx,
2959 vars,
2960 commands,
2961 window,
2962 } => {
2963 let node = NestedWindowNode {
2964 c: Arc::new(Mutex::new(NestedContentCtrl {
2965 content: ContentCtrl::new(vars, commands, window),
2966 pending_layout: None,
2967 pending_render: None,
2968 #[cfg(feature = "image")]
2969 pending_frame_capture: FrameCapture::None,
2970 ctx: ctx.share(),
2971 host: None,
2972 })),
2973 };
2974 self.c = OpenNestedHandlerArgsValue::Nested { ctx, node: node.c.clone() };
2975 node
2976 }
2977 _ => panic!("already nesting"),
2978 }
2979 }
2980
2981 pub(crate) fn has_nested(&self) -> bool {
2982 matches!(&self.c, OpenNestedHandlerArgsValue::Nested { .. })
2983 }
2984
2985 pub(crate) fn take_normal(
2986 self,
2987 ) -> Result<(WindowCtx, WindowVars, WindowCommands, WindowRoot), (WindowCtx, Arc<Mutex<NestedContentCtrl>>)> {
2988 match self.c {
2989 OpenNestedHandlerArgsValue::Normal {
2990 ctx,
2991 vars,
2992 commands,
2993 window,
2994 } => Ok((ctx, vars, commands, window)),
2995 OpenNestedHandlerArgsValue::Nested { ctx, node } => Err((ctx, node)),
2996 OpenNestedHandlerArgsValue::TempNone => unreachable!(),
2997 }
2998 }
2999}