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..12c3b48671 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.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..c301ba5f07 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -710,6 +710,7 @@ fn handle_user_events(mtm: MainThreadMarker) { } drop(this); + #[allow(deprecated)] handler.handle_event(Event::UserEvent(HandlePendingUserEvents)); loop { @@ -745,6 +746,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..b36bda0c1d 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()); 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..b59bcd13c1 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}, }; @@ -256,6 +257,7 @@ impl EventLoop { // We make sure to call runner.clear_event_handler() before // returning unsafe { + #[allow(deprecated)] runner.set_event_handler(move |event| { // the shared `EventLoopRunner` is not parameterized // `EventLoopProxy::send_event()` calls `PostMessage` @@ -322,6 +324,7 @@ impl EventLoop { // to leave the runner in an unsound state with an associated // event handler. unsafe { + #[allow(deprecated)] runner.set_event_handler(move |event| { let event = match event.map_nonuser_event() { Ok(non_user_event) => non_user_event, @@ -517,7 +520,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 +756,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_hwnd(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_hwnd(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_hwnd(hwnd); + } + + unsafe fn drop_waker(_waker: *const ()) { + // Do nothing + } + + unsafe { Waker::from_raw(RawWaker::new(self.hwnd as *const (), &VTABLE)) } } } @@ -2429,6 +2459,7 @@ 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` + #[allow(deprecated)] userdata.send_event(Event::UserEvent(UserEventPlaceholder)); 0 } 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) }