Skip to main content

bern_runtime/
window.rs

1//! Presentation of window instances.
2//!
3//! The target owns the real windows. It reports what the platform shows —
4//! minimized, maximized, moved, focused — as facts tagged with their
5//! source and the instance generation, and the runtime keeps the latest
6//! facts of each instance with a version. Facts never dispatch commands:
7//! a window the user minimized is recorded as minimized, not minimized
8//! again, and external entries have no way to inject facts.
9
10use bern_protocol::Value;
11
12/// How a window kind is presented by the target.
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum Presentation {
15    /// A system window, such as an `NSWindow`.
16    Native,
17    /// A window drawn inside a host surface, such as a page.
18    Virtual,
19}
20
21/// Where the window is, as the platform reports it.
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum Visibility {
24    Visible,
25    Minimized,
26    /// Not on screen and not minimized, for example while the app is hidden.
27    Hidden,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub enum SizeState {
32    Normal,
33    Maximized,
34    FullScreen,
35}
36
37/// Window actions; `WindowFacts::actions` lists those available now.
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum WindowAction {
40    Activate,
41    Close,
42    Minimize,
43    Restore,
44    Maximize,
45    Move,
46    Resize,
47}
48
49impl WindowAction {
50    pub const ALL: [WindowAction; 7] = [
51        WindowAction::Activate,
52        WindowAction::Close,
53        WindowAction::Minimize,
54        WindowAction::Restore,
55        WindowAction::Maximize,
56        WindowAction::Move,
57        WindowAction::Resize,
58    ];
59
60    pub fn index(self) -> u32 {
61        Self::ALL.iter().position(|action| *action == self).unwrap() as u32
62    }
63
64    pub fn name(self) -> &'static str {
65        match self {
66            WindowAction::Activate => "activate",
67            WindowAction::Close => "close",
68            WindowAction::Minimize => "minimize",
69            WindowAction::Restore => "restore",
70            WindowAction::Maximize => "maximize",
71            WindowAction::Move => "move",
72            WindowAction::Resize => "resize",
73        }
74    }
75
76    /// Decode a set of actions from bit `index()` of `bits`.
77    pub fn from_bits(bits: u32) -> Vec<WindowAction> {
78        Self::ALL
79            .into_iter()
80            .filter(|action| bits & (1 << action.index()) != 0)
81            .collect()
82    }
83}
84
85/// Who caused the latest change of a window's facts.
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub enum FactSource {
88    /// A window command from any entry.
89    Command,
90    /// The user or the system, for example the minimize button.
91    System,
92}
93
94/// Outer frame in points. The origin is the top-left corner of the main
95/// display and `y` grows downwards.
96#[derive(Clone, Copy, Debug, PartialEq)]
97pub struct Frame {
98    pub x: f64,
99    pub y: f64,
100    pub width: f64,
101    pub height: f64,
102}
103
104/// What the platform shows for one window instance.
105#[derive(Clone, Debug, PartialEq)]
106pub struct WindowFacts {
107    pub visibility: Visibility,
108    pub size: SizeState,
109    pub frame: Frame,
110    pub focused: bool,
111    pub actions: Vec<WindowAction>,
112}
113
114/// Lifecycle of an open window instance.
115#[derive(Clone, Copy, Debug, PartialEq, Eq)]
116pub enum Lifecycle {
117    /// Attached, but the target has not reported its presentation yet.
118    Opening,
119    Open,
120    /// A close confirmation is waiting for a decision.
121    Closing,
122}
123
124/// `window.list` entry for one open instance.
125#[derive(Clone, Debug, PartialEq)]
126pub struct WindowInfo {
127    pub window: String,
128    pub kind: String,
129    pub presentation: Presentation,
130    pub lifecycle: Lifecycle,
131    /// `None` while the window is opening.
132    pub facts: Option<WindowFacts>,
133    /// Bumped by every change of the facts of this instance.
134    pub version: u64,
135    pub changed_by: Option<FactSource>,
136}
137
138impl WindowInfo {
139    /// The session catalog's `WindowInfo` record. While the window is
140    /// opening it is hidden, has no frame and offers no actions.
141    pub fn to_value(&self) -> Value {
142        let variant = |index: usize| Value::unit_variant(index as u32);
143        let facts = self.facts.as_ref();
144        Value::Record(vec![
145            Value::Text(self.window.clone()),
146            Value::Text(self.kind.clone()),
147            variant(self.presentation as usize),
148            variant(self.lifecycle as usize),
149            variant(facts.map_or(Visibility::Hidden, |facts| facts.visibility) as usize),
150            variant(facts.map_or(SizeState::Normal, |facts| facts.size) as usize),
151            match facts {
152                Some(facts) => Value::some(Value::Record(vec![
153                    Value::Float(facts.frame.x),
154                    Value::Float(facts.frame.y),
155                    Value::Float(facts.frame.width),
156                    Value::Float(facts.frame.height),
157                ])),
158                None => Value::none(),
159            },
160            Value::Bool(facts.is_some_and(|facts| facts.focused)),
161            Value::List(
162                facts
163                    .map(|facts| facts.actions.as_slice())
164                    .unwrap_or_default()
165                    .iter()
166                    .map(|action| variant(action.index() as usize))
167                    .collect(),
168            ),
169            Value::Int(self.version as i64),
170            match self.changed_by {
171                Some(source) => Value::some(variant(source as usize)),
172                None => Value::none(),
173            },
174        ])
175    }
176}