diff --git a/examples/child_window.rs b/examples/child_window.rs index 2693dbdc08..272828d2a2 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -53,7 +53,7 @@ fn main() -> Result<(), impl std::error::Error> { println!("parent window: {parent_window:?})"); - event_loop.run(move |event: Event<()>, elwt| { + event_loop.run(move |event: Event, elwt| { if let Event::WindowEvent { event, window_id } = event { match event { WindowEvent::CloseRequested => { diff --git a/examples/custom_events.rs b/examples/custom_events.rs index 40bf957cd4..cad0576970 100644 --- a/examples/custom_events.rs +++ b/examples/custom_events.rs @@ -2,6 +2,8 @@ #[cfg(not(web_platform))] fn main() -> Result<(), impl std::error::Error> { + use std::sync::mpsc; + use simple_logger::SimpleLogger; use winit::{ event::{Event, WindowEvent}, @@ -18,30 +20,35 @@ fn main() -> Result<(), impl std::error::Error> { } SimpleLogger::new().init().unwrap(); - let event_loop = EventLoopBuilder::::with_user_event() - .build() - .unwrap(); + let event_loop = EventLoopBuilder::new().build().unwrap(); let window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) .unwrap(); - // `EventLoopProxy` allows you to dispatch custom events to the main Winit event - // loop from any thread. - let event_loop_proxy = event_loop.create_proxy(); + let waker = event_loop.create_proxy().waker(); + + let (sender, receiver) = mpsc::channel(); std::thread::spawn(move || { - // Wake up the `event_loop` once every second and dispatch a custom event - // from a different thread. + // Dispatch a custom event from a different thread once every second, + // and wake the `event_loop` so that it can handle it. loop { std::thread::sleep(std::time::Duration::from_secs(1)); - event_loop_proxy.send_event(CustomEvent::Timer).ok(); + if sender.send(CustomEvent::Timer).is_err() { + break; + } + waker.wake_by_ref(); } }); event_loop.run(move |event, elwt| match event { - Event::UserEvent(event) => println!("user event: {event:?}"), + Event::NewEvents(_) => { + for event in receiver.try_iter() { + println!("user event: {event:?}"); + } + } Event::WindowEvent { event: WindowEvent::CloseRequested, .. diff --git a/examples/web.rs b/examples/web.rs index 82534d6b4e..d7e1a06628 100644 --- a/examples/web.rs +++ b/examples/web.rs @@ -110,7 +110,7 @@ mod wasm { log_list } - pub fn log_event(log_list: &web_sys::Element, event: &Event<()>) { + pub fn log_event(log_list: &web_sys::Element, event: &Event) { log::debug!("{:?}", event); // Getting access to browser logs requires a lot of setup on mobile devices. diff --git a/src/event.rs b/src/event.rs index 3c1fd9c0db..f965b247c5 100644 --- a/src/event.rs +++ b/src/event.rs @@ -58,7 +58,7 @@ use crate::{ /// /// See the module-level docs for more information on the event loop manages each event. #[derive(Debug, Clone, PartialEq)] -pub enum Event { +pub enum Event { /// Emitted when new events arrive from the OS to be processed. /// /// This event type is useful as a place to put code that should be done before you start @@ -80,6 +80,7 @@ pub enum Event { }, /// Emitted when an event is sent from [`EventLoopProxy::send_event`](crate::event_loop::EventLoopProxy::send_event) + #[deprecated = "use `EventLoopProxy::waker`, and listen for wakeups in `NewEvents`"] UserEvent(T), /// Emitted when the application has been suspended. @@ -257,9 +258,11 @@ pub enum Event { impl Event { #[allow(clippy::result_large_err)] + #[deprecated = "Event::UserEvent is deprecated, so there is no need for this any more"] pub fn map_nonuser_event(self) -> Result, Event> { use self::Event::*; match self { + #[allow(deprecated)] UserEvent(_) => Err(self), WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }), DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }), @@ -1164,6 +1167,7 @@ mod tests { // Mainline events. let wid = unsafe { WindowId::dummy() }; + #[allow(deprecated)] x(UserEvent(())); x(NewEvents(event::StartCause::Init)); x(AboutToWait); @@ -1278,6 +1282,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_map_nonuser_event() { foreach_event!(|event: event::Event<()>| { let is_user = matches!(event, event::Event::UserEvent(())); diff --git a/src/event_loop.rs b/src/event_loop.rs index 93392efc89..fa9012f4b3 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -12,6 +12,7 @@ use std::ops::Deref; #[cfg(any(x11_platform, wayland_platform))] use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::task::Waker; use std::{error, fmt}; #[cfg(not(web_platform))] @@ -67,7 +68,10 @@ impl EventLoopBuilder<()> { /// Start building a new event loop. #[inline] pub fn new() -> Self { - Self::with_user_event() + Self { + platform_specific: Default::default(), + _p: PhantomData, + } } } @@ -77,6 +81,7 @@ impl EventLoopBuilder { /// Start building a new event loop, with the given type as the user event /// type. #[inline] + #[deprecated = "use `EventLoopProxy` with your own event channel instead"] pub fn with_user_event() -> Self { Self { platform_specific: Default::default(), @@ -205,6 +210,7 @@ impl EventLoop<()> { impl EventLoop { #[deprecated = "Use `EventLoopBuilder::::with_user_event().build()` instead."] pub fn with_user_event() -> Result, EventLoopError> { + #[allow(deprecated)] EventLoopBuilder::::with_user_event().build() } @@ -246,7 +252,8 @@ impl EventLoop { self.event_loop.run(event_handler) } - /// Creates an [`EventLoopProxy`] that can be used to dispatch user events to the main event loop. + /// Creates an [`EventLoopProxy`] that can be used to control the event + /// loop from a different thread. pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy(), @@ -442,7 +449,10 @@ unsafe impl rwh_05::HasRawDisplayHandle for OwnedDisplayHandle { } /// Used to send custom events to [`EventLoop`]. -pub struct EventLoopProxy { +/// +/// This has a generic type `T` that represents a user event, but that is +/// deprecated. +pub struct EventLoopProxy { event_loop_proxy: platform_impl::EventLoopProxy, } @@ -462,9 +472,31 @@ impl EventLoopProxy { /// Returns an `Err` if the associated [`EventLoop`] no longer exists. /// /// [`UserEvent(event)`]: Event::UserEvent + #[deprecated = "get a `waker` and wake that instead"] pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { self.event_loop_proxy.send_event(event) } + + /// Create a [`Waker`] that can wake the event loop from any thread. + /// + /// This is usually used in combination with [`mpsc::channel`] to send the + /// data that should be processed by the event loop. + /// + /// If you do use a channel, the data will be accessible from inside + /// [`Event::NewEvents`]. + /// + /// [`mpsc::channel`]: std::sync::mpsc::channel + pub fn waker(self) -> Waker { + self.event_loop_proxy.waker() + } +} + +// Note: This does not have the generic from `EventLoopProxy`, since this +// is the new API that shouldn't need it. +impl From for Waker { + fn from(proxy: EventLoopProxy) -> Self { + proxy.waker() + } } impl fmt::Debug for EventLoopProxy { diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 642d9a4c72..6f4b0981e2 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -333,6 +333,7 @@ impl EventLoop { // Empty the user event buffer { while let Ok(event) = self.user_events_receiver.try_recv() { + #[allow(deprecated)] callback(crate::event::Event::UserEvent(event), self.window_target()); } } diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index eac89365f8..51d2e8008d 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -45,6 +45,7 @@ macro_rules! bug_assert { }; } +/// The event loop may have queued user events ready. #[derive(Debug)] pub(crate) struct HandlePendingUserEvents; @@ -710,6 +711,7 @@ fn handle_user_events(mtm: MainThreadMarker) { } drop(this); + #[allow(deprecated)] handler.handle_event(Event::UserEvent(HandlePendingUserEvents)); loop { @@ -745,6 +747,7 @@ fn handle_user_events(mtm: MainThreadMarker) { } } + #[allow(deprecated)] handler.handle_event(Event::UserEvent(HandlePendingUserEvents)); } } diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index cf69eec5a8..41267d83d0 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -4,6 +4,7 @@ use std::{ marker::PhantomData, ptr, sync::mpsc::{self, Receiver, Sender}, + task::{RawWaker, RawWakerVTable, Waker}, }; use core_foundation::base::{CFIndex, CFRelease}; @@ -108,6 +109,7 @@ impl OwnedDisplayHandle { } } +#[allow(deprecated)] fn map_user_event( mut handler: impl FnMut(Event, &RootEventLoopWindowTarget), receiver: mpsc::Receiver, @@ -208,7 +210,10 @@ impl EventLoop { } pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy::new(self.sender.clone()) + EventLoopProxy { + sender: self.sender.clone(), + waker: waker(), + } } pub fn window_target(&self) -> &RootEventLoopWindowTarget { @@ -223,70 +228,92 @@ impl EventLoop { } } -pub struct EventLoopProxy { - sender: Sender, - source: CFRunLoopSourceRef, -} +pub fn waker() -> Waker { + fn new_raw_waker() -> RawWaker { + // just wake up the eventloop + extern "C" fn event_loop_proxy_handler(_: *const c_void) {} + + // adding a Source to the main CFRunLoop lets us wake it up and + // process user events through the normal OS EventLoop mechanisms. + let rl = unsafe { CFRunLoopGetMain() }; + let mut context = CFRunLoopSourceContext { + version: 0, + info: ptr::null_mut(), + retain: None, + release: None, + copyDescription: None, + equal: None, + hash: None, + schedule: None, + cancel: None, + perform: event_loop_proxy_handler, + }; + let source = unsafe { + CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context) + }; + unsafe { CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes) }; + unsafe { CFRunLoopWakeUp(rl) }; + RawWaker::new( + source as *const (), + &RawWakerVTable::new(clone_waker, wake, wake_by_ref, drop_waker), + ) + } -unsafe impl Send for EventLoopProxy {} + unsafe fn clone_waker(waker: *const ()) -> RawWaker { + let _source = waker as CFRunLoopSourceRef; + new_raw_waker() + } -impl Clone for EventLoopProxy { - fn clone(&self) -> EventLoopProxy { - EventLoopProxy::new(self.sender.clone()) + unsafe fn wake(waker: *const ()) { + unsafe { wake_by_ref(waker) }; + unsafe { drop_waker(waker) }; } -} -impl Drop for EventLoopProxy { - fn drop(&mut self) { + unsafe fn wake_by_ref(waker: *const ()) { + let source = waker as CFRunLoopSourceRef; unsafe { - CFRunLoopSourceInvalidate(self.source); - CFRelease(self.source as _); + // let the main thread know there's a new event + CFRunLoopSourceSignal(source); + let rl = CFRunLoopGetMain(); + CFRunLoopWakeUp(rl); } } -} -impl EventLoopProxy { - fn new(sender: Sender) -> EventLoopProxy { - unsafe { - // just wake up the eventloop - extern "C" fn event_loop_proxy_handler(_: *const c_void) {} + unsafe fn drop_waker(waker: *const ()) { + let source = waker as CFRunLoopSourceRef; + unsafe { CFRunLoopSourceInvalidate(source) }; + unsafe { CFRelease(source as _) }; + } - // adding a Source to the main CFRunLoop lets us wake it up and - // process user events through the normal OS EventLoop mechanisms. - let rl = CFRunLoopGetMain(); - let mut context = CFRunLoopSourceContext { - version: 0, - info: ptr::null_mut(), - retain: None, - release: None, - copyDescription: None, - equal: None, - hash: None, - schedule: None, - cancel: None, - perform: event_loop_proxy_handler, - }; - let source = - CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context); - CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes); - CFRunLoopWakeUp(rl); + unsafe { Waker::from_raw(new_raw_waker()) } +} - EventLoopProxy { sender, source } +pub struct EventLoopProxy { + sender: Sender, + waker: Waker, +} + +impl Clone for EventLoopProxy { + fn clone(&self) -> Self { + Self { + sender: self.sender.clone(), + waker: self.waker.clone(), } } +} +impl EventLoopProxy { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { self.sender .send(event) - .map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?; - unsafe { - // let the main thread know there's a new event - CFRunLoopSourceSignal(self.source); - let rl = CFRunLoopGetMain(); - CFRunLoopWakeUp(rl); - } + .map_err(|mpsc::SendError(x)| EventLoopClosed(x))?; + self.waker.wake_by_ref(); Ok(()) } + + pub fn waker(self) -> Waker { + self.waker + } } fn setup_control_flow_observers() { diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index f881cba3a9..248c14ff48 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -347,6 +347,7 @@ impl EventLoop { // Handle pending user events. We don't need back buffer, since we can't dispatch // user events indirectly via callback to the user. for user_event in self.pending_user_events.borrow_mut().drain(..) { + #[allow(deprecated)] callback(Event::UserEvent(user_event), &self.window_target); } @@ -447,6 +448,7 @@ impl EventLoop { buffer_sink.append(&mut state.window_events_sink.lock().unwrap()); }); for event in buffer_sink.drain() { + #[allow(deprecated)] let event = event.map_nonuser_event().unwrap(); callback(event, &self.window_target); } @@ -456,6 +458,7 @@ impl EventLoop { buffer_sink.append(&mut state.events_sink); }); for event in buffer_sink.drain() { + #[allow(deprecated)] let event = event.map_nonuser_event().unwrap(); callback(event, &self.window_target); } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 32b5cd62ec..c5126162af 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -587,6 +587,7 @@ impl EventLoop { // Empty the user event buffer { while let Ok(event) = self.user_receiver.try_recv() { + #[allow(deprecated)] callback(crate::event::Event::UserEvent(event), &self.target); } } diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs index ee3ac878d3..9a2eab0d49 100644 --- a/src/platform_impl/macos/app_delegate.rs +++ b/src/platform_impl/macos/app_delegate.rs @@ -393,6 +393,7 @@ impl ApplicationDelegate { } self.set_in_callback(true); + #[allow(deprecated)] self.handle_event(Event::UserEvent(HandlePendingUserEvents)); let events = mem::take(&mut *self.ivars().pending_events.borrow_mut()); @@ -490,6 +491,7 @@ pub(crate) enum QueuedEvent { }, } +/// The event loop may have queued user events ready. #[derive(Debug)] pub(crate) struct HandlePendingUserEvents; diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 0af4abe2c7..d4f3525759 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -9,13 +9,15 @@ use std::{ ptr, rc::{Rc, Weak}, sync::mpsc, + task::{RawWaker, RawWakerVTable, Waker}, time::{Duration, Instant}, }; use core_foundation::base::{CFIndex, CFRelease}; use core_foundation::runloop::{ kCFRunLoopCommonModes, CFRunLoopAddSource, CFRunLoopGetMain, CFRunLoopSourceContext, - CFRunLoopSourceCreate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp, + CFRunLoopSourceCreate, CFRunLoopSourceInvalidate, CFRunLoopSourceRef, CFRunLoopSourceSignal, + CFRunLoopWakeUp, }; use icrate::AppKit::{ NSApplication, NSApplicationActivationPolicyAccessory, NSApplicationActivationPolicyProhibited, @@ -152,6 +154,7 @@ impl EventLoopWindowTarget { } } +#[allow(deprecated)] fn map_user_event( mut handler: impl FnMut(Event, &RootWindowTarget), receiver: Rc>, @@ -472,7 +475,10 @@ impl EventLoop { } pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy::new(self.sender.clone()) + EventLoopProxy { + sender: self.sender.clone(), + waker: waker(), + } } } @@ -530,67 +536,90 @@ pub fn stop_app_on_panic R + UnwindSafe, R>( } } -pub struct EventLoopProxy { - sender: mpsc::Sender, - source: CFRunLoopSourceRef, -} +pub fn waker() -> Waker { + fn new_raw_waker() -> RawWaker { + // just wake up the eventloop + extern "C" fn event_loop_proxy_handler(_: *const c_void) {} + + // adding a Source to the main CFRunLoop lets us wake it up and + // process user events through the normal OS EventLoop mechanisms. + let rl = unsafe { CFRunLoopGetMain() }; + let mut context = CFRunLoopSourceContext { + version: 0, + info: ptr::null_mut(), + retain: None, + release: None, + copyDescription: None, + equal: None, + hash: None, + schedule: None, + cancel: None, + perform: event_loop_proxy_handler, + }; + let source = unsafe { + CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context) + }; + unsafe { CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes) }; + unsafe { CFRunLoopWakeUp(rl) }; + RawWaker::new( + source as *const (), + &RawWakerVTable::new(clone_waker, wake, wake_by_ref, drop_waker), + ) + } -unsafe impl Send for EventLoopProxy {} + unsafe fn clone_waker(waker: *const ()) -> RawWaker { + let _source = waker as CFRunLoopSourceRef; + new_raw_waker() + } + + unsafe fn wake(waker: *const ()) { + unsafe { wake_by_ref(waker) }; + unsafe { drop_waker(waker) }; + } -impl Drop for EventLoopProxy { - fn drop(&mut self) { + unsafe fn wake_by_ref(waker: *const ()) { + let source = waker as CFRunLoopSourceRef; unsafe { - CFRelease(self.source as _); + // let the main thread know there's a new event + CFRunLoopSourceSignal(source); + let rl = CFRunLoopGetMain(); + CFRunLoopWakeUp(rl); } } -} -impl Clone for EventLoopProxy { - fn clone(&self) -> Self { - EventLoopProxy::new(self.sender.clone()) + unsafe fn drop_waker(waker: *const ()) { + let source = waker as CFRunLoopSourceRef; + unsafe { CFRunLoopSourceInvalidate(source) }; + unsafe { CFRelease(source as _) }; } -} -impl EventLoopProxy { - fn new(sender: mpsc::Sender) -> Self { - unsafe { - // just wake up the eventloop - extern "C" fn event_loop_proxy_handler(_: *const c_void) {} + unsafe { Waker::from_raw(new_raw_waker()) } +} - // adding a Source to the main CFRunLoop lets us wake it up and - // process user events through the normal OS EventLoop mechanisms. - let rl = CFRunLoopGetMain(); - let mut context = CFRunLoopSourceContext { - version: 0, - info: ptr::null_mut(), - retain: None, - release: None, - copyDescription: None, - equal: None, - hash: None, - schedule: None, - cancel: None, - perform: event_loop_proxy_handler, - }; - let source = - CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context); - CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes); - CFRunLoopWakeUp(rl); +pub struct EventLoopProxy { + sender: mpsc::Sender, + waker: Waker, +} - EventLoopProxy { sender, source } +impl Clone for EventLoopProxy { + fn clone(&self) -> Self { + Self { + sender: self.sender.clone(), + waker: self.waker.clone(), } } +} +impl EventLoopProxy { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { self.sender .send(event) .map_err(|mpsc::SendError(x)| EventLoopClosed(x))?; - unsafe { - // let the main thread know there's a new event - CFRunLoopSourceSignal(self.source); - let rl = CFRunLoopGetMain(); - CFRunLoopWakeUp(rl); - } + self.waker.wake_by_ref(); Ok(()) } + + pub fn waker(self) -> Waker { + self.waker + } } diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index aa7acb2a6f..8f1fc81821 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -4,6 +4,7 @@ use std::{ marker::PhantomData, mem, slice, sync::{mpsc, Arc, Mutex}, + task::Waker, time::Instant, }; @@ -584,6 +585,7 @@ impl EventLoop { } while let Ok(event) = self.user_events_receiver.try_recv() { + #[allow(deprecated)] event_handler(event::Event::UserEvent(event), &self.window_target); } @@ -683,14 +685,14 @@ impl EventLoop { pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { user_events_sender: self.user_events_sender.clone(), - wake_socket: self.window_target.p.wake_socket.clone(), + waker: Waker::from(self.window_target.p.wake_socket.clone()), } } } pub struct EventLoopProxy { user_events_sender: mpsc::Sender, - wake_socket: Arc, + waker: Waker, } impl EventLoopProxy { @@ -699,17 +701,21 @@ impl EventLoopProxy { .send(event) .map_err(|mpsc::SendError(x)| event_loop::EventLoopClosed(x))?; - self.wake_socket.wake().unwrap(); + self.waker.wake_by_ref(); Ok(()) } + + pub fn waker(self) -> Waker { + self.waker + } } impl Clone for EventLoopProxy { fn clone(&self) -> Self { Self { user_events_sender: self.user_events_sender.clone(), - wake_socket: self.wake_socket.clone(), + waker: self.waker.clone(), } } } diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs index 4d54499871..0cff0b7469 100644 --- a/src/platform_impl/orbital/mod.rs +++ b/src/platform_impl/orbital/mod.rs @@ -92,6 +92,16 @@ impl TimeSocket { } } +impl std::task::Wake for TimeSocket { + fn wake(self: Arc) { + TimeSocket::wake(&*self).unwrap(); + } + + fn wake_by_ref(self: &Arc) { + TimeSocket::wake(&**self).unwrap(); + } +} + #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) struct PlatformSpecificEventLoopAttributes {} diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 2cc9d27d52..df16beaf97 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -48,6 +48,7 @@ impl EventLoop { }; // SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`. + #[allow(deprecated)] let handler: Box)> = Box::new(|event| { let event = match event.map_nonuser_event() { Ok(event) => event, @@ -85,6 +86,7 @@ impl EventLoop { }; self.elw.p.run( + #[allow(deprecated)] Box::new(move |event| { let event = match event.map_nonuser_event() { Ok(event) => event, diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index f7932ff76e..325b683804 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -154,6 +154,7 @@ impl Shared { Shared(Rc::::new_cyclic(|weak| { let proxy_spawner = WakerSpawner::new(main_thread, weak.clone(), |runner, count| { if let Some(runner) = runner.upgrade() { + #[allow(deprecated)] Shared(runner).send_events(iter::repeat(Event::UserEvent(())).take(count)) } }) @@ -646,6 +647,7 @@ impl Shared { let mut events = self.0.events.borrow_mut(); // Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle. + #[allow(deprecated)] events.extend( iter::repeat(Event::UserEvent(())) .take(self.0.proxy_spawner.fetch()) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 2e78eef1b1..dc73f072a3 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -14,6 +14,7 @@ use std::{ mpsc::{self, Receiver, Sender}, Arc, Mutex, MutexGuard, }, + task::{RawWaker, RawWakerVTable, Waker}, time::{Duration, Instant}, }; @@ -67,6 +68,8 @@ use windows_sys::Win32::{ }, }; +use self::runner::{EventLoopRunner, RunnerState}; +use super::{window::set_skip_taskbar, SelectedCursor}; use crate::{ dpi::{PhysicalPosition, PhysicalSize}, error::EventLoopError, @@ -92,36 +95,32 @@ use crate::{ }, window::WindowId as RootWindowId, }; -use runner::{EventLoopRunner, EventLoopRunnerShared}; - -use self::runner::RunnerState; -use super::{window::set_skip_taskbar, SelectedCursor}; +/// `EventLoopProxy::waker()` calls `PostMessageW` to wakeup and dispatch a +/// placeholder event, which we then receive in the mpsc channel here. +#[allow(deprecated)] +fn map_user_event<'a, T: 'static>( + mut handler: impl FnMut(Event, &RootELW) + 'a, + elwt: &'a RootELW, + receiver: &'a Receiver, +) -> impl FnMut(Event) + 'a { + move |event| match event.map_nonuser_event() { + Ok(event) => (handler)(event, elwt), + Err(_) => { + for event in receiver.try_iter() { + (handler)(Event::UserEvent(event), elwt); + } + } + } +} -/// some backends like macos uses an uninhabited `Never` type, -/// on windows, `UserEvent`s are also dispatched through the -/// WNDPROC callback, and due to the re-entrant nature of the -/// callback, recursively delivered events must be queued in a -/// buffer, the current implementation put this queue in -/// `EventLoopRunner`, which is shared between the event pumping -/// loop and the callback. because it's hard to decide from the -/// outside whether a event needs to be buffered, I decided not -/// use `Event` for the shared runner state, but use unit -/// as a placeholder so user events can be buffered as usual, -/// the real `UserEvent` is pulled from the mpsc channel directly -/// when the placeholder event is delivered to the event handler -pub(crate) struct UserEventPlaceholder; - -// here below, the generic `EventLoopRunnerShared` is replaced with -// `EventLoopRunnerShared` so we can get rid -// of the generic parameter T in types which don't depend on T. -// this is the approach which requires minimum changes to current -// backend implementation. it should be considered transitional -// and should be refactored and cleaned up eventually, I hope. +/// The event loop may have queued user events ready. +#[derive(Debug)] +pub(crate) struct HandlePendingUserEvents; pub(crate) struct WindowData { pub window_state: Arc>, - pub event_loop_runner: EventLoopRunnerShared, + pub event_loop_runner: Rc, pub key_event_builder: KeyEventBuilder, pub _file_drop_handler: Option, pub userdata_removed: Cell, @@ -129,7 +128,7 @@ pub(crate) struct WindowData { } impl WindowData { - fn send_event(&self, event: Event) { + fn send_event(&self, event: Event) { self.event_loop_runner.send_event(event); } @@ -139,11 +138,11 @@ impl WindowData { } struct ThreadMsgTargetData { - event_loop_runner: EventLoopRunnerShared, + event_loop_runner: Rc, } impl ThreadMsgTargetData { - fn send_event(&self, event: Event) { + fn send_event(&self, event: Event) { self.event_loop_runner.send_event(event); } } @@ -181,7 +180,7 @@ impl Default for PlatformSpecificEventLoopAttributes { pub struct EventLoopWindowTarget { thread_id: u32, thread_msg_target: HWND, - pub(crate) runner_shared: EventLoopRunnerShared, + pub(crate) runner_shared: Rc, } impl EventLoop { @@ -240,7 +239,7 @@ impl EventLoop { self.run_on_demand(event_handler) } - pub fn run_on_demand(&mut self, mut event_handler: F) -> Result<(), EventLoopError> + pub fn run_on_demand(&mut self, event_handler: F) -> Result<(), EventLoopError> where F: FnMut(Event, &RootELW), { @@ -250,29 +249,15 @@ impl EventLoop { return Err(EventLoopError::AlreadyRunning); } - let event_loop_windows_ref = &self.window_target; - let user_event_receiver = &self.user_event_receiver; // # Safety // We make sure to call runner.clear_event_handler() before // returning unsafe { - runner.set_event_handler(move |event| { - // the shared `EventLoopRunner` is not parameterized - // `EventLoopProxy::send_event()` calls `PostMessage` - // to wakeup and dispatch a placeholder `UserEvent`, - // when we received the placeholder event here, the - // real UserEvent(T) should already be put in the - // mpsc channel and ready to be pulled - let event = match event.map_nonuser_event() { - Ok(non_user_event) => non_user_event, - Err(_user_event_placeholder) => Event::UserEvent( - user_event_receiver - .try_recv() - .expect("user event signaled but not received"), - ), - }; - event_handler(event, event_loop_windows_ref) - }); + runner.set_event_handler(map_user_event( + event_handler, + &self.window_target, + &self.user_event_receiver, + )); } } @@ -305,14 +290,12 @@ impl EventLoop { } } - pub fn pump_events(&mut self, timeout: Option, mut event_handler: F) -> PumpStatus + pub fn pump_events(&mut self, timeout: Option, event_handler: F) -> PumpStatus where F: FnMut(Event, &RootELW), { { let runner = &self.window_target.p.runner_shared; - let event_loop_windows_ref = &self.window_target; - let user_event_receiver = &self.user_event_receiver; // # Safety // We make sure to call runner.clear_event_handler() before @@ -322,17 +305,11 @@ impl EventLoop { // to leave the runner in an unsound state with an associated // event handler. unsafe { - runner.set_event_handler(move |event| { - let event = match event.map_nonuser_event() { - Ok(non_user_event) => non_user_event, - Err(_user_event_placeholder) => Event::UserEvent( - user_event_receiver - .recv() - .expect("user event signaled but not received"), - ), - }; - event_handler(event, event_loop_windows_ref) - }); + runner.set_event_handler(map_user_event( + event_handler, + &self.window_target, + &self.user_event_receiver, + )); runner.wakeup(); } } @@ -517,7 +494,7 @@ impl EventLoop { pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { - target_window: self.window_target.p.thread_msg_target, + hwnd: self.window_target.p.thread_msg_target, event_send: self.user_event_sender.clone(), } } @@ -753,29 +730,56 @@ impl EventLoopThreadExecutor { type ThreadExecFn = Box>; pub struct EventLoopProxy { - target_window: HWND, + hwnd: HWND, event_send: Sender, } -unsafe impl Send for EventLoopProxy {} impl Clone for EventLoopProxy { fn clone(&self) -> Self { Self { - target_window: self.target_window, + hwnd: self.hwnd, event_send: self.event_send.clone(), } } } +fn wake_with_user_event(hwnd: HWND) { + unsafe { PostMessageW(hwnd, USER_EVENT_MSG_ID.get(), 0, 0) }; +} + impl EventLoopProxy { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { self.event_send .send(event) - .map(|result| { - unsafe { PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) }; - result - }) - .map_err(|e| EventLoopClosed(e.0)) + .map_err(|e| EventLoopClosed(e.0))?; + wake_with_user_event(self.hwnd); + Ok(()) + } + + pub fn waker(self) -> Waker { + const VTABLE: RawWakerVTable = + RawWakerVTable::new(clone_waker, wake, wake_by_ref, drop_waker); + + unsafe fn clone_waker(waker: *const ()) -> RawWaker { + let hwnd = waker as HWND; + RawWaker::new(hwnd as *const (), &VTABLE) + } + + unsafe fn wake(waker: *const ()) { + unsafe { wake_by_ref(waker) }; + unsafe { drop_waker(waker) }; + } + + unsafe fn wake_by_ref(waker: *const ()) { + let hwnd = waker as HWND; + wake_with_user_event(hwnd); + } + + unsafe fn drop_waker(_waker: *const ()) { + // Do nothing + } + + unsafe { Waker::from_raw(RawWaker::new(self.hwnd as *const (), &VTABLE)) } } } @@ -913,7 +917,7 @@ fn create_event_target_window() -> HWND { fn insert_event_target_window_data( thread_msg_target: HWND, - event_loop_runner: EventLoopRunnerShared, + event_loop_runner: Rc, ) { let userdata = ThreadMsgTargetData { event_loop_runner }; let input_ptr = Box::into_raw(Box::new(userdata)); @@ -2429,7 +2433,8 @@ unsafe extern "system" fn thread_event_target_callback( // user event is still in the mpsc channel and will be pulled // once the placeholder event is delivered to the wrapper // `event_handler` - userdata.send_event(Event::UserEvent(UserEventPlaceholder)); + #[allow(deprecated)] + userdata.send_event(Event::UserEvent(HandlePendingUserEvents)); 0 } _ if msg == EXEC_MSG_ID.get() => { diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index 4254c41ce8..2df625affe 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -3,7 +3,6 @@ use std::{ cell::{Cell, RefCell}, collections::VecDeque, mem, panic, - rc::Rc, sync::{Arc, Mutex}, time::Instant, }; @@ -14,7 +13,7 @@ use crate::{ dpi::PhysicalSize, event::{Event, InnerSizeWriter, StartCause, WindowEvent}, platform_impl::platform::{ - event_loop::{WindowData, GWL_USERDATA}, + event_loop::{HandlePendingUserEvents, WindowData, GWL_USERDATA}, get_window_long, }, window::WindowId, @@ -22,11 +21,9 @@ use crate::{ use super::ControlFlow; -pub(crate) type EventLoopRunnerShared = Rc>; +type EventHandler = Cell)>>>; -type EventHandler = Cell)>>>; - -pub(crate) struct EventLoopRunner { +pub(crate) struct EventLoopRunner { // The event loop's win32 handles pub(super) thread_msg_target: HWND, @@ -39,8 +36,8 @@ pub(crate) struct EventLoopRunner { exit: Cell>, runner_state: Cell, last_events_cleared: Cell, - event_handler: EventHandler, - event_buffer: RefCell>>, + event_handler: EventHandler, + event_buffer: RefCell>, panic_error: Cell>, } @@ -61,14 +58,17 @@ pub(crate) enum RunnerState { Destroyed, } -enum BufferedEvent { - Event(Event), +/// `UserEvent`s are dispatched through the WNDPROC callback, and due to the +/// re-entrant nature of the callback, we must buffer the events here. +#[derive(Debug)] +enum BufferedEvent { + Event(Event), ScaleFactorChanged(WindowId, f64, PhysicalSize), } -impl EventLoopRunner { - pub(crate) fn new(thread_msg_target: HWND) -> EventLoopRunner { - EventLoopRunner { +impl EventLoopRunner { + pub(crate) fn new(thread_msg_target: HWND) -> Self { + Self { thread_msg_target, interrupt_msg_dispatch: Cell::new(false), runner_state: Cell::new(RunnerState::Uninitialized), @@ -94,12 +94,15 @@ impl EventLoopRunner { /// undefined behaviour. pub(crate) unsafe fn set_event_handler(&self, f: F) where - F: FnMut(Event), + F: FnMut(Event), { // Erase closure lifetime. // SAFETY: Caller upholds that the lifetime of the closure is upheld. let f = unsafe { - mem::transmute::)>, Box)>>(Box::new(f)) + mem::transmute::< + Box)>, + Box)>, + >(Box::new(f)) }; let old_event_handler = self.event_handler.replace(Some(f)); assert!(old_event_handler.is_none()); @@ -130,7 +133,7 @@ impl EventLoopRunner { } /// State retrieval functions. -impl EventLoopRunner { +impl EventLoopRunner { #[allow(unused)] pub fn thread_msg_target(&self) -> HWND { self.thread_msg_target @@ -176,7 +179,7 @@ impl EventLoopRunner { } /// Misc. functions -impl EventLoopRunner { +impl EventLoopRunner { pub fn catch_unwind(&self, f: impl FnOnce() -> R) -> Option { let panic_error = self.panic_error.take(); if panic_error.is_none() { @@ -206,7 +209,7 @@ impl EventLoopRunner { } /// Event dispatch functions. -impl EventLoopRunner { +impl EventLoopRunner { pub(crate) fn prepare_wait(&self) { self.move_state_to(RunnerState::Idle); } @@ -215,7 +218,7 @@ impl EventLoopRunner { self.move_state_to(RunnerState::HandlingMainEvents); } - pub(crate) fn send_event(&self, event: Event) { + pub(crate) fn send_event(&self, event: Event) { if let Event::WindowEvent { event: WindowEvent::RedrawRequested, .. @@ -242,7 +245,7 @@ impl EventLoopRunner { self.move_state_to(RunnerState::Destroyed); } - fn call_event_handler(&self, event: Event) { + fn call_event_handler(&self, event: Event) { self.catch_unwind(|| { let mut event_handler = self.event_handler.take() .expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)"); @@ -375,8 +378,8 @@ impl EventLoopRunner { } } -impl BufferedEvent { - pub fn from_event(event: Event) -> BufferedEvent { +impl BufferedEvent { + pub fn from_event(event: Event) -> BufferedEvent { match event { Event::WindowEvent { event: @@ -399,7 +402,7 @@ impl BufferedEvent { } } - pub fn dispatch_event(self, dispatch: impl FnOnce(Event)) { + pub fn dispatch_event(self, dispatch: impl FnOnce(Event)) { match self { Self::Event(event) => dispatch(event), Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => { diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 7a77ae8152..09a2e12105 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -1197,6 +1197,7 @@ impl<'a> InitData<'a> { let file_drop_handler = FileDropHandler::new( win.window, Box::new(move |event| { + #[allow(deprecated)] if let Ok(e) = event.map_nonuser_event() { file_drop_runner.send_event(e) }