1use std::collections::HashMap;
12use std::sync::Arc;
13use std::time::Instant;
14
15use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
16
17use kozan_core::input::*;
18use kozan_primitives::geometry::{Offset, Point};
19
20use crate::context::ViewContext;
21use crate::event::{LifecycleEvent, ViewEvent};
22use crate::host::PlatformHost;
23use crate::id::WindowId;
24use crate::pipeline::render_loop::{OnSurfaceLost, RenderEvent};
25use crate::pipeline::{PipelineConfig, ViewportInfo, WindowPipeline};
26use crate::renderer::{Renderer, RendererError};
27use crate::view_thread::SpawnError;
28use crate::window_state::WindowState;
29
30pub struct WindowCreateConfig {
35 pub window_id: WindowId,
36 pub host: Arc<dyn PlatformHost>,
37 pub on_surface_lost: OnSurfaceLost,
38 pub viewport: ViewportInfo,
39}
40
41#[derive(Debug)]
43pub enum CreateWindowError {
44 Renderer(RendererError),
45 Spawn(SpawnError),
46}
47
48impl std::fmt::Display for CreateWindowError {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 match self {
51 Self::Renderer(e) => write!(f, "renderer: {e}"),
52 Self::Spawn(e) => write!(f, "spawn: {e}"),
53 }
54 }
55}
56
57impl std::error::Error for CreateWindowError {}
58
59pub struct WindowManager<R: Renderer> {
65 renderer: R,
66 windows: HashMap<WindowId, WindowState>,
67}
68
69impl<R: Renderer> WindowManager<R> {
70 pub fn new(renderer: R) -> Self {
71 Self {
72 renderer,
73 windows: HashMap::new(),
74 }
75 }
76
77 pub fn create_window<W, F>(
84 &mut self,
85 window_handle: &W,
86 config: WindowCreateConfig,
87 view_init: F,
88 ) -> Result<(), CreateWindowError>
89 where
90 W: HasWindowHandle + HasDisplayHandle,
91 F: FnOnce(&ViewContext) + Send + 'static,
92 {
93 let vp = config.viewport;
94 let surface = self
95 .renderer
96 .create_surface(window_handle, vp.width, vp.height)
97 .map_err(CreateWindowError::Renderer)?;
98
99 let pipeline_config = PipelineConfig {
100 surface,
101 on_surface_lost: config.on_surface_lost,
102 host: config.host,
103 window_id: config.window_id,
104 viewport: vp,
105 };
106
107 let pipeline =
108 WindowPipeline::spawn(pipeline_config, view_init).map_err(CreateWindowError::Spawn)?;
109
110 self.windows.insert(
111 config.window_id,
112 WindowState::new(pipeline, vp.scale_factor),
113 );
114 Ok(())
115 }
116
117 pub fn close_window(&mut self, id: WindowId) {
118 if let Some(mut state) = self.windows.remove(&id) {
119 state.shutdown();
120 }
121 }
122
123 pub fn has_windows(&self) -> bool {
124 !self.windows.is_empty()
125 }
126
127 pub fn shutdown_all(&mut self) {
128 for (_, mut state) in self.windows.drain() {
129 state.shutdown();
130 }
131 }
132
133 pub fn scale_factor(&self, id: WindowId) -> Option<f64> {
135 self.windows.get(&id).map(|s| s.input().scale_factor())
136 }
137
138 pub fn on_resize(&mut self, id: WindowId, width: u32, height: u32) {
141 let Some(state) = self.windows.get_mut(&id) else {
142 return;
143 };
144 state.send_to_render(RenderEvent::Resize { width, height });
145 state.send_to_view(ViewEvent::Lifecycle(LifecycleEvent::Resized {
146 width,
147 height,
148 }));
149 }
150
151 pub fn on_scale_factor_changed(
152 &mut self,
153 id: WindowId,
154 scale_factor: f64,
155 refresh_rate_millihertz: Option<u32>,
156 ) {
157 let Some(state) = self.windows.get_mut(&id) else {
158 return;
159 };
160 state.input_mut().set_scale_factor(scale_factor);
161 state.send_to_render(RenderEvent::ScaleFactorChanged(scale_factor));
162 state.send_to_view(ViewEvent::Lifecycle(LifecycleEvent::ScaleFactorChanged {
163 scale_factor,
164 refresh_rate_millihertz,
165 }));
166 }
167
168 pub fn on_focus_changed(&mut self, id: WindowId, focused: bool) {
169 let Some(state) = self.windows.get(&id) else {
170 return;
171 };
172 state.send_to_view(ViewEvent::Lifecycle(LifecycleEvent::Focused(focused)));
173 }
174
175 pub fn on_redraw(&self, id: WindowId) {
177 let Some(state) = self.windows.get(&id) else {
178 return;
179 };
180 state.send_to_view(ViewEvent::Paint);
181 }
182
183 pub fn on_cursor_moved(&mut self, id: WindowId, physical_x: f64, physical_y: f64) {
186 let Some(state) = self.windows.get_mut(&id) else {
187 return;
188 };
189 state
190 .input_mut()
191 .set_cursor_physical(physical_x, physical_y);
192 let (x, y) = state.input().cursor();
193 let modifiers = state.input().modifiers();
194 state.send_to_view(ViewEvent::Input(InputEvent::MouseMove(MouseMoveEvent {
195 x,
196 y,
197 modifiers,
198 timestamp: Instant::now(),
199 })));
200 }
201
202 pub fn on_cursor_entered(&mut self, id: WindowId) {
203 let Some(state) = self.windows.get(&id) else {
204 return;
205 };
206 let (x, y) = state.input().cursor();
207 let modifiers = state.input().modifiers();
208 state.send_to_view(ViewEvent::Input(InputEvent::MouseEnter(MouseEnterEvent {
209 x,
210 y,
211 modifiers,
212 timestamp: Instant::now(),
213 })));
214 }
215
216 pub fn on_cursor_left(&mut self, id: WindowId) {
217 let Some(state) = self.windows.get(&id) else {
218 return;
219 };
220 let modifiers = state.input().modifiers();
221 state.send_to_view(ViewEvent::Input(InputEvent::MouseLeave(MouseLeaveEvent {
222 modifiers,
223 timestamp: Instant::now(),
224 })));
225 }
226
227 pub fn on_mouse_input(&mut self, id: WindowId, button: MouseButton, btn_state: ButtonState) {
228 let Some(state) = self.windows.get_mut(&id) else {
229 return;
230 };
231 state.input_mut().update_button_modifier(&button, btn_state);
232 let (x, y) = state.input().cursor();
233 let modifiers = state.input().modifiers();
234 state.send_to_view(ViewEvent::Input(InputEvent::MouseButton(
235 MouseButtonEvent {
236 x,
237 y,
238 button,
239 state: btn_state,
240 modifiers,
241 click_count: 1,
242 timestamp: Instant::now(),
243 },
244 )));
245 }
246
247 pub fn on_mouse_wheel(&mut self, id: WindowId, delta: WheelDelta) {
250 let Some(state) = self.windows.get(&id) else {
251 return;
252 };
253 let (x, y) = state.input().cursor();
254 let modifiers = state.input().modifiers();
255
256 state.send_to_render(RenderEvent::Scroll {
257 delta: Offset::new(-delta.px_dx(), -delta.px_dy()),
258 point: Point::new(x as f32, y as f32),
259 });
260
261 state.send_to_view(ViewEvent::Input(InputEvent::Wheel(wheel::WheelEvent {
262 x,
263 y,
264 delta,
265 modifiers,
266 timestamp: Instant::now(),
267 })));
268 }
269
270 pub fn on_keyboard_input(
273 &mut self,
274 id: WindowId,
275 key: KeyCode,
276 key_state: ButtonState,
277 text: Option<String>,
278 repeat: bool,
279 ) {
280 let Some(state) = self.windows.get(&id) else {
281 return;
282 };
283 let mut modifiers = state.input().modifiers();
284 if repeat {
285 modifiers = modifiers.with_auto_repeat();
286 }
287 state.send_to_view(ViewEvent::Input(InputEvent::Keyboard(
288 keyboard::KeyboardEvent {
289 key,
290 state: key_state,
291 modifiers,
292 text,
293 timestamp: Instant::now(),
294 },
295 )));
296 }
297
298 pub fn on_modifiers_changed(
299 &mut self,
300 id: WindowId,
301 shift: bool,
302 ctrl: bool,
303 alt: bool,
304 meta: bool,
305 ) {
306 let Some(state) = self.windows.get_mut(&id) else {
307 return;
308 };
309 state
310 .input_mut()
311 .set_modifiers_from_keyboard(shift, ctrl, alt, meta);
312 }
313}