Skip to main content

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}