1use std::{
2 collections::HashMap, hash::{Hash, Hasher}, io::Read, sync::{atomic::{AtomicBool, AtomicUsize}, Arc, Mutex}, thread::ThreadId, time::Duration
3};
4
5use crate::{input::{self, InputInner}, math::{Point2, Timing}, utils::{ArcMut, ArcRef}, window::{Window, WindowBuilder, WindowInner}};
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
22pub fn new() -> Result<Runner, RunnerError> {
27 Runner::new()
28}
29
30lazy_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
45unsafe impl Sync for EventLoopWrapper {}
49unsafe impl Send for EventLoopWrapper {}
50
51#[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) input_events_attributes: Vec<ArcRef<InputInner>>,
65 pub(crate) rate_timing: Timing,
66 pub(crate) pending_events: Vec<Event>,
67}
68
69impl Runner {
70 pub(crate) fn new() -> Result<Self, RunnerError> {
71 let thread_id = std::thread::current().id();
72
73 if CURRENT_LOOP_THREAD_ID.lock().unwrap().is_none() {
74 *CURRENT_LOOP_THREAD_ID.lock().unwrap() = Some(thread_id);
75 } else if CURRENT_LOOP_THREAD_ID.lock().unwrap().as_ref() != Some(&thread_id) {
76 return Err(RunnerError::ThreadMissmatch);
77 }
78
79 let event_loop = if let Some(current_loop) = CURRENT_LOOP.lock().unwrap().as_ref() {
80 current_loop.event_loop.clone()
81 } else {
82 let event_loop_result = std::panic::catch_unwind(|| {
83 let mut event_loop_builder = EventLoop::<WindowEvent>::with_user_event();
84
85 #[cfg(any(target_os = "windows", target_os = "linux"))]
86 {
87 event_loop_builder.with_any_thread(true);
88 }
89
90 event_loop_builder.build()
91 });
92
93 if event_loop_result.is_err() {
95 *CURRENT_LOOP_THREAD_ID.lock().unwrap() = None;
96
97 return Err(RunnerError::WinitEventLoopPanic);
98 }
99
100 let event_loop_result = event_loop_result.unwrap();
102 if event_loop_result.is_err() {
103 *CURRENT_LOOP_THREAD_ID.lock().unwrap() = None;
104
105 return Err(RunnerError::WinitEventLoopFailed);
106 }
107
108 let event_loop_result = ArcRef::new(event_loop_result.unwrap());
109 *CURRENT_LOOP.lock().unwrap() = Some(EventLoopWrapper {
110 event_loop: event_loop_result.clone(),
111 });
112
113 event_loop_result
114 };
115
116 let event_loop_proxy = {
117 let event_loop = event_loop.wait_borrow_mut();
118 event_loop.create_proxy()
119 };
120
121 Ok(Self {
122 app_runner: RunnerInner::new(),
123 event_loop,
124 event_loop_proxy,
125 window_events_attributes: Vec::new(),
126 input_events_attributes: Vec::new(),
127 rate_timing: Timing::new(0),
128 pending_events: Vec::new(),
129 })
130 }
131
132 pub fn get_events(&self) -> &Vec<Event> {
134 &self.pending_events
135 }
136
137 pub fn create_window(&mut self, title: &str, size: Point2) -> WindowBuilder {
139 WindowBuilder::new(self, title, size)
140 }
141
142 pub fn create_input(&mut self, window_id: Option<&Window>) -> input::Input {
149 let window_id = window_id.map(|w| w.id());
150
151 input::Input::new(self, window_id)
152 }
153
154 pub(crate) fn internal_new_window(
156 &mut self,
157 parent: Option<usize>,
158 title: String,
159 size: Point2,
160 pos: Option<Point2>,
161 ) -> Result<(usize, EventLoopProxy<WindowEvent>), RunnerError> {
162 let mut event_loop = self.event_loop.wait_borrow_mut();
163 let event_loop_proxy = event_loop.create_proxy();
164
165 let window_id = CURRENT_WINDOW_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
166 if window_id >= 1000 {
167 return Err(RunnerError::MaximumWindowReached);
169 }
170
171 let res = event_loop_proxy.send_event(WindowEvent::Create {
172 ref_id: window_id,
173 parent_ref_id: parent,
174 title,
175 size,
176 pos,
177 });
178
179 if res.is_err() {
180 let err = self
181 .app_runner
182 .last_error
183 .clone()
184 .unwrap_or_else(|| "Failed to create window!".to_string());
185
186 return Err(RunnerError::FailedToCreateWindow(err));
187 }
188
189 event_loop.pump_app_events(Some(Duration::ZERO), &mut self.app_runner);
190
191 let mut found = false;
192 for (_id, handle) in self.app_runner.handles.iter() {
193 if handle.ref_id == window_id {
194 found = true;
195 break;
196 }
197 }
198
199 if !found {
200 let err = self
201 .app_runner
202 .last_error
203 .clone()
204 .unwrap_or_else(|| "Failed to create window!".to_string());
205
206 return Err(RunnerError::FailedToCreateWindow(err));
207 }
208
209 Ok((window_id, event_loop_proxy))
210 }
211
212 pub fn pump_events<T>(&mut self, mode: T) -> bool
228 where
229 T: Into<Option<PumpMode>>,
230 {
231 let mut event_loop = self.event_loop.wait_borrow_mut();
232 let mode = mode.into();
233
234 let duration = match mode {
235 Some(PumpMode::Poll) => Some(Duration::ZERO),
236 Some(PumpMode::Wait) => None,
237 Some(PumpMode::WaitDraw) => None,
238 None => Some(Duration::ZERO),
239 };
240
241 let wait_for_redraw = match mode {
242 Some(PumpMode::WaitDraw) => true,
243 _ => false,
244 };
245
246 self.pending_events.clear();
247
248 loop {
249 match event_loop.pump_app_events(duration, &mut self.app_runner) {
250 PumpStatus::Continue => {
251 for window in self.window_events_attributes.iter() {
252 if let Some(mut window) = window.try_borrow_mut() {
253 window.process_event();
254
255 {
256 let window_events = window.window_events.wait_borrow_mut();
257 for event in window_events.iter() {
258 match event {
259 event::WindowEvent::CloseRequested => {
260 self.pending_events.push(Event::WindowClosed {
261 window_id: window.window_id,
262 });
263 }
264 event::WindowEvent::Resized(size) => {
265 self.pending_events.push(Event::WindowResized {
266 window_id: window.window_id,
267 size: Point2::new(size.width, size.height),
268 });
269 }
270 event::WindowEvent::Moved(pos) => {
271 self.pending_events.push(Event::WindowMoved {
272 window_id: window.window_id,
273 pos: Point2::new(pos.x, pos.y),
274 });
275 }
276 event::WindowEvent::RedrawRequested => {
277 self.pending_events.push(Event::RedrawRequested {
278 window_id: window.window_id,
279 });
280 }
281 event::WindowEvent::KeyboardInput {
282 event,
283 is_synthetic,
284 ..
285 } => {
286 if *is_synthetic {
287 continue;
288 }
289
290 let is_pressed =
291 event.state == event::ElementState::Pressed;
292
293 match event.logical_key {
294 Key::Character(ref smol_str) => {
295 let smol_key = smol_str.clone();
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::Named(ref named_key) => {
304 let smol_key = named_key_to_str(named_key);
305 if smol_key.is_none() {
306 continue;
307 }
308
309 let smol_key = smol_key.unwrap();
310
311 self.pending_events.push(Event::KeyboardInput {
312 window_id: window.window_id,
313 key: smol_key,
314 pressed: is_pressed,
315 });
316 }
317 Key::Unidentified(NativeKey::Windows(virtual_key)) => {
318 let fmt = format!("virtual-key:{:?}", virtual_key);
319 let smol_key = SmolStr::new(fmt);
320
321 self.pending_events.push(Event::KeyboardInput {
322 window_id: window.window_id,
323 key: smol_key,
324 pressed: is_pressed,
325 });
326 }
327 _ => {
328 }
330 }
331 }
332 event::WindowEvent::MouseWheel {
333 delta, phase: _, ..
334 } => {
335 let delta = match delta {
336 event::MouseScrollDelta::LineDelta(
337 delta_x,
338 delta_y,
339 ) => MouseScrollDelta::LineDelta {
340 delta_x: *delta_x,
341 delta_y: *delta_y,
342 },
343 event::MouseScrollDelta::PixelDelta(delta_pos) => {
344 MouseScrollDelta::PixelDelta {
345 delta_x: delta_pos.x as f32,
346 delta_y: delta_pos.y as f32,
347 }
348 }
349 };
350
351 self.pending_events.push(Event::MouseWheel {
352 window_id: window.window_id,
353 delta,
354 });
355 }
356 event::WindowEvent::MouseInput {
357 device_id: _,
358 state,
359 button,
360 } => {
361 let is_pressed = *state == event::ElementState::Pressed;
362 let smoll_str = match button {
363 event::MouseButton::Left => SmolStr::new("Left"),
364 event::MouseButton::Right => SmolStr::new("Right"),
365 event::MouseButton::Middle => SmolStr::new("Middle"),
366 event::MouseButton::Back => SmolStr::new("Back"),
367 event::MouseButton::Forward => SmolStr::new("Forward"),
368 event::MouseButton::Other(_) => continue, };
370
371 self.pending_events.push(Event::MouseInput {
372 window_id: window.window_id,
373 button: smoll_str,
374 pressed: is_pressed,
375 });
376 }
377 event::WindowEvent::CursorEntered { device_id: _ } => {
378 self.pending_events.push(Event::CursorEntered {
379 window_id: window.window_id,
380 });
381 }
382 event::WindowEvent::CursorLeft { device_id: _ } => {
383 self.pending_events.push(Event::CursorLeft {
384 window_id: window.window_id,
385 });
386 }
387 event::WindowEvent::CursorMoved {
388 device_id: _,
389 position,
390 } => {
391 self.pending_events.push(Event::CursorMoved {
392 window_id: window.window_id,
393 pos: Point2::new(position.x, position.y),
394 });
395 }
396 event::WindowEvent::Focused(focused) => {
397 self.pending_events.push(Event::WindowFocused {
398 window_id: window.window_id,
399 focused: *focused,
400 });
401 }
402 _ => {}
403 }
404 }
405 }
406
407 window.cycle();
408 }
409 }
410 }
411 PumpStatus::Exit(_code) => {
412 crate::dbg_log!("Event loop exited with code: {}", _code);
414
415 return false;
416 }
417 }
418
419 for window in self.window_events_attributes.iter() {
420 window.wait_borrow().window_events.wait_borrow_mut().clear();
421 }
422
423 if self.input_events_attributes.len() > 0 {
424 for event in self.pending_events.iter() {
425 for input in self.input_events_attributes.iter() {
426 if let Some(mut input) = input.try_borrow_mut() {
427 input.process_event(event);
428 }
429 }
430 }
431 }
432
433 if wait_for_redraw {
434 if self
435 .app_runner
436 .has_redraw_requested
437 .load(std::sync::atomic::Ordering::SeqCst)
438 {
439 break;
440 }
441 } else {
442 break;
443 }
444 }
445
446 drop(event_loop);
447
448 self.rate_timing.sleep();
449
450 true
451 }
452
453 pub fn set_rate(&mut self, rate: Option<Duration>) {
459 let rate = {
460 if let Some(rate) = rate {
461 1.0 / (rate.as_secs_f64() * 1000.0)
462 } else {
463 0.0
464 }
465 };
466
467 self.rate_timing.set_fps(rate as u32);
468 }
469
470 pub fn set_target_fps(&mut self, fps: u32) {
476 self.rate_timing.set_fps(fps);
477 }
478
479 pub fn get_target_fps(&self) -> u32 {
485 self.rate_timing.get_fps()
486 }
487
488 pub fn get_frame_time(&self) -> f64 {
494 self.rate_timing.get_frame_time()
495 }
496
497 pub(crate) fn get_events_pointer(
498 &self,
499 window_id: usize,
500 ) -> Option<ArcRef<Vec<event::WindowEvent>>> {
501 self.app_runner.get_window_events_by_ref(window_id)
502 }
503
504 pub(crate) fn get_window_pointer(&self, window_id: usize) -> Option<ArcMut<Handle>> {
505 self.app_runner.get_window_handle_by_ref(window_id)
506 }
507}
508
509#[derive(Clone, Debug)]
510pub(crate) struct Handle {
511 pub window: Option<Arc<WinitWindow>>,
512 pub is_closed: bool,
513 pub is_pinned: bool,
514}
515
516#[allow(dead_code)]
517impl Handle {
518 pub fn new(window: Arc<WinitWindow>) -> Self {
519 Self {
520 window: Some(window),
521 is_closed: false,
522 is_pinned: false,
523 }
524 }
525
526 pub fn is_closed(&self) -> bool {
527 self.is_closed
528 }
529
530 pub fn close(&mut self) {
531 self.window = None;
532 self.is_closed = true;
533 }
534
535 pub fn set_window(&mut self, window: Option<Arc<WinitWindow>>) {
536 self.window = window;
537 }
538
539 pub fn get_window(&self) -> &Arc<WinitWindow> {
540 if self.is_closed {
541 panic!("Window is closed");
542 }
543
544 self.window.as_ref().unwrap()
545 }
546
547 pub fn get_window_id(&self) -> WindowId {
548 if self.is_closed {
549 panic!("Window is closed");
550 }
551
552 self.window.as_ref().unwrap().id()
553 }
554
555 pub fn is_pinned(&self) -> bool {
556 self.is_pinned
557 }
558
559 pub fn set_pinned(&mut self, pinned: bool) {
560 self.is_pinned = pinned;
561 }
562}
563
564pub(crate) struct WindowHandle {
565 pub window: ArcMut<Handle>,
566 pub events: ArcRef<Vec<event::WindowEvent>>,
567
568 pub ref_id: usize,
569}
570
571impl Drop for WindowHandle {
572 fn drop(&mut self) {
573 crate::dbg_log!("WindowHandle dropped: {:?}", self.ref_id);
574 }
575}
576
577pub(crate) struct RunnerInner {
578 pub handles: HashMap<WindowId, WindowHandle>,
579 pub last_error: Option<String>,
580 pub has_redraw_requested: AtomicBool,
581 pub cursor_cache: HashMap<u64, CustomCursor>,
582}
583
584impl RunnerInner {
585 pub fn new() -> Self {
586 Self {
587 handles: HashMap::new(),
588 last_error: None,
589 has_redraw_requested: AtomicBool::new(false),
590 cursor_cache: HashMap::new(),
591 }
592 }
593
594 pub fn get_window_handle_by_ref(&self, ref_id: usize) -> Option<ArcMut<Handle>> {
595 self.handles
596 .iter()
597 .find(|(_, handle)| handle.ref_id == ref_id)
598 .map(|(_, handle)| handle.window.clone())
599 }
600
601 pub fn get_window_events_by_ref(
602 &self,
603 ref_id: usize,
604 ) -> Option<ArcRef<Vec<event::WindowEvent>>> {
605 self.handles
606 .iter()
607 .find(|(_, handle)| handle.ref_id == ref_id)
608 .map(|(_, handle)| handle.events.clone())
609 }
610}
611
612impl ApplicationHandler<WindowEvent> for RunnerInner {
613 fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
614
615 fn window_event(
616 &mut self,
617 event_loop: &ActiveEventLoop,
618 window_id: WindowId,
619 event: event::WindowEvent,
620 ) {
621 if self.handles.is_empty() {
622 return;
623 }
624
625 let mut to_remove = None;
626
627 if let Some((_ref_id, _)) = self
628 .handles
629 .iter()
630 .find(|(ref_id, _)| **ref_id == window_id)
631 {
632 match event {
633 event::WindowEvent::CloseRequested => {
634 if self.handles.is_empty() {
635 event_loop.exit();
636 return;
637 }
638
639 to_remove = Some(window_id);
640 }
641 event::WindowEvent::RedrawRequested => {
642 self.has_redraw_requested
643 .store(true, std::sync::atomic::Ordering::SeqCst);
644 }
645 _ => {}
646 }
647
648 if let Some(handle) = self.handles.get_mut(&window_id) {
649 handle.events.borrow_mut().push(event.clone());
650 }
651 }
652
653 if let Some(window_id) = to_remove {
654 self.handles.remove(&window_id);
655 if self.handles.is_empty() {
656 event_loop.exit();
657 }
658 }
659 }
660
661 #[allow(unused_variables, unreachable_patterns)]
662 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: WindowEvent) {
663 match event {
664 WindowEvent::Create {
665 ref_id,
666 parent_ref_id,
667 title,
668 size,
669 pos,
670 } => {
671 let size: PhysicalSize<u32> = PhysicalSize::new(size.x as u32, size.y as u32);
672 let mut window_attributes = WindowAttributes::default()
673 .with_title(title)
674 .with_visible(true)
675 .with_inner_size(size)
676 .with_resizable(false)
677 .with_max_inner_size(size)
678 .with_min_inner_size(size);
679
680 #[cfg(target_os = "windows")]
681 {
682 use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows};
683
684 window_attributes =
685 window_attributes.with_corner_preference(CornerPreference::DoNotRound);
686 }
687
688 if let Some(pos) = pos {
689 let pos: PhysicalPosition<i32> =
690 PhysicalPosition::new(pos.x as i32, pos.y as i32);
691 window_attributes = window_attributes.with_position(pos);
692 }
693
694 if let Some(parent_ref_id) = parent_ref_id {
695 if let Some(parent_window) = self.get_window_handle_by_ref(parent_ref_id) {
696 let parent_window = parent_window.lock();
697
698 unsafe {
701 if parent_window.is_closed() {
702 self.last_error = Some(format!(
703 "Parent window is None for ref_id: {}",
704 parent_ref_id
705 ));
706 return;
707 }
708
709 let parent_window = parent_window.get_window().window_handle();
710
711 if let Err(e) = parent_window {
712 self.last_error =
713 Some(format!("Failed to set parent window: {:?}", e));
714
715 return;
716 }
717
718 let parent_window_handle = parent_window.unwrap().as_raw();
719 window_attributes =
720 window_attributes.with_parent_window(Some(parent_window_handle));
721 }
722 }
723 }
724
725 let window = event_loop.create_window(window_attributes);
726
727 if let Ok(window) = window {
728 let window_id = window.id();
729 let handle = Handle::new(Arc::new(window));
730
731 let window_handle = WindowHandle {
732 window: ArcMut::new(handle),
733 events: ArcRef::new(Vec::new()),
734 ref_id,
735 };
736
737 crate::dbg_log!("Window {} created", ref_id);
738 self.handles.insert(window_id, window_handle);
739 } else {
740 crate::dbg_log!("Failed to create window: {:?}", window);
741 self.last_error = Some(format!("Failed to create window: {:?}", window));
742 }
743 }
744 WindowEvent::Close { ref_id } => {
745 if self.handles.is_empty() {
746 event_loop.exit();
747
748 return;
749 }
750
751 let mut to_remove = None;
752
753 for (window_id, handle) in &self.handles {
754 if handle.ref_id == ref_id {
755 to_remove = Some(*window_id);
756 break;
757 }
758 }
759
760 if let Some(window_id) = to_remove {
761 if let Some(handle) = self.handles.get_mut(&window_id) {
762 handle.window.lock().close();
763 }
764
765 crate::dbg_log!("Window {} closed", ref_id);
766 self.handles.remove(&window_id);
767 }
768
769 if self.handles.is_empty() {
770 crate::dbg_log!("All windows closed, exiting event loop");
771 event_loop.exit();
772 }
773 }
774 WindowEvent::Title { ref_id, title } => {
775 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
776 let window = handle.lock();
777 let window = window.get_window();
778
779 crate::dbg_log!("Window {} title: {}", ref_id, title);
780
781 window.set_title(title.as_str());
782 }
783 }
784 WindowEvent::Size { ref_id, size } => {
785 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
786 let size: PhysicalSize<u32> = size.into();
787
788 let handle_ref = handle.lock();
789 let window = handle_ref.get_window();
790
791 crate::dbg_log!("Window {} size: {:?}", ref_id, size);
792
793 window.set_max_inner_size(Some(size));
794 window.set_min_inner_size(Some(size));
795 _ = window.request_inner_size(size);
796 }
797 }
798 WindowEvent::Position { ref_id, pos } => {
799 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
800 let pos = PhysicalPosition::new(pos.x as i32, pos.y as i32);
801
802 let handle_ref = handle.lock();
803 let window = handle_ref.get_window();
804
805 crate::dbg_log!("Window {} position: {:?}", ref_id, pos);
806 window.set_outer_position(pos);
807 }
808 }
809 WindowEvent::Visible { ref_id, visible } => {
810 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
811 let handle_ref = handle.lock();
812 let window = handle_ref.get_window();
813
814 crate::dbg_log!("Window {} visible: {}", ref_id, visible);
815 window.set_visible(visible);
816 }
817 }
818 WindowEvent::Redraw { ref_id } => {
819 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
820 let handle_ref = handle.lock();
821 let window = handle_ref.get_window();
822
823 window.request_redraw();
824 }
825 }
826 WindowEvent::Cursor { ref_id, cursor } => {
827 if let Some(CursorIcon::Custom(cursor)) = cursor {
828 let mut hash = std::collections::hash_map::DefaultHasher::new();
829 cursor.hash(&mut hash);
830 let hash = hash.finish();
831
832 if let Some(cached_cursor) = self.cursor_cache.get(&hash).cloned() {
833 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
834 let handle_ref = handle.lock();
835 let window = handle_ref.get_window();
836
837 window.set_cursor(cached_cursor.clone());
838 }
839 return;
840 }
841
842 let cursor = decode_cursor(cursor);
843 if let Err(e) = cursor {
844 self.last_error = Some(format!("Failed to decode cursor: {:?}", e));
845 return;
846 }
847
848 let cursor_src = cursor.unwrap();
849 let cursor = event_loop.create_custom_cursor(cursor_src);
850
851 self.cursor_cache.insert(hash, cursor.clone());
852
853 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
854 let handle_ref = handle.lock();
855 let window = handle_ref.get_window();
856
857 window.set_cursor(cursor.clone());
858 }
859 } else {
860 if let Some(handle) = self.get_window_handle_by_ref(ref_id) {
861 let handle_ref = handle.lock();
862 let window = handle_ref.get_window();
863
864 window.set_cursor(cursor.clone().unwrap());
865 }
866 }
867 }
868 _ => {
869 println!("Unhandled event: {:?}", event);
870 }
871 }
872 }
873}
874
875fn decode_cursor(cursor: CustomCursorItem) -> Result<CustomCursorSource, String> {
876 let image_src = match cursor {
877 CustomCursorItem::Path(s) => {
878 let file = std::fs::File::open(s).unwrap();
879 let mut reader = std::io::BufReader::new(file);
880 let mut buffer = Vec::new();
881 let result = reader.read_to_end(&mut buffer);
882 if let Err(e) = result {
883 return Err(format!("Failed to read cursor file: {:?}", e));
884 }
885
886 buffer
887 }
888 CustomCursorItem::Image(b) => b,
889 };
890
891 let image = image::load_from_memory(&image_src);
892 if let Err(e) = image {
893 return Err(format!("Failed to load image: {:?}", e));
894 }
895
896 let image = image.unwrap();
897 let image = image.to_rgba8();
898 let (width, height) = image.dimensions();
899 let w = width as u16;
900 let h = height as u16;
901
902 let result = CustomCursor::from_rgba(image.into_raw(), w, h, w / 2, h / 2);
903
904 if let Err(e) = result {
905 return Err(format!("Failed to create custom cursor: {:?}", e));
906 }
907
908 let cursor = result.unwrap();
909 Ok(cursor)
910}
911
912pub(crate) fn named_key_to_str(key: &NamedKey) -> Option<SmolStr> {
913 match key {
914 NamedKey::Alt => Some(SmolStr::new("Alt")),
915 NamedKey::AltGraph => Some(SmolStr::new("AltGraph")),
916 NamedKey::CapsLock => Some(SmolStr::new("CapsLock")),
917 NamedKey::Control => Some(SmolStr::new("Control")),
918 NamedKey::Fn => Some(SmolStr::new("Fn")),
919 NamedKey::FnLock => Some(SmolStr::new("FnLock")),
920 NamedKey::NumLock => Some(SmolStr::new("NumLock")),
921 NamedKey::ScrollLock => Some(SmolStr::new("ScrollLock")),
922 NamedKey::Shift => Some(SmolStr::new("Shift")),
923 NamedKey::Symbol => Some(SmolStr::new("Symbol")),
924 NamedKey::SymbolLock => Some(SmolStr::new("SymbolLock")),
925 NamedKey::Meta => Some(SmolStr::new("Meta")),
926 NamedKey::Hyper => Some(SmolStr::new("Hyper")),
927 NamedKey::Super => Some(SmolStr::new("Super")),
928 NamedKey::Enter => Some(SmolStr::new("Enter")),
929 NamedKey::Tab => Some(SmolStr::new("Tab")),
930 NamedKey::Space => Some(SmolStr::new("Space")),
931 NamedKey::ArrowDown => Some(SmolStr::new("ArrowDown")),
932 NamedKey::ArrowLeft => Some(SmolStr::new("ArrowLeft")),
933 NamedKey::ArrowRight => Some(SmolStr::new("ArrowRight")),
934 NamedKey::ArrowUp => Some(SmolStr::new("ArrowUp")),
935 NamedKey::End => Some(SmolStr::new("End")),
936 NamedKey::Home => Some(SmolStr::new("Home")),
937 NamedKey::PageDown => Some(SmolStr::new("PageDown")),
938 NamedKey::PageUp => Some(SmolStr::new("PageUp")),
939 NamedKey::Backspace => Some(SmolStr::new("Backspace")),
940 NamedKey::Clear => Some(SmolStr::new("Clear")),
941 NamedKey::Delete => Some(SmolStr::new("Delete")),
942 NamedKey::Insert => Some(SmolStr::new("Insert")),
943 NamedKey::Escape => Some(SmolStr::new("Escape")),
944 NamedKey::Pause => Some(SmolStr::new("Pause")),
945 NamedKey::F1 => Some(SmolStr::new("F1")),
946 NamedKey::F2 => Some(SmolStr::new("F2")),
947 NamedKey::F3 => Some(SmolStr::new("F3")),
948 NamedKey::F4 => Some(SmolStr::new("F4")),
949 NamedKey::F5 => Some(SmolStr::new("F5")),
950 NamedKey::F6 => Some(SmolStr::new("F6")),
951 NamedKey::F7 => Some(SmolStr::new("F7")),
952 NamedKey::F8 => Some(SmolStr::new("F8")),
953 NamedKey::F9 => Some(SmolStr::new("F9")),
954 NamedKey::F10 => Some(SmolStr::new("F10")),
955 NamedKey::F11 => Some(SmolStr::new("F11")),
956 NamedKey::F12 => Some(SmolStr::new("F12")),
957 _ => None,
958 }
959}
960
961#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
962pub enum PumpMode {
963 Poll,
965 Wait,
967 WaitDraw,
970}
971
972#[derive(Debug, Clone, Copy)]
973pub enum MouseScrollDelta {
974 LineDelta { delta_x: f32, delta_y: f32 },
975 PixelDelta { delta_x: f32, delta_y: f32 },
976}
977
978impl PartialEq for MouseScrollDelta {
979 fn eq(&self, other: &Self) -> bool {
980 match (self, other) {
983 (
984 MouseScrollDelta::LineDelta { delta_x, delta_y },
985 MouseScrollDelta::LineDelta {
986 delta_x: other_x,
987 delta_y: other_y,
988 },
989 ) => {
990 (delta_x - other_x).abs() < f32::EPSILON && (delta_y - other_y).abs() < f32::EPSILON
991 }
992 (
993 MouseScrollDelta::PixelDelta { delta_x, delta_y },
994 MouseScrollDelta::PixelDelta {
995 delta_x: other_x,
996 delta_y: other_y,
997 },
998 ) => {
999 (delta_x - other_x).abs() < f32::EPSILON && (delta_y - other_y).abs() < f32::EPSILON
1000 }
1001 _ => false,
1002 }
1003 }
1004}
1005
1006impl PartialOrd for MouseScrollDelta {
1007 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1008 match (self, other) {
1009 (
1010 MouseScrollDelta::LineDelta { delta_x, delta_y },
1011 MouseScrollDelta::LineDelta {
1012 delta_x: other_x,
1013 delta_y: other_y,
1014 },
1015 ) => Some(
1016 delta_x
1017 .partial_cmp(other_x)?
1018 .then(delta_y.partial_cmp(other_y)?),
1019 ),
1020 (
1021 MouseScrollDelta::PixelDelta { delta_x, delta_y },
1022 MouseScrollDelta::PixelDelta {
1023 delta_x: other_x,
1024 delta_y: other_y,
1025 },
1026 ) => Some(
1027 delta_x
1028 .partial_cmp(other_x)?
1029 .then(delta_y.partial_cmp(other_y)?),
1030 ),
1031 _ => None,
1032 }
1033 }
1034}
1035
1036impl Ord for MouseScrollDelta {
1037 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1038 match (self, other) {
1039 (
1040 MouseScrollDelta::LineDelta { delta_x, delta_y },
1041 MouseScrollDelta::LineDelta {
1042 delta_x: other_x,
1043 delta_y: other_y,
1044 },
1045 ) => delta_x
1046 .partial_cmp(other_x)
1047 .unwrap_or(std::cmp::Ordering::Equal)
1048 .then(
1049 delta_y
1050 .partial_cmp(other_y)
1051 .unwrap_or(std::cmp::Ordering::Equal),
1052 ),
1053 (
1054 MouseScrollDelta::PixelDelta { delta_x, delta_y },
1055 MouseScrollDelta::PixelDelta {
1056 delta_x: other_x,
1057 delta_y: other_y,
1058 },
1059 ) => delta_x
1060 .partial_cmp(other_x)
1061 .unwrap_or(std::cmp::Ordering::Equal)
1062 .then(
1063 delta_y
1064 .partial_cmp(other_y)
1065 .unwrap_or(std::cmp::Ordering::Equal),
1066 ),
1067 _ => std::cmp::Ordering::Equal,
1068 }
1069 }
1070}
1071
1072impl Eq for MouseScrollDelta {}
1073
1074#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1075pub enum DragAndDropEvent {
1076 Dragleft,
1078 DragEntered,
1080 DragMoved,
1082 DragDropped(Vec<String>), }
1085
1086#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1087pub enum Event {
1088 WindowClosed {
1090 window_id: usize,
1094 },
1095 WindowCreated {
1097 window_id: usize,
1101 parent_ref_id: Option<usize>,
1105 title: String,
1107 size: Point2,
1109 pos: Option<Point2>,
1111 },
1112 WindowFocused {
1114 window_id: usize,
1118 focused: bool,
1120 },
1121 WindowResized {
1123 window_id: usize,
1127 size: Point2,
1129 },
1130 WindowMoved {
1132 window_id: usize,
1136 pos: Point2,
1138 },
1139 CursorEntered {
1141 window_id: usize,
1145 },
1146 CursorLeft {
1148 window_id: usize,
1152 },
1153 CursorMoved {
1155 window_id: usize,
1159 pos: Point2, },
1162 MouseWheel {
1164 window_id: usize,
1168 delta: MouseScrollDelta,
1170 },
1171 MouseInput {
1173 window_id: usize,
1177 button: SmolStr, pressed: bool, },
1184 RedrawRequested {
1188 window_id: usize,
1192 },
1193 KeyboardInput {
1195 window_id: usize,
1199 key: SmolStr,
1204 pressed: bool, },
1207 DragAndDrop {
1209 window_id: usize,
1213 event: DragAndDropEvent,
1215 },
1216}
1217
1218#[allow(dead_code)]
1219#[derive(Clone, Debug)]
1220pub(crate) enum WindowEvent {
1221 Create {
1222 ref_id: usize,
1223 parent_ref_id: Option<usize>,
1224 title: String,
1225 size: Point2,
1226 pos: Option<Point2>,
1227 },
1228 Close {
1229 ref_id: usize,
1230 },
1231 Title {
1232 ref_id: usize,
1233 title: String,
1234 },
1235 Cursor {
1236 ref_id: usize,
1237 cursor: Option<CursorIcon>,
1238 },
1239 Size {
1240 ref_id: usize,
1241 size: Point2,
1242 },
1243 Position {
1244 ref_id: usize,
1245 pos: Point2,
1246 },
1247 Visible {
1248 ref_id: usize,
1249 visible: bool,
1250 },
1251 Redraw {
1252 ref_id: usize,
1253 },
1254}
1255
1256#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1263pub enum CursorIcon {
1264 Default,
1265 ContextMenu,
1266 Help,
1267 Pointer,
1268 Progress,
1269 Wait,
1270 Cell,
1271 Crosshair,
1272 Text,
1273 VerticalText,
1274 Alias,
1275 Copy,
1276 Move,
1277 NoDrop,
1278 NotAllowed,
1279 Grab,
1280 Grabbing,
1281 EResize,
1282 NResize,
1283 NeResize,
1284 NwResize,
1285 SResize,
1286 SeResize,
1287 SwResize,
1288 WResize,
1289 EwResize,
1290 NsResize,
1291 NeswResize,
1292 NwseResize,
1293 ColResize,
1294 RowResize,
1295 AllScroll,
1296 ZoomIn,
1297 ZoomOut,
1298
1299 Custom(CustomCursorItem),
1300}
1301
1302#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1303pub enum CustomCursorItem {
1304 Path(String),
1305 Image(Vec<u8>),
1306}
1307
1308impl Into<Cursor> for CursorIcon {
1309 fn into(self) -> Cursor {
1310 match self {
1311 CursorIcon::Default => Cursor::Icon(winit::window::CursorIcon::Default),
1312 CursorIcon::ContextMenu => Cursor::Icon(winit::window::CursorIcon::ContextMenu),
1313 CursorIcon::Help => Cursor::Icon(winit::window::CursorIcon::Help),
1314 CursorIcon::Pointer => Cursor::Icon(winit::window::CursorIcon::Pointer),
1315 CursorIcon::Progress => Cursor::Icon(winit::window::CursorIcon::Progress),
1316 CursorIcon::Wait => Cursor::Icon(winit::window::CursorIcon::Wait),
1317 CursorIcon::Cell => Cursor::Icon(winit::window::CursorIcon::Cell),
1318 CursorIcon::Crosshair => Cursor::Icon(winit::window::CursorIcon::Crosshair),
1319 CursorIcon::Text => Cursor::Icon(winit::window::CursorIcon::Text),
1320 CursorIcon::VerticalText => Cursor::Icon(winit::window::CursorIcon::VerticalText),
1321 CursorIcon::Alias => Cursor::Icon(winit::window::CursorIcon::Alias),
1322 CursorIcon::Copy => Cursor::Icon(winit::window::CursorIcon::Copy),
1323 CursorIcon::Move => Cursor::Icon(winit::window::CursorIcon::Move),
1324 CursorIcon::NoDrop => Cursor::Icon(winit::window::CursorIcon::NoDrop),
1325 CursorIcon::NotAllowed => Cursor::Icon(winit::window::CursorIcon::NotAllowed),
1326 CursorIcon::Grab => Cursor::Icon(winit::window::CursorIcon::Grab),
1327 CursorIcon::Grabbing => Cursor::Icon(winit::window::CursorIcon::Grabbing),
1328 CursorIcon::EResize => Cursor::Icon(winit::window::CursorIcon::EResize),
1329 CursorIcon::NResize => Cursor::Icon(winit::window::CursorIcon::NResize),
1330 CursorIcon::NeResize => Cursor::Icon(winit::window::CursorIcon::NeResize),
1331 CursorIcon::NwResize => Cursor::Icon(winit::window::CursorIcon::NwResize),
1332 CursorIcon::SResize => Cursor::Icon(winit::window::CursorIcon::SResize),
1333 CursorIcon::SeResize => Cursor::Icon(winit::window::CursorIcon::SeResize),
1334 CursorIcon::SwResize => Cursor::Icon(winit::window::CursorIcon::SwResize),
1335 CursorIcon::WResize => Cursor::Icon(winit::window::CursorIcon::WResize),
1336 CursorIcon::EwResize => Cursor::Icon(winit::window::CursorIcon::EwResize),
1337 CursorIcon::NsResize => Cursor::Icon(winit::window::CursorIcon::NsResize),
1338 CursorIcon::NeswResize => Cursor::Icon(winit::window::CursorIcon::NeswResize),
1339 CursorIcon::NwseResize => Cursor::Icon(winit::window::CursorIcon::NwseResize),
1340 CursorIcon::ColResize => Cursor::Icon(winit::window::CursorIcon::ColResize),
1341 CursorIcon::RowResize => Cursor::Icon(winit::window::CursorIcon::RowResize),
1342 CursorIcon::AllScroll => Cursor::Icon(winit::window::CursorIcon::AllScroll),
1343 CursorIcon::ZoomIn => Cursor::Icon(winit::window::CursorIcon::ZoomIn),
1344 CursorIcon::ZoomOut => Cursor::Icon(winit::window::CursorIcon::ZoomOut),
1345 CursorIcon::Custom(_) => panic!("This should not handled here!"),
1346 }
1347 }
1348}
1349
1350#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1351pub enum RunnerError {
1352 ThreadMissmatch,
1353 WinitEventLoopPanic,
1354 WinitEventLoopFailed,
1355 MaximumWindowReached,
1356 FailedToCreateWindow(String),
1357}