Skip to main content

pebble/wgpu/
window.rs

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/// Shared handle to the frame's input state.
15///
16/// Cheap to clone (an `Arc` internally). Call [`Input::get`] to read it —
17/// the returned [`InputGuard`] derefs straight to [`WinitInputHelper`], so
18/// there's no `.lock().unwrap()` at every call site.
19#[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    /// Borrow the current input state. Panics if the lock is poisoned (a
28    /// prior holder panicked while holding it), matching how the rest of
29    /// this codebase treats poisoning as an unrecoverable bug.
30    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        let window = Arc::new(
61            WindowBuilder::new()
62                .with_title(config.title)
63                .with_inner_size(PhysicalSize::new(config.width, config.height))
64                .build(&event_loop)
65                .unwrap(),
66        );
67
68        Self {
69            window,
70            event_loop,
71            input: Input::new(),
72        }
73    }
74
75    fn size(handle: &Self::Handle) -> (u32, u32) {
76        let s = handle.inner_size();
77        (s.width, s.height)
78    }
79
80    fn exposed(&self) -> Self::Exposed {
81        self.input.clone()
82    }
83
84    fn handle(&self) -> &Self::Handle {
85        &self.window
86    }
87}
88
89impl WindowRunner for WinitWindow {
90    fn run(self, mut on_frame: impl FnMut() + 'static) {
91        let Self {
92            window,
93            event_loop,
94            input,
95        } = self;
96
97        event_loop
98            .run(move |event, elwt| {
99                input.update(&event);
100
101                match &event {
102                    Event::WindowEvent {
103                        event: WindowEvent::CloseRequested,
104                        ..
105                    } => elwt.exit(),
106                    Event::WindowEvent {
107                        event: WindowEvent::RedrawRequested,
108                        ..
109                    } => on_frame(),
110                    Event::AboutToWait => window.request_redraw(),
111                    _ => {}
112                }
113            })
114            .unwrap();
115    }
116}
117
118impl PresentableWindow for WinitWindow {}