rt_local/runtime/
windows.rs1use rt_local_core::base::{on_idle, RuntimeLoop, RuntimeWaker};
2use std::{future::Future, marker::PhantomData, ops::ControlFlow, sync::Arc};
3use windows::Win32::{
4 Foundation::{HWND, LPARAM, WPARAM},
5 System::Threading::GetCurrentThreadId,
6 UI::WindowsAndMessaging::{
7 DispatchMessageW, GetMessageW, PeekMessageW, PostThreadMessageW, TranslateMessage, MSG,
8 PM_REMOVE, WM_NULL, WM_QUIT,
9 },
10};
11
12pub fn run<F: Future>(future: F) -> F::Output {
14 rt_local_core::base::run(&WindowsMessageLoop::new(), future)
15}
16
17pub use rt_local_macros::windows_main as main;
18pub use rt_local_macros::windows_test as test;
19
20struct WindowsMessageLoop {
21 waker: Arc<Waker>,
22 _not_send: PhantomData<*mut ()>,
23}
24
25impl WindowsMessageLoop {
26 fn new() -> Self {
27 unsafe {
28 let thread_id = GetCurrentThreadId();
29 Self {
30 waker: Arc::new(Waker { thread_id }),
31 _not_send: PhantomData,
32 }
33 }
34 }
35}
36impl RuntimeLoop for WindowsMessageLoop {
37 fn waker(&self) -> Arc<dyn RuntimeWaker> {
38 self.waker.clone()
39 }
40 fn run<T>(&self, mut on_step: impl FnMut() -> ControlFlow<T>) -> T {
41 loop {
42 if let ControlFlow::Break(value) = on_step() {
43 return value;
44 }
45 let mut msg = MSG::default();
46 unsafe {
47 if !PeekMessageW(&mut msg, HWND(0), 0, 0, PM_REMOVE).as_bool() {
48 if on_idle() {
49 continue;
50 } else {
51 GetMessageW(&mut msg, HWND(0), 0, 0).ok().unwrap();
52 }
53 }
54 if msg.message == WM_QUIT {
55 panic!("message loop terminated");
56 }
57 TranslateMessage(&msg);
58 DispatchMessageW(&msg);
59 }
60 }
61 }
62}
63
64struct Waker {
65 thread_id: u32,
66}
67impl RuntimeWaker for Waker {
68 fn wake(&self) {
69 unsafe {
70 let _ = PostThreadMessageW(self.thread_id, WM_NULL, WPARAM(0), LPARAM(0));
71 }
72 }
73}