mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +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,
|
event: WindowEvent::CloseRequested,
|
||||||
window_id,
|
window_id,
|
||||||
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
|
} 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
|
//! 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.
|
//! add a `WindowState` entry to a list of window to be used by the callback.
|
||||||
|
|
||||||
|
mod runner;
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
|
||||||
cell::RefCell,
|
|
||||||
collections::VecDeque,
|
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem, panic, ptr,
|
mem, panic, ptr,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
mpsc::{self, Receiver, Sender},
|
mpsc::{self, Receiver, Sender},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
|
@ -44,9 +42,10 @@ use winapi::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::runner::{ELRShared, EventLoopRunnerShared};
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
|
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},
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||||
platform_impl::platform::{
|
platform_impl::platform::{
|
||||||
dpi::{
|
dpi::{
|
||||||
|
@ -127,7 +126,6 @@ pub struct EventLoop<T: 'static> {
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T> {
|
pub struct EventLoopWindowTarget<T> {
|
||||||
thread_id: DWORD,
|
thread_id: DWORD,
|
||||||
trigger_newevents_on_redraw: Arc<AtomicBool>,
|
|
||||||
thread_msg_target: HWND,
|
thread_msg_target: HWND,
|
||||||
pub(crate) runner_shared: EventLoopRunnerShared<T>,
|
pub(crate) runner_shared: EventLoopRunnerShared<T>,
|
||||||
}
|
}
|
||||||
|
@ -167,10 +165,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn new_dpi_unaware_any_thread() -> EventLoop<T> {
|
pub fn new_dpi_unaware_any_thread() -> EventLoop<T> {
|
||||||
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||||
let runner_shared = Rc::new(ELRShared {
|
let runner_shared = Rc::new(ELRShared::new());
|
||||||
runner: RefCell::new(None),
|
|
||||||
buffer: RefCell::new(VecDeque::new()),
|
|
||||||
});
|
|
||||||
let (thread_msg_target, thread_msg_sender) =
|
let (thread_msg_target, thread_msg_sender) =
|
||||||
thread_event_target_window(runner_shared.clone());
|
thread_event_target_window(runner_shared.clone());
|
||||||
|
|
||||||
|
@ -179,7 +174,6 @@ impl<T: 'static> EventLoop<T> {
|
||||||
window_target: RootELW {
|
window_target: RootELW {
|
||||||
p: EventLoopWindowTarget {
|
p: EventLoopWindowTarget {
|
||||||
thread_id,
|
thread_id,
|
||||||
trigger_newevents_on_redraw: Arc::new(AtomicBool::new(true)),
|
|
||||||
thread_msg_target,
|
thread_msg_target,
|
||||||
runner_shared,
|
runner_shared,
|
||||||
},
|
},
|
||||||
|
@ -206,44 +200,23 @@ impl<T: 'static> EventLoop<T> {
|
||||||
{
|
{
|
||||||
let event_loop_windows_ref = &self.window_target;
|
let event_loop_windows_ref = &self.window_target;
|
||||||
|
|
||||||
let mut runner = unsafe {
|
unsafe {
|
||||||
EventLoopRunner::new(self, move |event, control_flow| {
|
self.window_target
|
||||||
event_handler(event, event_loop_windows_ref, control_flow)
|
.p
|
||||||
})
|
.runner_shared
|
||||||
};
|
.set_runner(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! runner {
|
let runner = &self.window_target.p.runner_shared;
|
||||||
() => {
|
|
||||||
self.window_target
|
|
||||||
.p
|
|
||||||
.runner_shared
|
|
||||||
.runner
|
|
||||||
.borrow_mut()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut msg = mem::zeroed();
|
let mut msg = mem::zeroed();
|
||||||
let mut msg_unprocessed = false;
|
let mut msg_unprocessed = false;
|
||||||
|
|
||||||
'main: loop {
|
'main: loop {
|
||||||
runner!().new_events();
|
runner.new_events();
|
||||||
loop {
|
loop {
|
||||||
if !msg_unprocessed {
|
if !msg_unprocessed {
|
||||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
||||||
|
@ -255,13 +228,14 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
msg_unprocessed = false;
|
msg_unprocessed = false;
|
||||||
}
|
}
|
||||||
runner!().events_cleared();
|
runner.events_cleared();
|
||||||
if let Some(payload) = runner!().panic_error.take() {
|
if let Err(payload) = runner.take_panic_error() {
|
||||||
|
runner.destroy_runner();
|
||||||
panic::resume_unwind(payload);
|
panic::resume_unwind(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !msg_unprocessed {
|
if !msg_unprocessed {
|
||||||
let control_flow = runner!().control_flow;
|
let control_flow = runner.control_flow();
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => break 'main,
|
ControlFlow::Exit => break 'main,
|
||||||
ControlFlow::Wait => {
|
ControlFlow::Wait => {
|
||||||
|
@ -279,8 +253,10 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runner!().call_event_handler(Event::LoopDestroyed);
|
unsafe {
|
||||||
*self.window_target.p.runner_shared.runner.borrow_mut() = None;
|
runner.call_event_handler(Event::LoopDestroyed);
|
||||||
|
}
|
||||||
|
runner.destroy_runner();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||||
|
@ -296,7 +272,6 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
|
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
|
||||||
EventLoopThreadExecutor {
|
EventLoopThreadExecutor {
|
||||||
thread_id: self.thread_id,
|
thread_id: self.thread_id,
|
||||||
trigger_newevents_on_redraw: self.trigger_newevents_on_redraw.clone(),
|
|
||||||
target_window: self.thread_msg_target,
|
target_window: self.thread_msg_target,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,291 +292,6 @@ fn main_thread_id() -> DWORD {
|
||||||
unsafe { MAIN_THREAD_ID }
|
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.
|
// 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 {
|
unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool {
|
||||||
let mut msg = mem::zeroed();
|
let mut msg = mem::zeroed();
|
||||||
|
@ -667,7 +357,6 @@ impl<T> Drop for EventLoop<T> {
|
||||||
|
|
||||||
pub(crate) struct EventLoopThreadExecutor {
|
pub(crate) struct EventLoopThreadExecutor {
|
||||||
thread_id: DWORD,
|
thread_id: DWORD,
|
||||||
trigger_newevents_on_redraw: Arc<AtomicBool>,
|
|
||||||
target_window: HWND,
|
target_window: HWND,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,10 +370,6 @@ impl EventLoopThreadExecutor {
|
||||||
self.thread_id == cur_thread_id
|
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,
|
/// Executes a function in the event loop thread. If we're already in the event loop thread,
|
||||||
/// we just call the function directly.
|
/// we just call the function directly.
|
||||||
///
|
///
|
||||||
|
@ -784,12 +469,6 @@ lazy_static! {
|
||||||
winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR)
|
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
|
// 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 ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe {
|
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,
|
_: UINT_PTR,
|
||||||
subclass_input_ptr: DWORD_PTR,
|
subclass_input_ptr: DWORD_PTR,
|
||||||
) -> LRESULT {
|
) -> LRESULT {
|
||||||
let subclass_input = &mut *(subclass_input_ptr as *mut SubclassInput<T>);
|
let subclass_input = &*(subclass_input_ptr as *const SubclassInput<T>);
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
winuser::WM_ENTERSIZEMOVE => {
|
winuser::WM_ENTERSIZEMOVE => {
|
||||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
subclass_input.event_loop_runner.set_modal_loop(true);
|
||||||
if let Some(ref mut runner) = *runner {
|
|
||||||
runner.in_modal_loop = true;
|
|
||||||
}
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
winuser::WM_EXITSIZEMOVE => {
|
winuser::WM_EXITSIZEMOVE => {
|
||||||
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
|
subclass_input.event_loop_runner.set_modal_loop(false);
|
||||||
if let Some(ref mut runner) = *runner {
|
|
||||||
runner.in_modal_loop = false;
|
|
||||||
}
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
winuser::WM_NCCREATE => {
|
winuser::WM_NCCREATE => {
|
||||||
|
@ -975,48 +648,13 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||||
event: Destroyed,
|
event: Destroyed,
|
||||||
});
|
});
|
||||||
|
|
||||||
Box::from_raw(subclass_input);
|
|
||||||
drop(subclass_input);
|
drop(subclass_input);
|
||||||
|
Box::from_raw(subclass_input_ptr as *mut SubclassInput<T>);
|
||||||
0
|
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 => {
|
winuser::WM_PAINT => {
|
||||||
use crate::event::WindowEvent::RedrawRequested;
|
subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window))));
|
||||||
subclass_input.send_event(Event::WindowEvent {
|
|
||||||
window_id: RootWindowId(WindowId(window)),
|
|
||||||
event: RedrawRequested,
|
|
||||||
});
|
|
||||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1984,14 +1622,7 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
||||||
winuser::RDW_INTERNALPAINT,
|
winuser::RDW_INTERNALPAINT,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
let in_modal_loop = {
|
let in_modal_loop = subclass_input.event_loop_runner.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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if in_modal_loop {
|
if in_modal_loop {
|
||||||
let mut msg = mem::zeroed();
|
let mut msg = mem::zeroed();
|
||||||
loop {
|
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();
|
let runner = &subclass_input.event_loop_runner;
|
||||||
if let Some(ref mut runner) = *runner {
|
runner.events_cleared();
|
||||||
runner.events_cleared();
|
match runner.control_flow() {
|
||||||
match runner.control_flow {
|
// Waiting is handled by the modal loop.
|
||||||
// Waiting is handled by the modal loop.
|
ControlFlow::Exit | ControlFlow::Wait => runner.new_events(),
|
||||||
ControlFlow::Exit | ControlFlow::Wait => runner.new_events(),
|
ControlFlow::WaitUntil(resume_time) => {
|
||||||
ControlFlow::WaitUntil(resume_time) => {
|
wait_until_time_or_msg(resume_time);
|
||||||
wait_until_time_or_msg(resume_time);
|
runner.new_events();
|
||||||
runner.new_events();
|
queue_call_again();
|
||||||
queue_call_again();
|
}
|
||||||
}
|
ControlFlow::Poll => {
|
||||||
ControlFlow::Poll => {
|
runner.new_events();
|
||||||
runner.new_events();
|
queue_call_again();
|
||||||
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,
|
drop_handler::FileDropHandler,
|
||||||
event_loop::{
|
event_loop::{
|
||||||
self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID,
|
self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID,
|
||||||
REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID,
|
|
||||||
},
|
},
|
||||||
icon::{self, IconType, WinIcon},
|
icon::{self, IconType, WinIcon},
|
||||||
monitor,
|
monitor,
|
||||||
|
@ -142,20 +141,12 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_redraw(&self) {
|
pub fn request_redraw(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.thread_executor.trigger_newevents_on_redraw() {
|
winuser::RedrawWindow(
|
||||||
winuser::RedrawWindow(
|
self.window.0,
|
||||||
self.window.0,
|
ptr::null(),
|
||||||
ptr::null(),
|
ptr::null_mut(),
|
||||||
ptr::null_mut(),
|
winuser::RDW_INTERNALPAINT,
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue