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
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) 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 if event_loop_result.is_err() {
94 *CURRENT_LOOP_THREAD_ID.lock().unwrap() = None;
95
96 return Err(RunnerError::WinitEventLoopPanic);
97 }
98
99 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 pub fn get_events(&self) -> &Vec<Event> {
132 &self.pending_events
133 }
134
135 pub fn create_window(&mut self, title: &str, size: Point2) -> WindowBuilder {
137 WindowBuilder::new(self, title, size)
138 }
139
140 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(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 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 }
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, };
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 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 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 pub fn set_target_fps(&mut self, fps: u32) {
452 self.rate_timing.set_fps(fps);
453 }
454
455 pub fn get_target_fps(&self) -> u32 {
461 self.rate_timing.get_fps()
462 }
463
464 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 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 Poll,
941 Wait,
943 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 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 Dragleft,
1054 DragEntered,
1056 DragMoved,
1058 DragDropped(Vec<String>), }
1061
1062#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1063pub enum Event {
1064 WindowClosed {
1066 window_id: usize,
1070 },
1071 WindowCreated {
1073 window_id: usize,
1077 parent_ref_id: Option<usize>,
1081 title: String,
1083 size: Point2,
1085 pos: Option<Point2>,
1087 },
1088 WindowFocused {
1090 window_id: usize,
1094 focused: bool,
1096 },
1097 WindowResized {
1099 window_id: usize,
1103 size: Point2,
1105 },
1106 WindowMoved {
1108 window_id: usize,
1112 pos: Point2,
1114 },
1115 CursorEntered {
1117 window_id: usize,
1121 },
1122 CursorLeft {
1124 window_id: usize,
1128 },
1129 CursorMoved {
1131 window_id: usize,
1135 pos: Point2, },
1138 MouseWheel {
1140 window_id: usize,
1144 delta: MouseScrollDelta,
1146 },
1147 MouseInput {
1149 window_id: usize,
1153 button: SmolStr, pressed: bool, },
1160 RedrawRequested {
1164 window_id: usize,
1168 },
1169 KeyboardInput {
1171 window_id: usize,
1175 key: SmolStr,
1180 pressed: bool, },
1183 DragAndDrop {
1185 window_id: usize,
1189 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, 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}