Skip to content

Commit

Permalink
TMP waker
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jan 25, 2024
1 parent b36d8d1 commit 87c7468
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 107 deletions.
12 changes: 12 additions & 0 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down Expand Up @@ -247,11 +248,22 @@ impl<T> EventLoop<T> {
}

/// Creates an [`EventLoopProxy`] that can be used to dispatch user events to the main event loop.
#[deprecated = "use `waker` with your own event channel instead"]
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
event_loop_proxy: self.event_loop.create_proxy(),
}
}

/// 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.
///
/// [`mpsc::channel`]: std::sync::mpsc::channel
pub fn waker(&self) -> Waker {
self.event_loop.waker()
}
}

#[cfg(feature = "rwh_06")]
Expand Down
114 changes: 67 additions & 47 deletions src/platform_impl/ios/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
marker::PhantomData,
ptr,
sync::mpsc::{self, Receiver, Sender},
task::{RawWaker, RawWakerVTable, Waker},
};

use core_foundation::base::{CFIndex, CFRelease};
Expand Down Expand Up @@ -208,52 +209,21 @@ impl<T: 'static> EventLoop<T> {
}

pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy::new(self.sender.clone())
EventLoopProxy::new(self.sender.clone(), self.waker())
}

pub fn window_target(&self) -> &RootEventLoopWindowTarget {
&self.window_target
}
}

// EventLoopExtIOS
impl<T: 'static> EventLoop<T> {
pub fn idiom(&self) -> Idiom {
UIDevice::current(self.mtm).userInterfaceIdiom().into()
}
}

pub struct EventLoopProxy<T> {
sender: Sender<T>,
source: CFRunLoopSourceRef,
}

unsafe impl<T: Send> Send for EventLoopProxy<T> {}

impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> EventLoopProxy<T> {
EventLoopProxy::new(self.sender.clone())
}
}

impl<T> Drop for EventLoopProxy<T> {
fn drop(&mut self) {
unsafe {
CFRunLoopSourceInvalidate(self.source);
CFRelease(self.source as _);
}
}
}

impl<T> EventLoopProxy<T> {
fn new(sender: Sender<T>) -> EventLoopProxy<T> {
unsafe {
pub fn waker(&self) -> 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 = CFRunLoopGetMain();
let rl = unsafe { CFRunLoopGetMain() };
let mut context = CFRunLoopSourceContext {
version: 0,
info: ptr::null_mut(),
Expand All @@ -266,25 +236,75 @@ impl<T> EventLoopProxy<T> {
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);
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 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) };
}

EventLoopProxy { sender, source }
unsafe fn wake_by_ref(waker: *const ()) {
let source = waker as CFRunLoopSourceRef;
unsafe {
// let the main thread know there's a new event
CFRunLoopSourceSignal(source);
let rl = CFRunLoopGetMain();
CFRunLoopWakeUp(rl);
}
}

unsafe fn drop_waker(waker: *const ()) {
let source = waker as CFRunLoopSourceRef;
unsafe { CFRunLoopSourceInvalidate(source) };
unsafe { CFRelease(source as _) };
}

unsafe { Waker::from_raw(new_raw_waker()) }
}
}

// EventLoopExtIOS
impl<T: 'static> EventLoop<T> {
pub fn idiom(&self) -> Idiom {
UIDevice::current(self.mtm).userInterfaceIdiom().into()
}
}

pub struct EventLoopProxy<T> {
sender: Sender<T>,
waker: Waker,
}

impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self {
EventLoopProxy::new(self.sender.clone(), self.waker.clone())
}
}

impl<T> EventLoopProxy<T> {
fn new(sender: Sender<T>, waker: Waker) -> Self {
EventLoopProxy { sender, waker }
}

pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
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(())
}
}
Expand Down
116 changes: 69 additions & 47 deletions src/platform_impl/macos/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -472,7 +474,67 @@ impl<T> EventLoop<T> {
}

pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy::new(self.sender.clone())
EventLoopProxy::new(self.sender.clone(), self.waker())
}

pub fn waker(&self) -> 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 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) };
}

unsafe fn wake_by_ref(waker: *const ()) {
let source = waker as CFRunLoopSourceRef;
unsafe {
// let the main thread know there's a new event
CFRunLoopSourceSignal(source);
let rl = CFRunLoopGetMain();
CFRunLoopWakeUp(rl);
}
}

unsafe fn drop_waker(waker: *const ()) {
let source = waker as CFRunLoopSourceRef;
unsafe { CFRunLoopSourceInvalidate(source) };
unsafe { CFRelease(source as _) };
}

unsafe { Waker::from_raw(new_raw_waker()) }
}
}

Expand Down Expand Up @@ -532,65 +594,25 @@ pub fn stop_app_on_panic<F: FnOnce() -> R + UnwindSafe, R>(

pub struct EventLoopProxy<T> {
sender: mpsc::Sender<T>,
source: CFRunLoopSourceRef,
}

unsafe impl<T: Send> Send for EventLoopProxy<T> {}

impl<T> Drop for EventLoopProxy<T> {
fn drop(&mut self) {
unsafe {
CFRelease(self.source as _);
}
}
waker: Waker,
}

impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self {
EventLoopProxy::new(self.sender.clone())
EventLoopProxy::new(self.sender.clone(), self.waker.clone())
}
}

impl<T> EventLoopProxy<T> {
fn new(sender: mpsc::Sender<T>) -> Self {
unsafe {
// 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 = 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);

EventLoopProxy { sender, source }
}
fn new(sender: mpsc::Sender<T>, waker: Waker) -> Self {
EventLoopProxy { sender, waker }
}

pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
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(())
}
}
13 changes: 9 additions & 4 deletions src/platform_impl/orbital/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
marker::PhantomData,
mem, slice,
sync::{mpsc, Arc, Mutex},
task::Waker,
time::Instant,
};

Expand Down Expand Up @@ -683,14 +684,18 @@ impl<T: 'static> EventLoop<T> {
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
user_events_sender: self.user_events_sender.clone(),
wake_socket: self.window_target.p.wake_socket.clone(),
waker: self.waker(),
}
}

pub fn waker(&self) -> Waker {
Waker::from(self.window_target.p.wake_socket.clone())
}
}

pub struct EventLoopProxy<T: 'static> {
user_events_sender: mpsc::Sender<T>,
wake_socket: Arc<TimeSocket>,
waker: Waker,
}

impl<T> EventLoopProxy<T> {
Expand All @@ -699,7 +704,7 @@ impl<T> EventLoopProxy<T> {
.send(event)
.map_err(|mpsc::SendError(x)| event_loop::EventLoopClosed(x))?;

self.wake_socket.wake().unwrap();
self.waker.wake_by_ref();

Ok(())
}
Expand All @@ -709,7 +714,7 @@ impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self {
Self {
user_events_sender: self.user_events_sender.clone(),
wake_socket: self.wake_socket.clone(),
waker: self.waker.clone(),
}
}
}
Expand Down

0 comments on commit 87c7468

Please sign in to comment.