zng_ext_window/
vars.rs

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