mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 22:31:30 +11:00
Re-implement resize patch using Mutex + Convar
This commit is contained in:
parent
d2034b1700
commit
657860a233
|
@ -1,12 +1,12 @@
|
||||||
//! An events loop on Win32 is a background thread.
|
//! An events loop on Win32 is a background thread.
|
||||||
//!
|
//!
|
||||||
//! Creating an events loop spawns a thread and blocks it in a permanent Win32 events loop.
|
//! Creating an events loop spawns a thread and blocks it in a permanent Win32 events loop.
|
||||||
//! Destroying the events loop stops the thread.
|
//! Destroying the events loop stops the thread.
|
||||||
//!
|
//!
|
||||||
//! You can use the `execute_in_thread` method to execute some code in the background thread.
|
//! You can use the `execute_in_thread` method to execute some code in the background thread.
|
||||||
//! Since Win32 requires you to create a window in the right thread, you must use this method
|
//! Since Win32 requires you to create a window in the right thread, you must use this method
|
||||||
//! to create a window.
|
//! to create a window.
|
||||||
//!
|
//!
|
||||||
//! If you create a window whose class is set to `callback`, the window's events will be
|
//! If you create a window whose class is set to `callback`, the window's events will be
|
||||||
//! propagated with `run_forever` and `poll_events`.
|
//! propagated with `run_forever` and `poll_events`.
|
||||||
//! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to
|
//! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to
|
||||||
|
@ -22,7 +22,7 @@ use std::ptr;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::sync::Barrier;
|
use std::sync::Condvar;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use kernel32;
|
use kernel32;
|
||||||
|
@ -79,16 +79,18 @@ pub struct EventsLoop {
|
||||||
thread_id: winapi::DWORD,
|
thread_id: winapi::DWORD,
|
||||||
// Receiver for the events. The sender is in the background thread.
|
// Receiver for the events. The sender is in the background thread.
|
||||||
receiver: mpsc::Receiver<Event>,
|
receiver: mpsc::Receiver<Event>,
|
||||||
// Barrier used to unblock the event loop thread after a resize event is processed.
|
// Variable that contains the block state of the win32 event loop thread during a WM_SIZE event.
|
||||||
resize_barrier: Arc<Barrier>
|
// The mutex's value is `true` when it's blocked, and should be set to false when it's done
|
||||||
|
// blocking. That's done by the parent thread when it receives a Resized event.
|
||||||
|
win32_block_loop: Arc<(Mutex<bool>, Condvar)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
pub fn new() -> EventsLoop {
|
pub fn new() -> EventsLoop {
|
||||||
// The main events transfer channel.
|
// The main events transfer channel.
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let resize_barrier = Arc::new(Barrier::new(2));
|
let win32_block_loop = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
let resize_barrier_child = resize_barrier.clone();
|
let win32_block_loop_child = win32_block_loop.clone();
|
||||||
|
|
||||||
// Local channel in order to block the `new()` function until the background thread has
|
// Local channel in order to block the `new()` function until the background thread has
|
||||||
// an events queue.
|
// an events queue.
|
||||||
|
@ -99,8 +101,7 @@ impl EventsLoop {
|
||||||
*context_stash.borrow_mut() = Some(ThreadLocalData {
|
*context_stash.borrow_mut() = Some(ThreadLocalData {
|
||||||
sender: tx,
|
sender: tx,
|
||||||
windows: HashMap::with_capacity(4),
|
windows: HashMap::with_capacity(4),
|
||||||
resize_barrier: resize_barrier_child,
|
win32_block_loop: win32_block_loop_child
|
||||||
deferred_waits: 0
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -130,15 +131,6 @@ impl EventsLoop {
|
||||||
x if x == *WAKEUP_MSG_ID => {
|
x if x == *WAKEUP_MSG_ID => {
|
||||||
send_event(Event::Awakened);
|
send_event(Event::Awakened);
|
||||||
},
|
},
|
||||||
x if x == *USE_WAIT_ID => CONTEXT_STASH.with(|context_stash| {
|
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
|
||||||
let cstash = context_stash.as_mut().unwrap();
|
|
||||||
// Run a deferred wait
|
|
||||||
if cstash.deferred_waits > 0 {
|
|
||||||
cstash.deferred_waits -= 1;
|
|
||||||
cstash.resize_barrier.wait();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
_ => {
|
_ => {
|
||||||
// Calls `callback` below.
|
// Calls `callback` below.
|
||||||
user32::TranslateMessage(&msg);
|
user32::TranslateMessage(&msg);
|
||||||
|
@ -155,7 +147,7 @@ impl EventsLoop {
|
||||||
EventsLoop {
|
EventsLoop {
|
||||||
thread_id: unsafe { kernel32::GetThreadId(thread.as_raw_handle()) },
|
thread_id: unsafe { kernel32::GetThreadId(thread.as_raw_handle()) },
|
||||||
receiver: rx,
|
receiver: rx,
|
||||||
resize_barrier: resize_barrier
|
win32_block_loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +196,10 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_with_thread(&self) {
|
fn sync_with_thread(&self) {
|
||||||
let res = unsafe{ user32::PostThreadMessageA(self.thread_id, *USE_WAIT_ID, 0, 0) };
|
let (ref mutex, ref cvar) = *self.win32_block_loop;
|
||||||
self.resize_barrier.wait();
|
let mut block_thread = mutex.lock().unwrap();
|
||||||
assert!(res != 0, "PostThreadMessage failed ; is the messages queue full?");
|
*block_thread = false;
|
||||||
|
cvar.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a function in the background thread.
|
/// Executes a function in the background thread.
|
||||||
|
@ -282,13 +275,6 @@ lazy_static! {
|
||||||
user32::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as *const i8)
|
user32::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as *const i8)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Message sent when the parent thread receives a resize event and wants this thread to use any
|
|
||||||
// deferred waits it may have.
|
|
||||||
static ref USE_WAIT_ID: u32 = {
|
|
||||||
unsafe {
|
|
||||||
user32::RegisterWindowMessageA("Winit::UseWait\0".as_ptr() as *const i8)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no parameters passed to the callback function, so it needs to get its context stashed
|
// There's no parameters passed to the callback function, so it needs to get its context stashed
|
||||||
|
@ -297,8 +283,7 @@ thread_local!(static CONTEXT_STASH: RefCell<Option<ThreadLocalData>> = RefCell::
|
||||||
struct ThreadLocalData {
|
struct ThreadLocalData {
|
||||||
sender: mpsc::Sender<Event>,
|
sender: mpsc::Sender<Event>,
|
||||||
windows: HashMap<winapi::HWND, Arc<Mutex<WindowState>>>,
|
windows: HashMap<winapi::HWND, Arc<Mutex<WindowState>>>,
|
||||||
resize_barrier: Arc<Barrier>,
|
win32_block_loop: Arc<(Mutex<bool>, Condvar)>
|
||||||
deferred_waits: u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_is_resize(event: &Event) -> bool {
|
fn event_is_resize(event: &Event) -> bool {
|
||||||
|
@ -361,13 +346,16 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
let mut context_stash = context_stash.borrow_mut();
|
||||||
let cstash = context_stash.as_mut().unwrap();
|
let cstash = context_stash.as_mut().unwrap();
|
||||||
|
|
||||||
|
// If this window has been inserted into the window map, the resize event happened
|
||||||
|
// during the event loop. If it hasn't, the event happened on window creation and
|
||||||
|
// should be ignored.
|
||||||
if cstash.windows.get(&window).is_some() {
|
if cstash.windows.get(&window).is_some() {
|
||||||
cstash.resize_barrier.wait();
|
let (ref mutex, ref cvar) = *cstash.win32_block_loop;
|
||||||
} else {
|
let mut block_thread = mutex.lock().unwrap();
|
||||||
// If the window isn't in the hashmap, this is the resize event that was sent
|
*block_thread = true;
|
||||||
// upon window creation. The parent thread isn't going to wait until the event
|
while *block_thread {
|
||||||
// loop, so record that a wait must happen when the event loop is reached.
|
block_thread = cvar.wait(block_thread).unwrap();
|
||||||
cstash.deferred_waits += 1;
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
0
|
0
|
||||||
|
@ -425,7 +413,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseEntered { device_id: DEVICE_ID },
|
event: MouseEntered { device_id: DEVICE_ID },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Calling TrackMouseEvent in order to receive mouse leave events.
|
// Calling TrackMouseEvent in order to receive mouse leave events.
|
||||||
user32::TrackMouseEvent(&mut winapi::TRACKMOUSEEVENT {
|
user32::TrackMouseEvent(&mut winapi::TRACKMOUSEEVENT {
|
||||||
cbSize: mem::size_of::<winapi::TRACKMOUSEEVENT>() as winapi::DWORD,
|
cbSize: mem::size_of::<winapi::TRACKMOUSEEVENT>() as winapi::DWORD,
|
||||||
|
@ -612,7 +600,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
||||||
use events::WindowEvent::MouseInput;
|
use events::WindowEvent::MouseInput;
|
||||||
use events::MouseButton::Other;
|
use events::MouseButton::Other;
|
||||||
use events::ElementState::Released;
|
use events::ElementState::Released;
|
||||||
let xbutton = winapi::HIWORD(wparam as winapi::DWORD) as winapi::c_int;
|
let xbutton = winapi::HIWORD(wparam as winapi::DWORD) as winapi::c_int;
|
||||||
send_event(Event::WindowEvent {
|
send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8) }
|
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8) }
|
||||||
|
@ -702,7 +690,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
||||||
|
|
||||||
if call_def_window_proc {
|
if call_def_window_proc {
|
||||||
user32::DefWindowProcW(window, msg, wparam, lparam)
|
user32::DefWindowProcW(window, msg, wparam, lparam)
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue