use std::{
any::Any,
cell::{Cell, RefCell},
collections::{HashSet, VecDeque},
mem, panic, ptr,
rc::Rc,
time::Instant,
};
use windows_sys::Win32::{
Foundation::HWND,
Graphics::Gdi::{RedrawWindow, RDW_INTERNALPAINT},
};
use crate::{
dpi::PhysicalSize,
event::{Event, StartCause, WindowEvent},
event_loop::ControlFlow,
platform_impl::platform::{
event_loop::{WindowData, GWL_USERDATA},
get_window_long,
},
window::WindowId,
};
pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
type EventHandler<T> = Cell<Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>>>;
pub(crate) struct EventLoopRunner<T: 'static> {
pub(super) thread_msg_target: HWND,
wait_thread_id: u32,
control_flow: Cell<ControlFlow>,
runner_state: Cell<RunnerState>,
last_events_cleared: Cell<Instant>,
event_handler: EventHandler<T>,
event_buffer: RefCell<VecDeque<BufferedEvent<T>>>,
owned_windows: Cell<HashSet<HWND>>,
panic_error: Cell<Option<PanicError>>,
}
pub type PanicError = Box<dyn Any + Send + 'static>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum RunnerState {
Uninitialized,
Idle,
HandlingMainEvents,
HandlingRedrawEvents,
Destroyed,
}
enum BufferedEvent<T: 'static> {
Event(Event<'static, T>),
ScaleFactorChanged(WindowId, f64, PhysicalSize<u32>),
}
impl<T> EventLoopRunner<T> {
pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: u32) -> EventLoopRunner<T> {
EventLoopRunner {
thread_msg_target,
wait_thread_id,
runner_state: Cell::new(RunnerState::Uninitialized),
control_flow: Cell::new(ControlFlow::Poll),
panic_error: Cell::new(None),
last_events_cleared: Cell::new(Instant::now()),
event_handler: Cell::new(None),
event_buffer: RefCell::new(VecDeque::new()),
owned_windows: Cell::new(HashSet::new()),
}
}
pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
where
F: FnMut(Event<'_, T>, &mut ControlFlow),
{
let old_event_handler = self.event_handler.replace(mem::transmute::<
Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>>,
Option<Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>>,
>(Some(Box::new(f))));
assert!(old_event_handler.is_none());
}
pub(crate) fn reset_runner(&self) {
let EventLoopRunner {
thread_msg_target: _,
wait_thread_id: _,
runner_state,
panic_error,
control_flow,
last_events_cleared: _,
event_handler,
event_buffer: _,
owned_windows: _,
} = self;
runner_state.set(RunnerState::Uninitialized);
panic_error.set(None);
control_flow.set(ControlFlow::Poll);
event_handler.set(None);
}
}
impl<T> EventLoopRunner<T> {
pub fn thread_msg_target(&self) -> HWND {
self.thread_msg_target
}
pub fn wait_thread_id(&self) -> u32 {
self.wait_thread_id
}
pub fn redrawing(&self) -> bool {
self.runner_state.get() == RunnerState::HandlingRedrawEvents
}
pub fn take_panic_error(&self) -> Result<(), PanicError> {
match self.panic_error.take() {
Some(err) => Err(err),
None => Ok(()),
}
}
pub fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub fn handling_events(&self) -> bool {
self.runner_state.get() != RunnerState::Idle
}
pub fn should_buffer(&self) -> bool {
let handler = self.event_handler.take();
let should_buffer = handler.is_none();
self.event_handler.set(handler);
should_buffer
}
}
impl<T> EventLoopRunner<T> {
pub fn catch_unwind<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
let panic_error = self.panic_error.take();
if panic_error.is_none() {
let result = panic::catch_unwind(panic::AssertUnwindSafe(f));
match self.panic_error.take() {
None => match result {
Ok(r) => Some(r),
Err(e) => {
self.panic_error.set(Some(e));
None
}
},
Some(e) => {
self.panic_error.set(Some(e));
None
}
}
} else {
self.panic_error.set(panic_error);
None
}
}
pub fn register_window(&self, window: HWND) {
let mut owned_windows = self.owned_windows.take();
owned_windows.insert(window);
self.owned_windows.set(owned_windows);
}
pub fn remove_window(&self, window: HWND) {
let mut owned_windows = self.owned_windows.take();
owned_windows.remove(&window);
self.owned_windows.set(owned_windows);
}
pub fn owned_windows(&self, mut f: impl FnMut(HWND)) {
let mut owned_windows = self.owned_windows.take();
for hwnd in &owned_windows {
f(*hwnd);
}
let new_owned_windows = self.owned_windows.take();
owned_windows.extend(&new_owned_windows);
self.owned_windows.set(owned_windows);
}
}
impl<T> EventLoopRunner<T> {
pub(crate) unsafe fn poll(&self) {
self.move_state_to(RunnerState::HandlingMainEvents);
}
pub(crate) unsafe fn send_event(&self, event: Event<'_, T>) {
if let Event::RedrawRequested(_) = event {
if self.runner_state.get() != RunnerState::HandlingRedrawEvents {
warn!("RedrawRequested dispatched without explicit MainEventsCleared");
self.move_state_to(RunnerState::HandlingRedrawEvents);
}
self.call_event_handler(event);
} else if self.should_buffer() {
self.event_buffer
.borrow_mut()
.push_back(BufferedEvent::from_event(event))
} else {
self.move_state_to(RunnerState::HandlingMainEvents);
self.call_event_handler(event);
self.dispatch_buffered_events();
}
}
pub(crate) unsafe fn main_events_cleared(&self) {
self.move_state_to(RunnerState::HandlingRedrawEvents);
}
pub(crate) unsafe fn redraw_events_cleared(&self) {
self.move_state_to(RunnerState::Idle);
}
pub(crate) unsafe fn loop_destroyed(&self) {
self.move_state_to(RunnerState::Destroyed);
}
unsafe fn call_event_handler(&self, event: Event<'_, T>) {
self.catch_unwind(|| {
let mut control_flow = self.control_flow.take();
let mut event_handler = self.event_handler.take()
.expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)");
if let ControlFlow::ExitWithCode(code) = control_flow {
event_handler(event, &mut ControlFlow::ExitWithCode(code));
} else {
event_handler(event, &mut control_flow);
}
assert!(self.event_handler.replace(Some(event_handler)).is_none());
self.control_flow.set(control_flow);
});
}
unsafe fn dispatch_buffered_events(&self) {
loop {
let buffered_event_opt = self.event_buffer.borrow_mut().pop_front();
match buffered_event_opt {
Some(e) => e.dispatch_event(|e| self.call_event_handler(e)),
None => break,
}
}
}
unsafe fn move_state_to(&self, new_runner_state: RunnerState) {
use RunnerState::{
Destroyed, HandlingMainEvents, HandlingRedrawEvents, Idle, Uninitialized,
};
match (
self.runner_state.replace(new_runner_state),
new_runner_state,
) {
(Uninitialized, Uninitialized)
| (Idle, Idle)
| (HandlingMainEvents, HandlingMainEvents)
| (HandlingRedrawEvents, HandlingRedrawEvents)
| (Destroyed, Destroyed) => (),
(Uninitialized, HandlingMainEvents) => {
self.call_new_events(true);
}
(Uninitialized, HandlingRedrawEvents) => {
self.call_new_events(true);
self.call_event_handler(Event::MainEventsCleared);
}
(Uninitialized, Idle) => {
self.call_new_events(true);
self.call_event_handler(Event::MainEventsCleared);
self.call_redraw_events_cleared();
}
(Uninitialized, Destroyed) => {
self.call_new_events(true);
self.call_event_handler(Event::MainEventsCleared);
self.call_redraw_events_cleared();
self.call_event_handler(Event::LoopDestroyed);
}
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
(Idle, HandlingMainEvents) => {
self.call_new_events(false);
}
(Idle, HandlingRedrawEvents) => {
self.call_new_events(false);
self.call_event_handler(Event::MainEventsCleared);
}
(Idle, Destroyed) => {
self.call_event_handler(Event::LoopDestroyed);
}
(HandlingMainEvents, HandlingRedrawEvents) => {
self.call_event_handler(Event::MainEventsCleared);
}
(HandlingMainEvents, Idle) => {
warn!("RedrawEventsCleared emitted without explicit MainEventsCleared");
self.call_event_handler(Event::MainEventsCleared);
self.call_redraw_events_cleared();
}
(HandlingMainEvents, Destroyed) => {
self.call_event_handler(Event::MainEventsCleared);
self.call_redraw_events_cleared();
self.call_event_handler(Event::LoopDestroyed);
}
(HandlingRedrawEvents, Idle) => {
self.call_redraw_events_cleared();
}
(HandlingRedrawEvents, HandlingMainEvents) => {
warn!("NewEvents emitted without explicit RedrawEventsCleared");
self.call_redraw_events_cleared();
self.call_new_events(false);
}
(HandlingRedrawEvents, Destroyed) => {
self.call_redraw_events_cleared();
self.call_event_handler(Event::LoopDestroyed);
}
(Destroyed, _) => panic!("cannot move state from Destroyed"),
}
}
unsafe fn call_new_events(&self, init: bool) {
let start_cause = match (init, self.control_flow()) {
(true, _) => StartCause::Init,
(false, ControlFlow::Poll) => StartCause::Poll,
(false, ControlFlow::ExitWithCode(_)) | (false, ControlFlow::Wait) => {
StartCause::WaitCancelled {
requested_resume: None,
start: self.last_events_cleared.get(),
}
}
(false, ControlFlow::WaitUntil(requested_resume)) => {
if Instant::now() < requested_resume {
StartCause::WaitCancelled {
requested_resume: Some(requested_resume),
start: self.last_events_cleared.get(),
}
} else {
StartCause::ResumeTimeReached {
requested_resume,
start: self.last_events_cleared.get(),
}
}
}
};
self.call_event_handler(Event::NewEvents(start_cause));
if init {
self.call_event_handler(Event::Resumed);
}
self.dispatch_buffered_events();
RedrawWindow(self.thread_msg_target, ptr::null(), 0, RDW_INTERNALPAINT);
}
unsafe fn call_redraw_events_cleared(&self) {
self.call_event_handler(Event::RedrawEventsCleared);
self.last_events_cleared.set(Instant::now());
}
}
impl<T> BufferedEvent<T> {
pub fn from_event(event: Event<'_, T>) -> BufferedEvent<T> {
match event {
Event::WindowEvent {
event:
WindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size,
},
window_id,
} => BufferedEvent::ScaleFactorChanged(window_id, scale_factor, *new_inner_size),
event => BufferedEvent::Event(event.to_static().unwrap()),
}
}
pub fn dispatch_event(self, dispatch: impl FnOnce(Event<'_, T>)) {
match self {
Self::Event(event) => dispatch(event),
Self::ScaleFactorChanged(window_id, scale_factor, mut new_inner_size) => {
dispatch(Event::WindowEvent {
window_id,
event: WindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size: &mut new_inner_size,
},
});
let window_flags = unsafe {
let userdata =
get_window_long(window_id.0.into(), GWL_USERDATA) as *mut WindowData<T>;
(*userdata).window_state_lock().window_flags
};
window_flags.set_size((window_id.0).0, new_inner_size);
}
}
}
}