mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 13:51:30 +11:00
Implement revamped RedrawRequested on Windows (#1050)
* Move event loop runner to runner module * Implement new redraw API
This commit is contained in:
parent
0c151f9fb3
commit
8eb7853a1a
|
@ -20,7 +20,10 @@ fn main() {
|
|||
event: WindowEvent::CloseRequested,
|
||||
window_id,
|
||||
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
|
||||
_ => *control_flow = ControlFlow::Wait,
|
||||
Event::MainEventsCleared => {
|
||||
window.request_redraw();
|
||||
}
|
||||
_ => *control_flow = ControlFlow::Poll,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,16 +13,14 @@
|
|||
//! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to
|
||||
//! add a `WindowState` entry to a list of window to be used by the callback.
|
||||
|
||||
mod runner;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
any::Any,
|
||||
cell::RefCell,
|
||||
collections::VecDeque,
|
||||
marker::PhantomData,
|
||||
mem, panic, ptr,
|
||||
rc::Rc,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::{self, Receiver, Sender},
|
||||
Arc,
|
||||
},
|
||||
|
@ -44,9 +42,10 @@ use winapi::{
|
|||
},
|
||||
};
|
||||
|
||||
use self::runner::{ELRShared, EventLoopRunnerShared};
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
|
||||
event::{DeviceEvent, Event, Force, KeyboardInput, StartCause, Touch, TouchPhase, WindowEvent},
|
||||
event::{DeviceEvent, Event, Force, KeyboardInput, Touch, TouchPhase, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||
platform_impl::platform::{
|
||||
dpi::{
|
||||
|
@ -127,7 +126,6 @@ pub struct EventLoop<T: 'static> {
|
|||
|
||||
pub struct EventLoopWindowTarget<T> {
|
||||
thread_id: DWORD,
|
||||
trigger_newevents_on_redraw: Arc<AtomicBool>,
|
||||
thread_msg_target: HWND,
|
||||
pub(crate) runner_shared: EventLoopRunnerShared<T>,
|
||||
}
|
||||
|
@ -167,10 +165,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
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),
|
||||
buffer: RefCell::new(VecDeque::new()),
|
||||
});
|
||||
let runner_shared = Rc::new(ELRShared::new());
|
||||
let (thread_msg_target, thread_msg_sender) =
|
||||
thread_event_target_window(runner_shared.clone());
|
||||
|
||||
|
@ -179,7 +174,6 @@ impl<T: 'static> EventLoop<T> {
|
|||
window_target: RootELW {
|
||||
p: EventLoopWindowTarget {
|
||||
thread_id,
|
||||
trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)),
|
||||
thread_msg_target,
|
||||
runner_shared,
|
||||
},
|
||||
|
@ -206,44 +200,23 @@ impl<T: 'static> EventLoop<T> {
|
|||
{
|
||||
let event_loop_windows_ref = &self.window_target;
|
||||
|
||||
let mut runner = unsafe {
|
||||
EventLoopRunner::new(self, move |event, control_flow| {
|
||||
event_handler(event, event_loop_windows_ref, control_flow)
|
||||
})
|
||||
};
|
||||
{
|
||||
let runner_shared = self.window_target.p.runner_shared.clone();
|
||||
let mut runner_ref = runner_shared.runner.borrow_mut();
|
||||
loop {
|
||||
let event = runner_shared.buffer.borrow_mut().pop_front();
|
||||
match event {
|
||||
Some(e) => {
|
||||
runner.process_event(e);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
*runner_ref = Some(runner);
|
||||
unsafe {
|
||||
self.window_target
|
||||
.p
|
||||
.runner_shared
|
||||
.set_runner(self, move |event, control_flow| {
|
||||
event_handler(event, event_loop_windows_ref, control_flow)
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! runner {
|
||||
() => {
|
||||
self.window_target
|
||||
.p
|
||||
.runner_shared
|
||||
.runner
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
};
|
||||
}
|
||||
let runner = &self.window_target.p.runner_shared;
|
||||
|
||||
unsafe {
|
||||
let mut msg = mem::zeroed();
|
||||
let mut msg_unprocessed = false;
|
||||
|
||||
'main: loop {
|
||||
runner!().new_events();
|
||||
runner.new_events();
|
||||
loop {
|
||||
if !msg_unprocessed {
|
||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
||||
|
@ -255,13 +228,14 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
msg_unprocessed = false;
|
||||
}
|
||||
runner!().events_cleared();
|
||||
if let Some(payload) = runner!().panic_error.take() {
|
||||
runner.events_cleared();
|
||||
if let Err(payload) = runner.take_panic_error() {
|
||||
runner.destroy_runner();
|
||||
panic::resume_unwind(payload);
|
||||
}
|
||||
|
||||
if !msg_unprocessed {
|
||||
let control_flow = runner!().control_flow;
|
||||
let control_flow = runner.control_flow();
|
||||
match control_flow {
|
||||
ControlFlow::Exit => break 'main,
|
||||
ControlFlow::Wait => {
|
||||
|
@ -279,8 +253,10 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
}
|
||||
|
||||
runner!().call_event_handler(Event::LoopDestroyed);
|
||||
*self.window_target.p.runner_shared.runner.borrow_mut() = None;
|
||||
unsafe {
|
||||
runner.call_event_handler(Event::LoopDestroyed);
|
||||
}
|
||||
runner.destroy_runner();
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
|
@ -296,7 +272,6 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
|
||||
EventLoopThreadExecutor {
|
||||
thread_id: self.thread_id,
|
||||
trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone(),
|
||||
target_window: self.thread_msg_target,
|
||||
}
|
||||
}
|
||||
|
@ -317,291 +292,6 @@ fn main_thread_id() -> DWORD {
|
|||
unsafe { MAIN_THREAD_ID }
|
||||
}
|
||||
|
||||
pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
||||
pub(crate) struct ELRShared<T> {
|
||||
runner: RefCell<Option<EventLoopRunner<T>>>,
|
||||
buffer: RefCell<VecDeque<Event<T>>>,
|
||||
}
|
||||
pub(crate) struct EventLoopRunner<T> {
|
||||
trigger_newevents_on_redraw: Arc<AtomicBool>,
|
||||
control_flow: ControlFlow,
|
||||
runner_state: RunnerState,
|
||||
modal_redraw_window: HWND,
|
||||
in_modal_loop: bool,
|
||||
in_repaint: bool,
|
||||
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
panic_error: Option<PanicError>,
|
||||
}
|
||||
type PanicError = Box<dyn Any + Send + 'static>;
|
||||
|
||||
impl<T> ELRShared<T> {
|
||||
pub(crate) unsafe fn send_event(&self, event: Event<T>) {
|
||||
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.process_event(event);
|
||||
|
||||
// Dispatch any events that were buffered during the call to `process_event`.
|
||||
loop {
|
||||
// We do this instead of using a `while let` loop because if we use a `while let`
|
||||
// loop the reference returned `borrow_mut()` doesn't get dropped until the end
|
||||
// of the loop's body and attempts to add events to the event buffer while in
|
||||
// `process_event` will fail.
|
||||
let buffered_event_opt = self.buffer.borrow_mut().pop_front();
|
||||
match buffered_event_opt {
|
||||
Some(event) => runner.process_event(event),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
|
||||
// the event to a buffer to be processed later.
|
||||
self.buffer.borrow_mut().push_back(event)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum RunnerState {
|
||||
/// The event loop has just been created, and an `Init` event must be sent.
|
||||
New,
|
||||
/// The event loop is idling, and began idling at the given instant.
|
||||
Idle(Instant),
|
||||
/// The event loop has received a signal from the OS that the loop may resume, but no winit
|
||||
/// events have been generated yet. We're waiting for an event to be processed or the events
|
||||
/// to be marked as cleared to send `NewEvents`, depending on the current `ControlFlow`.
|
||||
DeferredNewEvents(Instant),
|
||||
/// The event loop is handling the OS's events and sending them to the user's callback.
|
||||
/// `NewEvents` has been sent, and `EventsCleared` hasn't.
|
||||
HandlingEvents,
|
||||
}
|
||||
|
||||
impl<T> EventLoopRunner<T> {
|
||||
unsafe fn new<F>(event_loop: &EventLoop<T>, f: F) -> EventLoopRunner<T>
|
||||
where
|
||||
F: FnMut(Event<T>, &mut ControlFlow),
|
||||
{
|
||||
EventLoopRunner {
|
||||
trigger_newevents_on_redraw: event_loop
|
||||
.window_target
|
||||
.p
|
||||
.trigger_newevents_on_redraw
|
||||
.clone(),
|
||||
control_flow: ControlFlow::default(),
|
||||
runner_state: RunnerState::New,
|
||||
in_modal_loop: false,
|
||||
in_repaint: false,
|
||||
modal_redraw_window: event_loop.window_target.p.thread_msg_target,
|
||||
event_handler: mem::transmute::<
|
||||
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
>(Box::new(f)),
|
||||
panic_error: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_events(&mut self) {
|
||||
self.runner_state = match self.runner_state {
|
||||
// If we're already handling events or have deferred `NewEvents`, we don't need to do
|
||||
// do any processing.
|
||||
RunnerState::HandlingEvents | RunnerState::DeferredNewEvents(..) => self.runner_state,
|
||||
|
||||
// Send the `Init` `NewEvents` and immediately move into event processing.
|
||||
RunnerState::New => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Init));
|
||||
RunnerState::HandlingEvents
|
||||
}
|
||||
|
||||
// When `NewEvents` gets sent after an idle depends on the control flow...
|
||||
RunnerState::Idle(wait_start) => {
|
||||
match self.control_flow {
|
||||
// If we're polling, send `NewEvents` and immediately move into event processing.
|
||||
ControlFlow::Poll => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Poll));
|
||||
RunnerState::HandlingEvents
|
||||
},
|
||||
// If the user was waiting until a specific time, the `NewEvents` call gets sent
|
||||
// at varying times depending on the current time.
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
match Instant::now() >= resume_time {
|
||||
// If the current time is later than the requested resume time, we can tell the
|
||||
// user that the resume time has been reached with `NewEvents` and immdiately move
|
||||
// into event processing.
|
||||
true => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
}));
|
||||
RunnerState::HandlingEvents
|
||||
},
|
||||
// However, if the current time is EARLIER than the requested resume time, we
|
||||
// don't want to send the `WaitCancelled` event until we know an event is being
|
||||
// sent. Defer.
|
||||
false => RunnerState::DeferredNewEvents(wait_start)
|
||||
}
|
||||
},
|
||||
// If we're waiting, `NewEvents` doesn't get sent until winit gets an event, so
|
||||
// we defer.
|
||||
ControlFlow::Wait |
|
||||
// `Exit` shouldn't really ever get sent here, but if it does do something somewhat sane.
|
||||
ControlFlow::Exit => RunnerState::DeferredNewEvents(wait_start),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn process_event(&mut self, event: Event<T>) {
|
||||
// If we're in the modal loop, we need to have some mechanism for finding when the event
|
||||
// queue has been cleared so we can call `events_cleared`. Windows doesn't give any utilities
|
||||
// for doing this, but it DOES guarantee that WM_PAINT will only occur after input events have
|
||||
// been processed. So, we send WM_PAINT to a dummy window which calls `events_cleared` when
|
||||
// the events queue has been emptied.
|
||||
if self.in_modal_loop {
|
||||
unsafe {
|
||||
winuser::RedrawWindow(
|
||||
self.modal_redraw_window,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If new event processing has to be done (i.e. call NewEvents or defer), do it. If we're
|
||||
// already in processing nothing happens with this call.
|
||||
self.new_events();
|
||||
|
||||
// Now that an event has been received, we have to send any `NewEvents` calls that were
|
||||
// deferred.
|
||||
if let RunnerState::DeferredNewEvents(wait_start) = self.runner_state {
|
||||
match self.control_flow {
|
||||
ControlFlow::Exit | ControlFlow::Wait => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_resume: None,
|
||||
}))
|
||||
}
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
let start_cause = match Instant::now() >= resume_time {
|
||||
// If the current time is later than the requested resume time, the resume time
|
||||
// has been reached.
|
||||
true => StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
},
|
||||
// Otherwise, the requested resume time HASN'T been reached and we send a WaitCancelled.
|
||||
false => StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_resume: Some(resume_time),
|
||||
},
|
||||
};
|
||||
self.call_event_handler(Event::NewEvents(start_cause));
|
||||
}
|
||||
// This can be reached if the control flow is changed to poll during a `RedrawRequested`
|
||||
// that was sent after `EventsCleared`.
|
||||
ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)),
|
||||
}
|
||||
}
|
||||
|
||||
self.runner_state = RunnerState::HandlingEvents;
|
||||
match (self.in_repaint, &event) {
|
||||
(
|
||||
true,
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
..
|
||||
},
|
||||
)
|
||||
| (false, _) => self.call_event_handler(event),
|
||||
(true, _) => {
|
||||
self.events_cleared();
|
||||
self.new_events();
|
||||
self.process_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn events_cleared(&mut self) {
|
||||
self.in_repaint = false;
|
||||
|
||||
match self.runner_state {
|
||||
// If we were handling events, send the EventsCleared message.
|
||||
RunnerState::HandlingEvents => {
|
||||
self.call_event_handler(Event::EventsCleared);
|
||||
self.runner_state = RunnerState::Idle(Instant::now());
|
||||
}
|
||||
|
||||
// If we *weren't* handling events, we don't have to do anything.
|
||||
RunnerState::New | RunnerState::Idle(..) => (),
|
||||
|
||||
// Some control flows require a NewEvents call even if no events were received. This
|
||||
// branch handles those.
|
||||
RunnerState::DeferredNewEvents(wait_start) => {
|
||||
match self.control_flow {
|
||||
// If we had deferred a Poll, send the Poll NewEvents and EventsCleared.
|
||||
ControlFlow::Poll => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Poll));
|
||||
self.call_event_handler(Event::EventsCleared);
|
||||
}
|
||||
// If we had deferred a WaitUntil and the resume time has since been reached,
|
||||
// send the resume notification and EventsCleared event.
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
if Instant::now() >= resume_time {
|
||||
self.call_event_handler(Event::NewEvents(
|
||||
StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
},
|
||||
));
|
||||
self.call_event_handler(Event::EventsCleared);
|
||||
}
|
||||
}
|
||||
// If we deferred a wait and no events were received, the user doesn't have to
|
||||
// get an event.
|
||||
ControlFlow::Wait | ControlFlow::Exit => (),
|
||||
}
|
||||
// Mark that we've entered an idle state.
|
||||
self.runner_state = RunnerState::Idle(wait_start)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_event_handler(&mut self, event: Event<T>) {
|
||||
match event {
|
||||
Event::NewEvents(_) => self
|
||||
.trigger_newevents_on_redraw
|
||||
.store(true, Ordering::Relaxed),
|
||||
Event::EventsCleared => self
|
||||
.trigger_newevents_on_redraw
|
||||
.store(false, Ordering::Relaxed),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
..
|
||||
} => self.in_repaint = true,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if self.panic_error.is_none() {
|
||||
let EventLoopRunner {
|
||||
ref mut panic_error,
|
||||
ref mut event_handler,
|
||||
ref mut control_flow,
|
||||
..
|
||||
} = self;
|
||||
*panic_error = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
if *control_flow != ControlFlow::Exit {
|
||||
(*event_handler)(event, control_flow);
|
||||
} else {
|
||||
(*event_handler)(event, &mut ControlFlow::Exit);
|
||||
}
|
||||
}))
|
||||
.err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the wait time was reached, and false if a message must be processed.
|
||||
unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool {
|
||||
let mut msg = mem::zeroed();
|
||||
|
@ -667,7 +357,6 @@ impl<T> Drop for EventLoop<T> {
|
|||
|
||||
pub(crate) struct EventLoopThreadExecutor {
|
||||
thread_id: DWORD,
|
||||
trigger_newevents_on_redraw: Arc<AtomicBool>,
|
||||
target_window: HWND,
|
||||
}
|
||||
|
||||
|
@ -681,10 +370,6 @@ impl EventLoopThreadExecutor {
|
|||
self.thread_id == cur_thread_id
|
||||
}
|
||||
|
||||
pub(super) fn trigger_newevents_on_redraw(&self) -> bool {
|
||||
!self.in_event_loop_thread() || self.trigger_newevents_on_redraw.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Executes a function in the event loop thread. If we're already in the event loop thread,
|
||||
/// we just call the function directly.
|
||||
///
|
||||
|
@ -784,12 +469,6 @@ lazy_static! {
|
|||
winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR)
|
||||
}
|
||||
};
|
||||
// Message sent by a `Window` if it's requesting a redraw without sending a NewEvents.
|
||||
pub static ref REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID: u32 = {
|
||||
unsafe {
|
||||
winuser::RegisterWindowMessageA("Winit::RequestRedrawNoNewevents\0".as_ptr() as LPCSTR)
|
||||
}
|
||||
};
|
||||
// WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the
|
||||
// documentation in the `window_state` module for more information.
|
||||
pub static ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe {
|
||||
|
@ -922,21 +601,15 @@ unsafe extern "system" fn public_window_callback<T>(
|
|||
_: UINT_PTR,
|
||||
subclass_input_ptr: DWORD_PTR,
|
||||
) -> LRESULT {
|
||||
let subclass_input = &mut *(subclass_input_ptr as *mut SubclassInput<T>);
|
||||
let subclass_input = &*(subclass_input_ptr as *const SubclassInput<T>);
|
||||
|
||||
match msg {
|
||||
winuser::WM_ENTERSIZEMOVE => {
|
||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner {
|
||||
runner.in_modal_loop = true;
|
||||
}
|
||||
subclass_input.event_loop_runner.set_modal_loop(true);
|
||||
0
|
||||
}
|
||||
winuser::WM_EXITSIZEMOVE => {
|
||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner {
|
||||
runner.in_modal_loop = false;
|
||||
}
|
||||
subclass_input.event_loop_runner.set_modal_loop(false);
|
||||
0
|
||||
}
|
||||
winuser::WM_NCCREATE => {
|
||||
|
@ -975,48 +648,13 @@ unsafe extern "system" fn public_window_callback<T>(
|
|||
event: Destroyed,
|
||||
});
|
||||
|
||||
Box::from_raw(subclass_input);
|
||||
drop(subclass_input);
|
||||
Box::from_raw(subclass_input_ptr as *mut SubclassInput<T>);
|
||||
0
|
||||
}
|
||||
|
||||
_ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => {
|
||||
use crate::event::WindowEvent::RedrawRequested;
|
||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
subclass_input.window_state.lock().queued_out_of_band_redraw = false;
|
||||
if let Some(ref mut runner) = *runner {
|
||||
// This check makes sure that calls to `request_redraw()` during `EventsCleared`
|
||||
// handling dispatch `RedrawRequested` immediately after `EventsCleared`, without
|
||||
// spinning up a new event loop iteration. We do this because that's what the API
|
||||
// says to do.
|
||||
let runner_state = runner.runner_state;
|
||||
let mut request_redraw = || {
|
||||
runner.call_event_handler(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: RedrawRequested,
|
||||
});
|
||||
};
|
||||
match runner_state {
|
||||
RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => request_redraw(),
|
||||
RunnerState::HandlingEvents => {
|
||||
winuser::RedrawWindow(
|
||||
window,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
winuser::WM_PAINT => {
|
||||
use crate::event::WindowEvent::RedrawRequested;
|
||||
subclass_input.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(WindowId(window)),
|
||||
event: RedrawRequested,
|
||||
});
|
||||
subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window))));
|
||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
}
|
||||
|
||||
|
@ -1984,14 +1622,7 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
|||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
};
|
||||
let in_modal_loop = {
|
||||
let runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
if let Some(ref runner) = *runner {
|
||||
runner.in_modal_loop
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
let in_modal_loop = subclass_input.event_loop_runner.in_modal_loop();
|
||||
if in_modal_loop {
|
||||
let mut msg = mem::zeroed();
|
||||
loop {
|
||||
|
@ -2019,21 +1650,19 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
|||
}
|
||||
}
|
||||
|
||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner {
|
||||
runner.events_cleared();
|
||||
match runner.control_flow {
|
||||
// Waiting is handled by the modal loop.
|
||||
ControlFlow::Exit | ControlFlow::Wait => runner.new_events(),
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
wait_until_time_or_msg(resume_time);
|
||||
runner.new_events();
|
||||
queue_call_again();
|
||||
}
|
||||
ControlFlow::Poll => {
|
||||
runner.new_events();
|
||||
queue_call_again();
|
||||
}
|
||||
let runner = &subclass_input.event_loop_runner;
|
||||
runner.events_cleared();
|
||||
match runner.control_flow() {
|
||||
// Waiting is handled by the modal loop.
|
||||
ControlFlow::Exit | ControlFlow::Wait => runner.new_events(),
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
wait_until_time_or_msg(resume_time);
|
||||
runner.new_events();
|
||||
queue_call_again();
|
||||
}
|
||||
ControlFlow::Poll => {
|
||||
runner.new_events();
|
||||
queue_call_again();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
415
src/platform_impl/windows/event_loop/runner.rs
Normal file
415
src/platform_impl/windows/event_loop/runner.rs
Normal file
|
@ -0,0 +1,415 @@
|
|||
use std::{
|
||||
any::Any,
|
||||
cell::RefCell,
|
||||
collections::VecDeque,
|
||||
mem, panic, ptr,
|
||||
rc::Rc,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use winapi::{
|
||||
shared::{
|
||||
windef::HWND,
|
||||
},
|
||||
um::winuser,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
event::{Event, StartCause},
|
||||
event_loop::ControlFlow,
|
||||
platform_impl::platform::{
|
||||
event_loop::EventLoop,
|
||||
},
|
||||
window::WindowId,
|
||||
};
|
||||
|
||||
pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
||||
pub(crate) struct ELRShared<T> {
|
||||
runner: RefCell<Option<EventLoopRunner<T>>>,
|
||||
buffer: RefCell<VecDeque<Event<T>>>,
|
||||
redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>,
|
||||
}
|
||||
struct EventLoopRunner<T> {
|
||||
control_flow: ControlFlow,
|
||||
runner_state: RunnerState,
|
||||
modal_redraw_window: HWND,
|
||||
in_modal_loop: bool,
|
||||
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
panic_error: Option<PanicError>,
|
||||
redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>,
|
||||
}
|
||||
pub type PanicError = Box<dyn Any + Send + 'static>;
|
||||
|
||||
impl<T> ELRShared<T> {
|
||||
pub(crate) fn new() -> ELRShared<T> {
|
||||
ELRShared {
|
||||
runner: RefCell::new(None),
|
||||
buffer: RefCell::new(VecDeque::new()),
|
||||
redraw_buffer: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn set_runner<F>(&self, event_loop: &EventLoop<T>, f: F)
|
||||
where
|
||||
F: FnMut(Event<T>, &mut ControlFlow),
|
||||
{
|
||||
let mut runner = EventLoopRunner::new(event_loop, self.redraw_buffer.clone(), f);
|
||||
{
|
||||
let mut runner_ref = self.runner.borrow_mut();
|
||||
loop {
|
||||
let event = self.buffer.borrow_mut().pop_front();
|
||||
match event {
|
||||
Some(e) => {
|
||||
runner.process_event(e);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
*runner_ref = Some(runner);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn destroy_runner(&self) {
|
||||
*self.runner.borrow_mut() = None;
|
||||
}
|
||||
|
||||
pub(crate) fn new_events(&self) {
|
||||
let mut runner_ref = self.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.new_events();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn send_event(&self, event: Event<T>) {
|
||||
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.process_event(event);
|
||||
|
||||
// Dispatch any events that were buffered during the call to `process_event`.
|
||||
loop {
|
||||
// We do this instead of using a `while let` loop because if we use a `while let`
|
||||
// loop the reference returned `borrow_mut()` doesn't get dropped until the end
|
||||
// of the loop's body and attempts to add events to the event buffer while in
|
||||
// `process_event` will fail.
|
||||
let buffered_event_opt = self.buffer.borrow_mut().pop_front();
|
||||
match buffered_event_opt {
|
||||
Some(event) => runner.process_event(event),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
|
||||
// the event to a buffer to be processed later.
|
||||
self.buffer_event(event);
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn call_event_handler(&self, event: Event<T>) {
|
||||
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.call_event_handler(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn events_cleared(&self) {
|
||||
let mut runner_ref = self.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.events_cleared();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn take_panic_error(&self) -> Result<(), PanicError> {
|
||||
let mut runner_ref = self.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.take_panic_error()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_modal_loop(&self, in_modal_loop: bool) {
|
||||
let mut runner_ref = self.runner.borrow_mut();
|
||||
if let Some(ref mut runner) = *runner_ref {
|
||||
runner.in_modal_loop = in_modal_loop;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn in_modal_loop(&self) -> bool {
|
||||
let runner = self.runner.borrow();
|
||||
if let Some(ref runner) = *runner {
|
||||
runner.in_modal_loop
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn control_flow(&self) -> ControlFlow {
|
||||
let runner_ref = self.runner.borrow();
|
||||
if let Some(ref runner) = *runner_ref {
|
||||
runner.control_flow
|
||||
} else {
|
||||
ControlFlow::Exit
|
||||
}
|
||||
}
|
||||
|
||||
fn buffer_event(&self, event: Event<T>) {
|
||||
match event {
|
||||
Event::RedrawRequested(window_id) => self.redraw_buffer.borrow_mut().push_back(window_id),
|
||||
_ => self.buffer.borrow_mut().push_back(event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum RunnerState {
|
||||
/// The event loop has just been created, and an `Init` event must be sent.
|
||||
New,
|
||||
/// The event loop is idling, and began idling at the given instant.
|
||||
Idle(Instant),
|
||||
/// The event loop has received a signal from the OS that the loop may resume, but no winit
|
||||
/// events have been generated yet. We're waiting for an event to be processed or the events
|
||||
/// to be marked as cleared to send `NewEvents`, depending on the current `ControlFlow`.
|
||||
DeferredNewEvents(Instant),
|
||||
/// The event loop is handling the OS's events and sending them to the user's callback.
|
||||
/// `NewEvents` has been sent, and `EventsCleared` hasn't.
|
||||
HandlingEvents,
|
||||
HandlingRedraw,
|
||||
}
|
||||
|
||||
impl<T> EventLoopRunner<T> {
|
||||
unsafe fn new<F>(event_loop: &EventLoop<T>, redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>, f: F) -> EventLoopRunner<T>
|
||||
where
|
||||
F: FnMut(Event<T>, &mut ControlFlow),
|
||||
{
|
||||
EventLoopRunner {
|
||||
control_flow: ControlFlow::default(),
|
||||
runner_state: RunnerState::New,
|
||||
in_modal_loop: false,
|
||||
modal_redraw_window: event_loop.window_target.p.thread_msg_target,
|
||||
event_handler: mem::transmute::<
|
||||
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||
>(Box::new(f)),
|
||||
panic_error: None,
|
||||
redraw_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
fn take_panic_error(&mut self) -> Result<(), PanicError> {
|
||||
match self.panic_error.take() {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_events(&mut self) {
|
||||
self.runner_state = match self.runner_state {
|
||||
// If we're already handling events or have deferred `NewEvents`, we don't need to do
|
||||
// do any processing.
|
||||
RunnerState::HandlingEvents | RunnerState::HandlingRedraw | RunnerState::DeferredNewEvents(..) => self.runner_state,
|
||||
|
||||
// Send the `Init` `NewEvents` and immediately move into event processing.
|
||||
RunnerState::New => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Init));
|
||||
RunnerState::HandlingEvents
|
||||
}
|
||||
|
||||
// When `NewEvents` gets sent after an idle depends on the control flow...
|
||||
RunnerState::Idle(wait_start) => {
|
||||
match self.control_flow {
|
||||
// If we're polling, send `NewEvents` and immediately move into event processing.
|
||||
ControlFlow::Poll => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Poll));
|
||||
RunnerState::HandlingEvents
|
||||
},
|
||||
// If the user was waiting until a specific time, the `NewEvents` call gets sent
|
||||
// at varying times depending on the current time.
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
match Instant::now() >= resume_time {
|
||||
// If the current time is later than the requested resume time, we can tell the
|
||||
// user that the resume time has been reached with `NewEvents` and immdiately move
|
||||
// into event processing.
|
||||
true => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
}));
|
||||
RunnerState::HandlingEvents
|
||||
},
|
||||
// However, if the current time is EARLIER than the requested resume time, we
|
||||
// don't want to send the `WaitCancelled` event until we know an event is being
|
||||
// sent. Defer.
|
||||
false => RunnerState::DeferredNewEvents(wait_start)
|
||||
}
|
||||
},
|
||||
// If we're waiting, `NewEvents` doesn't get sent until winit gets an event, so
|
||||
// we defer.
|
||||
ControlFlow::Wait |
|
||||
// `Exit` shouldn't really ever get sent here, but if it does do something somewhat sane.
|
||||
ControlFlow::Exit => RunnerState::DeferredNewEvents(wait_start),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn process_event(&mut self, event: Event<T>) {
|
||||
// If we're in the modal loop, we need to have some mechanism for finding when the event
|
||||
// queue has been cleared so we can call `events_cleared`. Windows doesn't give any utilities
|
||||
// for doing this, but it DOES guarantee that WM_PAINT will only occur after input events have
|
||||
// been processed. So, we send WM_PAINT to a dummy window which calls `events_cleared` when
|
||||
// the events queue has been emptied.
|
||||
if self.in_modal_loop {
|
||||
unsafe {
|
||||
winuser::RedrawWindow(
|
||||
self.modal_redraw_window,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If new event processing has to be done (i.e. call NewEvents or defer), do it. If we're
|
||||
// already in processing nothing happens with this call.
|
||||
self.new_events();
|
||||
|
||||
// Now that an event has been received, we have to send any `NewEvents` calls that were
|
||||
// deferred.
|
||||
if let RunnerState::DeferredNewEvents(wait_start) = self.runner_state {
|
||||
match self.control_flow {
|
||||
ControlFlow::Exit | ControlFlow::Wait => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_resume: None,
|
||||
}))
|
||||
}
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
let start_cause = match Instant::now() >= resume_time {
|
||||
// If the current time is later than the requested resume time, the resume time
|
||||
// has been reached.
|
||||
true => StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
},
|
||||
// Otherwise, the requested resume time HASN'T been reached and we send a WaitCancelled.
|
||||
false => StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_resume: Some(resume_time),
|
||||
},
|
||||
};
|
||||
self.call_event_handler(Event::NewEvents(start_cause));
|
||||
}
|
||||
// This can be reached if the control flow is changed to poll during a `RedrawRequested`
|
||||
// that was sent after `EventsCleared`.
|
||||
ControlFlow::Poll => self.call_event_handler(Event::NewEvents(StartCause::Poll)),
|
||||
}
|
||||
}
|
||||
|
||||
match (self.runner_state, &event) {
|
||||
(RunnerState::HandlingRedraw, Event::RedrawRequested(_)) => self.call_event_handler(event),
|
||||
(_, Event::RedrawRequested(_)) => {
|
||||
self.call_event_handler(Event::MainEventsCleared);
|
||||
self.runner_state = RunnerState::HandlingRedraw;
|
||||
self.call_event_handler(event);
|
||||
},
|
||||
(RunnerState::HandlingRedraw, _) => {
|
||||
warn!("Non-redraw event dispatched durning redraw phase");
|
||||
self.events_cleared();
|
||||
self.new_events();
|
||||
self.call_event_handler(event);
|
||||
}
|
||||
(_, _) => {
|
||||
self.runner_state = RunnerState::HandlingEvents;
|
||||
self.call_event_handler(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_redraws(&mut self) {
|
||||
loop {
|
||||
let redraw_window_opt = self.redraw_buffer.borrow_mut().pop_front();
|
||||
match redraw_window_opt {
|
||||
Some(window_id) => self.process_event(Event::RedrawRequested(window_id)),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn events_cleared(&mut self) {
|
||||
match self.runner_state {
|
||||
// If we were handling events, send the EventsCleared message.
|
||||
RunnerState::HandlingEvents => {
|
||||
self.call_event_handler(Event::MainEventsCleared);
|
||||
self.flush_redraws();
|
||||
self.call_event_handler(Event::RedrawEventsCleared);
|
||||
self.runner_state = RunnerState::Idle(Instant::now());
|
||||
}
|
||||
|
||||
RunnerState::HandlingRedraw => {
|
||||
self.call_event_handler(Event::RedrawEventsCleared);
|
||||
self.runner_state = RunnerState::Idle(Instant::now());
|
||||
}
|
||||
|
||||
// If we *weren't* handling events, we don't have to do anything.
|
||||
RunnerState::New | RunnerState::Idle(..) => (),
|
||||
|
||||
// Some control flows require a NewEvents call even if no events were received. This
|
||||
// branch handles those.
|
||||
RunnerState::DeferredNewEvents(wait_start) => {
|
||||
match self.control_flow {
|
||||
// If we had deferred a Poll, send the Poll NewEvents and EventsCleared.
|
||||
ControlFlow::Poll => {
|
||||
self.call_event_handler(Event::NewEvents(StartCause::Poll));
|
||||
self.call_event_handler(Event::MainEventsCleared);
|
||||
self.flush_redraws();
|
||||
self.call_event_handler(Event::RedrawEventsCleared);
|
||||
}
|
||||
// If we had deferred a WaitUntil and the resume time has since been reached,
|
||||
// send the resume notification and EventsCleared event.
|
||||
ControlFlow::WaitUntil(resume_time) => {
|
||||
if Instant::now() >= resume_time {
|
||||
self.call_event_handler(Event::NewEvents(
|
||||
StartCause::ResumeTimeReached {
|
||||
start: wait_start,
|
||||
requested_resume: resume_time,
|
||||
},
|
||||
));
|
||||
self.call_event_handler(Event::MainEventsCleared);
|
||||
self.flush_redraws();
|
||||
self.call_event_handler(Event::RedrawEventsCleared);
|
||||
}
|
||||
}
|
||||
// If we deferred a wait and no events were received, the user doesn't have to
|
||||
// get an event.
|
||||
ControlFlow::Wait | ControlFlow::Exit => (),
|
||||
}
|
||||
// Mark that we've entered an idle state.
|
||||
self.runner_state = RunnerState::Idle(wait_start)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_event_handler(&mut self, event: Event<T>) {
|
||||
if self.panic_error.is_none() {
|
||||
let EventLoopRunner {
|
||||
ref mut panic_error,
|
||||
ref mut event_handler,
|
||||
ref mut control_flow,
|
||||
..
|
||||
} = self;
|
||||
*panic_error = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
if *control_flow != ControlFlow::Exit {
|
||||
(*event_handler)(event, control_flow);
|
||||
} else {
|
||||
(*event_handler)(event, &mut ControlFlow::Exit);
|
||||
}
|
||||
}))
|
||||
.err();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,6 @@ use crate::{
|
|||
drop_handler::FileDropHandler,
|
||||
event_loop::{
|
||||
self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID,
|
||||
REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID,
|
||||
},
|
||||
icon::{self, IconType, WinIcon},
|
||||
monitor,
|
||||
|
@ -142,20 +141,12 @@ impl Window {
|
|||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
unsafe {
|
||||
if self.thread_executor.trigger_newevents_on_redraw() {
|
||||
winuser::RedrawWindow(
|
||||
self.window.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
} else {
|
||||
let mut window_state = self.window_state.lock();
|
||||
if !window_state.queued_out_of_band_redraw {
|
||||
window_state.queued_out_of_band_redraw = true;
|
||||
winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0);
|
||||
}
|
||||
}
|
||||
winuser::RedrawWindow(
|
||||
self.window.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue