From a0d69c782ab3b27b69d246715c62d1de8062e5d6 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 29 Jun 2024 17:19:09 +0200 Subject: [PATCH] add: `ActiveEventLoop::create_proxy()` Co-authored-by: Kirill Chibisov --- src/changelog/unreleased.md | 4 ++++ src/event_loop.rs | 8 ++++++- src/platform_impl/android/mod.rs | 22 +++++++++---------- src/platform_impl/apple/appkit/app_state.rs | 7 ++++-- src/platform_impl/apple/appkit/event_loop.rs | 14 ++++-------- src/platform_impl/apple/uikit/app_state.rs | 7 ++++++ src/platform_impl/apple/uikit/event_loop.rs | 14 +++++------- src/platform_impl/linux/mod.rs | 8 +++---- .../linux/wayland/event_loop/mod.rs | 17 +++++++------- src/platform_impl/linux/x11/mod.rs | 12 +++++----- src/platform_impl/orbital/event_loop.rs | 18 +++++++-------- src/platform_impl/web/event_loop/mod.rs | 4 ---- .../web/event_loop/window_target.rs | 6 ++++- src/platform_impl/windows/event_loop.rs | 8 +++---- 14 files changed, 78 insertions(+), 71 deletions(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 9e9a479cb4..ebea7a3a6d 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -40,6 +40,10 @@ changelog entry. ## Unreleased +### Added + +- Add `ActiveEventLoop::create_proxy()`. + ### Changed - On Web, let events wake up event loop immediately when using `ControlFlow::Poll`. diff --git a/src/event_loop.rs b/src/event_loop.rs index e658699f8e..abfdee2978 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -247,7 +247,7 @@ impl EventLoop { /// Creates an [`EventLoopProxy`] that can be used to dispatch user events /// to the main event loop, possibly from another thread. pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy() } + EventLoopProxy { event_loop_proxy: self.event_loop.window_target().p.create_proxy() } } /// Gets a persistent reference to the underlying platform display. @@ -345,6 +345,12 @@ impl AsRawFd for EventLoop { } impl ActiveEventLoop { + /// Creates an [`EventLoopProxy`] that can be used to dispatch user events + /// to the main event loop, possibly from another thread. + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { event_loop_proxy: self.p.create_proxy() } + } + /// Create the window. /// /// Possible causes of error include denied permission, incompatible system, and lack of memory. diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 363298f12f..371b11befe 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -101,7 +101,6 @@ pub struct EventLoop { android_app: AndroidApp, window_target: event_loop::ActiveEventLoop, redraw_flag: SharedFlag, - proxy_wake_up: Arc, loop_running: bool, // Dispatched `NewEvents` running: bool, pending_redraw: bool, @@ -145,11 +144,11 @@ impl EventLoop { &redraw_flag, android_app.create_waker(), ), + proxy_wake_up, }, _marker: PhantomData, }, redraw_flag, - proxy_wake_up, loop_running: false, running: false, pending_redraw: false, @@ -278,7 +277,7 @@ impl EventLoop { }, } - if self.proxy_wake_up.swap(false, Ordering::Relaxed) { + if self.window_target.p.proxy_wake_up.swap(false, Ordering::Relaxed) { app.proxy_wake_up(self.window_target()); } @@ -485,7 +484,7 @@ impl EventLoop { self.pending_redraw |= self.redraw_flag.get_and_reset(); timeout = if self.running - && (self.pending_redraw || self.proxy_wake_up.load(Ordering::Relaxed)) + && (self.pending_redraw || self.window_target.p.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) @@ -517,7 +516,8 @@ impl EventLoop { // We also ignore wake ups while suspended. self.pending_redraw |= self.redraw_flag.get_and_reset(); if !self.running - || (!self.pending_redraw && !self.proxy_wake_up.load(Ordering::Relaxed)) + || (!self.pending_redraw + && !self.window_target.p.proxy_wake_up.load(Ordering::Relaxed)) { return; } @@ -551,13 +551,6 @@ impl EventLoop { &self.window_target } - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy { - proxy_wake_up: self.proxy_wake_up.clone(), - waker: self.android_app.create_waker(), - } - } - fn control_flow(&self) -> ControlFlow { self.window_target.p.control_flow() } @@ -585,9 +578,14 @@ pub struct ActiveEventLoop { control_flow: Cell, exit: Cell, redraw_requester: RedrawRequester, + proxy_wake_up: Arc, } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { proxy_wake_up: self.proxy_wake_up.clone(), waker: self.app.create_waker() } + } + pub fn primary_monitor(&self) -> Option { Some(MonitorHandle::new(self.app.clone())) } diff --git a/src/platform_impl/apple/appkit/app_state.rs b/src/platform_impl/apple/appkit/app_state.rs index 84d9a4fa53..0218af4a16 100644 --- a/src/platform_impl/apple/appkit/app_state.rs +++ b/src/platform_impl/apple/appkit/app_state.rs @@ -80,13 +80,12 @@ impl ApplicationDelegate { pub(super) fn new( mtm: MainThreadMarker, activation_policy: NSApplicationActivationPolicy, - proxy_wake_up: Arc, default_menu: bool, activate_ignoring_other_apps: bool, ) -> Retained { let this = mtm.alloc().set_ivars(AppState { activation_policy, - proxy_wake_up, + proxy_wake_up: Arc::new(AtomicBool::new(false)), default_menu, activate_ignoring_other_apps, run_loop: RunLoop::main(mtm), @@ -179,6 +178,10 @@ impl ApplicationDelegate { self.ivars().event_handler.set(handler, closure) } + pub fn proxy_wake_up(&self) -> Arc { + self.ivars().proxy_wake_up.clone() + } + /// If `pump_events` is called to progress the event loop then we /// bootstrap the event loop via `-[NSApplication run]` but will use /// `CFRunLoopRunInMode` for subsequent calls to `pump_events`. diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index 2d35bb4fb4..23a039a3f9 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -71,6 +71,10 @@ pub struct ActiveEventLoop { } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy::new(self.delegate.proxy_wake_up()) + } + pub(super) fn new_root(delegate: Retained) -> RootWindowTarget { let mtm = MainThreadMarker::from(&*delegate); let p = Self { delegate, mtm }; @@ -166,8 +170,6 @@ pub struct EventLoop { /// keep it around here as well. delegate: Retained, - proxy_wake_up: Arc, - window_target: RootWindowTarget, panic_info: Rc, } @@ -212,12 +214,9 @@ impl EventLoop { ActivationPolicy::Prohibited => NSApplicationActivationPolicy::Prohibited, }; - let proxy_wake_up = Arc::new(AtomicBool::new(false)); - let delegate = ApplicationDelegate::new( mtm, activation_policy, - proxy_wake_up.clone(), attributes.default_menu, attributes.activate_ignoring_other_apps, ); @@ -236,7 +235,6 @@ impl EventLoop { p: ActiveEventLoop { delegate, mtm }, _marker: PhantomData, }, - proxy_wake_up, panic_info, }) } @@ -358,10 +356,6 @@ impl EventLoop { }) }) } - - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy::new(self.proxy_wake_up.clone()) - } } #[derive(Clone)] diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index a7cd751edb..0bf0b16b63 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -3,6 +3,7 @@ use std::cell::{RefCell, RefMut}; use std::collections::HashSet; use std::os::raw::c_void; +use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Instant; use std::{fmt, mem, ptr}; @@ -135,6 +136,7 @@ pub(crate) struct AppState { app_state: Option, control_flow: ControlFlow, waker: EventLoopWaker, + proxy_wake_up: Arc, } impl AppState { @@ -158,6 +160,7 @@ impl AppState { }), control_flow: ControlFlow::default(), waker, + proxy_wake_up: Arc::new(AtomicBool::new(false)), }); } init_guard(&mut guard); @@ -402,6 +405,10 @@ impl AppState { } } + pub(crate) fn proxy_wake_up(&self) -> Arc { + self.proxy_wake_up.clone() + } + pub(crate) fn set_control_flow(&mut self, control_flow: ControlFlow) { self.control_flow = control_flow; } diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index f30bbbb823..69d5bb4585 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -34,6 +34,10 @@ pub struct ActiveEventLoop { } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy::new(AppState::get_mut(self.mtm).proxy_wake_up()) + } + pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor { let _ = source.inner; CustomCursor { inner: super::PlatformCustomCursor } @@ -134,7 +138,6 @@ fn map_user_event( pub struct EventLoop { mtm: MainThreadMarker, - proxy_wake_up: Arc, window_target: RootActiveEventLoop, } @@ -160,11 +163,8 @@ impl EventLoop { // this line sets up the main run loop before `UIApplicationMain` setup_control_flow_observers(); - let proxy_wake_up = Arc::new(AtomicBool::new(false)); - Ok(EventLoop { mtm, - proxy_wake_up, window_target: RootActiveEventLoop { p: ActiveEventLoop { mtm }, _marker: PhantomData }, }) } @@ -179,7 +179,7 @@ impl EventLoop { `EventLoop::run_app` calls `UIApplicationMain` on iOS", ); - let handler = map_user_event(app, self.proxy_wake_up.clone()); + let handler = map_user_event(app, AppState::get_mut(self.mtm).proxy_wake_up()); let handler = unsafe { std::mem::transmute::< @@ -212,10 +212,6 @@ impl EventLoop { unreachable!() } - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy::new(self.proxy_wake_up.clone()) - } - pub fn window_target(&self) -> &RootActiveEventLoop { &self.window_target } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 64bae79298..3bd2d252bc 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -789,10 +789,6 @@ impl EventLoop { } } - pub fn create_proxy(&self) -> EventLoopProxy { - x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy) - } - pub fn run_app(self, app: &mut A) -> Result<(), EventLoopError> { x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app)) } @@ -843,6 +839,10 @@ pub enum ActiveEventLoop { } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + x11_or_wayland!(match self; ActiveEventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy) + } + #[inline] pub fn is_wayland(&self) -> bool { match *self { diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index ab494a7da2..59e03c3316 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -47,9 +47,6 @@ pub struct EventLoop { compositor_updates: Vec, window_ids: Vec, - /// Event loop proxy - event_loop_proxy: EventLoopProxy, - /// The Wayland dispatcher to has raw access to the queue when needed, such as /// when creating a new window. wayland_dispatcher: WaylandDispatcher, @@ -139,6 +136,7 @@ impl EventLoop { connection: connection.clone(), wayland_dispatcher: wayland_dispatcher.clone(), event_loop_awakener, + event_loop_proxy: EventLoopProxy::new(ping), queue_handle, control_flow: Cell::new(ControlFlow::default()), exit: Cell::new(None), @@ -152,7 +150,6 @@ impl EventLoop { window_ids: Vec::new(), connection, wayland_dispatcher, - event_loop_proxy: EventLoopProxy::new(ping), event_loop, window_target: RootActiveEventLoop { p: PlatformActiveEventLoop::Wayland(window_target), @@ -512,11 +509,6 @@ impl EventLoop { std::mem::swap(&mut self.window_ids, &mut window_ids); } - #[inline] - pub fn create_proxy(&self) -> EventLoopProxy { - self.event_loop_proxy.clone() - } - #[inline] pub fn window_target(&self) -> &RootActiveEventLoop { &self.window_target @@ -589,6 +581,9 @@ impl AsRawFd for EventLoop { } pub struct ActiveEventLoop { + /// Event loop proxy + event_loop_proxy: EventLoopProxy, + /// The event loop wakeup source. pub event_loop_awakener: calloop::ping::Ping, @@ -613,6 +608,10 @@ pub struct ActiveEventLoop { } impl ActiveEventLoop { + pub(crate) fn create_proxy(&self) -> EventLoopProxy { + self.event_loop_proxy.clone() + } + pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { self.control_flow.set(control_flow) } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index b299cfb36b..e057ae2066 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -137,6 +137,7 @@ pub struct ActiveEventLoop { windows: RefCell>>, redraw_sender: WakeSender, activation_sender: WakeSender, + event_loop_proxy: EventLoopProxy, device_events: Cell, } @@ -146,7 +147,6 @@ pub struct EventLoop { event_processor: EventProcessor, redraw_receiver: PeekableReceiver, activation_receiver: PeekableReceiver, - event_loop_proxy: EventLoopProxy, /// The current state of the event loop. state: EventLoopState, @@ -302,6 +302,7 @@ impl EventLoop { sender: activation_token_sender, // not used again so no clone waker: waker.clone(), }, + event_loop_proxy, device_events: Default::default(), }; @@ -360,15 +361,10 @@ impl EventLoop { event_processor, redraw_receiver: PeekableReceiver::from_recv(redraw_channel), activation_receiver: PeekableReceiver::from_recv(activation_token_channel), - event_loop_proxy, state: EventLoopState { x11_readiness: Readiness::EMPTY, proxy_wake_up: false }, } } - pub fn create_proxy(&self) -> EventLoopProxy { - self.event_loop_proxy.clone() - } - pub(crate) fn window_target(&self) -> &RootAEL { &self.event_processor.target } @@ -629,6 +625,10 @@ impl AsRawFd for EventLoop { } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + self.event_loop_proxy.clone() + } + /// Returns the `XConnection` of this events loop. #[inline] pub(crate) fn x_connection(&self) -> &Arc { diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 4ef1a79fa7..eea7cfd961 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -275,7 +275,6 @@ impl EventState { pub struct EventLoop { windows: Vec<(Arc, EventState)>, window_target: event_loop::ActiveEventLoop, - user_events_sender: mpsc::SyncSender<()>, user_events_receiver: mpsc::Receiver<()>, } @@ -317,10 +316,10 @@ impl EventLoop { destroys: Arc::new(Mutex::new(VecDeque::new())), event_socket, wake_socket, + user_events_sender, }, _marker: PhantomData, }, - user_events_sender, user_events_receiver, }) } @@ -684,13 +683,6 @@ impl EventLoop { pub fn window_target(&self) -> &event_loop::ActiveEventLoop { &self.window_target } - - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy { - user_events_sender: self.user_events_sender.clone(), - wake_socket: self.window_target.p.wake_socket.clone(), - } - } } pub struct EventLoopProxy { @@ -727,9 +719,17 @@ pub struct ActiveEventLoop { pub(super) destroys: Arc>>, pub(super) event_socket: Arc, pub(super) wake_socket: Arc, + user_events_sender: mpsc::SyncSender<()>, } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { + user_events_sender: self.user_events_sender.clone(), + wake_socket: self.wake_socket.clone(), + } + } + pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor { let _ = source.inner; RootCustomCursor { inner: super::PlatformCustomCursor } diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 6e66e8e0b9..860b97464f 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -58,10 +58,6 @@ impl EventLoop { self.elw.p.run(Box::new(move |event| handle_event(&mut app, &target, event)), true); } - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy::new(self.elw.p.waker()) - } - pub fn window_target(&self) -> &RootActiveEventLoop { &self.elw } diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 69c081c2b0..9df6748cf5 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -12,7 +12,7 @@ use super::super::KeyEventExtra; use super::device::DeviceId; use super::runner::{EventWrapper, Execution}; use super::window::WindowId; -use super::{backend, runner}; +use super::{backend, runner, EventLoopProxy}; use crate::event::{ DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent, }; @@ -68,6 +68,10 @@ impl ActiveEventLoop { WindowId(self.runner.generate_id()) } + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy::new(self.waker()) + } + pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor { RootCustomCursor { inner: CustomCursor::new(self, source.inner) } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index f4a02c230e..66cf9ff65c 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -468,16 +468,16 @@ impl EventLoop { } } - pub fn create_proxy(&self) -> EventLoopProxy { - EventLoopProxy { target_window: self.window_target.p.thread_msg_target } - } - fn exit_code(&self) -> Option { self.window_target.p.exit_code() } } impl ActiveEventLoop { + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { target_window: self.thread_msg_target } + } + #[inline(always)] pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { EventLoopThreadExecutor { thread_id: self.thread_id, target_window: self.thread_msg_target }