lumen_core/window.rs
1//! Backend-neutral description of the app's window and its native menu bar.
2//!
3//! Every launch path (the CLI, the C-ABI, the SDKs) resolves the same
4//! values - size, title, clear color, chrome, menu bar - before a window
5//! exists, and a window backend consumes them when it opens one. Keeping
6//! the description here means the composition point can build it without
7//! naming a backend, and a second window backend can consume it without
8//! inventing a parallel type.
9//!
10//! The menu tree ([`MenuModel`], [`Menu`], [`MenuEntry`]) is pure data: it
11//! says what the menu bar contains, not how a platform draws it.
12//! `lumen-os-menu` re-exports these types and owns the native attach.
13
14use crate::components::Color;
15
16/// Fallback GPU clear color painted before the very first frame - what a
17/// user sees for an instant during window creation, and behind any pixel
18/// the app's tree doesn't cover. This is the single Rust-side source of
19/// truth for that fallback; `lumen_runtime::run::RunOptions::clear` (the
20/// value every launch path reaches - CLI, FFI, SDK) defaults to it too,
21/// so the two never drift apart the way they used to.
22///
23/// A resolved `--lumen-window-bg` custom property (from the app's own
24/// `:root` or its active skin) overrides this at build time - see
25/// `lumen_runtime::run::app_build::build_app`. This constant is only what
26/// remains when no layer defines that token, or a caller constructs
27/// [`WindowOptions`] directly without going through `RunOptions` at all.
28pub const DEFAULT_CLEAR: Color = Color::rgb(0.07, 0.07, 0.09);
29
30/// Everything a window backend needs to open the app's window.
31pub struct WindowOptions {
32 /// Initial window inner size in logical pixels.
33 pub size: (u32, u32),
34 /// Window title.
35 pub title: String,
36 /// Background clear color (writes [`crate::render_world::Viewport::clear`]
37 /// on init). See [`DEFAULT_CLEAR`] for the fallback this defaults to.
38 pub clear: Color,
39 /// Maximize the window on launch. Useful for full-bleed app demos.
40 pub maximized: bool,
41 /// Suppress OS window chrome (title bar, borders, close/min/max
42 /// buttons). Custom title bars and per-platform window drag must
43 /// be implemented inside the app - see the `<title-bar drag>`
44 /// region (TODO S31).
45 pub frameless: bool,
46 /// Initial outer position in physical pixels. `None` lets the OS
47 /// place the window (the default). Wired up so callers can
48 /// restore the last-known window position from disk (P1.3).
49 pub start_position: Option<(i32, i32)>,
50 /// Callback invoked once per close with the current window
51 /// position, inner size (logical), and maximized flag. `None`
52 /// (the default) disables state persistence. Implementations
53 /// typically serialise to disk via
54 /// `lumenc::window_state::save`.
55 pub on_close_state: Option<Box<dyn FnOnce(WindowGeometry) + Send>>,
56 /// Optional native menu bar spec. Built by the embedder from
57 /// the markup `<menubar>` element. `None` = no menu bar.
58 pub menubar: Option<MenuModel>,
59}
60
61impl Default for WindowOptions {
62 fn default() -> Self {
63 Self {
64 size: (800, 600),
65 title: "Lumen".into(),
66 clear: DEFAULT_CLEAR,
67 maximized: false,
68 frameless: false,
69 start_position: None,
70 on_close_state: None,
71 menubar: None,
72 }
73 }
74}
75
76/// Snapshot of geometry handed to [`WindowOptions::on_close_state`] so
77/// the embedder can persist `(position, size, maximized)` to disk.
78#[derive(Debug, Clone, Copy)]
79pub struct WindowGeometry {
80 /// Outer window position in physical pixels (winit
81 /// `Window::outer_position`).
82 pub position: Option<(i32, i32)>,
83 /// Inner window size in logical pixels.
84 pub size: (u32, u32),
85 /// Last maximized state.
86 pub maximized: bool,
87}
88
89/// The app's native menu bar, as parsed from `<menubar>`.
90#[derive(Debug, Clone, Default)]
91pub struct MenuModel {
92 /// Top-level submenus, in source order.
93 pub menus: Vec<Menu>,
94}
95
96/// One submenu (`<menu label="File">...</menu>`).
97#[derive(Debug, Clone)]
98pub struct Menu {
99 /// Display label shown in the menu bar.
100 pub label: String,
101 /// Items inside the submenu.
102 pub items: Vec<MenuEntry>,
103}
104
105/// One submenu entry - either a clickable item or a separator.
106#[derive(Debug, Clone)]
107pub enum MenuEntry {
108 /// `<menuitem id label accel?>`.
109 Item {
110 /// `id="..."` - dispatched as `MenuClicked { id }` to scripts.
111 id: String,
112 /// Display label.
113 label: String,
114 /// Optional accelerator string in muda format.
115 accelerator: Option<String>,
116 },
117 /// `<separator />`.
118 Separator,
119}