win_win/runloop.rs
1use std::mem;
2use std::ptr::null_mut;
3
4use winapi::shared::minwindef::BOOL;
5use winapi::shared::windef::HACCEL;
6use winapi::um::winuser::{DispatchMessageW, GetMessageW, TranslateAcceleratorW, TranslateMessage};
7
8/// A basic winapi runloop.
9///
10/// This runloop blocks on receiving messages and dispatches them to windows. It exits
11/// on [`WM_QUIT`].
12///
13/// It is tempting to try to get fancier with runloops, for example waiting on semaphores
14/// or other events, but these strategies are risky. In particular, the main runloop is not
15/// always in control; when the window is being resized, or a modal dialog is open, then
16/// that runloop takes precedence. For waking the UI thread from another thread,
17/// [`SendMessage`] is probably the best bet.
18///
19/// # Safety
20///
21/// The `accel` argument must be a valid HACCEL handle (though `null_mut()` is valid).
22///
23/// [`WM_QUIT`]: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-quit
24/// [`SendMessage`]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
25pub unsafe fn runloop(accel: HACCEL) -> BOOL {
26 loop {
27 let mut msg = mem::MaybeUninit::uninit();
28 let res = GetMessageW(msg.as_mut_ptr(), null_mut(), 0, 0);
29 if res <= 0 {
30 return res;
31 }
32 let mut msg = msg.assume_init();
33 if accel.is_null() || TranslateAcceleratorW(msg.hwnd, accel, &mut msg) == 0 {
34 TranslateMessage(&msg);
35 DispatchMessageW(&msg);
36 }
37 }
38}