From 08f8f89702e4212a4512921021151132542bd316 Mon Sep 17 00:00:00 2001 From: aloucks Date: Thu, 30 May 2019 00:33:52 -0400 Subject: [PATCH] Fix control flow issues with Window::request_redraw (eventloop-2.0) (#890) * Fix request_redraw with Poll and WaitUntil(time_in_the_past) on Windows `Window::request_redraw` now fires a `RedrawRequested` event when called from an `Event::EventsCleared` callback while the control flow is set to `Poll`. A control flow of `WaitUntil(resume_time)`, will now also fire the `RedrawRequested` event when `resume_time` is in the past. * Prevent panic on x11 when WaitUntil(resume_time) is in the past * Prevent panic on wayland when WaitUntil(resume_time) is in the past --- src/platform_impl/linux/wayland/event_loop.rs | 6 ++++- src/platform_impl/linux/x11/mod.rs | 6 ++++- src/platform_impl/windows/event_loop.rs | 23 +++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index a3276064..c73a225f 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -266,7 +266,11 @@ impl EventLoop { ControlFlow::WaitUntil(deadline) => { let start = Instant::now(); // compute the blocking duration - let duration = deadline.duration_since(::std::cmp::max(deadline, start)); + let duration = if deadline > start { + deadline - start + } else { + ::std::time::Duration::from_millis(0) + }; self.inner_loop.dispatch(Some(duration), &mut ()).unwrap(); control_flow = ControlFlow::default(); let now = Instant::now(); diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index bd2103ab..5339bef2 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -301,7 +301,11 @@ impl EventLoop { ControlFlow::WaitUntil(deadline) => { let start = ::std::time::Instant::now(); // compute the blocking duration - let duration = deadline.duration_since(::std::cmp::max(deadline, start)); + let duration = if deadline > start { + deadline - start + } else { + ::std::time::Duration::from_millis(0) + }; self.inner_loop.dispatch(Some(duration), &mut ()).unwrap(); control_flow = ControlFlow::default(); let now = std::time::Instant::now(); diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 959fbac6..7fbde380 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -843,12 +843,27 @@ unsafe extern "system" fn public_window_callback( // 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. - match runner.runner_state { - RunnerState::Idle(..) | - RunnerState::DeferredNewEvents(..) => runner.call_event_handler(Event::WindowEvent { + let control_flow = runner.control_flow; + let mut request_redraw = || { + runner.call_event_handler(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: RedrawRequested, - }), + }); + }; + match runner.runner_state { + RunnerState::Idle(..) | + RunnerState::DeferredNewEvents(..) => request_redraw(), + RunnerState::HandlingEvents => { + match control_flow { + ControlFlow::Poll => request_redraw(), + ControlFlow::WaitUntil(resume_time) => { + if resume_time <= Instant::now() { + request_redraw() + } + }, + _ => () + } + } _ => () } }