zng_ext_window/
vars.rs

1use core::fmt;
2use std::sync::Arc;
3
4use crate::{AutoSize, CursorSource, MonitorQuery, WindowIcon, WindowInstanceState};
5use zng_app::{
6    widget::{WidgetId, base::Parallel, info::access::AccessEnabled},
7    window::{MonitorId, WINDOW, WindowId},
8};
9use zng_color::LightDark;
10use zng_layout::unit::{
11    Dip, DipPoint, DipRect, DipSideOffsets, DipSize, DipToPx, Factor, FactorUnits, Length, LengthUnits, Point, PxPoint, PxSize, Size,
12};
13use zng_state_map::{StateId, static_id};
14use zng_txt::Txt;
15use zng_unique_id::IdSet;
16use zng_var::{Var, VarValue, merge_var, var, var_from};
17use zng_view_api::{
18    config::{ColorScheme, ColorsConfig},
19    window::{CursorIcon, FocusIndicator, RenderMode, VideoMode, WindowButton, WindowState, WindowStateAll},
20};
21
22#[cfg(feature = "image")]
23use crate::FrameCaptureMode;
24#[cfg(feature = "image")]
25use zng_ext_image::ImageEntry;
26
27pub(crate) struct WindowVarsData {
28    pub(crate) instance_state: Var<WindowInstanceState>,
29
30    pub(crate) chrome: Var<bool>,
31    pub(crate) icon: Var<WindowIcon>,
32    #[cfg(feature = "image")]
33    pub(crate) actual_icon: Var<Option<ImageEntry>>,
34    pub(crate) cursor: Var<CursorSource>,
35    #[cfg(feature = "image")]
36    pub(crate) actual_cursor_img: Var<Option<(ImageEntry, PxPoint)>>,
37    pub(crate) title: Var<Txt>,
38
39    pub(crate) state: Var<WindowState>,
40    pub(crate) focus_indicator: Var<Option<FocusIndicator>>,
41
42    pub(crate) position: Var<Point>,
43    pub(crate) monitor: Var<MonitorQuery>,
44    pub(crate) video_mode: Var<VideoMode>,
45
46    pub(crate) size: Var<Size>,
47    pub(crate) auto_size: Var<AutoSize>,
48    pub(crate) auto_size_origin: Var<Point>,
49    pub(crate) min_size: Var<Size>,
50    pub(crate) max_size: Var<Size>,
51
52    pub(crate) font_size: Var<Length>,
53
54    pub(crate) actual_position: Var<DipPoint>,
55    pub(crate) global_position: Var<PxPoint>,
56    pub(crate) actual_monitor: Var<Option<MonitorId>>,
57    pub(crate) actual_size: Var<DipSize>,
58    pub(crate) actual_min_size: Var<DipSize>,
59    pub(crate) actual_max_size: Var<DipSize>,
60    pub(crate) safe_padding: Var<DipSideOffsets>,
61
62    pub(crate) scale_factor: Var<Factor>,
63
64    pub(crate) restore_state: Var<WindowState>,
65    pub(crate) restore_rect: Var<DipRect>,
66
67    pub(crate) enabled_buttons: Var<WindowButton>,
68
69    pub(crate) resizable: Var<bool>,
70    pub(crate) movable: Var<bool>,
71
72    pub(crate) always_on_top: Var<bool>,
73
74    pub(crate) visible: Var<bool>,
75    pub(crate) taskbar_visible: Var<bool>,
76
77    pub(crate) parent: Var<Option<WindowId>>,
78    pub(crate) nest_parent: Var<Option<WidgetId>>,
79    modal: Var<bool>,
80    pub(crate) children: Var<IdSet<WindowId>>,
81
82    pub(crate) color_scheme: Var<Option<ColorScheme>>,
83    pub(crate) actual_color_scheme: Var<ColorScheme>,
84    pub(crate) accent_color: Var<Option<LightDark>>,
85    pub(crate) actual_accent_color: Var<LightDark>,
86
87    pub(crate) focused: Var<bool>,
88
89    #[cfg(feature = "image")]
90    pub(crate) frame_capture_mode: Var<FrameCaptureMode>,
91    pub(crate) render_mode: Var<RenderMode>,
92
93    pub(crate) access_enabled: Var<AccessEnabled>,
94    pub(crate) system_shutdown_warn: Var<Txt>,
95
96    parallel: Var<Parallel>,
97}
98
99/// Variables that configure the opening or open window.
100///
101/// You can get the vars for any window using [`WINDOWS.vars`].
102///
103/// You can get the vars for the current context window using [`WINDOW.vars`].
104///
105/// [`WINDOWS.vars`]: crate::WINDOWS::vars
106/// [`WINDOW.vars`]: crate::WINDOW_Ext::vars
107#[derive(Clone)]
108pub struct WindowVars(pub(crate) Arc<WindowVarsData>);
109impl fmt::Debug for WindowVars {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        f.debug_tuple("WindowVars").finish_non_exhaustive()
112    }
113}
114impl WindowVars {
115    pub(crate) fn new(default_render_mode: RenderMode, primary_scale_factor: Factor, system_colors: ColorsConfig) -> Self {
116        let vars = Arc::new(WindowVarsData {
117            instance_state: var(WindowInstanceState::Building),
118            chrome: var(true),
119            icon: var(WindowIcon::Default),
120            #[cfg(feature = "image")]
121            actual_icon: var(None),
122            cursor: var_from(CursorIcon::Default),
123            #[cfg(feature = "image")]
124            actual_cursor_img: var(None),
125            title: var(zng_env::about().app.clone()),
126
127            state: var(WindowState::Normal),
128            focus_indicator: var(None),
129
130            position: var(Point::default()),
131            monitor: var(MonitorQuery::default()),
132            video_mode: var(VideoMode::default()),
133            size: var(Size::default()),
134
135            font_size: var(11.pt()),
136
137            actual_position: var(DipPoint::zero()),
138            global_position: var(PxPoint::zero()),
139            actual_monitor: var(None),
140            actual_size: var(DipSize::zero()),
141            actual_min_size: var(DipSize::zero()),
142            actual_max_size: var(DipSize::splat(Dip::MAX)),
143            safe_padding: var(DipSideOffsets::zero()),
144
145            scale_factor: var(primary_scale_factor),
146
147            restore_state: var(WindowState::Normal),
148            restore_rect: var(DipRect::new(
149                DipPoint::new(Dip::new(30), Dip::new(30)),
150                DipSize::new(Dip::new(800), Dip::new(600)),
151            )),
152
153            enabled_buttons: var(WindowButton::all()),
154
155            min_size: var(Size::new(192, 48)),
156            max_size: var(Size::new(100.pct(), 100.pct())),
157
158            auto_size: var(AutoSize::empty()),
159            auto_size_origin: var(Point::top_left()),
160
161            resizable: var(true),
162            movable: var(true),
163
164            always_on_top: var(false),
165
166            visible: var(true),
167            taskbar_visible: var(true),
168
169            parent: var(None),
170            nest_parent: var(None),
171            modal: var(false),
172            children: var(IdSet::default()),
173
174            color_scheme: var(None),
175            actual_color_scheme: var(system_colors.scheme),
176            accent_color: var(None),
177            actual_accent_color: var(system_colors.accent.into()),
178
179            focused: var(false),
180
181            #[cfg(feature = "image")]
182            frame_capture_mode: var(FrameCaptureMode::Sporadic),
183            render_mode: var(default_render_mode),
184
185            access_enabled: var(AccessEnabled::empty()),
186            system_shutdown_warn: var(Txt::from("")),
187
188            parallel: var(Parallel::default()),
189        });
190        Self(vars)
191    }
192
193    /// Require the window vars from the window state.
194    ///
195    /// # Panics
196    ///
197    /// Panics if called in a custom window context that did not setup the variables.
198    pub(crate) fn req() -> Self {
199        WINDOW.req_state(*WINDOW_VARS_ID)
200    }
201
202    /// Window instance state.
203    pub fn instance_state(&self) -> Var<WindowInstanceState> {
204        self.0.instance_state.read_only()
205    }
206
207    /// Defines if the window chrome is visible.
208    ///
209    /// The window chrome is the non-client area of the window, usually a border with resize handles and a title bar.
210    ///
211    /// The default value is `true`.
212    ///
213    /// Note that if the [`WINDOWS.system_chrome`] reports the windowing system prefers a custom chrome **and** does not
214    /// provide one the system chrome is not requested, even if this is `true`. Window widget implementers can use that variable to
215    /// detect when a fallback chrome must be provided.
216    ///
217    /// [`WINDOWS.system_chrome`]: crate::WINDOWS::system_chrome
218    pub fn chrome(&self) -> Var<bool> {
219        self.0.chrome.clone()
220    }
221
222    /// Window icon.
223    ///
224    /// See [`WindowIcon`] for details.
225    ///
226    /// The default value is [`WindowIcon::Default`].
227    ///
228    /// You can retrieve the custom icon image using [`actual_icon`].
229    ///
230    /// [`actual_icon`]: Self::actual_icon
231    pub fn icon(&self) -> Var<WindowIcon> {
232        self.0.icon.clone()
233    }
234
235    /// Window icon image.
236    ///
237    /// This is `None` if [`icon`] is [`WindowIcon::Default`], otherwise it is an [`ImageEntry`]
238    /// reference clone.
239    ///
240    /// [`icon`]: Self::icon
241    /// [`ImageEntry`]: zng_ext_image::ImageEntry
242    #[cfg(feature = "image")]
243    pub fn actual_icon(&self) -> Var<Option<ImageEntry>> {
244        self.0.actual_icon.read_only()
245    }
246
247    /// Window cursor icon and visibility.
248    ///
249    /// See [`CursorSource`] for details.
250    ///
251    /// The default is [`CursorIcon::Default`].
252    ///
253    /// [`CursorIcon`]: zng_view_api::window::CursorIcon
254    /// [`CursorIcon::Default`]: zng_view_api::window::CursorIcon::Default
255    pub fn cursor(&self) -> Var<CursorSource> {
256        self.0.cursor.clone()
257    }
258
259    /// Window custom cursor image.
260    ///
261    /// This is `None` if [`cursor`] is not set to a custom image, otherwise it is an [`ImageEntry`]
262    /// reference clone with computed hotspot [`PxPoint`].
263    ///
264    /// [`cursor`]: Self::cursor
265    /// [`ImageEntry`]: zng_ext_image::ImageEntry
266    /// [`PxPoint`]: zng_layout::unit::PxPoint
267    #[cfg(feature = "image")]
268    pub fn actual_cursor_img(&self) -> Var<Option<(ImageEntry, PxPoint)>> {
269        self.0.actual_cursor_img.read_only()
270    }
271
272    /// Window title text.
273    ///
274    /// The default value is `""`.
275    pub fn title(&self) -> Var<Txt> {
276        self.0.title.clone()
277    }
278
279    /// Window screen state.
280    ///
281    /// Minimized, maximized or fullscreen. See [`WindowState`] for details.
282    ///
283    /// The default value is [`WindowState::Normal`].
284    pub fn state(&self) -> Var<WindowState> {
285        self.0.state.clone()
286    }
287
288    /// Window monitor.
289    ///
290    /// The query selects the monitor to which the [`position`] and [`size`] is relative to.
291    ///
292    /// It evaluate once when the window opens and then once every time the variable updates. You can track
293    /// what the current monitor is by using [`actual_monitor`].
294    ///
295    /// # Behavior After Open
296    ///
297    /// If this variable is changed after the window has opened, and the new query produces a different
298    /// monitor from the [`actual_monitor`] and the window is visible; then the window is moved to
299    /// the new monitor:
300    ///
301    /// * **Maximized**: The window is maximized in the new monitor.
302    /// * **Fullscreen**: The window is fullscreen in the new monitor.
303    /// * **Normal**: The window is centered in the new monitor, keeping the same size, unless the
304    ///   [`position`] and [`size`] where set in the same update, in that case these values are used.
305    /// * **Minimized/Hidden**: The window remains hidden, the restore position and size are defined like **Normal**.
306    ///
307    /// [`position`]: WindowVars::position
308    /// [`actual_monitor`]: WindowVars::actual_monitor
309    /// [`size`]: WindowVars::size
310    pub fn monitor(&self) -> Var<MonitorQuery> {
311        self.0.monitor.clone()
312    }
313
314    /// Video mode for exclusive fullscreen.
315    pub fn video_mode(&self) -> Var<VideoMode> {
316        self.0.video_mode.clone()
317    }
318
319    /// Current monitor hosting the window.
320    ///
321    /// This is `None` only if the window has not opened yet (before first render) or if
322    /// no monitors where found in the operating system or if the window is headless without renderer.
323    pub fn actual_monitor(&self) -> Var<Option<MonitorId>> {
324        self.0.actual_monitor.read_only()
325    }
326
327    /// Available video modes in the current monitor.
328    pub fn video_modes(&self) -> Var<Vec<VideoMode>> {
329        self.0.actual_monitor.flat_map(|&m| {
330            m.and_then(|m| super::MONITORS.monitor(m))
331                .unwrap_or_else(super::MonitorInfo::fallback)
332                .video_modes()
333        })
334    }
335
336    /// Current scale factor of the current monitor hosting the window.
337    pub fn scale_factor(&self) -> Var<Factor> {
338        self.0.scale_factor.read_only()
339    }
340
341    /// Window actual position on the [monitor].
342    ///
343    /// This is a read-only variable that tracks the computed position of the window, it updates every
344    /// time the window moves.
345    ///
346    /// The initial value is `(0, 0)`, it starts updating once the window opens. The point
347    /// is relative to the origin of the [monitor].
348    ///
349    /// [monitor]: Self::actual_monitor
350    pub fn actual_position(&self) -> Var<DipPoint> {
351        self.0.actual_position.read_only()
352    }
353
354    /// Window actual position on the virtual screen that encompasses all monitors.
355    ///
356    /// This is a read-only variable that tracks the computed position of the window, it updates every
357    /// time the window moves.
358    ///
359    /// The initial value is `(0, 0)`, it starts updating once the window opens.
360    pub fn global_position(&self) -> Var<PxPoint> {
361        self.0.global_position.read_only()
362    }
363
364    /// Window restore state.
365    ///
366    /// The restore state that the window must be set to be restored, if the [current state] is [`Maximized`], [`Fullscreen`] or [`Exclusive`]
367    /// the restore state is [`Normal`], if the [current state] is [`Minimized`] the restore state is the previous state.
368    ///
369    /// When the restore state is [`Normal`] the [`restore_rect`] defines the window position and size.
370    ///
371    /// [current state]: Self::state
372    /// [`Maximized`]: WindowState::Maximized
373    /// [`Fullscreen`]: WindowState::Fullscreen
374    /// [`Exclusive`]: WindowState::Exclusive
375    /// [`Normal`]: WindowState::Normal
376    /// [`Minimized`]: WindowState::Minimized
377    /// [`restore_rect`]: Self::restore_rect
378    pub fn restore_state(&self) -> Var<WindowState> {
379        self.0.restore_state.read_only()
380    }
381
382    /// Window restore position and size when restoring to [`Normal`].
383    ///
384    /// The restore rectangle is the window position and size when its state is [`Normal`], when the state is not [`Normal`]
385    /// this variable tracks the last normal position and size, it will be the window [`actual_position`] and [`actual_size`] again
386    /// when the state is set back to [`Normal`].
387    ///
388    /// This is a read-only variable, to programmatically set it assign the [`position`] and [`size`] variables. The initial
389    /// value is `(30, 30).at(800, 600)`, it starts updating when the window opens.
390    ///
391    /// Note that to restore the window you only need to set [`state`] to [`restore_state`], if the restore state is [`Normal`]
392    /// this position and size will be applied automatically.
393    ///
394    /// [`Normal`]: WindowState::Normal
395    /// [`actual_position`]: Self::actual_position
396    /// [`actual_size`]: Self::actual_size
397    /// [`position`]: Self::position
398    /// [`size`]: Self::size
399    /// [`monitor`]: Self::monitor
400    /// [`actual_monitor`]: Self::actual_monitor
401    /// [`state`]: Self::state
402    /// [`restore_state`]: Self::restore_state
403    pub fn restore_rect(&self) -> Var<DipRect> {
404        self.0.restore_rect.read_only()
405    }
406
407    /// Window top-left offset on the [`monitor`] when the window is [`Normal`].
408    ///
409    /// Relative values are computed in relation to the [`monitor`] size, updating every time the
410    /// position or monitor variable updates.
411    ///
412    /// When the user moves the window this value is considered stale, when it updates it overwrites the window position again,
413    /// note that the window is only moved if it is in the [`Normal`] state, otherwise only the [`restore_rect`] updates.
414    ///
415    /// When the window is moved by the user this variable does **not** update back, to track the current position of the window
416    /// use [`actual_position`], to track the restore position use [`restore_rect`].
417    ///
418    /// The [`Length::Default`] value causes the OS to select a value.
419    ///
420    /// [`restore_rect`]: WindowVars::restore_rect
421    /// [`actual_position`]: WindowVars::actual_position
422    /// [`monitor`]: WindowVars::monitor
423    /// [`Normal`]: WindowState::Normal
424    /// [`Length::Default`]: zng_layout::unit::Length::Default
425    pub fn position(&self) -> Var<Point> {
426        self.0.position.clone()
427    }
428
429    /// Window actual size on the screen.
430    ///
431    /// This is a read-only variable that tracks the computed size of the window, it updates every time
432    /// the window resizes.
433    ///
434    /// The initial value is `(0, 0)`, it starts updating when the window opens.
435    pub fn actual_size(&self) -> Var<DipSize> {
436        self.0.actual_size.read_only()
437    }
438
439    /// Window [`actual_size`], converted to pixels given the [`scale_factor`].
440    ///
441    /// [`actual_size`]: Self::actual_size
442    /// [`scale_factor`]: Self::scale_factor
443    pub fn actual_size_px(&self) -> Var<PxSize> {
444        merge_var!(self.0.actual_size.clone(), self.0.scale_factor.clone(), |size, factor| {
445            PxSize::new(size.width.to_px(*factor), size.height.to_px(*factor))
446        })
447    }
448
449    /// Window actual min size.
450    ///
451    /// This is a read-only variable that tracks the computed min size of the window.
452    pub fn actual_min_size(&self) -> Var<DipSize> {
453        self.0.actual_min_size.read_only()
454    }
455
456    /// Window actual max size.
457    ///
458    /// This is a read-only variable that tracks the computed min size of the window.
459    pub fn actual_max_size(&self) -> Var<DipSize> {
460        self.0.actual_max_size.read_only()
461    }
462
463    /// Padding that must be applied to the window content so that it stays clear of screen obstructions
464    /// such as a camera notch cutout.
465    ///
466    /// Note that the *unsafe* area must still be rendered as it may be partially visible, just don't place nay
467    /// interactive or important content outside of this padding.
468    pub fn safe_padding(&self) -> Var<DipSideOffsets> {
469        self.0.safe_padding.read_only()
470    }
471
472    /// Window width and height on the screen when the window is [`Normal`].
473    ///
474    /// Relative values are computed in relation to the [`monitor`] size, updating every time the
475    /// size or monitor variable updates.
476    ///
477    /// When the user resizes the window this value is considered stale, when it updates it overwrites the window size again,
478    /// note that the window is only resized if it is in the [`Normal`] state, otherwise only the [`restore_rect`] updates.
479    ///
480    /// When the window is resized this variable is **not** updated back, to track the current window size use [`actual_size`],
481    /// to track the restore size use [`restore_rect`].
482    ///
483    /// The default value is `(800, 600)`.
484    ///
485    /// [`actual_size`]: WindowVars::actual_size
486    /// [`monitor`]: WindowVars::monitor
487    /// [`restore_rect`]: WindowVars::restore_rect
488    /// [`Normal`]: WindowState::Normal
489    pub fn size(&self) -> Var<Size> {
490        self.0.size.clone()
491    }
492
493    /// Defines if and how the window size is controlled by the content layout.
494    ///
495    /// When enabled overwrites previously set window size, but is still coerced by [`min_size`]
496    /// and [`max_size`]. Auto-size is disabled if the user resizes the window or if [`size`]
497    /// is set.
498    ///
499    /// The default value is [`AutoSize::DISABLED`].
500    ///
501    /// [`size`]: Self::size
502    /// [`min_size`]: Self::min_size
503    /// [`max_size`]: Self::max_size
504    pub fn auto_size(&self) -> Var<AutoSize> {
505        self.0.auto_size.clone()
506    }
507
508    /// The point in the window content that does not move when the window is resized by [`auto_size`].
509    ///
510    /// When the window size increases it *grows* to the right-bottom, the top-left corner does not move because
511    /// the origin of windows it at the top-left and the position did not change, this variables overwrites this origin
512    /// for [`auto_size`] size changes, the window position is adjusted so that it is the center of the resize.
513    ///
514    /// Note this only applies to resizes, the initial auto-size when the window opens is positioned according to the [`StartPosition`] value.
515    ///
516    /// The default value is [`Point::top_left`].
517    ///
518    /// [`auto_size`]: Self::auto_size
519    /// [`monitor`]: WindowVars::monitor
520    /// [`StartPosition`]: crate::StartPosition
521    /// [`Point::top_left`]: zng_layout::unit::Point::top_left
522    pub fn auto_size_origin(&self) -> Var<Point> {
523        self.0.auto_size_origin.clone()
524    }
525
526    /// Minimal window width and height constraint on the [`size`].
527    ///
528    /// Relative values are computed in relation to the [`monitor`] size, updating every time the
529    /// size or monitor variable updates.
530    ///
531    /// Note that the OS can also define a minimum size that supersedes this variable.
532    ///
533    /// The default value is `(192, 48)`.
534    ///
535    /// [`monitor`]: WindowVars::monitor
536    /// [`size`]: Self::size
537    pub fn min_size(&self) -> Var<Size> {
538        self.0.min_size.clone()
539    }
540
541    /// Maximal window width and height constraint on the [`size`].
542    ///
543    /// Relative values are computed in relation to the [`monitor`] size, updating every time the
544    /// size or monitor variable updates.
545    ///
546    /// Note that the OS can also define a maximum size that supersedes this variable.
547    ///
548    /// The default value is `(100.pct(), 100.pct())`
549    ///
550    /// [`monitor`]: WindowVars::monitor
551    /// [`size`]: Self::size
552    pub fn max_size(&self) -> Var<Size> {
553        self.0.max_size.clone()
554    }
555
556    /// Root font size.
557    ///
558    /// This is the font size in all widget branches  that do not override the font size. The [`rem`] unit is relative to this value.
559    ///
560    /// [`rem`]: LengthUnits::rem
561    pub fn font_size(&self) -> Var<Length> {
562        self.0.font_size.clone()
563    }
564
565    /// Defines if the user can resize the window using the window frame.
566    ///
567    /// Note that even if disabled the window can still be resized from other sources.
568    ///
569    /// The default value is `true`.
570    pub fn resizable(&self) -> Var<bool> {
571        self.0.resizable.clone()
572    }
573
574    /// Defines if the user can move the window using the window frame.
575    ///
576    /// Note that even if disabled the window can still be moved from other sources.
577    ///
578    /// The default value is `true`.
579    pub fn movable(&self) -> Var<bool> {
580        self.0.movable.clone()
581    }
582
583    /// Defines the enabled state of the window chrome buttons.
584    pub fn enabled_buttons(&self) -> Var<WindowButton> {
585        self.0.enabled_buttons.clone()
586    }
587
588    /// Defines if the window should always stay on top of other windows.
589    ///
590    /// Note this only applies to other windows that are not also "always-on-top".
591    ///
592    /// The default value is `false`.
593    pub fn always_on_top(&self) -> Var<bool> {
594        self.0.always_on_top.clone()
595    }
596
597    /// Defines if the window is visible on the screen and in the task-bar.
598    ///
599    /// This variable is observed only after the first frame render, before that the window
600    /// is always not visible.
601    ///
602    /// The default value is `true`.
603    pub fn visible(&self) -> Var<bool> {
604        self.0.visible.clone()
605    }
606
607    /// Defines if the window is visible in the task-bar.
608    ///
609    /// The default value is `true`.
610    pub fn taskbar_visible(&self) -> Var<bool> {
611        self.0.taskbar_visible.clone()
612    }
613
614    /// Defines the parent window.
615    ///
616    /// If a parent is set this behavior applies:
617    ///
618    /// * If the parent is minimized, this window is also minimized.
619    /// * If the parent window is maximized, this window is restored.
620    /// * This window is always on-top of the parent window.
621    /// * If the parent window is closed, this window is also closed.
622    /// * If [`modal`] is set, the parent window cannot be focused while this window is open.
623    /// * If a [`color_scheme`] is not set, the fallback is the parent's actual scheme.
624    /// * If an [`accent_color`] is not set, the fallback is the parent's actual accent.
625    ///
626    /// The default value is `None`.
627    ///
628    /// # Validation
629    ///
630    /// The parent window cannot have a parent, if it has, that parent ID is used instead.
631    /// The parent window must exist. This window (child) cannot have children, it also can't set itself as the parent.
632    ///
633    /// If any of these conditions are not met, an error is logged and the parent var is restored to the previous value.
634    ///
635    /// [`modal`]: Self::modal
636    /// [`color_scheme`]: Self::color_scheme
637    /// [`accent_color`]: Self::accent_color
638    pub fn parent(&self) -> Var<Option<WindowId>> {
639        self.0.parent.clone()
640    }
641
642    /// Gets the widget in [`parent`] that hosts the window, if it is nesting.
643    ///
644    /// Nesting windows are presented as an widget, similar to an "iframe".
645    ///
646    /// [`parent`]: Self::parent
647    pub fn nest_parent(&self) -> Var<Option<WidgetId>> {
648        self.0.nest_parent.read_only()
649    }
650
651    /// Defines the [`parent`](Self::parent) connection.
652    ///
653    /// Value is ignored if `parent` is not set. When this is `true` the parent window cannot be focused while this window is open.
654    ///
655    /// The default value is `false`.
656    pub fn modal(&self) -> Var<bool> {
657        self.0.modal.clone()
658    }
659
660    /// Window children.
661    ///
662    /// This is a set of other windows that have this window as a [`parent`].
663    ///
664    /// [`parent`]: Self::parent
665    pub fn children(&self) -> Var<IdSet<WindowId>> {
666        self.0.children.read_only()
667    }
668
669    /// Override the preferred color scheme.
670    ///
671    /// If set to `None` the system preference is used, see [`actual_color_scheme`].
672    ///
673    /// [`actual_color_scheme`]: Self::actual_color_scheme
674    pub fn color_scheme(&self) -> Var<Option<ColorScheme>> {
675        self.0.color_scheme.clone()
676    }
677
678    /// Actual color scheme to use.
679    ///
680    /// This is the system preference, or [`color_scheme`] if it is set.
681    ///
682    /// [`color_scheme`]: Self::color_scheme
683    pub fn actual_color_scheme(&self) -> Var<ColorScheme> {
684        self.0.actual_color_scheme.read_only()
685    }
686
687    /// Override the preferred accent color.
688    ///
689    /// If set to `None` the system preference is used, see [`actual_accent_color`].
690    ///
691    /// [`actual_accent_color`]: Self::actual_accent_color
692    pub fn accent_color(&self) -> Var<Option<LightDark>> {
693        self.0.accent_color.clone()
694    }
695
696    /// Actual accent color to use.
697    ///
698    /// This is the system preference, or [`color_scheme`] if it is set.
699    ///
700    /// The window widget also sets [`ACCENT_COLOR_VAR`] to this variable.
701    ///
702    /// [`color_scheme`]: Self::color_scheme
703    /// [`ACCENT_COLOR_VAR`]: zng_color::colors::ACCENT_COLOR_VAR
704    pub fn actual_accent_color(&self) -> Var<LightDark> {
705        self.0.actual_accent_color.read_only()
706    }
707
708    /// Read-only variable that tracks if the window is focused in the system window manager.
709    ///
710    /// Note that most of the time its preferable to use the `FOCUS` service as it also tracks the widget focus.
711    pub fn is_focused(&self) -> Var<bool> {
712        self.0.focused.read_only()
713    }
714
715    /// Defines the active user attention required indicator.
716    ///
717    /// This is usually a visual indication on the taskbar icon that prompts the user to focus on the window, it is automatically
718    /// changed to `None` once the window receives focus or you can set it to `None` to cancel the indicator.
719    ///
720    /// Prefer using the `FOCUS` service and advanced `FocusRequest` configs instead of setting this variable directly.
721    pub fn focus_indicator(&self) -> Var<Option<FocusIndicator>> {
722        self.0.focus_indicator.clone()
723    }
724
725    /// Defines if and how the frame pixels are captured for the next rendered frames.
726    ///
727    /// If set to [`Next`] the value will change to [`Sporadic`] after the next frame is rendered.
728    ///
729    /// Note that setting this to [`Next`] does not cause a frame request. Use [`WIDGET.render_update`] for that.
730    ///
731    /// [`Next`]: FrameCaptureMode::Next
732    /// [`Sporadic`]: FrameCaptureMode::Sporadic
733    /// [`WIDGET.render_update`]: zng_app::widget::WIDGET::render_update
734    #[cfg(feature = "image")]
735    pub fn frame_capture_mode(&self) -> Var<FrameCaptureMode> {
736        self.0.frame_capture_mode.clone()
737    }
738
739    /// Window actual render mode.
740    ///
741    /// The initial value is the [`default_render_mode`], it can update after the window is created, when the view-process
742    /// actually creates the backend window and after a view-process respawn.
743    ///
744    /// [`default_render_mode`]: crate::WINDOWS::default_render_mode
745    pub fn render_mode(&self) -> Var<RenderMode> {
746        self.0.render_mode.read_only()
747    }
748
749    /// If an accessibility service has requested info from this window.
750    ///
751    /// You can enable this in the app-process using [`enable_access`], the
752    /// view-process can also enable it on the first request for accessibility info by an external tool.
753    ///
754    /// This variable does not update to fully disabled after first enable, but the VIEW bit can disable and re-enable.
755    ///
756    /// [`enable_access`]: crate::WINDOW_Ext::enable_access
757    pub fn access_enabled(&self) -> Var<AccessEnabled> {
758        self.0.access_enabled.read_only()
759    }
760
761    /// Attempt to set a system wide shutdown warning associated with the window.
762    ///
763    /// Operating systems that support this show the text in a warning for the user, it must be a short text
764    /// that identifies the critical operation that cannot be cancelled.
765    ///
766    /// Set to an empty text to remove the warning.
767    ///
768    /// Note that this does not stop the window from closing or the app from exiting normally, you must
769    /// handle window close requests and show some feedback to the user, the view-process will send a window close
770    /// request when a system shutdown attempt is detected.
771    ///
772    /// Note that there is no guarantee that the view-process or operating system will actually set a block, there
773    /// is no error result because operating systems can silently ignore block requests at any moment, even after
774    /// an initial successful block.
775    ///
776    /// ## Current Limitations
777    ///
778    /// The current `zng::view_process` or `zng-view` only implements this feature on Windows and it will only work properly
779    /// under these conditions:
780    ///
781    /// * It must be running in `run_same_process` mode. Windows kills all other processes, so in a run with `init` the app-process
782    ///   will be lost. Note that this also mean that the crash handler and worker processes are also killed.
783    /// * Must be built with `#![windows_subsystem = "windows"]` and must be running from the Windows Explorer (desktop).
784    pub fn system_shutdown_warn(&self) -> Var<Txt> {
785        self.0.system_shutdown_warn.clone()
786    }
787
788    /// Defines what node list methods can run in parallel in the window widgets.
789    ///
790    /// The window binds [`PARALLEL_VAR`] to this value at the root node ensuring all window nodes are
791    /// configured.
792    ///
793    /// See also [`WINDOWS.parallel`] to define parallelization between windows.
794    ///
795    /// [`PARALLEL_VAR`]: zng_app::widget::base::PARALLEL_VAR
796    /// [`WINDOWS.parallel`]: crate::WINDOWS::parallel
797    pub fn parallel(&self) -> Var<Parallel> {
798        self.0.parallel.clone()
799    }
800
801    #[cfg(feature = "image")]
802    pub(crate) fn take_frame_capture(&self) -> zng_view_api::window::FrameCapture {
803        use zng_view_api::window::FrameCapture;
804        match self.0.frame_capture_mode.get() {
805            FrameCaptureMode::Sporadic => FrameCapture::None,
806            FrameCaptureMode::Next => {
807                self.0.frame_capture_mode.set(FrameCaptureMode::Sporadic);
808                FrameCapture::Full
809            }
810            FrameCaptureMode::All => FrameCapture::Full,
811            FrameCaptureMode::NextMask(m) => {
812                self.0.frame_capture_mode.set(FrameCaptureMode::Sporadic);
813                FrameCapture::Mask(m)
814            }
815            FrameCaptureMode::AllMask(m) => FrameCapture::Mask(m),
816        }
817    }
818    #[cfg(not(feature = "image"))]
819    pub(crate) fn take_frame_capture(&self) -> zng_view_api::window::FrameCapture {
820        zng_view_api::window::FrameCapture::None
821    }
822
823    pub(crate) fn window_state_all(&self) -> WindowStateAll {
824        WindowStateAll::new(
825            self.0.state.get(),
826            self.0.global_position.get(),
827            self.0.restore_rect.get(),
828            self.0.restore_state.get(),
829            self.0.actual_min_size.get(),
830            self.0.actual_max_size.get(),
831            self.0.chrome.get(),
832        )
833    }
834
835    pub(crate) fn set_from_view<T: VarValue>(&self, var: impl FnOnce(&Self) -> &Var<T>, new_value: T) {
836        var(self).modify(move |a| {
837            if a.set(new_value) {
838                a.push_tag(SetFromViewTag);
839            }
840        });
841    }
842}
843impl PartialEq for WindowVars {
844    fn eq(&self, other: &Self) -> bool {
845        Arc::ptr_eq(&self.0, &other.0)
846    }
847}
848impl Eq for WindowVars {}
849
850static_id! {
851    pub(crate) static ref WINDOW_VARS_ID: StateId<WindowVars>;
852}
853
854/// Identifies a variable update set from the view-process.
855#[derive(Debug, Clone, Copy, PartialEq, Eq)]
856pub struct SetFromViewTag;
857
858/// Identifies a variable update set from layout, meaning it should not request window layout back.
859#[derive(Debug, Clone, Copy, PartialEq, Eq)]
860pub struct SetFromLayoutTag;