Skip to main content

zng_ext_window/
vars.rs

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