Skip to main content

incular_runtime/
application_types.rs

1use crate::context::BuildContext;
2use crate::profiling::SchedulerCounters;
3use crate::tasks::TaskFailure;
4use incular_core::RestorationKey;
5use incular_platform::WindowOptionsError;
6use incular_widgets::Widget;
7use incular_widgets::internal::TreeError;
8use std::rc::Rc;
9
10#[derive(Clone, Copy, Debug, Default)]
11pub(crate) struct ApplicationSchedulerCounters {
12    pub(crate) runtime_wakes: u64,
13    pub(crate) redraw_requests: u64,
14    pub(crate) frames_started: u64,
15    pub(crate) frames_presented: u64,
16    pub(crate) frames_skipped: u64,
17}
18
19impl ApplicationSchedulerCounters {
20    pub(crate) fn apply_to(self, scheduler: &mut SchedulerCounters) {
21        scheduler.runtime_wakes = self.runtime_wakes;
22        scheduler.redraw_requests = self.redraw_requests;
23        scheduler.frames_started = self.frames_started;
24        scheduler.frames_presented = self.frames_presented;
25        scheduler.frames_skipped = self.frames_skipped;
26    }
27}
28
29/// Backend-neutral application lifecycle. Desktop adapters may only emit a
30/// subset; runtime users must therefore treat transitions as advisory rather
31/// than assume every state is observable on every platform.
32#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
33pub enum ApplicationLifecycle {
34    #[default]
35    Starting,
36    Active,
37    Inactive,
38    Suspended,
39    Stopping,
40    Terminated,
41}
42
43/// A lifecycle update normalized by a platform adapter.
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45pub struct LifecycleTransition {
46    pub previous: ApplicationLifecycle,
47    pub current: ApplicationLifecycle,
48}
49
50/// Runtime-level failure report intended for application logging/telemetry
51/// hooks. Framework panics never unwind into the native event-loop callback.
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct RuntimeErrorReport {
54    pub failure: TaskFailure,
55}
56
57/// Policy applied after a close accepts the final visible Incular window.
58/// `ExitOnLastWindow` is the default so a hidden auxiliary window cannot keep
59/// an application alive accidentally. `KeepRunning` is explicit headless or
60/// background-service policy; a native adapter remains free to wait idle.
61#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
62pub enum LastWindowPolicy {
63    #[default]
64    ExitOnLastWindow,
65    KeepRunning,
66}
67
68/// Failure while creating or addressing an Incular-owned window.
69#[derive(Debug, thiserror::Error)]
70pub enum WindowError {
71    #[error("invalid window options: {0}")]
72    Options(WindowOptionsError),
73    #[error("window tree error: {0}")]
74    Tree(TreeError),
75    #[error("invalid restoration window: {0}")]
76    Restoration(String),
77    #[error("the Incular application has stopped")]
78    ApplicationStopped,
79}
80
81impl From<WindowOptionsError> for WindowError {
82    fn from(error: WindowOptionsError) -> Self {
83        Self::Options(error)
84    }
85}
86
87impl From<TreeError> for WindowError {
88    fn from(error: TreeError) -> Self {
89        Self::Tree(error)
90    }
91}
92
93/// Application-defined identity for a window that should survive a restart.
94/// It is intentionally unrelated to the session-local generational
95/// window ID.
96#[derive(Clone, Debug, PartialEq, Eq, Hash)]
97pub struct WindowRestorationId(pub(crate) RestorationKey);
98
99impl WindowRestorationId {
100    pub fn new(value: impl Into<String>) -> Result<Self, incular_core::RestorationKeyError> {
101        RestorationKey::new(value).map(Self)
102    }
103
104    #[must_use]
105    pub fn as_key(&self) -> &RestorationKey {
106        &self.0
107    }
108}
109
110/// Application-owned factory for a persisted auxiliary window kind. It is
111/// registered in memory at startup; it is never serialized.
112pub type RestorableWindowFactory = Rc<dyn Fn(&mut BuildContext) -> Widget>;
113
114impl TryFrom<&str> for WindowRestorationId {
115    type Error = incular_core::RestorationKeyError;
116
117    fn try_from(value: &str) -> Result<Self, Self::Error> {
118        Self::new(value)
119    }
120}
121
122#[derive(Clone)]
123pub(crate) struct RestorableWindowMetadata {
124    pub(crate) id: WindowRestorationId,
125    pub(crate) kind: String,
126}
127
128impl RestorableWindowMetadata {
129    pub(crate) fn new(
130        id: WindowRestorationId,
131        kind: impl Into<String>,
132    ) -> Result<Self, WindowError> {
133        let kind = kind.into();
134        if kind.trim().is_empty() || kind.chars().any(char::is_control) {
135            return Err(WindowError::Restoration(
136                "window kind must be a non-empty printable stable identifier".to_owned(),
137            ));
138        }
139        Ok(Self { id, kind })
140    }
141}