Skip to content

Commit 8ad0163

Browse files
authored
chore: move event loop recreation check into backends themselves
1 parent 5f2c735 commit 8ad0163

File tree

12 files changed

+64
-25
lines changed

12 files changed

+64
-25
lines changed

src/event_loop.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use std::marker::PhantomData;
1212
#[cfg(any(x11_platform, wayland_platform))]
1313
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
14-
use std::sync::atomic::{AtomicBool, Ordering};
1514

1615
use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
1716
pub use winit_core::event_loop::*;
@@ -53,8 +52,6 @@ pub struct EventLoopBuilder {
5352
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
5453
}
5554

56-
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
57-
5855
impl EventLoopBuilder {
5956
/// Builds a new event loop.
6057
///
@@ -93,22 +90,13 @@ impl EventLoopBuilder {
9390
pub fn build(&mut self) -> Result<EventLoop, EventLoopError> {
9491
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
9592

96-
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
97-
return Err(EventLoopError::RecreationAttempt);
98-
}
99-
10093
// Certain platforms accept a mutable reference in their API.
10194
#[allow(clippy::unnecessary_mut_passed)]
10295
Ok(EventLoop {
10396
event_loop: platform_impl::EventLoop::new(&mut self.platform_specific)?,
10497
_marker: PhantomData,
10598
})
10699
}
107-
108-
#[cfg(web_platform)]
109-
pub(crate) fn allow_event_loop_recreation() {
110-
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
111-
}
112100
}
113101

114102
impl EventLoop {

src/platform_impl/web/event_loop/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::atomic::{AtomicBool, Ordering};
2+
13
use winit_core::application::ApplicationHandler;
24
use winit_core::error::{EventLoopError, NotSupportedError};
35
use winit_core::event_loop::ActiveEventLoop as RootActiveEventLoop;
@@ -20,11 +22,22 @@ pub struct EventLoop {
2022
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
2123
pub(crate) struct PlatformSpecificEventLoopAttributes {}
2224

25+
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
26+
2327
impl EventLoop {
2428
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
29+
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
30+
// For better cross-platformness.
31+
return Err(EventLoopError::RecreationAttempt);
32+
}
33+
2534
Ok(EventLoop { elw: ActiveEventLoop::new() })
2635
}
2736

37+
fn allow_event_loop_recreation() {
38+
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
39+
}
40+
2841
pub fn run_app<A: ApplicationHandler>(self, app: A) -> ! {
2942
let app = Box::new(app);
3043

src/platform_impl/web/event_loop/runner.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use super::super::main_thread::MainThreadMarker;
2222
use super::super::monitor::MonitorHandler;
2323
use super::proxy::EventLoopProxy;
2424
use super::state::State;
25-
use super::{backend, ActiveEventLoop};
25+
use super::{backend, ActiveEventLoop, EventLoop};
2626
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
2727
use crate::platform_impl::platform::backend::{EventListenerHandle, SafeAreaHandle};
2828
use crate::platform_impl::platform::r#async::DispatchRunner;
@@ -773,7 +773,7 @@ impl Shared {
773773
// * The `register_redraw_request` closure.
774774
// * The `destroy_fn` closure.
775775
if self.0.event_loop_recreation.get() {
776-
crate::event_loop::EventLoopBuilder::allow_event_loop_recreation();
776+
EventLoop::allow_event_loop_recreation();
777777
}
778778
}
779779

winit-android/src/event_loop.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ const GLOBAL_WINDOW: WindowId = WindowId::from_raw(0);
128128

129129
impl EventLoop {
130130
pub fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
131+
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
132+
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
133+
// For better cross-platformness.
134+
return Err(EventLoopError::RecreationAttempt);
135+
}
136+
131137
let android_app = attributes.android_app.as_ref().expect(
132138
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
133139
Android",

winit-appkit/src/app_state.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl AppState {
5858
activation_policy: Option<NSApplicationActivationPolicy>,
5959
default_menu: bool,
6060
activate_ignoring_other_apps: bool,
61-
) -> Rc<Self> {
61+
) -> Option<Rc<Self>> {
6262
let event_loop_proxy = Arc::new(EventLoopProxy::new(mtm, move || {
6363
Self::get(mtm).with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
6464
}));
@@ -85,8 +85,7 @@ impl AppState {
8585
pending_redraw: RefCell::new(vec![]),
8686
});
8787

88-
GLOBAL.get(mtm).set(this.clone()).expect("application state can only be set once");
89-
this
88+
GLOBAL.get(mtm).set(this.clone()).ok().and(Some(this))
9089
}
9190

9291
pub fn get(mtm: MainThreadMarker) -> Rc<Self> {

winit-appkit/src/event_loop.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ impl EventLoop {
182182
activation_policy,
183183
attributes.default_menu,
184184
attributes.activate_ignoring_other_apps,
185-
);
185+
)
186+
.ok_or_else(|| EventLoopError::RecreationAttempt)?;
186187

187188
// Initialize the application (if it has not already been).
188189
let app = NSApplication::sharedApplication(mtm);

winit-core/src/error.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ pub enum EventLoopError {
1919
impl fmt::Display for EventLoopError {
2020
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2121
match self {
22-
Self::RecreationAttempt => write!(f, "EventLoop can't be recreated"),
22+
Self::RecreationAttempt => {
23+
write!(
24+
f,
25+
"EventLoop can't be recreated, only a single instance of it is supported (for \
26+
cross-platform compatibility)"
27+
)
28+
},
2329
Self::Os(err) => err.fmt(f),
2430
Self::ExitFailure(status) => write!(f, "Exit Failure: {status}"),
2531
Self::NotSupported(err) => err.fmt(f),

winit-orbital/src/event_loop.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cell::Cell;
22
use std::collections::VecDeque;
3+
use std::sync::atomic::{AtomicBool, Ordering};
34
use std::sync::{mpsc, Arc, Mutex};
45
use std::time::Instant;
56
use std::{iter, mem, slice};
@@ -280,6 +281,12 @@ pub struct EventLoop {
280281

281282
impl EventLoop {
282283
pub fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
284+
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
285+
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
286+
// For better cross-platformness.
287+
return Err(EventLoopError::RecreationAttempt);
288+
}
289+
283290
// NOTE: Create a channel which can hold only one event to automatically _squash_ user
284291
// events.
285292
let (user_events_sender, user_events_receiver) = mpsc::sync_channel(1);

winit-uikit/src/event_loop.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ impl EventLoop {
148148

149149
static mut SINGLETON_INIT: bool = false;
150150
unsafe {
151-
assert!(
152-
!SINGLETON_INIT,
153-
"Only one `EventLoop` is supported on iOS. `EventLoopProxy` might be helpful"
154-
);
151+
if SINGLETON_INIT {
152+
// Required, AppState is global state, and event loop can only be run once.
153+
return Err(EventLoopError::RecreationAttempt);
154+
}
155155
SINGLETON_INIT = true;
156156
}
157157

winit-wayland/src/event_loop/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::io::Result as IOResult;
55
use std::mem;
66
use std::os::fd::OwnedFd;
77
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
8-
use std::sync::atomic::Ordering;
8+
use std::sync::atomic::{AtomicBool, Ordering};
99
use std::sync::{Arc, Condvar, Mutex};
1010
use std::thread::JoinHandle;
1111
use std::time::{Duration, Instant};
@@ -80,6 +80,12 @@ pub struct EventLoop {
8080

8181
impl EventLoop {
8282
pub fn new() -> Result<EventLoop, EventLoopError> {
83+
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
84+
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
85+
// For better cross-platformness.
86+
return Err(EventLoopError::RecreationAttempt);
87+
}
88+
8389
let connection = Connection::connect_to_env().map_err(|err| os_error!(err))?;
8490

8591
let (globals, mut event_queue) =

0 commit comments

Comments
 (0)