Skip to content

Commit

Permalink
api: make EventLoopProxy wrap an opaque type
Browse files Browse the repository at this point in the history
The proxy is intended to be Clone, thus use `Arc` for it internally and
don't require backends for it to be `Clone`. Use `EventLoopProxyProvider`
to hide the backend's proxy implementation details.

Co-authored-by: daxpedda <[email protected]>
  • Loading branch information
kchibisov and daxpedda authored Nov 12, 2024
1 parent ae4c449 commit 3a60cba
Show file tree
Hide file tree
Showing 24 changed files with 256 additions and 307 deletions.
22 changes: 16 additions & 6 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::marker::PhantomData;
#[cfg(any(x11_platform, wayland_platform))]
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
#[cfg(not(web_platform))]
use std::time::{Duration, Instant};

Expand Down Expand Up @@ -452,10 +453,21 @@ impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
}
}

pub(crate) trait EventLoopProxyProvider: Send + Sync {
/// See [`EventLoopProxy::wake_up`] for details.
fn wake_up(&self);
}

/// Control the [`EventLoop`], possibly from a different thread, without referencing it directly.
#[derive(Clone)]
pub struct EventLoopProxy {
pub(crate) event_loop_proxy: platform_impl::EventLoopProxy,
pub(crate) proxy: Arc<dyn EventLoopProxyProvider>,
}

impl fmt::Debug for EventLoopProxy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventLoopProxy").finish_non_exhaustive()
}
}

impl EventLoopProxy {
Expand All @@ -475,13 +487,11 @@ impl EventLoopProxy {
///
/// [#3687]: https://github.com/rust-windowing/winit/pull/3687
pub fn wake_up(&self) {
self.event_loop_proxy.wake_up();
self.proxy.wake_up();
}
}

impl fmt::Debug for EventLoopProxy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ActiveEventLoop").finish_non_exhaustive()
pub(crate) fn new(proxy: Arc<dyn EventLoopProxyProvider>) -> Self {
Self { proxy }
}
}

Expand Down
40 changes: 22 additions & 18 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use crate::error::{EventLoopError, NotSupportedError, RequestError};
use crate::event::{self, DeviceId, FingerId, Force, StartCause, SurfaceSizeWriter};
use crate::event_loop::{
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
OwnedDisplayHandle as RootOwnedDisplayHandle,
};
use crate::monitor::MonitorHandle as RootMonitorHandle;
use crate::platform::pump_events::PumpStatus;
Expand Down Expand Up @@ -131,12 +132,13 @@ impl EventLoop {
pub(crate) fn new(
attributes: &PlatformSpecificEventLoopAttributes,
) -> Result<Self, EventLoopError> {
let proxy_wake_up = Arc::new(AtomicBool::new(false));

let android_app = attributes.android_app.as_ref().expect(
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
Android",
);

let event_loop_proxy = Arc::new(EventLoopProxy::new(android_app.create_waker()));

let redraw_flag = SharedFlag::new();

Ok(Self {
Expand All @@ -147,7 +149,7 @@ impl EventLoop {
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(false),
redraw_requester: RedrawRequester::new(&redraw_flag, android_app.create_waker()),
proxy_wake_up,
event_loop_proxy,
},
redraw_flag,
loop_running: false,
Expand Down Expand Up @@ -276,7 +278,7 @@ impl EventLoop {
},
}

if self.window_target.proxy_wake_up.swap(false, Ordering::Relaxed) {
if self.window_target.event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
app.proxy_wake_up(&self.window_target);
}

Expand Down Expand Up @@ -562,7 +564,8 @@ impl EventLoop {
self.pending_redraw |= self.redraw_flag.get_and_reset();

timeout = if self.running
&& (self.pending_redraw || self.window_target.proxy_wake_up.load(Ordering::Relaxed))
&& (self.pending_redraw
|| self.window_target.event_loop_proxy.wake_up.load(Ordering::Relaxed))
{
// If we already have work to do then we don't want to block on the next poll
Some(Duration::ZERO)
Expand Down Expand Up @@ -595,7 +598,7 @@ impl EventLoop {
self.pending_redraw |= self.redraw_flag.get_and_reset();
if !self.running
|| (!self.pending_redraw
&& !self.window_target.proxy_wake_up.load(Ordering::Relaxed))
&& !self.window_target.event_loop_proxy.wake_up.load(Ordering::Relaxed))
{
return;
}
Expand Down Expand Up @@ -634,15 +637,20 @@ impl EventLoop {
}
}

#[derive(Clone)]
pub struct EventLoopProxy {
proxy_wake_up: Arc<AtomicBool>,
wake_up: AtomicBool,
waker: AndroidAppWaker,
}

impl EventLoopProxy {
pub fn wake_up(&self) {
self.proxy_wake_up.store(true, Ordering::Relaxed);
fn new(waker: AndroidAppWaker) -> Self {
Self { wake_up: AtomicBool::new(false), waker }
}
}

impl EventLoopProxyProvider for EventLoopProxy {
fn wake_up(&self) {
self.wake_up.store(true, Ordering::Relaxed);
self.waker.wake();
}
}
Expand All @@ -652,7 +660,7 @@ pub struct ActiveEventLoop {
control_flow: Cell<ControlFlow>,
exit: Cell<bool>,
redraw_requester: RedrawRequester,
proxy_wake_up: Arc<AtomicBool>,
event_loop_proxy: Arc<EventLoopProxy>,
}

impl ActiveEventLoop {
Expand All @@ -662,12 +670,8 @@ impl ActiveEventLoop {
}

impl RootActiveEventLoop for ActiveEventLoop {
fn create_proxy(&self) -> RootEventLoopProxy {
let event_loop_proxy = EventLoopProxy {
proxy_wake_up: self.proxy_wake_up.clone(),
waker: self.app.create_waker(),
};
RootEventLoopProxy { event_loop_proxy }
fn create_proxy(&self) -> CoreEventLoopProxy {
CoreEventLoopProxy::new(self.event_loop_proxy.clone())
}

fn create_window(
Expand Down
14 changes: 7 additions & 7 deletions src/platform_impl/apple/appkit/app_state.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::cell::{Cell, OnceCell, RefCell};
use std::mem;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::sync::atomic::Ordering as AtomicOrdering;
use std::sync::Arc;
use std::time::Instant;

use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy};
use objc2_foundation::{MainThreadMarker, NSNotification};

use super::super::event_handler::EventHandler;
use super::event_loop::{stop_app_immediately, ActiveEventLoop, PanicInfo};
use super::event_loop::{stop_app_immediately, ActiveEventLoop, EventLoopProxy, PanicInfo};
use super::menu;
use super::observer::{EventLoopWaker, RunLoop};
use crate::application::ApplicationHandler;
Expand All @@ -24,7 +24,7 @@ pub(super) struct AppState {
default_menu: bool,
activate_ignoring_other_apps: bool,
run_loop: RunLoop,
proxy_wake_up: Arc<AtomicBool>,
event_loop_proxy: Arc<EventLoopProxy>,
event_handler: EventHandler,
stop_on_launch: Cell<bool>,
stop_before_wait: Cell<bool>,
Expand Down Expand Up @@ -72,7 +72,7 @@ impl AppState {
let this = Rc::new(AppState {
mtm,
activation_policy,
proxy_wake_up: Arc::new(AtomicBool::new(false)),
event_loop_proxy: Arc::new(EventLoopProxy::new()),
default_menu,
activate_ignoring_other_apps,
run_loop: RunLoop::main(mtm),
Expand Down Expand Up @@ -165,8 +165,8 @@ impl AppState {
self.event_handler.set(handler, closure)
}

pub fn proxy_wake_up(&self) -> Arc<AtomicBool> {
self.proxy_wake_up.clone()
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
&self.event_loop_proxy
}

/// If `pump_events` is called to progress the event loop then we
Expand Down Expand Up @@ -350,7 +350,7 @@ impl AppState {
return;
}

if self.proxy_wake_up.swap(false, AtomicOrdering::Relaxed) {
if self.event_loop_proxy.wake_up.swap(false, AtomicOrdering::Relaxed) {
self.with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
}

Expand Down
30 changes: 13 additions & 17 deletions src/platform_impl/apple/appkit/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::panic::{catch_unwind, resume_unwind, RefUnwindSafe, UnwindSafe};
use std::ptr;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::sync::Arc;
use std::time::{Duration, Instant};

use core_foundation::base::{CFIndex, CFRelease};
Expand All @@ -32,7 +31,8 @@ use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, RequestError};
use crate::event_loop::{
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
OwnedDisplayHandle as RootOwnedDisplayHandle,
};
use crate::monitor::MonitorHandle as RootMonitorHandle;
use crate::platform::macos::ActivationPolicy;
Expand Down Expand Up @@ -95,9 +95,8 @@ impl ActiveEventLoop {
}

impl RootActiveEventLoop for ActiveEventLoop {
fn create_proxy(&self) -> RootEventLoopProxy {
let event_loop_proxy = EventLoopProxy::new(self.app_state.proxy_wake_up());
RootEventLoopProxy { event_loop_proxy }
fn create_proxy(&self) -> CoreEventLoopProxy {
CoreEventLoopProxy::new(self.app_state.event_loop_proxy().clone())
}

fn create_window(
Expand Down Expand Up @@ -436,8 +435,9 @@ pub fn stop_app_on_panic<F: FnOnce() -> R + UnwindSafe, R>(
}
}

#[derive(Debug)]
pub struct EventLoopProxy {
proxy_wake_up: Arc<AtomicBool>,
pub(crate) wake_up: AtomicBool,
source: CFRunLoopSourceRef,
}

Expand All @@ -452,14 +452,8 @@ impl Drop for EventLoopProxy {
}
}

impl Clone for EventLoopProxy {
fn clone(&self) -> Self {
EventLoopProxy::new(self.proxy_wake_up.clone())
}
}

impl EventLoopProxy {
fn new(proxy_wake_up: Arc<AtomicBool>) -> Self {
pub(crate) fn new() -> Self {
unsafe {
// just wake up the eventloop
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
Expand All @@ -483,14 +477,16 @@ impl EventLoopProxy {
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
CFRunLoopWakeUp(rl);

EventLoopProxy { proxy_wake_up, source }
EventLoopProxy { wake_up: AtomicBool::new(false), source }
}
}
}

pub fn wake_up(&self) {
self.proxy_wake_up.store(true, AtomicOrdering::Relaxed);
impl EventLoopProxyProvider for EventLoopProxy {
fn wake_up(&self) {
self.wake_up.store(true, AtomicOrdering::Relaxed);
unsafe {
// let the main thread know there's a new event
// Let the main thread know there's a new event.
CFRunLoopSourceSignal(self.source);
let rl = CFRunLoopGetMain();
CFRunLoopWakeUp(rl);
Expand Down
3 changes: 1 addition & 2 deletions src/platform_impl/apple/appkit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ mod window_delegate;
pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor;
pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra};
pub(crate) use self::event_loop::{
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
PlatformSpecificEventLoopAttributes,
ActiveEventLoop, EventLoop, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes,
};
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
pub(crate) use self::window::Window;
Expand Down
18 changes: 9 additions & 9 deletions src/platform_impl/apple/uikit/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::cell::{OnceCell, RefCell, RefMut};
use std::collections::HashSet;
use std::os::raw::c_void;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex, OnceLock};
use std::time::Instant;
use std::{mem, ptr};
Expand All @@ -24,7 +24,7 @@ use objc2_ui_kit::{UIApplication, UICoordinateSpace, UIView, UIWindow};

use super::super::event_handler::EventHandler;
use super::window::WinitUIWindow;
use super::ActiveEventLoop;
use super::{ActiveEventLoop, EventLoopProxy};
use crate::application::ApplicationHandler;
use crate::dpi::PhysicalSize;
use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent};
Expand Down Expand Up @@ -139,7 +139,7 @@ pub(crate) struct AppState {
app_state: Option<AppStateImpl>,
control_flow: ControlFlow,
waker: EventLoopWaker,
proxy_wake_up: Arc<AtomicBool>,
event_loop_proxy: Arc<EventLoopProxy>,
}

impl AppState {
Expand All @@ -164,7 +164,7 @@ impl AppState {
}),
control_flow: ControlFlow::default(),
waker,
proxy_wake_up: Arc::new(AtomicBool::new(false)),
event_loop_proxy: Arc::new(EventLoopProxy::new()),
});
}
init_guard(&mut guard);
Expand Down Expand Up @@ -376,8 +376,8 @@ impl AppState {
}
}

pub(crate) fn proxy_wake_up(&self) -> Arc<AtomicBool> {
self.proxy_wake_up.clone()
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
&self.event_loop_proxy
}

pub(crate) fn set_control_flow(&mut self, control_flow: ControlFlow) {
Expand Down Expand Up @@ -543,10 +543,10 @@ fn handle_user_events(mtm: MainThreadMarker) {
if processing_redraws {
bug!("user events attempted to be sent out while `ProcessingRedraws`");
}
let proxy_wake_up = this.proxy_wake_up.clone();
let event_loop_proxy = this.event_loop_proxy().clone();
drop(this);

if proxy_wake_up.swap(false, Ordering::Relaxed) {
if event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
handle_event(mtm, Event::UserWakeUp);
}

Expand Down Expand Up @@ -578,7 +578,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
}
}

if proxy_wake_up.swap(false, Ordering::Relaxed) {
if event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
handle_event(mtm, Event::UserWakeUp);
}
}
Expand Down
Loading

0 comments on commit 3a60cba

Please sign in to comment.