est_render/
runner.rs

1use std::{
2    collections::HashMap, hash::{Hash, Hasher}, io::Read, sync::{atomic::{AtomicBool, AtomicUsize}, Arc, Mutex}, thread::ThreadId, time::Duration
3};
4
5use crate::{math::{Point2, Timing}, utils::{ArcMut, ArcRef}, window::{WindowInner, WindowBuilder}};
6
7use smol_str::SmolStr;
8use wgpu::rwh::HasWindowHandle;
9use winit::{
10    application::ApplicationHandler, dpi::{PhysicalPosition, PhysicalSize}, event, event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy}, keyboard::{Key, NamedKey, NativeKey}, platform::pump_events::{EventLoopExtPumpEvents, PumpStatus}, window::{Cursor, CustomCursor, CustomCursorSource, Window as WinitWindow, WindowAttributes, WindowId}
11};
12
13#[cfg(target_os = "windows")]
14use winit::platform::windows::EventLoopBuilderExtWindows;
15
16#[cfg(all(not(feature = "x11"), target_os = "linux"))]
17use winit::platform::wayland::EventLoopBuilderExtWayland;
18
19#[cfg(all(feature = "x11", target_os = "linux"))]
20use winit::platform::x11::EventLoopBuilderExtX11;
21
22/// Create a [Runner] instance, required for creating one or more windows.
23///
24/// **NOTE:** When calling this function, the thread will be made the main thread,
25/// future calls to this function will panic if called from a different thread.
26pub fn new() -> Result<Runner, RunnerError> {
27    Runner::new()
28}
29
30// This is the most laziest workaround to able construct multiple event loops
31// in the same process, but only one at a time.
32//
33// However, this will lock the event loop to the thread that created it, and
34// will panic if called from a different thread after the first call.
35lazy_static::lazy_static! {
36    static ref CURRENT_LOOP_THREAD_ID: Mutex<Option<ThreadId>> = Mutex::new(None);
37    static ref CURRENT_LOOP: Mutex<Option<EventLoopWrapper>> = Mutex::new(None);
38    static ref CURRENT_WINDOW_ID: AtomicUsize = AtomicUsize::new(0);
39}
40
41pub(crate) struct EventLoopWrapper {
42    pub event_loop: ArcRef<EventLoop<WindowEvent>>,
43}
44
45// This needed for global access to the event loop
46// But the actual uses, still limit it to the callers thread
47// This is a workaround for the fact that winit's EventLoop is not Send or Sync
48unsafe impl Sync for EventLoopWrapper {}
49unsafe impl Send for EventLoopWrapper {}
50
51/// Provide almost cross-platform event loop for the application.
52///
53/// This wrap winit's [EventLoop] and provides a way to create windows and handle events.
54/// But with some limitations:
55/// - No support for iOS and WASM platforms.
56/// - macOS platform have to use [PollMode::WaitDraw] or drawing at event [Event::RedrawRequested] because
57/// how winit setup the window drawing on macOS.
58#[allow(dead_code)]
59pub struct Runner {
60    pub(crate) app_runner: RunnerInner,
61    pub(crate) event_loop: ArcRef<EventLoop<WindowEvent>>,
62    pub(crate) event_loop_proxy: EventLoopProxy<WindowEvent>,
63    pub(crate) window_events_attributes: Vec<ArcRef<WindowInner>>,
64    pub(crate) rate_timing: Timing,
65    pub(crate) pending_events: Vec<Event>,
66}
67
68impl Runner {
69    pub(crate) fn new() -> Result<Self, RunnerError> {
70        let thread_id = std::thread::current().id();
71
72        if CURRENT_LOOP_THREAD_ID.lock().unwrap().is_none() {
73            *CURRENT_LOOP_THREAD_ID.lock().unwrap() = Some(thread_id);
74        } else if CURRENT_LOOP_THREAD_ID.lock().unwrap().as_ref() != Some(&thread_id) {
75            return Err(RunnerError::ThreadMissmatch);
76        }
77
78        let event_loop = if let Some(current_loop) = CURRENT_LOOP.lock().unwrap().as_ref() {
79            current_loop.event_loop.clone()
80        } else {
81            let event_loop_result = std::panic::catch_unwind(|| {
82                let mut event_loop_builder = EventLoop::<WindowEvent>::with_user_event();
83
84                #[cfg(any(target_os = "windows", target_os = "linux"))]
85                {
86                    event_loop_builder.with_any_thread(true);
87                }
88
89                event_loop_builder.build()
90            });
91
92            // Winit panic if the event loop is already created in another? thread.
93            if event_loop_result.is_err() {
94                *CURRENT_LOOP_THREAD_ID.lock().unwrap() = None;
95
96                return Err(RunnerError::WinitEventLoopPanic);
97            }
98
99            // If the event loop creation failed, we return an error.
100            let event_loop_result = event_loop_result.unwrap();
101            if event_loop_result.is_err() {
102                *CURRENT_LOOP_THREAD_ID.lock().unwrap() = None;
103
104                return Err(RunnerError::WinitEventLoopFailed);
105            }
106
107            let event_loop_result = ArcRef::new(event_loop_result.unwrap());
108            *CURRENT_LOOP.lock().unwrap() = Some(EventLoopWrapper {
109                event_loop: event_loop_result.clone(),
110            });
111
112            event_loop_result
113        };
114
115        let event_loop_proxy = {
116            let event_loop = event_loop.wait_borrow_mut();
117            event_loop.create_proxy()
118        };
119
120        Ok(Self {
121            app_runner: RunnerInner::new(),
122            event_loop,
123            event_loop_proxy,
124            window_events_attributes: Vec::new(),
125            rate_timing: Timing::new(0),
126            pending_events: Vec::new(),
127        })
128    }
129
130    /// Returns the pending events that have been processed by the event loop in [Runner::pool_events].
131    pub fn get_events(&self) -> &Vec<Event> {
132        &self.pending_events
133    }
134
135    /// Creates a new [WindowBuilder] instance to build a new window.
136    pub fn create_window(&mut self, title: &str, size: Point2) -> WindowBuilder {
137        WindowBuilder::new(self, title, size)
138    }
139
140    /// This called from [WindowBuilder] to create a new window.
141    pub(crate) fn internal_new_window(
142        &mut self,
143        parent: Option<usize>,
144        title: String,
145        size: Point2,
146        pos: Option<Point2>,
147    ) -> Result<(usize, EventLoopProxy<WindowEvent>), RunnerError> {
148        let mut event_loop = self.event_loop.wait_borrow_mut();
149        let event_loop_proxy = event_loop.create_proxy();
150
151        let window_id = CURRENT_WINDOW_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
152        if window_id >= 1000 {
153            // return Err("Maximum window reached!".to_string());
154            return Err(RunnerError::MaximumWindowReached);
155        }
156
157        let res = event_loop_proxy.send_event(WindowEvent::Create {
158            ref_id: window_id,
159            parent_ref_id: parent,
160            title,
161            size,
162            pos,
163        });
164
165        if res.is_err() {
166            let err = self
167                .app_runner
168                .last_error
169                .clone()
170                .unwrap_or_else(|| "Failed to create window!".to_string());
171
172            return Err(RunnerError::FailedToCreateWindow(err));
173        }
174
175        event_loop.pump_app_events(Some(Duration::ZERO), &mut self.app_runner);
176
177        let mut found = false;
178        for (_id, handle) in self.app_runner.handles.iter() {
179            if handle.ref_id == window_id {
180                found = true;
181                break;
182            }
183        }
184
185        if !found {
186            let err = self
187                .app_runner
188                .last_error
189                .clone()
190                .unwrap_or_else(|| "Failed to create window!".to_string());
191
192            return Err(RunnerError::FailedToCreateWindow(err));
193        }
194
195        Ok((window_id, event_loop_proxy))
196    }
197
198    /// Pump the event loop and process events.
199    ///
200    /// This method will block based on the provided `mode`.
201    /// - [PollMode::Poll] will return immediately if there are no events.
202    /// - [PollMode::Wait] will block until an event is available.
203    /// - [PollMode::WaitDraw] will block until a redraw is requested (Recommended for MacOS platform).
204    ///
205    /// You can also pass [None] to use the default behavior, which is equivalent to `PollMode::Poll`.
206    ///
207    /// After calling this method, you can access the processed events using the [Runner::get_events] method.
208    ///
209    /// # Incompatible platforms
210    /// - iOS: This method is not supported on iOS due to platform limitations.
211    /// - WASM: This method is not supported on WASM due to how the browser handles events, unless
212    /// you using the emscripten event loop.
213    pub fn pool_events<T>(&mut self, mode: T) -> bool
214    where
215        T: Into<Option<PollMode>>,
216    {
217        let mut event_loop = self.event_loop.wait_borrow_mut();
218        let mode = mode.into();
219
220        let duration = match mode {
221            Some(PollMode::Poll) => Some(Duration::ZERO),
222            Some(PollMode::Wait) => None,
223            Some(PollMode::WaitDraw) => None,
224            None => Some(Duration::ZERO),
225        };
226
227        let wait_for_redraw = match mode {
228            Some(PollMode::WaitDraw) => true,
229            _ => false,
230        };
231
232        self.pending_events.clear();
233
234        loop {
235            match event_loop.pump_app_events(duration, &mut self.app_runner) {
236                PumpStatus::Continue => {
237                    for window in self.window_events_attributes.iter() {
238                        if let Some(mut window) = window.try_borrow_mut() {
239                            window.process_event();
240
241                            {
242                                let window_events = window.window_events.wait_borrow_mut();
243                                for event in window_events.iter() {
244                                    match event {
245                                        event::WindowEvent::CloseRequested => {
246                                            self.pending_events.push(Event::WindowClosed {
247                                                window_id: window.window_id,
248                                            });
249                                        }
250                                        event::WindowEvent::Resized(size) => {
251                                            self.pending_events.push(Event::WindowResized {
252                                                window_id: window.window_id,
253                                                size: Point2::new(size.width, size.height),
254                                            });
255                                        }
256                                        event::WindowEvent::Moved(pos) => {
257                                            self.pending_events.push(Event::WindowMoved {
258                                                window_id: window.window_id,
259                                                pos: Point2::new(pos.x, pos.y),
260                                            });
261                                        }
262                                        event::WindowEvent::RedrawRequested => {
263                                            self.pending_events.push(Event::RedrawRequested {
264                                                window_id: window.window_id,
265                                            });
266                                        }
267                                        event::WindowEvent::KeyboardInput {
268                                            event,
269                                            is_synthetic,
270                                            ..
271                                        } => {
272                                            if *is_synthetic {
273                                                continue;
274                                            }
275
276                                            let is_pressed =
277                                                event.state == event::ElementState::Pressed;
278
279                                            match event.logical_key {
280                                                Key::Character(ref smol_str) => {
281                                                    let smol_key = smol_str.clone();
282
283                                                    self.pending_events.push(Event::KeyboardInput {
284                                                        window_id: window.window_id,
285                                                        key: smol_key,
286                                                        pressed: is_pressed,
287                                                    });
288                                                }
289                                                Key::Named(ref named_key) => {
290                                                    let smol_key = named_key_to_str(named_key);
291                                                    if smol_key.is_none() {
292                                                        continue;
293                                                    }
294
295                                                    let smol_key = smol_key.unwrap();
296
297                                                    self.pending_events.push(Event::KeyboardInput {
298                                                        window_id: window.window_id,
299                                                        key: smol_key,
300                                                        pressed: is_pressed,
301                                                    });
302                                                }
303                                                Key::Unidentified(NativeKey::Windows(virtual_key)) => {
304                                                    let fmt = format!("virtual-key:{:?}", virtual_key);
305                                                    let smol_key = SmolStr::new(fmt);
306
307                                                    self.pending_events.push(Event::KeyboardInput {
308                                                        window_id: window.window_id,
309                                                        key: smol_key,
310                                                        pressed: is_pressed,
311                                                    });
312                                                }
313                                                _ => {
314                                                    // ignore
315                                                }
316                                            }
317                                        }
318                                        event::WindowEvent::MouseWheel {
319                                            delta, phase: _, ..
320                                        } => {
321                                            let delta = match delta {
322                                                event::MouseScrollDelta::LineDelta(
323                                                    delta_x,
324                                                    delta_y,
325                                                ) => MouseScrollDelta::LineDelta {
326                                                    delta_x: *delta_x,
327                                                    delta_y: *delta_y,
328                                                },
329                                                event::MouseScrollDelta::PixelDelta(delta_pos) => {
330                                                    MouseScrollDelta::PixelDelta {
331                                                        delta_x: delta_pos.x as f32,
332                                                        delta_y: delta_pos.y as f32,
333                                                    }
334                                                }
335                                            };
336
337                                            self.pending_events.push(Event::MouseWheel {
338                                                window_id: window.window_id,
339                                                delta,
340                                            });
341                                        }
342                                        event::WindowEvent::MouseInput {
343                                            device_id: _,
344                                            state,
345                                            button,
346                                        } => {
347                                            let is_pressed = *state == event::ElementState::Pressed;
348                                            let smoll_str = match button {
349                                                event::MouseButton::Left => SmolStr::new("Left"),
350                                                event::MouseButton::Right => SmolStr::new("Right"),
351                                                event::MouseButton::Middle => SmolStr::new("Middle"),
352                                                event::MouseButton::Back => SmolStr::new("Back"),
353                                                event::MouseButton::Forward => SmolStr::new("Forward"),
354                                                event::MouseButton::Other(_) => continue, // Ignore other buttons
355                                            };
356
357                                            self.pending_events.push(Event::MouseInput {
358                                                window_id: window.window_id,
359                                                button: smoll_str,
360                                                pressed: is_pressed,
361                                            });
362                                        }
363                                        event::WindowEvent::CursorEntered { device_id: _ } => {
364                                            self.pending_events.push(Event::CursorEntered {
365                                                window_id: window.window_id,
366                                            });
367                                        }
368                                        event::WindowEvent::CursorLeft { device_id: _ } => {
369                                            self.pending_events.push(Event::CursorLeft {
370                                                window_id: window.window_id,
371                                            });
372                                        }
373                                        event::WindowEvent::CursorMoved {
374                                            device_id: _,
375                                            position,
376                                        } => {
377                                            self.pending_events.push(Event::CursorMoved {
378                                                window_id: window.window_id,
379                                                pos: Point2::new(position.x, position.y),
380                                            });
381                                        }
382                                        event::WindowEvent::Focused(focused) => {
383                                            self.pending_events.push(Event::WindowFocused {
384                                                window_id: window.window_id,
385                                                focused: *focused,
386                                            });
387                                        }
388                                        _ => {}
389                                    }
390                                }
391                            }
392
393                            window.cycle();
394                        }
395                    }
396                }
397                PumpStatus::Exit(_code) => {
398                    // Exit the event loop
399                    crate::dbg_log!("Event loop exited with code: {}", _code);
400
401                    return false;
402                }
403            }
404
405            for window in self.window_events_attributes.iter() {
406                window.wait_borrow().window_events.wait_borrow_mut().clear();
407            }
408
409            if wait_for_redraw {
410                if self
411                    .app_runner
412                    .has_redraw_requested
413                    .load(std::sync::atomic::Ordering::SeqCst)
414                {
415                    break;
416                }
417            } else {
418                break;
419            }
420        }
421
422        drop(event_loop);
423
424        self.rate_timing.sleep();
425
426        true
427    }
428
429    /// Set the rate (frame rate) for the event loop.
430    ///
431    /// This only useful if you want to control the frame rate of the event loop.
432    /// Not effective if you use `PollMode::Wait` or `PollMode::WaitDraw`, or multi
433    /// window mode, or multiple threads.
434    pub fn set_rate(&mut self, rate: Option<Duration>) {
435        let rate = {
436            if let Some(rate) = rate {
437                1.0 / (rate.as_secs_f64() * 1000.0)
438            } else {
439                0.0
440            }
441        };
442
443        self.rate_timing.set_fps(rate as u32);
444    }
445
446    /// Set the target frames per second (FPS) for the event loop.
447    ///
448    /// This only useful if you want to control the frame rate of the event loop.
449    /// Not effective if you use `PollMode::Wait` or `PollMode::WaitDraw`, or multi
450    /// window mode, or multiple threads.
451    pub fn set_target_fps(&mut self, fps: u32) {
452        self.rate_timing.set_fps(fps);
453    }
454
455    /// Get the current frame rate (FPS) of the event loop.
456    ///
457    /// This only useful if you want to control the frame rate of the event loop.
458    /// Not effective if you use `PollMode::Wait` or `PollMode::WaitDraw`, or multi
459    /// window mode, or multiple threads.
460    pub fn get_target_fps(&self) -> u32 {
461        self.rate_timing.get_fps()
462    }
463
464    /// Get the time taken for each frame in milliseconds.
465    ///
466    /// This only useful if you want to control the frame rate of the event loop.
467    /// Not effective if you use `PollMode::Wait` or `PollMode::WaitDraw`, or multi
468    /// window mode, or multiple threads.
469    pub fn get_frame_time(&self) -> f64 {
470        self.rate_timing.get_frame_time()
471    }
472
473    pub(crate) fn get_events_pointer(
474        &self,
475        window_id: usize,
476    ) -> Option<ArcRef<Vec<event::WindowEvent>>> {
477        self.app_runner.get_window_events_by_ref(window_id)
478    }
479
480    pub(crate) fn get_window_pointer(&self, window_id: usize) -> Option<ArcMut<Handle>> {
481        self.app_runner.get_window_handle_by_ref(window_id)
482    }
483}
484
485#[derive(Clone, Debug)]
486pub(crate) struct Handle {
487    pub window: Option<Arc<WinitWindow>>,
488    pub is_closed: bool,
489    pub is_pinned: bool,
490}
491
492#[allow(dead_code)]
493impl Handle {
494    pub fn new(window: Arc<WinitWindow>) -> Self {
495        Self {
496            window: Some(window),
497            is_closed: false,
498            is_pinned: false,
499        }
500    }
501
502    pub fn is_closed(&self) -> bool {
503        self.is_closed
504    }
505
506    pub fn close(&mut self) {
507        self.window = None;
508        self.is_closed = true;
509    }
510
511    pub fn set_window(&mut self, window: Option<Arc<WinitWindow>>) {
512        self.window = window;
513    }
514
515    pub fn get_window(&self) -> &Arc<WinitWindow> {
516        if self.is_closed {
517            panic!("Window is closed");
518        }
519
520        self.window.as_ref().unwrap()
521    }
522
523    pub fn get_window_id(&self) -> WindowId {
524        if self.is_closed {
525            panic!("Window is closed");
526        }
527
528        self.window.as_ref().unwrap().id()
529    }
530
531    pub fn is_pinned(&self) -> bool {
532        self.is_pinned
533    }
534
535    pub fn set_pinned(&mut self, pinned: bool) {
536        self.is_pinned = pinned;
537    }
538}
539
540pub(crate) struct WindowHandle {
541    pub window: ArcMut<Handle>,
542    pub events: ArcRef<Vec<event::WindowEvent>>,
543
544    pub ref_id: usize,
545}
546
547impl Drop for WindowHandle {
548    fn drop(&mut self) {
549        crate::dbg_log!("WindowHandle dropped: {:?}", self.ref_id);
550    }
551}
552
553pub(crate) struct RunnerInner {
554    pub handles: HashMap<WindowId, WindowHandle>,
555    pub last_error: Option<String>,
556    pub has_redraw_requested: AtomicBool,
557    pub cursor_cache: HashMap<u64, CustomCursor>,
558}
559
560impl RunnerInner {
561    pub fn new() -> Self {
562        Self {
563            handles: HashMap::new(),
564            last_error: None,
565            has_redraw_requested: AtomicBool::new(false),
566            cursor_cache: HashMap::new(),
567        }
568    }
569
570    pub fn get_window_handle_by_ref(&self, ref_id: usize) -> Option<ArcMut<Handle>> {
571        self.handles
572            .iter()
573            .find(|(_, handle)| handle.ref_id == ref_id)
574            .map(|(_, handle)| handle.window.clone())
575    }
576
577    pub fn get_window_events_by_ref(
578        &self,
579        ref_id: usize,
580    ) -> Option<ArcRef<Vec<event::WindowEvent>>> {
581        self.handles
582            .iter()
583            .find(|(_, handle)| handle.ref_id == ref_id)
584            .map(|(_, handle)| handle.events.clone())
585    }
586}
587
588impl ApplicationHandler<WindowEvent> for RunnerInner {
589    fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
590
591    fn window_event(
592        &mut self,
593        event_loop: &ActiveEventLoop,
594        window_id: WindowId,
595        event: event::WindowEvent,
596    ) {
597        if self.handles.is_empty() {
598            return;
599        }
600
601        let mut to_remove = None;
602
603        if let Some((_ref_id, _)) = self
604            .handles
605            .iter()
606            .find(|(ref_id, _)| **ref_id == window_id)
607        {
608            match event {
609                event::WindowEvent::CloseRequested => {
610                    if self.handles.is_empty() {
611                        event_loop.exit();
612                        return;
613                    }
614
615                    to_remove = Some(window_id);
616                }
617                event::WindowEvent::RedrawRequested => {
618                    self.has_redraw_requested
619                        .store(true, std::sync::atomic::Ordering::SeqCst);
620                }
621                _ => {}
622            }
623
624            if let Some(handle) = self.handles.get_mut(&window_id) {
625                handle.events.borrow_mut().push(event.clone());
626            }
627        }
628
629        if let Some(window_id) = to_remove {
630            self.handles.remove(&window_id);
631            if self.handles.is_empty() {
632                event_loop.exit();
633            }
634        }
635    }
636
637    #[allow(unused_variables, unreachable_patterns)]
638    fn user_event(&mut self, event_loop: &ActiveEventLoop, event: WindowEvent) {
639        match event {
640            WindowEvent::Create {
641                ref_id,
642                parent_ref_id,
643                title,
644                size,
645                pos,
646            } => {
647                let size: PhysicalSize<u32> = PhysicalSize::new(size.x as u32, size.y as u32);
648                let mut window_attributes = WindowAttributes::default()
649                    .with_title(title)
650                    .with_visible(true)
651                    .with_inner_size(size)
652                    .with_resizable(false)
653                    .with_max_inner_size(size)
654                    .with_min_inner_size(size);
655
656                #[cfg(target_os = "windows")]
657                {
658                    use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows};
659
660                    window_attributes =
661                        window_attributes.with_corner_preference(CornerPreference::DoNotRound);
662                }
663
664                if let Some(pos) = pos {
665                    let pos: PhysicalPosition<i32> =
666                        PhysicalPosition::new(pos.x as i32, pos.y as i32);
667                    window_attributes = window_attributes.with_position(pos);
668                }
669
670                if let Some(parent_ref_id) = parent_ref_id {
671                    if let Some(parent_window) = self.get_window_handle_by_ref(parent_ref_id) {
672                        let parent_window = parent_window.lock();
673
674                        // SAFETY: We are using the `window_handle` method to get the raw window handle,
675                        // which is safe as long as the window is valid and not dropped.
676                        unsafe {
677                            if parent_window.is_closed() {
678                                self.last_error = Some(format!(
679                                    "Parent window is None for ref_id: {}",
680                                    parent_ref_id
681                                ));
682                                return;
683                            }
684
685                            let parent_window = parent_window.get_window().window_handle();
686
687                            if let Err(e) = parent_window {
688                                self.last_error =
689                                    Some(format!("Failed to set parent window: {:?}", e));
690
691                                return;
692                            }
693
694                            let parent_window_handle = parent_window.unwrap().as_raw();
695                            window_attributes =
696                                window_attributes.with_parent_window(Some(parent_window_handle));
697                        }
698                    }
699                }
700
701                let window = event_loop.create_window(window_attributes);
702
703                if let Ok(window) = window {
704                    let window_id = window.id();
705                    let handle = Handle::new(Arc::new(window));
706
707                    let window_handle = WindowHandle {
708                        window: ArcMut::new(handle),
709                        events: ArcRef::new(Vec::new()),
710                        ref_id,
711                    };
712
713                    crate::dbg_log!("Window {} created", ref_id);
714                    self.handles.insert(window_id, window_handle);
715                } else {
716                    crate::dbg_log!("Failed to create window: {:?}", window);
717                    self.last_error = Some(format!("Failed to create window: {:?}", window));
718                }
719            }
720            WindowEvent::Close { ref_id } => {
721                if self.handles.is_empty() {
722                    event_loop.exit();
723
724                    return;
725                }
726
727                let mut to_remove = None;
728
729                for (window_id, handle) in &self.handles {
730                    if handle.ref_id == ref_id {
731                        to_remove = Some(*window_id);
732                        break;
733                    }
734                }
735
736                if let Some(window_id) = to_remove {
737                    if let Some(handle) = self.handles.get_mut(&window_id) {
738                        handle.window.lock().close();
739                    }
740
741                    crate::dbg_log!("Window {} closed", ref_id);
742                    self.handles.remove(&window_id);
743                }
744
745                if self.handles.is_empty() {
746                    crate::dbg_log!("All windows closed, exiting event loop");
747                    event_loop.exit();
748                }
749            }
750            WindowEvent::Title { ref_id, title } => {
751                if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
752                    let window = handle.lock();
753                    let window = window.get_window();
754
755                    crate::dbg_log!("Window {} title: {}", ref_id, title);
756
757                    window.set_title(title.as_str());
758                }
759            }
760            WindowEvent::Size { ref_id, size } => {
761                if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
762                    let size: PhysicalSize<u32> = size.into();
763
764                    let handle_ref = handle.lock();
765                    let window = handle_ref.get_window();
766
767                    crate::dbg_log!("Window {} size: {:?}", ref_id, size);
768
769                    window.set_max_inner_size(Some(size));
770                    window.set_min_inner_size(Some(size));
771                    _ = window.request_inner_size(size);
772                }
773            }
774            WindowEvent::Position { ref_id, pos } => {
775                if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
776                    let pos = PhysicalPosition::new(pos.x as i32, pos.y as i32);
777
778                    let handle_ref = handle.lock();
779                    let window = handle_ref.get_window();
780
781                    crate::dbg_log!("Window {} position: {:?}", ref_id, pos);
782                    window.set_outer_position(pos);
783                }
784            }
785            WindowEvent::Visible { ref_id, visible } => {
786                if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
787                    let handle_ref = handle.lock();
788                    let window = handle_ref.get_window();
789
790                    crate::dbg_log!("Window {} visible: {}", ref_id, visible);
791                    window.set_visible(visible);
792                }
793            }
794            WindowEvent::Redraw { ref_id } => {
795                if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
796                    let handle_ref = handle.lock();
797                    let window = handle_ref.get_window();
798
799                    window.request_redraw();
800                }
801            }
802            WindowEvent::Cursor { ref_id, cursor } => {
803                if let Some(CursorIcon::Custom(cursor)) = cursor {
804                    let mut hash = std::collections::hash_map::DefaultHasher::new();
805                    cursor.hash(&mut hash);
806                    let hash = hash.finish();
807
808                    if let Some(cached_cursor) = self.cursor_cache.get(&hash).cloned() {
809                        if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
810                            let handle_ref = handle.lock();
811                            let window = handle_ref.get_window();
812
813                            window.set_cursor(cached_cursor.clone());
814                        }
815                        return;
816                    }
817
818                    let cursor = decode_cursor(cursor);
819                    if let Err(e) = cursor {
820                        self.last_error = Some(format!("Failed to decode cursor: {:?}", e));
821                        return;
822                    }
823
824                    let cursor_src = cursor.unwrap();
825                    let cursor = event_loop.create_custom_cursor(cursor_src);
826
827                    self.cursor_cache.insert(hash, cursor.clone());
828
829                    if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
830                        let handle_ref = handle.lock();
831                        let window = handle_ref.get_window();
832
833                        window.set_cursor(cursor.clone());
834                    }
835                } else {
836                    if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
837                        let handle_ref = handle.lock();
838                        let window = handle_ref.get_window();
839
840                        window.set_cursor(cursor.clone().unwrap());
841                    }
842                }
843            }
844            _ => {
845                println!("Unhandled event: {:?}", event);
846            }
847        }
848    }
849}
850
851fn decode_cursor(cursor: CustomCursorItem) -> Result<CustomCursorSource, String> {
852    let image_src = match cursor {
853        CustomCursorItem::Path(s) => {
854            let file = std::fs::File::open(s).unwrap();
855            let mut reader = std::io::BufReader::new(file);
856            let mut buffer = Vec::new();
857            let result = reader.read_to_end(&mut buffer);
858            if let Err(e) = result {
859                return Err(format!("Failed to read cursor file: {:?}", e));
860            }
861
862            buffer
863        }
864        CustomCursorItem::Image(b) => b,
865    };
866
867    let image = image::load_from_memory(&image_src);
868    if let Err(e) = image {
869        return Err(format!("Failed to load image: {:?}", e));
870    }
871
872    let image = image.unwrap();
873    let image = image.to_rgba8();
874    let (width, height) = image.dimensions();
875    let w = width as u16;
876    let h = height as u16;
877
878    let result = CustomCursor::from_rgba(image.into_raw(), w, h, w / 2, h / 2);
879
880    if let Err(e) = result {
881        return Err(format!("Failed to create custom cursor: {:?}", e));
882    }
883
884    let cursor = result.unwrap();
885    Ok(cursor)
886}
887
888pub(crate) fn named_key_to_str(key: &NamedKey) -> Option<SmolStr> {
889    match key {
890        NamedKey::Alt => Some(SmolStr::new("Alt")),
891        NamedKey::AltGraph => Some(SmolStr::new("AltGraph")),
892        NamedKey::CapsLock => Some(SmolStr::new("CapsLock")),
893        NamedKey::Control => Some(SmolStr::new("Control")),
894        NamedKey::Fn => Some(SmolStr::new("Fn")),
895        NamedKey::FnLock => Some(SmolStr::new("FnLock")),
896        NamedKey::NumLock => Some(SmolStr::new("NumLock")),
897        NamedKey::ScrollLock => Some(SmolStr::new("ScrollLock")),
898        NamedKey::Shift => Some(SmolStr::new("Shift")),
899        NamedKey::Symbol => Some(SmolStr::new("Symbol")),
900        NamedKey::SymbolLock => Some(SmolStr::new("SymbolLock")),
901        NamedKey::Meta => Some(SmolStr::new("Meta")),
902        NamedKey::Hyper => Some(SmolStr::new("Hyper")),
903        NamedKey::Super => Some(SmolStr::new("Super")),
904        NamedKey::Enter => Some(SmolStr::new("Enter")),
905        NamedKey::Tab => Some(SmolStr::new("Tab")),
906        NamedKey::Space => Some(SmolStr::new("Space")),
907        NamedKey::ArrowDown => Some(SmolStr::new("ArrowDown")),
908        NamedKey::ArrowLeft => Some(SmolStr::new("ArrowLeft")),
909        NamedKey::ArrowRight => Some(SmolStr::new("ArrowRight")),
910        NamedKey::ArrowUp => Some(SmolStr::new("ArrowUp")),
911        NamedKey::End => Some(SmolStr::new("End")),
912        NamedKey::Home => Some(SmolStr::new("Home")),
913        NamedKey::PageDown => Some(SmolStr::new("PageDown")),
914        NamedKey::PageUp => Some(SmolStr::new("PageUp")),
915        NamedKey::Backspace => Some(SmolStr::new("Backspace")),
916        NamedKey::Clear => Some(SmolStr::new("Clear")),
917        NamedKey::Delete => Some(SmolStr::new("Delete")),
918        NamedKey::Insert => Some(SmolStr::new("Insert")),
919        NamedKey::Escape => Some(SmolStr::new("Escape")),
920        NamedKey::Pause => Some(SmolStr::new("Pause")),
921        NamedKey::F1 => Some(SmolStr::new("F1")),
922        NamedKey::F2 => Some(SmolStr::new("F2")),
923        NamedKey::F3 => Some(SmolStr::new("F3")),
924        NamedKey::F4 => Some(SmolStr::new("F4")),
925        NamedKey::F5 => Some(SmolStr::new("F5")),
926        NamedKey::F6 => Some(SmolStr::new("F6")),
927        NamedKey::F7 => Some(SmolStr::new("F7")),
928        NamedKey::F8 => Some(SmolStr::new("F8")),
929        NamedKey::F9 => Some(SmolStr::new("F9")),
930        NamedKey::F10 => Some(SmolStr::new("F10")),
931        NamedKey::F11 => Some(SmolStr::new("F11")),
932        NamedKey::F12 => Some(SmolStr::new("F12")),
933        _ => None,
934    }
935}
936
937#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
938pub enum PollMode {
939    /// The event loop will poll for events and return immediately.
940    Poll,
941    /// The event loop will wait for events and return when an event is available.
942    Wait,
943    /// The event loop will wait for events and return when the window needs to be redrawn.
944    /// Unless calling the [Window::request_redraw] method.
945    WaitDraw,
946}
947
948#[derive(Debug, Clone, Copy)]
949pub enum MouseScrollDelta {
950    LineDelta { delta_x: f32, delta_y: f32 },
951    PixelDelta { delta_x: f32, delta_y: f32 },
952}
953
954impl PartialEq for MouseScrollDelta {
955    fn eq(&self, other: &Self) -> bool {
956        // use near equality for floating point comparison
957
958        match (self, other) {
959            (
960                MouseScrollDelta::LineDelta { delta_x, delta_y },
961                MouseScrollDelta::LineDelta {
962                    delta_x: other_x,
963                    delta_y: other_y,
964                },
965            ) => {
966                (delta_x - other_x).abs() < f32::EPSILON && (delta_y - other_y).abs() < f32::EPSILON
967            }
968            (
969                MouseScrollDelta::PixelDelta { delta_x, delta_y },
970                MouseScrollDelta::PixelDelta {
971                    delta_x: other_x,
972                    delta_y: other_y,
973                },
974            ) => {
975                (delta_x - other_x).abs() < f32::EPSILON && (delta_y - other_y).abs() < f32::EPSILON
976            }
977            _ => false,
978        }
979    }
980}
981
982impl PartialOrd for MouseScrollDelta {
983    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
984        match (self, other) {
985            (
986                MouseScrollDelta::LineDelta { delta_x, delta_y },
987                MouseScrollDelta::LineDelta {
988                    delta_x: other_x,
989                    delta_y: other_y,
990                },
991            ) => Some(
992                delta_x
993                    .partial_cmp(other_x)?
994                    .then(delta_y.partial_cmp(other_y)?),
995            ),
996            (
997                MouseScrollDelta::PixelDelta { delta_x, delta_y },
998                MouseScrollDelta::PixelDelta {
999                    delta_x: other_x,
1000                    delta_y: other_y,
1001                },
1002            ) => Some(
1003                delta_x
1004                    .partial_cmp(other_x)?
1005                    .then(delta_y.partial_cmp(other_y)?),
1006            ),
1007            _ => None,
1008        }
1009    }
1010}
1011
1012impl Ord for MouseScrollDelta {
1013    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1014        match (self, other) {
1015            (
1016                MouseScrollDelta::LineDelta { delta_x, delta_y },
1017                MouseScrollDelta::LineDelta {
1018                    delta_x: other_x,
1019                    delta_y: other_y,
1020                },
1021            ) => delta_x
1022                .partial_cmp(other_x)
1023                .unwrap_or(std::cmp::Ordering::Equal)
1024                .then(
1025                    delta_y
1026                        .partial_cmp(other_y)
1027                        .unwrap_or(std::cmp::Ordering::Equal),
1028                ),
1029            (
1030                MouseScrollDelta::PixelDelta { delta_x, delta_y },
1031                MouseScrollDelta::PixelDelta {
1032                    delta_x: other_x,
1033                    delta_y: other_y,
1034                },
1035            ) => delta_x
1036                .partial_cmp(other_x)
1037                .unwrap_or(std::cmp::Ordering::Equal)
1038                .then(
1039                    delta_y
1040                        .partial_cmp(other_y)
1041                        .unwrap_or(std::cmp::Ordering::Equal),
1042                ),
1043            _ => std::cmp::Ordering::Equal,
1044        }
1045    }
1046}
1047
1048impl Eq for MouseScrollDelta {}
1049
1050#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1051pub enum DragAndDropEvent {
1052    /// Occured when a drag enter the window.
1053    Dragleft,
1054    /// Occured when a drag is moved over the window.
1055    DragEntered,
1056    /// Occured when a drag is moved over the window.
1057    DragMoved,
1058    /// Occured when a drag dropped on the window.
1059    DragDropped(Vec<String>), // List of file paths
1060}
1061
1062#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1063pub enum Event {
1064    /// Happen when the window is closed, either by user action (such clicking X button on window) or programmatically.
1065    WindowClosed {
1066        /// The ID of the window that was closed, which can be used to identify the window in the application.
1067        ///
1068        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1069        window_id: usize,
1070    },
1071    /// Happen when a new window is created.
1072    WindowCreated {
1073        /// The ID of the window that was closed, which can be used to identify the window in the application.
1074        ///
1075        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1076        window_id: usize,
1077        /// The ID of the parent window, if any. will be [None] if the window is a top-level window.
1078        ///
1079        /// This can be achived when creating a new window using the [WindowBuilder::with_parent_window] method.
1080        parent_ref_id: Option<usize>,
1081        /// The title of the window.
1082        title: String,
1083        /// The size of the window in pixels.
1084        size: Point2,
1085        /// The position of the window in pixels, if specified.
1086        pos: Option<Point2>,
1087    },
1088    /// Happen when the window is focused or unfocused.
1089    WindowFocused {
1090        /// The ID of the window that was closed, which can be used to identify the window in the application.
1091        ///
1092        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1093        window_id: usize,
1094        /// Focused state of the window.
1095        focused: bool,
1096    },
1097    /// Happen when the window is resized.
1098    WindowResized {
1099        /// The ID of the window that was closed, which can be used to identify the window in the application.
1100        ///
1101        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1102        window_id: usize,
1103        /// The new size of the window in pixels.
1104        size: Point2,
1105    },
1106    /// Happen when the window is moved.
1107    WindowMoved {
1108        /// The ID of the window that was closed, which can be used to identify the window in the application.
1109        ///
1110        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1111        window_id: usize,
1112        /// The new position of the window in pixels.
1113        pos: Point2,
1114    },
1115    /// Happen when the cursor enters the window.
1116    CursorEntered {
1117        /// The ID of the window that was closed, which can be used to identify the window in the application.
1118        ///
1119        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1120        window_id: usize,
1121    },
1122    /// Happen when the cursor leaves the window.
1123    CursorLeft {
1124        /// The ID of the window that was closed, which can be used to identify the window in the application.
1125        ///
1126        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1127        window_id: usize,
1128    },
1129    /// Happen when the cursor is moved within the window.
1130    CursorMoved {
1131        /// The ID of the window that was closed, which can be used to identify the window in the application.
1132        ///
1133        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1134        window_id: usize,
1135        /// The new position of the cursor in pixels.
1136        pos: Point2, // Position in pixels
1137    },
1138    /// Happen when the mouse wheel is scrolled.
1139    MouseWheel {
1140        /// The ID of the window that was closed, which can be used to identify the window in the application.
1141        ///
1142        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1143        window_id: usize,
1144        /// The delta of the mouse wheel scroll.
1145        delta: MouseScrollDelta,
1146    },
1147    /// Happen when a mouse button is pressed or released.
1148    MouseInput {
1149        /// The ID of the window that was closed, which can be used to identify the window in the application.
1150        ///
1151        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1152        window_id: usize,
1153        /// The button that was pressed or released.
1154        ///
1155        /// Either "Left", "Right", "Middle", "Back", or "Forward".
1156        button: SmolStr, // "Left", "Right", "Middle", "Back", "Forward"
1157        /// Whether the button was pressed or released.
1158        pressed: bool, // true if pressed, false if released
1159    },
1160    /// Happen when the window requests a redraw.
1161    ///
1162    /// Can be manually invoked by calling [Window::request_redraw] method.
1163    RedrawRequested {
1164        /// The ID of the window that was closed, which can be used to identify the window in the application.
1165        ///
1166        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1167        window_id: usize,
1168    },
1169    /// Happen when a keyboard key is pressed or released.
1170    KeyboardInput {
1171        /// The ID of the window that was closed, which can be used to identify the window in the application.
1172        ///
1173        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1174        window_id: usize,
1175        /// The key that was pressed or released.
1176        ///
1177        /// The key string can be modifier keys like "Alt", "Control", "Shift", etc.
1178        /// Which where the cases like `a` can be `A`.
1179        key: SmolStr,
1180        /// Whether the key was pressed or released.
1181        pressed: bool, // true if pressed, false if released
1182    },
1183    /// Happen when a drag and drop event occurs in the window.
1184    DragAndDrop {
1185        /// The ID of the window that was closed, which can be used to identify the window in the application.
1186        ///
1187        /// The window ID can be obtained from the [Window] instance using the [Window::id] method.
1188        window_id: usize,
1189        /// The drag and drop event that occurred.
1190        event: DragAndDropEvent,
1191    },
1192}
1193
1194#[allow(dead_code)]
1195#[derive(Clone, Debug)]
1196pub(crate) enum WindowEvent {
1197    Create {
1198        ref_id: usize,
1199        parent_ref_id: Option<usize>,
1200        title: String,
1201        size: Point2,
1202        pos: Option<Point2>,
1203    },
1204    Close {
1205        ref_id: usize,
1206    },
1207    Title {
1208        ref_id: usize,
1209        title: String,
1210    },
1211    Cursor {
1212        ref_id: usize,
1213        cursor: Option<CursorIcon>,
1214    },
1215    Size {
1216        ref_id: usize,
1217        size: Point2,
1218    },
1219    Position {
1220        ref_id: usize,
1221        pos: Point2,
1222    },
1223    Visible {
1224        ref_id: usize,
1225        visible: bool,
1226    },
1227    Redraw {
1228        ref_id: usize,
1229    },
1230}
1231
1232// #[derive(Clone, Debug, Hash)]
1233// pub enum CursorSource {
1234//     String(&'static str),
1235//     Buffer(Vec<u8>),
1236// }
1237
1238#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1239pub enum CursorIcon {
1240    Default,
1241    ContextMenu,
1242    Help,
1243    Pointer,
1244    Progress,
1245    Wait,
1246    Cell,
1247    Crosshair,
1248    Text,
1249    VerticalText,
1250    Alias,
1251    Copy,
1252    Move,
1253    NoDrop,
1254    NotAllowed,
1255    Grab,
1256    Grabbing,
1257    EResize,
1258    NResize,
1259    NeResize,
1260    NwResize,
1261    SResize,
1262    SeResize,
1263    SwResize,
1264    WResize,
1265    EwResize,
1266    NsResize,
1267    NeswResize,
1268    NwseResize,
1269    ColResize,
1270    RowResize,
1271    AllScroll,
1272    ZoomIn,
1273    ZoomOut,
1274
1275    Custom(CustomCursorItem),
1276}
1277
1278#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1279pub enum CustomCursorItem {
1280    Path(String),
1281    Image(Vec<u8>),
1282}
1283
1284impl Into<Cursor> for CursorIcon {
1285    fn into(self) -> Cursor {
1286        match self {
1287            CursorIcon::Default => Cursor::Icon(winit::window::CursorIcon::Default),
1288            CursorIcon::ContextMenu => Cursor::Icon(winit::window::CursorIcon::ContextMenu),
1289            CursorIcon::Help => Cursor::Icon(winit::window::CursorIcon::Help),
1290            CursorIcon::Pointer => Cursor::Icon(winit::window::CursorIcon::Pointer),
1291            CursorIcon::Progress => Cursor::Icon(winit::window::CursorIcon::Progress),
1292            CursorIcon::Wait => Cursor::Icon(winit::window::CursorIcon::Wait),
1293            CursorIcon::Cell => Cursor::Icon(winit::window::CursorIcon::Cell),
1294            CursorIcon::Crosshair => Cursor::Icon(winit::window::CursorIcon::Crosshair),
1295            CursorIcon::Text => Cursor::Icon(winit::window::CursorIcon::Text),
1296            CursorIcon::VerticalText => Cursor::Icon(winit::window::CursorIcon::VerticalText),
1297            CursorIcon::Alias => Cursor::Icon(winit::window::CursorIcon::Alias),
1298            CursorIcon::Copy => Cursor::Icon(winit::window::CursorIcon::Copy),
1299            CursorIcon::Move => Cursor::Icon(winit::window::CursorIcon::Move),
1300            CursorIcon::NoDrop => Cursor::Icon(winit::window::CursorIcon::NoDrop),
1301            CursorIcon::NotAllowed => Cursor::Icon(winit::window::CursorIcon::NotAllowed),
1302            CursorIcon::Grab => Cursor::Icon(winit::window::CursorIcon::Grab),
1303            CursorIcon::Grabbing => Cursor::Icon(winit::window::CursorIcon::Grabbing),
1304            CursorIcon::EResize => Cursor::Icon(winit::window::CursorIcon::EResize),
1305            CursorIcon::NResize => Cursor::Icon(winit::window::CursorIcon::NResize),
1306            CursorIcon::NeResize => Cursor::Icon(winit::window::CursorIcon::NeResize),
1307            CursorIcon::NwResize => Cursor::Icon(winit::window::CursorIcon::NwResize),
1308            CursorIcon::SResize => Cursor::Icon(winit::window::CursorIcon::SResize),
1309            CursorIcon::SeResize => Cursor::Icon(winit::window::CursorIcon::SeResize),
1310            CursorIcon::SwResize => Cursor::Icon(winit::window::CursorIcon::SwResize),
1311            CursorIcon::WResize => Cursor::Icon(winit::window::CursorIcon::WResize),
1312            CursorIcon::EwResize => Cursor::Icon(winit::window::CursorIcon::EwResize),
1313            CursorIcon::NsResize => Cursor::Icon(winit::window::CursorIcon::NsResize),
1314            CursorIcon::NeswResize => Cursor::Icon(winit::window::CursorIcon::NeswResize),
1315            CursorIcon::NwseResize => Cursor::Icon(winit::window::CursorIcon::NwseResize),
1316            CursorIcon::ColResize => Cursor::Icon(winit::window::CursorIcon::ColResize),
1317            CursorIcon::RowResize => Cursor::Icon(winit::window::CursorIcon::RowResize),
1318            CursorIcon::AllScroll => Cursor::Icon(winit::window::CursorIcon::AllScroll),
1319            CursorIcon::ZoomIn => Cursor::Icon(winit::window::CursorIcon::ZoomIn),
1320            CursorIcon::ZoomOut => Cursor::Icon(winit::window::CursorIcon::ZoomOut),
1321            CursorIcon::Custom(_) => panic!("This should not handled here!"),
1322        }
1323    }
1324}
1325
1326#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1327pub enum RunnerError {
1328    ThreadMissmatch,
1329    WinitEventLoopPanic,
1330    WinitEventLoopFailed,
1331    MaximumWindowReached,
1332    FailedToCreateWindow(String),
1333}