From 6a330a2894873d29fbbfdeebfc1a215577213996 Mon Sep 17 00:00:00 2001 From: Osspial Date: Mon, 6 Jan 2020 15:28:58 -0500 Subject: [PATCH] On Windows, fix bug where RedrawRequested would only get emitted every other iteration of the event loop (#1366) * Fix bug causing RedrawRequested events to only get emitted every other iteration of the event loop. * Initialize simple_logger in examples. This PR's primary bug was discovered because a friend of mine reported that winit was emitting concerning log messages, which I'd never seen since none of the examples print out the log messages. This addresses that, to hopefully reduce the chance of bugs going unnoticed in the future. * Add changelog entry * Format --- CHANGELOG.md | 2 + Cargo.toml | 2 +- examples/cursor.rs | 1 + examples/cursor_grab.rs | 1 + examples/custom_events.rs | 1 + examples/fullscreen.rs | 1 + examples/handling_close.rs | 1 + examples/min_max_size.rs | 1 + examples/minimize.rs | 1 + examples/monitor_list.rs | 1 + examples/multithreaded.rs | 4 +- examples/multiwindow.rs | 1 + examples/request_redraw.rs | 1 + examples/resizable.rs | 1 + examples/timer.rs | 1 + examples/transparent.rs | 1 + examples/video_modes.rs | 1 + examples/window.rs | 1 + examples/window_debug.rs | 1 + examples/window_icon.rs | 2 + examples/window_run_return.rs | 1 + src/platform_impl/windows/event_loop.rs | 137 ++++++----- .../windows/event_loop/runner.rs | 225 +++++++++++++++--- src/platform_impl/windows/util.rs | 32 +++ src/platform_impl/windows/window.rs | 36 +-- 25 files changed, 329 insertions(+), 128 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 937995c66..6548f5813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- On Windows, fix bug where `RedrawRequested` would only get emitted every other iteration of the event loop. + # 0.20.0 (2020-01-05) - On X11, fix `ModifiersChanged` emitting incorrect modifier change events diff --git a/Cargo.toml b/Cargo.toml index be6b94309..a1948b921 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ bitflags = "1" [dev-dependencies] image = "0.21" -env_logger = "0.5" +simple_logger = "1" [target.'cfg(target_os = "android")'.dependencies.android_glue] version = "0.2" diff --git a/examples/cursor.rs b/examples/cursor.rs index 70c2ec032..de45adae3 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -5,6 +5,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index dd25179c1..5ed193ecb 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -5,6 +5,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() diff --git a/examples/custom_events.rs b/examples/custom_events.rs index 3ed0c8b2e..c59299cab 100644 --- a/examples/custom_events.rs +++ b/examples/custom_events.rs @@ -11,6 +11,7 @@ fn main() { Timer, } + simple_logger::init().unwrap(); let event_loop = EventLoop::::with_user_event(); let _window = WindowBuilder::new() diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index d4b83bb0f..4cdb7b63e 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -5,6 +5,7 @@ use winit::monitor::{MonitorHandle, VideoMode}; use winit::window::{Fullscreen, WindowBuilder}; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); print!("Please choose the fullscreen mode: (1) exclusive, (2) borderless: "); diff --git a/examples/handling_close.rs b/examples/handling_close.rs index d67c0046a..cbd570536 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -5,6 +5,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let _window = WindowBuilder::new() diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 8a5b6699a..f4fd00c1b 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -6,6 +6,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); diff --git a/examples/minimize.rs b/examples/minimize.rs index cce72de31..871cfe2ed 100644 --- a/examples/minimize.rs +++ b/examples/minimize.rs @@ -5,6 +5,7 @@ use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() diff --git a/examples/monitor_list.rs b/examples/monitor_list.rs index a6b24d296..66f48bafe 100644 --- a/examples/monitor_list.rs +++ b/examples/monitor_list.rs @@ -1,6 +1,7 @@ use winit::{event_loop::EventLoop, window::WindowBuilder}; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs index 65e85464b..60f9d802d 100644 --- a/examples/multithreaded.rs +++ b/examples/multithreaded.rs @@ -1,7 +1,5 @@ #[cfg(not(target_arch = "wasm32"))] fn main() { - extern crate env_logger; - use std::{collections::HashMap, sync::mpsc, thread, time::Duration}; use winit::{ @@ -14,7 +12,7 @@ fn main() { const WINDOW_COUNT: usize = 3; const WINDOW_SIZE: PhysicalSize = PhysicalSize::new(600, 400); - env_logger::init(); + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let mut window_senders = HashMap::with_capacity(WINDOW_COUNT); for _ in 0..WINDOW_COUNT { diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 57a20c5ba..01c91bb64 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -6,6 +6,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let mut windows = HashMap::new(); diff --git a/examples/request_redraw.rs b/examples/request_redraw.rs index ea6760d65..5d761ae47 100644 --- a/examples/request_redraw.rs +++ b/examples/request_redraw.rs @@ -5,6 +5,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() diff --git a/examples/resizable.rs b/examples/resizable.rs index 2ddb8b25e..6a9039193 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -6,6 +6,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let mut resizable = false; diff --git a/examples/timer.rs b/examples/timer.rs index e1e3f2909..52a1444ec 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -7,6 +7,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let _window = WindowBuilder::new() diff --git a/examples/transparent.rs b/examples/transparent.rs index a1fdefe93..78e3c4da3 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -5,6 +5,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() diff --git a/examples/video_modes.rs b/examples/video_modes.rs index f923fa920..366c51959 100644 --- a/examples/video_modes.rs +++ b/examples/video_modes.rs @@ -1,6 +1,7 @@ use winit::event_loop::EventLoop; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let monitor = event_loop.primary_monitor(); diff --git a/examples/window.rs b/examples/window.rs index 331ee98aa..c028a50f3 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -5,6 +5,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() diff --git a/examples/window_debug.rs b/examples/window_debug.rs index 5f8293f87..f6e960a79 100644 --- a/examples/window_debug.rs +++ b/examples/window_debug.rs @@ -8,6 +8,7 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() diff --git a/examples/window_icon.rs b/examples/window_icon.rs index 86ea9556c..b7c84679b 100644 --- a/examples/window_icon.rs +++ b/examples/window_icon.rs @@ -7,6 +7,8 @@ use winit::{ }; fn main() { + simple_logger::init().unwrap(); + // You'll have to choose an icon size at your own discretion. On X11, the desired size varies // by WM, and on Windows, you still have to account for screen scaling. Here we use 32px, // since it seems to work well enough in most cases. Be careful about going too high, or diff --git a/examples/window_run_return.rs b/examples/window_run_return.rs index 703c12eee..bde7f6a17 100644 --- a/examples/window_run_return.rs +++ b/examples/window_run_return.rs @@ -18,6 +18,7 @@ fn main() { }; let mut event_loop = EventLoop::new(); + simple_logger::init().unwrap(); let _window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 53e937a04..8d90e2476 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -100,13 +100,9 @@ pub(crate) struct SubclassInput { } impl SubclassInput { - unsafe fn send_event(&self, event: Event<'static, T>) { + unsafe fn send_event(&self, event: Event<'_, T>) { self.event_loop_runner.send_event(event); } - - unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, T>> { - self.event_loop_runner.send_event_unbuffered(event) - } } struct ThreadMsgTargetSubclassInput { @@ -116,7 +112,7 @@ struct ThreadMsgTargetSubclassInput { } impl ThreadMsgTargetSubclassInput { - unsafe fn send_event(&self, event: Event<'static, T>) { + unsafe fn send_event(&self, event: Event<'_, T>) { self.event_loop_runner.send_event(event); } } @@ -216,28 +212,57 @@ impl EventLoop { unsafe { let mut msg = mem::zeroed(); - let mut msg_unprocessed = false; + let mut unread_message_exists = false; 'main: loop { - runner.new_events(); - loop { - if !msg_unprocessed { - if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { - break; - } - } - winuser::TranslateMessage(&mut msg); - winuser::DispatchMessageW(&mut msg); - - msg_unprocessed = false; - } - runner.events_cleared(); if let Err(payload) = runner.take_panic_error() { runner.destroy_runner(); panic::resume_unwind(payload); } - if !msg_unprocessed { + runner.new_events(); + loop { + if !unread_message_exists { + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) { + break; + } + } + if msg.message == winuser::WM_PAINT { + unread_message_exists = true; + break; + } + winuser::TranslateMessage(&mut msg); + winuser::DispatchMessageW(&mut msg); + + unread_message_exists = false; + } + runner.main_events_cleared(); + loop { + if !unread_message_exists { + if 0 == winuser::PeekMessageW( + &mut msg, + ptr::null_mut(), + winuser::WM_PAINT, + winuser::WM_PAINT, + 1, + ) { + break; + } + } + + winuser::TranslateMessage(&mut msg); + winuser::DispatchMessageW(&mut msg); + + unread_message_exists = false; + } + if runner.redraw_events_cleared().events_buffered() { + if runner.control_flow() == ControlFlow::Exit { + break 'main; + } + continue; + } + + if !unread_message_exists { let control_flow = runner.control_flow(); match control_flow { ControlFlow::Exit => break 'main, @@ -245,7 +270,7 @@ impl EventLoop { if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { break 'main; } - msg_unprocessed = true; + unread_message_exists = true; } ControlFlow::WaitUntil(resume_time) => { wait_until_time_or_msg(resume_time); @@ -651,6 +676,7 @@ unsafe extern "system" fn public_window_callback( } winuser::WM_PAINT => { + subclass_input.event_loop_runner.main_events_cleared(); subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window)))); commctrl::DefSubclassProc(window, msg, wparam, lparam) } @@ -1497,7 +1523,7 @@ unsafe extern "system" fn public_window_callback( false => old_physical_inner_size, }; - let _ = subclass_input.send_event_unbuffered(Event::WindowEvent { + let _ = subclass_input.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: ScaleFactorChanged { scale_factor: new_dpi_factor, @@ -1697,44 +1723,49 @@ unsafe extern "system" fn thread_event_target_callback( let in_modal_loop = subclass_input.event_loop_runner.in_modal_loop(); if in_modal_loop { let mut msg = mem::zeroed(); - loop { - if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { - break; + if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) { + if msg.message != 0 && msg.message != winuser::WM_PAINT { + queue_call_again(); + return 0; } - // Clear all paint/timer messages from the queue before sending the events cleared message. - match msg.message { - // Flush the event queue of WM_PAINT messages. - winuser::WM_PAINT | winuser::WM_TIMER => { - // Remove the message from the message queue. - winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1); - if msg.hwnd != window { - winuser::TranslateMessage(&mut msg); - winuser::DispatchMessageW(&mut msg); - } + subclass_input.event_loop_runner.main_events_cleared(); + loop { + if 0 == winuser::PeekMessageW( + &mut msg, + ptr::null_mut(), + winuser::WM_PAINT, + winuser::WM_PAINT, + 1, + ) { + break; } - // If the message isn't one of those three, it may be handled by the modal - // loop so we should return control flow to it. - _ => { - queue_call_again(); - return 0; + + if msg.hwnd != window { + winuser::TranslateMessage(&mut msg); + winuser::DispatchMessageW(&mut msg); } } } + // we don't borrow until here because TODO SAFETY 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(); + if runner.redraw_events_cleared().events_buffered() { + queue_call_again(); + runner.new_events(); + } else { + 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(); + } } } } diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index db807caca..ce376eb28 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -3,16 +3,17 @@ use std::{any::Any, cell::RefCell, collections::VecDeque, mem, panic, ptr, rc::R use winapi::{shared::windef::HWND, um::winuser}; use crate::{ - event::{Event, StartCause}, + dpi::PhysicalSize, + event::{Event, StartCause, WindowEvent}, event_loop::ControlFlow, - platform_impl::platform::event_loop::EventLoop, + platform_impl::platform::{event_loop::EventLoop, util}, window::WindowId, }; pub(crate) type EventLoopRunnerShared = Rc>; pub(crate) struct ELRShared { runner: RefCell>>, - buffer: RefCell>>, + buffer: RefCell>>, redraw_buffer: Rc>>, } struct EventLoopRunner { @@ -26,6 +27,63 @@ struct EventLoopRunner { } pub type PanicError = Box; +pub enum BufferedEvent { + Event(Event<'static, T>), + ScaleFactorChanged(WindowId, f64, PhysicalSize), +} + +#[must_use] +#[derive(Debug, Clone, Copy)] +pub enum AreEventsBuffered { + EventsBuffered, + ReadyToSleep, +} + +impl AreEventsBuffered { + pub fn events_buffered(&self) -> bool { + match self { + Self::EventsBuffered => true, + Self::ReadyToSleep => false, + } + } +} + +impl BufferedEvent { + pub fn from_event(event: Event<'_, T>) -> BufferedEvent { + 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, + }, + }); + util::set_inner_size_physical( + (window_id.0).0, + new_inner_size.width as _, + new_inner_size.height as _, + ); + } + } + } +} + impl ELRShared { pub(crate) fn new() -> ELRShared { ELRShared { @@ -45,9 +103,7 @@ impl ELRShared { loop { let event = self.buffer.borrow_mut().pop_front(); match event { - Some(e) => { - runner.process_event(e); - } + Some(e) => e.dispatch_event(|e| runner.process_event(e)), None => break, } } @@ -63,35 +119,65 @@ impl ELRShared { let mut runner_ref = self.runner.borrow_mut(); if let Some(ref mut runner) = *runner_ref { runner.new_events(); + loop { + let buffered_event_opt = self.buffer.borrow_mut().pop_front(); + match buffered_event_opt { + Some(e) => e.dispatch_event(|e| runner.process_event(e)), + None => break, + } + } } } - pub(crate) unsafe fn send_event(&self, event: Event<'static, T>) { - if let Err(event) = self.send_event_unbuffered(event) { - // 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 send_event(&self, event: Event<'_, T>) { + let handling_redraw = self + .runner + .borrow() + .as_ref() + .map(|r| RunnerState::HandlingRedraw == r.runner_state) + .unwrap_or(false); + let mut send = None; + if handling_redraw { + if let Event::RedrawRequested(_) = event { + send = Some(event); + } else { + self.buffer_event(event); + } + } else { + send = Some(event); + } + if let Some(event) = send { + if let Err(event) = self.send_event_unbuffered(event) { + // 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 send_event_unbuffered<'e>( - &self, - event: Event<'e, T>, - ) -> Result<(), Event<'e, T>> { + unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, 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, + let handling_redraw = if let RunnerState::HandlingRedraw = runner.runner_state { + true + } else { + false + }; + + if !handling_redraw { + // 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(e) => e.dispatch_event(|e| runner.process_event(e)), + None => break, + } } } @@ -111,10 +197,21 @@ impl ELRShared { } } - pub(crate) fn events_cleared(&self) { + pub(crate) fn main_events_cleared(&self) { let mut runner_ref = self.runner.borrow_mut(); if let Some(ref mut runner) = *runner_ref { - runner.events_cleared(); + runner.main_events_cleared(); + } + } + + pub(crate) fn redraw_events_cleared(&self) -> AreEventsBuffered { + let mut runner_ref = self.runner.borrow_mut(); + if let Some(ref mut runner) = *runner_ref { + runner.redraw_events_cleared(); + } + match self.buffer.borrow().len() { + 0 => AreEventsBuffered::ReadyToSleep, + _ => AreEventsBuffered::EventsBuffered, } } @@ -152,12 +249,15 @@ impl ELRShared { } } - fn buffer_event(&self, event: Event<'static, T>) { + 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), + _ => self + .buffer + .borrow_mut() + .push_back(BufferedEvent::from_event(event)), } } } @@ -317,16 +417,20 @@ impl EventLoopRunner { (RunnerState::HandlingRedraw, Event::RedrawRequested(_)) => { self.call_event_handler(event) } - (_, Event::RedrawRequested(_)) => { - self.call_event_handler(Event::MainEventsCleared); - self.runner_state = RunnerState::HandlingRedraw; + (RunnerState::New, Event::RedrawRequested(_)) + | (RunnerState::Idle(..), Event::RedrawRequested(_)) => { + self.new_events(); + self.main_events_cleared(); self.call_event_handler(event); } + (_, Event::RedrawRequested(_)) => { + panic!("redraw event in non-redraw phase"); + } (RunnerState::HandlingRedraw, _) => { - warn!("Non-redraw event dispatched durning redraw phase"); - self.events_cleared(); - self.new_events(); - self.call_event_handler(event); + panic!( + "Non-redraw event dispatched durning redraw phase: {:?}", + event.map_nonuser_event::<()>().ok() + ); } (_, _) => { self.runner_state = RunnerState::HandlingEvents; @@ -345,17 +449,64 @@ impl EventLoopRunner { } } - fn events_cleared(&mut self) { + fn main_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.runner_state = RunnerState::HandlingRedraw; + } + + RunnerState::HandlingRedraw => (), + + // 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.runner_state = RunnerState::HandlingRedraw; + } + // 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.runner_state = RunnerState::HandlingRedraw; + } + } + // If we deferred a wait and no events were received, the user doesn't have to + // get an event. + ControlFlow::Wait | ControlFlow::Exit => (), + } + } + } + } + + fn redraw_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.runner_state = RunnerState::HandlingRedraw; self.flush_redraws(); self.call_event_handler(Event::RedrawEventsCleared); self.runner_state = RunnerState::Idle(Instant::now()); } RunnerState::HandlingRedraw => { + self.flush_redraws(); self.call_event_handler(Event::RedrawEventsCleared); self.runner_state = RunnerState::Idle(Instant::now()); } diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 1b9845038..a5c60f9bf 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -88,6 +88,38 @@ pub fn adjust_size(hwnd: HWND, size: PhysicalSize) -> PhysicalSize { PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _) } +pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) { + unsafe { + let rect = adjust_window_rect( + window, + RECT { + top: 0, + left: 0, + bottom: y as LONG, + right: x as LONG, + }, + ) + .expect("adjust_window_rect failed"); + + let outer_x = (rect.right - rect.left).abs() as _; + let outer_y = (rect.top - rect.bottom).abs() as _; + winuser::SetWindowPos( + window, + ptr::null_mut(), + 0, + 0, + outer_x, + outer_y, + winuser::SWP_ASYNCWINDOWPOS + | winuser::SWP_NOZORDER + | winuser::SWP_NOREPOSITION + | winuser::SWP_NOMOVE + | winuser::SWP_NOACTIVATE, + ); + winuser::UpdateWindow(window); + } +} + pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option { unsafe { let style = winuser::GetWindowLongW(hwnd, winuser::GWL_STYLE); diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 83609a27c..f3e7851a1 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -24,7 +24,7 @@ use winapi::{ oleidl::LPDROPTARGET, shobjidl_core::{CLSID_TaskbarList, ITaskbarList2}, wingdi::{CreateRectRgn, DeleteObject}, - winnt::{LONG, LPCWSTR}, + winnt::LPCWSTR, winuser, }, }; @@ -215,38 +215,6 @@ impl Window { .unwrap() } - pub(crate) fn set_inner_size_physical(&self, x: u32, y: u32) { - unsafe { - let rect = util::adjust_window_rect( - self.window.0, - RECT { - top: 0, - left: 0, - bottom: y as LONG, - right: x as LONG, - }, - ) - .expect("adjust_window_rect failed"); - - let outer_x = (rect.right - rect.left).abs() as c_int; - let outer_y = (rect.top - rect.bottom).abs() as c_int; - winuser::SetWindowPos( - self.window.0, - ptr::null_mut(), - 0, - 0, - outer_x, - outer_y, - winuser::SWP_ASYNCWINDOWPOS - | winuser::SWP_NOZORDER - | winuser::SWP_NOREPOSITION - | winuser::SWP_NOMOVE - | winuser::SWP_NOACTIVATE, - ); - winuser::UpdateWindow(self.window.0); - } - } - #[inline] pub fn set_inner_size(&self, size: Size) { let dpi_factor = self.scale_factor(); @@ -260,7 +228,7 @@ impl Window { }); }); - self.set_inner_size_physical(width, height); + util::set_inner_size_physical(self.window.0, width, height); } #[inline]