1use std::ops::Deref;
2use std::sync::{Arc, Mutex, MutexGuard};
3
4use winit::{
5 dpi::PhysicalSize,
6 event::{Event, WindowEvent},
7 event_loop::EventLoop,
8 window::{Window, WindowBuilder},
9};
10use winit_input_helper::WinitInputHelper;
11
12use crate::rendering::window::{PresentableWindow, WindowConfig, WindowProvider, WindowRunner};
13
14#[derive(Clone)]
20pub struct Input(Arc<Mutex<WinitInputHelper>>);
21
22impl Input {
23 fn new() -> Self {
24 Self(Arc::new(Mutex::new(WinitInputHelper::new())))
25 }
26
27 pub fn get(&self) -> InputGuard<'_> {
31 InputGuard(self.0.lock().unwrap())
32 }
33
34 fn update(&self, event: &Event<()>) {
35 self.0.lock().unwrap().update(event);
36 }
37}
38
39pub struct InputGuard<'a>(MutexGuard<'a, WinitInputHelper>);
40
41impl Deref for InputGuard<'_> {
42 type Target = WinitInputHelper;
43 fn deref(&self) -> &Self::Target {
44 &self.0
45 }
46}
47
48pub struct WinitWindow {
49 window: Arc<Window>,
50 event_loop: EventLoop<()>,
51 input: Input,
52}
53
54impl WindowProvider for WinitWindow {
55 type Handle = Arc<Window>;
56 type Exposed = Input;
57
58 fn create(config: &WindowConfig) -> Self {
59 let event_loop = EventLoop::new().unwrap();
60
61 let window_builder = WindowBuilder::new()
62 .with_title(config.title)
63 .with_inner_size(PhysicalSize::new(config.width, config.height));
64
65 #[cfg(target_arch = "wasm32")]
66 let window = {
67 use wasm_bindgen::JsCast;
68 use winit::platform::web::WindowBuilderExtWebSys;
69
70 let web_window = web_sys::window().expect("no global `window` exists");
71 let document = web_window
72 .document()
73 .expect("should have a document on window");
74 let canvas = document
75 .get_element_by_id("canvas")
76 .expect("no element with id `canvas` found — add <canvas id=\"wgpu_canvas\"></canvas> to index.html")
77 .unchecked_into::<web_sys::HtmlCanvasElement>();
78
79 Arc::new(
80 window_builder
81 .with_canvas(Some(canvas))
82 .build(&event_loop)
83 .unwrap(),
84 )
85 };
86
87 #[cfg(not(target_arch = "wasm32"))]
88 let window = Arc::new(window_builder.build(&event_loop).unwrap());
89
90 Self {
91 window,
92 event_loop,
93 input: Input::new(),
94 }
95 }
96
97 fn size(handle: &Self::Handle) -> (u32, u32) {
98 let s = handle.inner_size();
99 (s.width, s.height)
100 }
101
102 fn exposed(&self) -> Self::Exposed {
103 self.input.clone()
104 }
105
106 fn handle(&self) -> &Self::Handle {
107 &self.window
108 }
109}
110
111impl WindowRunner for WinitWindow {
112 fn run(self, mut on_frame: impl FnMut() + 'static) {
113 let Self {
114 window,
115 event_loop,
116 input,
117 } = self;
118
119 event_loop
120 .run(move |event, elwt| {
121 input.update(&event);
122
123 match &event {
124 Event::WindowEvent {
125 event: WindowEvent::CloseRequested,
126 ..
127 } => elwt.exit(),
128 Event::WindowEvent {
129 event: WindowEvent::RedrawRequested,
130 ..
131 } => on_frame(),
132 Event::AboutToWait => window.request_redraw(),
133 _ => {}
134 }
135 })
136 .unwrap();
137 }
138}
139
140impl PresentableWindow for WinitWindow {}