MacOS: implement pump_events_with_timeout internally

This layers pump_events on a pump_events_with_timeout API, like we have
for Linux and Android.

This is just an internal implementation detail for now but we could
consider making pump_events_with_timeout public, or just making it so
that pump_events() takes the timeout argument.
This commit is contained in:
Robert Bragg 2023-07-23 23:27:38 +01:00 committed by Kirill Chibisov
parent e5eb253698
commit b74cee8df1
4 changed files with 138 additions and 41 deletions

View file

@ -141,6 +141,16 @@ pub fn setup_control_flow_observers(panic_info: Weak<PanicInfo>) {
pub struct EventLoopWaker {
timer: CFRunLoopTimerRef,
/// An arbitrary instant in the past, that will trigger an immediate wake
/// We save this as the `next_fire_date` for consistency so we can
/// easily check if the next_fire_date needs updating.
start_instant: Instant,
/// This is what the `NextFireDate` has been set to.
/// `None` corresponds to `waker.stop()` and `start_instant` is used
/// for `waker.start()`
next_fire_date: Option<Instant>,
}
impl Drop for EventLoopWaker {
@ -169,31 +179,50 @@ impl Default for EventLoopWaker {
ptr::null_mut(),
);
CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
EventLoopWaker { timer }
EventLoopWaker {
timer,
start_instant: Instant::now(),
next_fire_date: None,
}
}
}
}
impl EventLoopWaker {
pub fn stop(&mut self) {
unsafe { CFRunLoopTimerSetNextFireDate(self.timer, std::f64::MAX) }
if self.next_fire_date.is_some() {
self.next_fire_date = None;
unsafe { CFRunLoopTimerSetNextFireDate(self.timer, std::f64::MAX) }
}
}
pub fn start(&mut self) {
unsafe { CFRunLoopTimerSetNextFireDate(self.timer, std::f64::MIN) }
if self.next_fire_date != Some(self.start_instant) {
self.next_fire_date = Some(self.start_instant);
unsafe { CFRunLoopTimerSetNextFireDate(self.timer, std::f64::MIN) }
}
}
pub fn start_at(&mut self, instant: Instant) {
pub fn start_at(&mut self, instant: Option<Instant>) {
let now = Instant::now();
if now >= instant {
self.start();
} else {
unsafe {
let current = CFAbsoluteTimeGetCurrent();
let duration = instant - now;
let fsecs =
duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64;
CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs)
match instant {
Some(instant) if now >= instant => {
self.start();
}
Some(instant) => {
if self.next_fire_date != Some(instant) {
self.next_fire_date = Some(instant);
unsafe {
let current = CFAbsoluteTimeGetCurrent();
let duration = instant - now;
let fsecs = duration.subsec_nanos() as f64 / 1_000_000_000.0
+ duration.as_secs() as f64;
CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs)
}
}
}
None => {
self.stop();
}
}
}