mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 14:49:07 -04:00
windows: Coalesce wake-up events
This commit is contained in:
@@ -140,12 +140,6 @@ impl EventLoopProxy {
|
||||
///
|
||||
/// [`proxy_wake_up`]: crate::application::ApplicationHandler::proxy_wake_up
|
||||
/// [`ApplicationHandler::proxy_wake_up()`]: crate::application::ApplicationHandler::proxy_wake_up
|
||||
///
|
||||
/// # Platform-specific
|
||||
///
|
||||
/// - **Windows**: The wake-up may be ignored under high contention, see [#3687].
|
||||
///
|
||||
/// [#3687]: https://github.com/rust-windowing/winit/pull/3687
|
||||
pub fn wake_up(&self) {
|
||||
self.proxy.wake_up();
|
||||
}
|
||||
|
||||
@@ -416,7 +416,10 @@ impl ActiveEventLoop {
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> RootEventLoopProxy {
|
||||
let event_loop_proxy = EventLoopProxy { target_window: self.0.thread_msg_target };
|
||||
let event_loop_proxy = EventLoopProxy {
|
||||
has_sent_wakeup_msg: self.0.has_sent_wakeup_msg.clone(),
|
||||
target_window: self.0.thread_msg_target,
|
||||
};
|
||||
RootEventLoopProxy::new(Arc::new(event_loop_proxy))
|
||||
}
|
||||
|
||||
@@ -766,6 +769,7 @@ type ThreadExecFn = Box<Box<dyn FnMut()>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventLoopProxy {
|
||||
has_sent_wakeup_msg: Arc<AtomicBool>,
|
||||
target_window: HWND,
|
||||
}
|
||||
|
||||
@@ -774,7 +778,18 @@ unsafe impl Sync for EventLoopProxy {}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
unsafe { PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) };
|
||||
if self.has_sent_wakeup_msg.swap(true, Ordering::AcqRel) {
|
||||
// Do not send a wakeup event if one has already been sent, but hasn't been processed
|
||||
// yet. This prevents errors when the internal message queue fills up, and effectively
|
||||
// coalesces wakeups.
|
||||
tracing::trace!("avoided sending wake up, previous wake-up has yet to be processed");
|
||||
return;
|
||||
}
|
||||
if unsafe { PostMessageW(self.target_window, PROXY_WAKEUP_MSG_ID.get(), 0, 0) } == 0 {
|
||||
// _can_ technically fail, but realistically won't, since we've prevented the most
|
||||
// common case (queue full) above.
|
||||
tracing::error!("failed waking event loop: {}", std::io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,7 +845,7 @@ impl LazyMessageId {
|
||||
|
||||
// Message sent by the `EventLoopProxy` when we want to wake up the thread.
|
||||
// WPARAM and LPARAM are unused.
|
||||
static USER_EVENT_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::WakeupMsg\0");
|
||||
static PROXY_WAKEUP_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::WakeupMsg\0");
|
||||
// Message sent when we want to execute a closure in the thread.
|
||||
// WPARAM contains a Box<Box<dyn FnMut()>> that must be retrieved with `Box::from_raw`,
|
||||
// and LPARAM is unused.
|
||||
@@ -2471,12 +2486,9 @@ unsafe extern "system" fn thread_event_target_callback(
|
||||
unsafe { DefWindowProcW(window, msg, wparam, lparam) }
|
||||
},
|
||||
|
||||
_ if msg == USER_EVENT_MSG_ID.get() => {
|
||||
// synthesis a placeholder UserEvent, so that if the callback is
|
||||
// re-entered it can be buffered for later delivery. the real
|
||||
// user event is still in the mpsc channel and will be pulled
|
||||
// once the placeholder event is delivered to the wrapper
|
||||
// `event_handler`
|
||||
_ if msg == PROXY_WAKEUP_MSG_ID.get() => {
|
||||
// Reset the sent state, allowing new `PROXY_WAKEUP_MSG_ID` messages to be sent.
|
||||
userdata.event_loop_runner.has_sent_wakeup_msg.store(false, Ordering::Release);
|
||||
userdata.send_wakeup();
|
||||
0
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::any::Any;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
use std::{fmt, mem, panic};
|
||||
@@ -30,6 +31,8 @@ pub(crate) struct EventLoopRunner {
|
||||
// can't stall an external loop beyond a frame
|
||||
pub(super) interrupt_msg_dispatch: Cell<bool>,
|
||||
|
||||
pub(super) has_sent_wakeup_msg: Arc<AtomicBool>,
|
||||
|
||||
control_flow: Cell<ControlFlow>,
|
||||
exit: Cell<Option<i32>>,
|
||||
runner_state: Cell<RunnerState>,
|
||||
@@ -69,8 +72,6 @@ pub(crate) enum Event {
|
||||
Device { device_id: DeviceId, event: DeviceEvent },
|
||||
Window { window_id: WindowId, event: WindowEvent },
|
||||
BufferedScaleFactorChanged(HWND, f64, PhysicalSize<u32>),
|
||||
// FIXME(madsmtm): Coalesce these into a flag (or similar) instead of handling them as events.
|
||||
// https://github.com/rust-windowing/winit/pull/3687
|
||||
WakeUp,
|
||||
}
|
||||
|
||||
@@ -80,6 +81,7 @@ impl EventLoopRunner {
|
||||
thread_id,
|
||||
thread_msg_target,
|
||||
interrupt_msg_dispatch: Cell::new(false),
|
||||
has_sent_wakeup_msg: Arc::new(AtomicBool::new(false)),
|
||||
runner_state: Cell::new(RunnerState::Uninitialized),
|
||||
control_flow: Cell::new(ControlFlow::default()),
|
||||
exit: Cell::new(None),
|
||||
@@ -131,6 +133,7 @@ impl EventLoopRunner {
|
||||
thread_id: _,
|
||||
thread_msg_target: _,
|
||||
interrupt_msg_dispatch,
|
||||
has_sent_wakeup_msg,
|
||||
runner_state,
|
||||
panic_error,
|
||||
control_flow: _,
|
||||
@@ -140,6 +143,7 @@ impl EventLoopRunner {
|
||||
event_buffer: _,
|
||||
} = self;
|
||||
interrupt_msg_dispatch.set(false);
|
||||
has_sent_wakeup_msg.store(false, Ordering::Release);
|
||||
runner_state.set(RunnerState::Uninitialized);
|
||||
panic_error.set(None);
|
||||
exit.set(None);
|
||||
|
||||
@@ -260,3 +260,4 @@ changelog entry.
|
||||
- On Windows, `Window::theme` will return the correct theme after setting it through `Window::set_theme`.
|
||||
- On Windows, `Window::set_theme` will change the title bar color immediately now.
|
||||
- On Windows 11, prevent incorrect shifting when dragging window onto a monitor with different DPI.
|
||||
- On Windows, coalesce wake-up events to avoid filling the message queue.
|
||||
|
||||
Reference in New Issue
Block a user