mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Replace lazy window message ids with a slimmer version (#2598)
This commit is contained in:
parent
69d6076310
commit
5ba6bdef49
|
@ -10,6 +10,7 @@ use std::{
|
||||||
mem, panic, ptr,
|
mem, panic, ptr,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{
|
sync::{
|
||||||
|
atomic::{AtomicU32, Ordering},
|
||||||
mpsc::{self, Receiver, Sender},
|
mpsc::{self, Receiver, Sender},
|
||||||
Arc, Mutex, MutexGuard,
|
Arc, Mutex, MutexGuard,
|
||||||
},
|
},
|
||||||
|
@ -382,11 +383,12 @@ fn get_wait_thread_id() -> u32 {
|
||||||
let result = GetMessageW(
|
let result = GetMessageW(
|
||||||
&mut msg,
|
&mut msg,
|
||||||
-1,
|
-1,
|
||||||
*SEND_WAIT_THREAD_ID_MSG_ID,
|
SEND_WAIT_THREAD_ID_MSG_ID.get(),
|
||||||
*SEND_WAIT_THREAD_ID_MSG_ID,
|
SEND_WAIT_THREAD_ID_MSG_ID.get(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
msg.message, *SEND_WAIT_THREAD_ID_MSG_ID,
|
msg.message,
|
||||||
|
SEND_WAIT_THREAD_ID_MSG_ID.get(),
|
||||||
"this shouldn't be possible. please open an issue with Winit. error code: {result}"
|
"this shouldn't be possible. please open an issue with Winit. error code: {result}"
|
||||||
);
|
);
|
||||||
msg.lParam as u32
|
msg.lParam as u32
|
||||||
|
@ -412,7 +414,7 @@ fn wait_thread(parent_thread_id: u32, msg_window_id: HWND) {
|
||||||
let cur_thread_id = GetCurrentThreadId();
|
let cur_thread_id = GetCurrentThreadId();
|
||||||
PostThreadMessageW(
|
PostThreadMessageW(
|
||||||
parent_thread_id,
|
parent_thread_id,
|
||||||
*SEND_WAIT_THREAD_ID_MSG_ID,
|
SEND_WAIT_THREAD_ID_MSG_ID.get(),
|
||||||
0,
|
0,
|
||||||
cur_thread_id as LPARAM,
|
cur_thread_id as LPARAM,
|
||||||
);
|
);
|
||||||
|
@ -436,9 +438,9 @@ fn wait_thread(parent_thread_id: u32, msg_window_id: HWND) {
|
||||||
DispatchMessageW(&msg);
|
DispatchMessageW(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.message == *WAIT_UNTIL_MSG_ID {
|
if msg.message == WAIT_UNTIL_MSG_ID.get() {
|
||||||
wait_until_opt = Some(*WaitUntilInstantBox::from_raw(msg.lParam as *mut _));
|
wait_until_opt = Some(*WaitUntilInstantBox::from_raw(msg.lParam as *mut _));
|
||||||
} else if msg.message == *CANCEL_WAIT_UNTIL_MSG_ID {
|
} else if msg.message == CANCEL_WAIT_UNTIL_MSG_ID.get() {
|
||||||
wait_until_opt = None;
|
wait_until_opt = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,11 +468,11 @@ fn wait_thread(parent_thread_id: u32, msg_window_id: HWND) {
|
||||||
timeEndPeriod(period);
|
timeEndPeriod(period);
|
||||||
}
|
}
|
||||||
if resume_reason == WAIT_TIMEOUT {
|
if resume_reason == WAIT_TIMEOUT {
|
||||||
PostMessageW(msg_window_id, *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
|
PostMessageW(msg_window_id, PROCESS_NEW_EVENTS_MSG_ID.get(), 0, 0);
|
||||||
wait_until_opt = None;
|
wait_until_opt = None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PostMessageW(msg_window_id, *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
|
PostMessageW(msg_window_id, PROCESS_NEW_EVENTS_MSG_ID.get(), 0, 0);
|
||||||
wait_until_opt = None;
|
wait_until_opt = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,7 +558,7 @@ impl EventLoopThreadExecutor {
|
||||||
|
|
||||||
let raw = Box::into_raw(boxed2);
|
let raw = Box::into_raw(boxed2);
|
||||||
|
|
||||||
let res = PostMessageW(self.target_window, *EXEC_MSG_ID, raw as usize, 0);
|
let res = PostMessageW(self.target_window, EXEC_MSG_ID.get(), raw as usize, 0);
|
||||||
assert!(
|
assert!(
|
||||||
res != false.into(),
|
res != false.into(),
|
||||||
"PostMessage failed; is the messages queue full?"
|
"PostMessage failed; is the messages queue full?"
|
||||||
|
@ -586,7 +588,7 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if PostMessageW(self.target_window, *USER_EVENT_MSG_ID, 0, 0) != false.into() {
|
if PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) != false.into() {
|
||||||
self.event_send.send(event).ok();
|
self.event_send.send(event).ok();
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -598,40 +600,84 @@ impl<T: 'static> EventLoopProxy<T> {
|
||||||
|
|
||||||
type WaitUntilInstantBox = Box<Instant>;
|
type WaitUntilInstantBox = Box<Instant>;
|
||||||
|
|
||||||
|
/// A lazily-initialized window message ID.
|
||||||
|
pub struct LazyMessageId {
|
||||||
|
/// The ID.
|
||||||
|
id: AtomicU32,
|
||||||
|
|
||||||
|
/// The name of the message.
|
||||||
|
name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An invalid custom window ID.
|
||||||
|
const INVALID_ID: u32 = 0x0;
|
||||||
|
|
||||||
|
impl LazyMessageId {
|
||||||
|
/// Create a new `LazyId`.
|
||||||
|
const fn new(name: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
id: AtomicU32::new(INVALID_ID),
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the message ID.
|
||||||
|
pub fn get(&self) -> u32 {
|
||||||
|
// Load the ID.
|
||||||
|
let id = self.id.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
if id != INVALID_ID {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the message.
|
||||||
|
// SAFETY: We are sure that the pointer is a valid C string ending with '\0'.
|
||||||
|
assert!(self.name.ends_with('\0'));
|
||||||
|
let new_id = unsafe { RegisterWindowMessageA(self.name.as_ptr()) };
|
||||||
|
|
||||||
|
assert_ne!(
|
||||||
|
new_id,
|
||||||
|
0,
|
||||||
|
"RegisterWindowMessageA returned zero for '{}': {}",
|
||||||
|
self.name,
|
||||||
|
std::io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Store the new ID. Since `RegisterWindowMessageA` returns the same value for any given string,
|
||||||
|
// the target value will always either be a). `INVALID_ID` or b). the correct ID. Therefore a
|
||||||
|
// compare-and-swap operation here (or really any consideration) is never necessary.
|
||||||
|
self.id.store(new_id, Ordering::Relaxed);
|
||||||
|
|
||||||
|
new_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Message sent by the `EventLoopProxy` when we want to wake up the thread.
|
// Message sent by the `EventLoopProxy` when we want to wake up the thread.
|
||||||
// WPARAM and LPARAM are unused.
|
// WPARAM and LPARAM are unused.
|
||||||
static USER_EVENT_MSG_ID: Lazy<u32> =
|
static USER_EVENT_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::WakeupMsg\0");
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::WakeupMsg\0".as_ptr()) });
|
|
||||||
// Message sent when we want to execute a closure in the thread.
|
// Message sent when we want to execute a closure in the thread.
|
||||||
// WPARAM contains a Box<Box<dyn FnMut()>> that must be retrieved with `Box::from_raw`,
|
// WPARAM contains a Box<Box<dyn FnMut()>> that must be retrieved with `Box::from_raw`,
|
||||||
// and LPARAM is unused.
|
// and LPARAM is unused.
|
||||||
static EXEC_MSG_ID: Lazy<u32> =
|
static EXEC_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::ExecMsg\0");
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr()) });
|
static PROCESS_NEW_EVENTS_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::ProcessNewEvents\0");
|
||||||
static PROCESS_NEW_EVENTS_MSG_ID: Lazy<u32> =
|
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::ProcessNewEvents\0".as_ptr()) });
|
|
||||||
/// lparam is the wait thread's message id.
|
/// lparam is the wait thread's message id.
|
||||||
static SEND_WAIT_THREAD_ID_MSG_ID: Lazy<u32> =
|
static SEND_WAIT_THREAD_ID_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::SendWaitThreadId\0");
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::SendWaitThreadId\0".as_ptr()) });
|
|
||||||
/// lparam points to a `Box<Instant>` signifying the time `PROCESS_NEW_EVENTS_MSG_ID` should
|
/// lparam points to a `Box<Instant>` signifying the time `PROCESS_NEW_EVENTS_MSG_ID` should
|
||||||
/// be sent.
|
/// be sent.
|
||||||
static WAIT_UNTIL_MSG_ID: Lazy<u32> =
|
static WAIT_UNTIL_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::WaitUntil\0");
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::WaitUntil\0".as_ptr()) });
|
static CANCEL_WAIT_UNTIL_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::CancelWaitUntil\0");
|
||||||
static CANCEL_WAIT_UNTIL_MSG_ID: Lazy<u32> =
|
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::CancelWaitUntil\0".as_ptr()) });
|
|
||||||
// Message sent by a `Window` when it wants to be destroyed by the main thread.
|
// Message sent by a `Window` when it wants to be destroyed by the main thread.
|
||||||
// WPARAM and LPARAM are unused.
|
// WPARAM and LPARAM are unused.
|
||||||
pub static DESTROY_MSG_ID: Lazy<u32> =
|
pub static DESTROY_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::DestroyMsg\0");
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::DestroyMsg\0".as_ptr()) });
|
|
||||||
// WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the
|
// WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the
|
||||||
// documentation in the `window_state` module for more information.
|
// documentation in the `window_state` module for more information.
|
||||||
pub static SET_RETAIN_STATE_ON_SIZE_MSG_ID: Lazy<u32> =
|
pub static SET_RETAIN_STATE_ON_SIZE_MSG_ID: LazyMessageId =
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("Winit::SetRetainMaximized\0".as_ptr()) });
|
LazyMessageId::new("Winit::SetRetainMaximized\0");
|
||||||
static THREAD_EVENT_TARGET_WINDOW_CLASS: Lazy<Vec<u16>> =
|
static THREAD_EVENT_TARGET_WINDOW_CLASS: Lazy<Vec<u16>> =
|
||||||
Lazy::new(|| util::encode_wide("Winit Thread Event Target"));
|
Lazy::new(|| util::encode_wide("Winit Thread Event Target"));
|
||||||
/// When the taskbar is created, it registers a message with the "TaskbarCreated" string and then broadcasts this message to all top-level windows
|
/// When the taskbar is created, it registers a message with the "TaskbarCreated" string and then broadcasts this message to all top-level windows
|
||||||
/// <https://docs.microsoft.com/en-us/windows/win32/shell/taskbar#taskbar-creation-notification>
|
/// <https://docs.microsoft.com/en-us/windows/win32/shell/taskbar#taskbar-creation-notification>
|
||||||
pub static TASKBAR_CREATED: Lazy<u32> =
|
pub static TASKBAR_CREATED: LazyMessageId = LazyMessageId::new("TaskbarCreated\0");
|
||||||
Lazy::new(|| unsafe { RegisterWindowMessageA("TaskbarCreated\0".as_ptr()) });
|
|
||||||
|
|
||||||
fn create_event_target_window<T: 'static>() -> HWND {
|
fn create_event_target_window<T: 'static>() -> HWND {
|
||||||
use windows_sys::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
|
use windows_sys::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
|
||||||
|
@ -783,13 +829,18 @@ unsafe fn flush_paint_messages<T: 'static>(
|
||||||
unsafe fn process_control_flow<T: 'static>(runner: &EventLoopRunner<T>) {
|
unsafe fn process_control_flow<T: 'static>(runner: &EventLoopRunner<T>) {
|
||||||
match runner.control_flow() {
|
match runner.control_flow() {
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
PostMessageW(runner.thread_msg_target(), *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
|
PostMessageW(
|
||||||
|
runner.thread_msg_target(),
|
||||||
|
PROCESS_NEW_EVENTS_MSG_ID.get(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ControlFlow::Wait => (),
|
ControlFlow::Wait => (),
|
||||||
ControlFlow::WaitUntil(until) => {
|
ControlFlow::WaitUntil(until) => {
|
||||||
PostThreadMessageW(
|
PostThreadMessageW(
|
||||||
runner.wait_thread_id(),
|
runner.wait_thread_id(),
|
||||||
*WAIT_UNTIL_MSG_ID,
|
WAIT_UNTIL_MSG_ID.get(),
|
||||||
0,
|
0,
|
||||||
Box::into_raw(WaitUntilInstantBox::new(until)) as isize,
|
Box::into_raw(WaitUntilInstantBox::new(until)) as isize,
|
||||||
);
|
);
|
||||||
|
@ -2244,16 +2295,16 @@ unsafe fn public_window_callback_inner<T: 'static>(
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
if msg == *DESTROY_MSG_ID {
|
if msg == DESTROY_MSG_ID.get() {
|
||||||
DestroyWindow(window);
|
DestroyWindow(window);
|
||||||
0
|
0
|
||||||
} else if msg == *SET_RETAIN_STATE_ON_SIZE_MSG_ID {
|
} else if msg == SET_RETAIN_STATE_ON_SIZE_MSG_ID.get() {
|
||||||
let mut window_state = userdata.window_state_lock();
|
let mut window_state = userdata.window_state_lock();
|
||||||
window_state.set_window_flags_in_place(|f| {
|
window_state.set_window_flags_in_place(|f| {
|
||||||
f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0)
|
f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0)
|
||||||
});
|
});
|
||||||
0
|
0
|
||||||
} else if msg == *TASKBAR_CREATED {
|
} else if msg == TASKBAR_CREATED.get() {
|
||||||
let window_state = userdata.window_state_lock();
|
let window_state = userdata.window_state_lock();
|
||||||
set_skip_taskbar(window, window_state.skip_taskbar);
|
set_skip_taskbar(window, window_state.skip_taskbar);
|
||||||
DefWindowProcW(window, msg, wparam, lparam)
|
DefWindowProcW(window, msg, wparam, lparam)
|
||||||
|
@ -2442,21 +2493,21 @@ unsafe extern "system" fn thread_event_target_callback<T: 'static>(
|
||||||
DefWindowProcW(window, msg, wparam, lparam)
|
DefWindowProcW(window, msg, wparam, lparam)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if msg == *USER_EVENT_MSG_ID => {
|
_ if msg == USER_EVENT_MSG_ID.get() => {
|
||||||
if let Ok(event) = userdata.user_event_receiver.recv() {
|
if let Ok(event) = userdata.user_event_receiver.recv() {
|
||||||
userdata.send_event(Event::UserEvent(event));
|
userdata.send_event(Event::UserEvent(event));
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
_ if msg == *EXEC_MSG_ID => {
|
_ if msg == EXEC_MSG_ID.get() => {
|
||||||
let mut function: ThreadExecFn = Box::from_raw(wparam as *mut _);
|
let mut function: ThreadExecFn = Box::from_raw(wparam as *mut _);
|
||||||
function();
|
function();
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
_ if msg == *PROCESS_NEW_EVENTS_MSG_ID => {
|
_ if msg == PROCESS_NEW_EVENTS_MSG_ID.get() => {
|
||||||
PostThreadMessageW(
|
PostThreadMessageW(
|
||||||
userdata.event_loop_runner.wait_thread_id(),
|
userdata.event_loop_runner.wait_thread_id(),
|
||||||
*CANCEL_WAIT_UNTIL_MSG_ID,
|
CANCEL_WAIT_UNTIL_MSG_ID.get(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
|
@ -841,7 +841,7 @@ impl Drop for Window {
|
||||||
unsafe {
|
unsafe {
|
||||||
// The window must be destroyed from the same thread that created it, so we send a
|
// The window must be destroyed from the same thread that created it, so we send a
|
||||||
// custom message to be handled by our callback to do the actual work.
|
// custom message to be handled by our callback to do the actual work.
|
||||||
PostMessageW(self.hwnd(), *DESTROY_MSG_ID, 0, 0);
|
PostMessageW(self.hwnd(), DESTROY_MSG_ID.get(), 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,7 +391,12 @@ impl WindowFlags {
|
||||||
let (style, style_ex) = new.to_window_styles();
|
let (style, style_ex) = new.to_window_styles();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
|
SendMessageW(
|
||||||
|
window,
|
||||||
|
event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID.get(),
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
// This condition is necessary to avoid having an unrestorable window
|
// This condition is necessary to avoid having an unrestorable window
|
||||||
if !new.contains(WindowFlags::MINIMIZED) {
|
if !new.contains(WindowFlags::MINIMIZED) {
|
||||||
|
@ -412,7 +417,12 @@ impl WindowFlags {
|
||||||
|
|
||||||
// Refresh the window frame
|
// Refresh the window frame
|
||||||
SetWindowPos(window, 0, 0, 0, 0, 0, flags);
|
SetWindowPos(window, 0, 0, 0, 0, 0, flags);
|
||||||
SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
|
SendMessageW(
|
||||||
|
window,
|
||||||
|
event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID.get(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue