Prevent EventLoop from getting initialized outside the main thread in cross-platform functions (#1186)
* Prevent EventLoop from getting initialized outside the main thread This only applies to the cross-platform functions. We expose functions to do this in a platform-specific manner, when available. * Add CHANGELOG entry * Formatting has changed since the latest stable update... * Fix error spacing * Unix: Prevent initializing EventLoop outside main thread * Updates libc dependency to 0.2.64, as required by BSD platforms * Update CHANGELOG.md for Linux implementation * Finish sentence * Consolidate documentation
This commit is contained in:
parent
af3ef52252
commit
28e3c35547
8 changed files with 224 additions and 35 deletions
|
|
@ -132,18 +132,40 @@ pub struct EventLoopWindowTarget<T> {
|
|||
pub(crate) runner_shared: EventLoopRunnerShared<T>,
|
||||
}
|
||||
|
||||
macro_rules! main_thread_check {
|
||||
($fn_name:literal) => {{
|
||||
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||
if thread_id != main_thread_id() {
|
||||
panic!(concat!(
|
||||
"Initializing the event loop outside of the main thread is a significant \
|
||||
cross-platform compatibility hazard. If you really, absolutely need to create an \
|
||||
EventLoop on a different thread, please use the `EventLoopExtWindows::",
|
||||
$fn_name,
|
||||
"` function."
|
||||
));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> EventLoop<T> {
|
||||
Self::with_dpi_awareness(true)
|
||||
main_thread_check!("new_any_thread");
|
||||
|
||||
Self::new_any_thread()
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &RootELW<T> {
|
||||
&self.window_target
|
||||
pub fn new_any_thread() -> EventLoop<T> {
|
||||
become_dpi_aware();
|
||||
Self::new_dpi_unaware_any_thread()
|
||||
}
|
||||
|
||||
pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop<T> {
|
||||
become_dpi_aware(dpi_aware);
|
||||
pub fn new_dpi_unaware() -> EventLoop<T> {
|
||||
main_thread_check!("new_dpi_unaware_any_thread");
|
||||
|
||||
Self::new_dpi_unaware_any_thread()
|
||||
}
|
||||
|
||||
pub fn new_dpi_unaware_any_thread() -> EventLoop<T> {
|
||||
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||
let runner_shared = Rc::new(ELRShared {
|
||||
runner: RefCell::new(None),
|
||||
|
|
@ -166,6 +188,10 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &RootELW<T> {
|
||||
&self.window_target
|
||||
}
|
||||
|
||||
pub fn run<F>(mut self, event_handler: F) -> !
|
||||
where
|
||||
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
|
|
@ -178,10 +204,6 @@ impl<T: 'static> EventLoop<T> {
|
|||
where
|
||||
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
unsafe {
|
||||
winuser::IsGUIThread(1);
|
||||
}
|
||||
|
||||
let event_loop_windows_ref = &self.window_target;
|
||||
|
||||
let mut runner = unsafe {
|
||||
|
|
@ -280,6 +302,21 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn main_thread_id() -> DWORD {
|
||||
static mut MAIN_THREAD_ID: DWORD = 0;
|
||||
#[used]
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[link_section = ".CRT$XCU"]
|
||||
static INIT_MAIN_THREAD_ID: unsafe fn() = {
|
||||
unsafe fn initer() {
|
||||
MAIN_THREAD_ID = processthreadsapi::GetCurrentThreadId();
|
||||
}
|
||||
initer
|
||||
};
|
||||
|
||||
unsafe { MAIN_THREAD_ID }
|
||||
}
|
||||
|
||||
pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
||||
pub(crate) struct ELRShared<T> {
|
||||
runner: RefCell<Option<EventLoopRunner<T>>>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue