mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Add EventLoopProxy::into_waker
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use std::ptr::NonNull;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::task::{RawWaker, RawWakerVTable, Waker};
|
||||||
|
|
||||||
use objc2::MainThreadMarker;
|
use objc2::MainThreadMarker;
|
||||||
use objc2_core_foundation::{
|
use objc2_core_foundation::{
|
||||||
kCFRunLoopCommonModes, CFIndex, CFRetained, CFRunLoop, CFRunLoopSource, CFRunLoopSourceContext,
|
kCFRunLoopCommonModes, CFIndex, CFRetained, CFRunLoop, CFRunLoopSource, CFRunLoopSourceContext,
|
||||||
|
Type,
|
||||||
};
|
};
|
||||||
use winit_core::event_loop::EventLoopProxyProvider;
|
use winit_core::event_loop::EventLoopProxyProvider;
|
||||||
|
|
||||||
@@ -119,4 +122,54 @@ impl EventLoopProxyProvider for EventLoopProxy {
|
|||||||
// main loop may be sleeping (and `CFRunLoopSourceSignal` won't wake it).
|
// main loop may be sleeping (and `CFRunLoopSourceSignal` won't wake it).
|
||||||
self.main_loop.wake_up();
|
self.main_loop.wake_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn waker(&self) -> Waker {
|
||||||
|
const VTABLE: RawWakerVTable =
|
||||||
|
RawWakerVTable::new(clone_waker, wake, wake_by_ref, drop_waker);
|
||||||
|
|
||||||
|
unsafe fn clone_waker(data: *const ()) -> RawWaker {
|
||||||
|
// SAFETY: The poiner came from `CFRunLoopSource` and is valid and non-null.
|
||||||
|
let source = unsafe { &*data.cast::<CFRunLoopSource>() };
|
||||||
|
|
||||||
|
// Increment reference count.
|
||||||
|
let source = source.retain();
|
||||||
|
|
||||||
|
// Pass ownership to the raw waker.
|
||||||
|
let data: *const CFRunLoopSource = CFRetained::into_raw(source).as_ptr();
|
||||||
|
RawWaker::new(data.cast(), &VTABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake(data: *const ()) {
|
||||||
|
unsafe { wake_by_ref(data) };
|
||||||
|
unsafe { drop_waker(data) };
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake_by_ref(data: *const ()) {
|
||||||
|
// SAFETY: The poiner came from `CFRunLoopSource` and is valid and non-null.
|
||||||
|
let source = unsafe { &*data.cast::<CFRunLoopSource>() };
|
||||||
|
|
||||||
|
// Signal the source, which ends up later invoking `perform` on the main thread.
|
||||||
|
//
|
||||||
|
// Multiple signals in quick succession are automatically coalesced into a single
|
||||||
|
// signal.
|
||||||
|
source.signal();
|
||||||
|
|
||||||
|
let main_loop = CFRunLoop::main().unwrap();
|
||||||
|
// Let the main thread know there's a new event.
|
||||||
|
//
|
||||||
|
// This is required since we may be (probably are) running on a different thread, and
|
||||||
|
// the main loop may be sleeping (and `CFRunLoopSourceSignal` won't wake it).
|
||||||
|
main_loop.wake_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn drop_waker(data: *const ()) {
|
||||||
|
let source = data.cast::<CFRunLoopSource>().cast_mut();
|
||||||
|
// SAFETY: The poiner came from `CFRunLoopSource` and is valid and non-null.
|
||||||
|
// We take ownership of a retain count here.
|
||||||
|
let _source = unsafe { CFRetained::from_raw(NonNull::new_unchecked(source)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: *const CFRunLoopSource = CFRetained::into_raw(self.source.clone()).as_ptr();
|
||||||
|
unsafe { Waker::from_raw(RawWaker::new(data.cast(), &VTABLE)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pub mod run_on_demand;
|
|||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::task::Waker;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
|
use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
|
||||||
@@ -150,6 +151,13 @@ impl EventLoopProxy {
|
|||||||
self.proxy.wake_up();
|
self.proxy.wake_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a [`Waker`] that calls [`wake_up`] on the proxy when awoken.
|
||||||
|
///
|
||||||
|
/// This may be useful to `async` code or otherwise interoperating with `std`.
|
||||||
|
pub fn waker(&self) -> Waker {
|
||||||
|
self.proxy.waker()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(proxy: Arc<dyn EventLoopProxyProvider>) -> Self {
|
pub fn new(proxy: Arc<dyn EventLoopProxyProvider>) -> Self {
|
||||||
Self { proxy }
|
Self { proxy }
|
||||||
}
|
}
|
||||||
@@ -158,6 +166,9 @@ impl EventLoopProxy {
|
|||||||
pub trait EventLoopProxyProvider: Send + Sync + Debug {
|
pub trait EventLoopProxyProvider: Send + Sync + Debug {
|
||||||
/// See [`EventLoopProxy::wake_up`] for details.
|
/// See [`EventLoopProxy::wake_up`] for details.
|
||||||
fn wake_up(&self);
|
fn wake_up(&self);
|
||||||
|
|
||||||
|
/// See [`EventLoopProxy::waker`] for details.
|
||||||
|
fn waker(&self) -> Waker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A proxy for the underlying display handle.
|
/// A proxy for the underlying display handle.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::cell::Cell;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{mpsc, Arc, Mutex};
|
use std::sync::{mpsc, Arc, Mutex};
|
||||||
|
use std::task::Waker;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::{iter, mem, slice};
|
use std::{iter, mem, slice};
|
||||||
|
|
||||||
@@ -276,7 +277,6 @@ impl EventState {
|
|||||||
pub struct EventLoop {
|
pub struct EventLoop {
|
||||||
windows: Vec<(Arc<RedoxSocket>, EventState)>,
|
windows: Vec<(Arc<RedoxSocket>, EventState)>,
|
||||||
window_target: ActiveEventLoop,
|
window_target: ActiveEventLoop,
|
||||||
user_events_receiver: mpsc::Receiver<()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
@@ -577,7 +577,7 @@ impl EventLoop {
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while self.user_events_receiver.try_recv().is_ok() {
|
if self.wake_up.swap(false, Ordering::Relaxed) {
|
||||||
app.proxy_wake_up(&self.window_target);
|
app.proxy_wake_up(&self.window_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,17 +666,26 @@ impl EventLoop {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EventLoopProxy {
|
pub struct EventLoopProxy {
|
||||||
user_events_sender: mpsc::SyncSender<()>,
|
waker: Waker,
|
||||||
pub(super) wake_socket: TimeSocket,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoopProxyProvider for EventLoopProxy {
|
impl EventLoopProxyProvider for EventLoopProxy {
|
||||||
fn wake_up(&self) {
|
fn wake_up(&self) {
|
||||||
// When we fail to send the event it means that we haven't woken up to read the previous
|
self.waker.wake_by_ref();
|
||||||
// event.
|
|
||||||
if self.user_events_sender.try_send(()).is_ok() {
|
|
||||||
self.wake_socket.wake().unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_waker(self) -> Waker {
|
||||||
|
self.waker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::task::Wake for TimeSocket {
|
||||||
|
fn wake(self: Arc<TimeSocket>) {
|
||||||
|
TimeSocket::wake(&*self).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wake_by_ref(self: &Arc<TimeSocket>) {
|
||||||
|
TimeSocket::wake(&**self).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user