1use std::fmt;
11use std::future::Future;
12use std::pin::Pin;
13use std::rc::Rc;
14use std::time::Duration;
15
16pub use raw_window_handle::RawWindowHandle;
17
18use crate::{Rect, ViewRef};
19
20#[derive(Clone, Debug, PartialEq)]
28pub struct WindowConfig {
29 pub title: String,
30 pub size: [f64; 2],
31 pub position: Option<[f64; 2]>,
33 pub decorations: bool,
35 pub resizable: bool,
36 pub level: WindowLevel,
37 pub activating: bool,
40 pub all_desktops: bool,
42 pub background: WindowBackground,
43 pub shadow: bool,
45 pub visible: bool,
46}
47
48impl Default for WindowConfig {
49 fn default() -> WindowConfig {
50 WindowConfig {
51 title: String::new(),
52 size: [400.0, 300.0],
53 position: None,
54 decorations: true,
55 resizable: true,
56 level: WindowLevel::Normal,
57 activating: true,
58 all_desktops: false,
59 background: WindowBackground::Solid,
60 shadow: true,
61 visible: true,
62 }
63 }
64}
65
66#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
67pub enum WindowLevel {
68 #[default]
69 Normal,
70 AlwaysOnTop,
72 AlwaysOnBottom,
74}
75
76#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
79pub enum WindowBackground {
80 #[default]
81 Solid,
82 Transparent,
83 Blurred,
85 Glass,
88}
89
90impl WindowBackground {
91 pub fn sees_through(self) -> bool {
93 self != WindowBackground::Solid
94 }
95}
96
97#[derive(Clone, Debug, PartialEq, Eq)]
98pub enum WindowError {
99 Unsupported,
101 Failed(String),
102}
103
104impl fmt::Display for WindowError {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 WindowError::Unsupported => f.write_str("the host does not support this window"),
108 WindowError::Failed(reason) => {
109 write!(f, "the host could not make the window: {reason}")
110 }
111 }
112 }
113}
114
115impl std::error::Error for WindowError {}
116
117pub type WindowFuture = Pin<Box<dyn Future<Output = Result<WindowRef, WindowError>>>>;
119
120pub type WindowRef = Rc<dyn HostWindow>;
121
122pub trait HostWindow: 'static {
125 fn view(&self) -> ViewRef;
126
127 fn frame(&self) -> Rect;
129
130 fn set_frame(&self, frame: Rect, animate: Option<Duration>);
132
133 fn set_title(&self, title: &str);
134
135 fn show(&self);
136
137 fn hide(&self);
138
139 fn close(&self);
141
142 fn native_handle(&self) -> Option<RawWindowHandle>;
144
145 fn set_close_requested(&self, handler: Option<Rc<dyn Fn()>>);
148}
149
150pub trait WindowingOwner: 'static {
153 fn create(&self, config: WindowConfig) -> WindowFuture;
156
157 fn adopt(&self, handle: RawWindowHandle) -> WindowFuture {
161 let _ = handle;
162 Box::pin(async { Err(WindowError::Unsupported) })
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn a_default_window_is_an_ordinary_visible_one() {
172 let config = WindowConfig::default();
173 assert!(config.decorations && config.visible && config.activating);
174 assert_eq!(config.level, WindowLevel::Normal);
175 assert_eq!(config.background, WindowBackground::Solid);
176 }
177
178 #[test]
179 fn every_background_but_solid_sees_through() {
180 assert!(!WindowBackground::Solid.sees_through());
181 assert!(WindowBackground::Transparent.sees_through());
182 assert!(WindowBackground::Blurred.sees_through());
183 assert!(WindowBackground::Glass.sees_through());
184 }
185
186 struct NoWindows;
187
188 impl WindowingOwner for NoWindows {
189 fn create(&self, _config: WindowConfig) -> WindowFuture {
190 Box::pin(async { Err(WindowError::Unsupported) })
191 }
192 }
193
194 #[test]
195 fn adoption_is_unsupported_unless_a_host_says_otherwise() {
196 let owner = NoWindows;
197 let mut future = owner.adopt(RawWindowHandle::Web(
198 raw_window_handle::WebWindowHandle::new(1),
199 ));
200 let waker = std::task::Waker::noop();
201 let mut cx = std::task::Context::from_waker(waker);
202 match future.as_mut().poll(&mut cx) {
203 std::task::Poll::Ready(Err(WindowError::Unsupported)) => {}
204 other => panic!(
205 "expected Unsupported, got {:?}",
206 other.map(|r| r.map(|_| ()))
207 ),
208 }
209 }
210}