chore: move event loop recreation check into backends themselves
This commit is contained in:
parent
5f2c7350e9
commit
8ad016362a
12 changed files with 64 additions and 25 deletions
|
|
@ -11,7 +11,6 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
#[cfg(any(x11_platform, wayland_platform))]
|
#[cfg(any(x11_platform, wayland_platform))]
|
||||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
|
use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
|
||||||
pub use winit_core::event_loop::*;
|
pub use winit_core::event_loop::*;
|
||||||
|
|
@ -53,8 +52,6 @@ pub struct EventLoopBuilder {
|
||||||
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
|
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
impl EventLoopBuilder {
|
impl EventLoopBuilder {
|
||||||
/// Builds a new event loop.
|
/// Builds a new event loop.
|
||||||
///
|
///
|
||||||
|
|
@ -93,10 +90,6 @@ impl EventLoopBuilder {
|
||||||
pub fn build(&mut self) -> Result<EventLoop, EventLoopError> {
|
pub fn build(&mut self) -> Result<EventLoop, EventLoopError> {
|
||||||
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
|
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
|
||||||
|
|
||||||
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
|
||||||
return Err(EventLoopError::RecreationAttempt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Certain platforms accept a mutable reference in their API.
|
// Certain platforms accept a mutable reference in their API.
|
||||||
#[allow(clippy::unnecessary_mut_passed)]
|
#[allow(clippy::unnecessary_mut_passed)]
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
|
|
@ -104,11 +97,6 @@ impl EventLoopBuilder {
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(web_platform)]
|
|
||||||
pub(crate) fn allow_event_loop_recreation() {
|
|
||||||
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use winit_core::application::ApplicationHandler;
|
use winit_core::application::ApplicationHandler;
|
||||||
use winit_core::error::{EventLoopError, NotSupportedError};
|
use winit_core::error::{EventLoopError, NotSupportedError};
|
||||||
use winit_core::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
use winit_core::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
||||||
|
|
@ -20,11 +22,22 @@ pub struct EventLoop {
|
||||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||||
|
|
||||||
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||||
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
// For better cross-platformness.
|
||||||
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(EventLoop { elw: ActiveEventLoop::new() })
|
Ok(EventLoop { elw: ActiveEventLoop::new() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn allow_event_loop_recreation() {
|
||||||
|
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(self, app: A) -> ! {
|
pub fn run_app<A: ApplicationHandler>(self, app: A) -> ! {
|
||||||
let app = Box::new(app);
|
let app = Box::new(app);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use super::super::main_thread::MainThreadMarker;
|
||||||
use super::super::monitor::MonitorHandler;
|
use super::super::monitor::MonitorHandler;
|
||||||
use super::proxy::EventLoopProxy;
|
use super::proxy::EventLoopProxy;
|
||||||
use super::state::State;
|
use super::state::State;
|
||||||
use super::{backend, ActiveEventLoop};
|
use super::{backend, ActiveEventLoop, EventLoop};
|
||||||
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
|
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
|
||||||
use crate::platform_impl::platform::backend::{EventListenerHandle, SafeAreaHandle};
|
use crate::platform_impl::platform::backend::{EventListenerHandle, SafeAreaHandle};
|
||||||
use crate::platform_impl::platform::r#async::DispatchRunner;
|
use crate::platform_impl::platform::r#async::DispatchRunner;
|
||||||
|
|
@ -773,7 +773,7 @@ impl Shared {
|
||||||
// * The `register_redraw_request` closure.
|
// * The `register_redraw_request` closure.
|
||||||
// * The `destroy_fn` closure.
|
// * The `destroy_fn` closure.
|
||||||
if self.0.event_loop_recreation.get() {
|
if self.0.event_loop_recreation.get() {
|
||||||
crate::event_loop::EventLoopBuilder::allow_event_loop_recreation();
|
EventLoop::allow_event_loop_recreation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,12 @@ const GLOBAL_WINDOW: WindowId = WindowId::from_raw(0);
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
pub fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
pub fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||||
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
// For better cross-platformness.
|
||||||
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
let android_app = attributes.android_app.as_ref().expect(
|
let android_app = attributes.android_app.as_ref().expect(
|
||||||
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
|
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
|
||||||
Android",
|
Android",
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ impl AppState {
|
||||||
activation_policy: Option<NSApplicationActivationPolicy>,
|
activation_policy: Option<NSApplicationActivationPolicy>,
|
||||||
default_menu: bool,
|
default_menu: bool,
|
||||||
activate_ignoring_other_apps: bool,
|
activate_ignoring_other_apps: bool,
|
||||||
) -> Rc<Self> {
|
) -> Option<Rc<Self>> {
|
||||||
let event_loop_proxy = Arc::new(EventLoopProxy::new(mtm, move || {
|
let event_loop_proxy = Arc::new(EventLoopProxy::new(mtm, move || {
|
||||||
Self::get(mtm).with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
|
Self::get(mtm).with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
|
||||||
}));
|
}));
|
||||||
|
|
@ -85,8 +85,7 @@ impl AppState {
|
||||||
pending_redraw: RefCell::new(vec![]),
|
pending_redraw: RefCell::new(vec![]),
|
||||||
});
|
});
|
||||||
|
|
||||||
GLOBAL.get(mtm).set(this.clone()).expect("application state can only be set once");
|
GLOBAL.get(mtm).set(this.clone()).ok().and(Some(this))
|
||||||
this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(mtm: MainThreadMarker) -> Rc<Self> {
|
pub fn get(mtm: MainThreadMarker) -> Rc<Self> {
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,8 @@ impl EventLoop {
|
||||||
activation_policy,
|
activation_policy,
|
||||||
attributes.default_menu,
|
attributes.default_menu,
|
||||||
attributes.activate_ignoring_other_apps,
|
attributes.activate_ignoring_other_apps,
|
||||||
);
|
)
|
||||||
|
.ok_or_else(|| EventLoopError::RecreationAttempt)?;
|
||||||
|
|
||||||
// Initialize the application (if it has not already been).
|
// Initialize the application (if it has not already been).
|
||||||
let app = NSApplication::sharedApplication(mtm);
|
let app = NSApplication::sharedApplication(mtm);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,13 @@ pub enum EventLoopError {
|
||||||
impl fmt::Display for EventLoopError {
|
impl fmt::Display for EventLoopError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::RecreationAttempt => write!(f, "EventLoop can't be recreated"),
|
Self::RecreationAttempt => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"EventLoop can't be recreated, only a single instance of it is supported (for \
|
||||||
|
cross-platform compatibility)"
|
||||||
|
)
|
||||||
|
},
|
||||||
Self::Os(err) => err.fmt(f),
|
Self::Os(err) => err.fmt(f),
|
||||||
Self::ExitFailure(status) => write!(f, "Exit Failure: {status}"),
|
Self::ExitFailure(status) => write!(f, "Exit Failure: {status}"),
|
||||||
Self::NotSupported(err) => err.fmt(f),
|
Self::NotSupported(err) => err.fmt(f),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{mpsc, Arc, Mutex};
|
use std::sync::{mpsc, Arc, Mutex};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::{iter, mem, slice};
|
use std::{iter, mem, slice};
|
||||||
|
|
@ -280,6 +281,12 @@ pub struct EventLoop {
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
pub fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
pub fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||||
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
// For better cross-platformness.
|
||||||
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Create a channel which can hold only one event to automatically _squash_ user
|
// NOTE: Create a channel which can hold only one event to automatically _squash_ user
|
||||||
// events.
|
// events.
|
||||||
let (user_events_sender, user_events_receiver) = mpsc::sync_channel(1);
|
let (user_events_sender, user_events_receiver) = mpsc::sync_channel(1);
|
||||||
|
|
|
||||||
|
|
@ -148,10 +148,10 @@ impl EventLoop {
|
||||||
|
|
||||||
static mut SINGLETON_INIT: bool = false;
|
static mut SINGLETON_INIT: bool = false;
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(
|
if SINGLETON_INIT {
|
||||||
!SINGLETON_INIT,
|
// Required, AppState is global state, and event loop can only be run once.
|
||||||
"Only one `EventLoop` is supported on iOS. `EventLoopProxy` might be helpful"
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
);
|
}
|
||||||
SINGLETON_INIT = true;
|
SINGLETON_INIT = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::io::Result as IOResult;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::fd::OwnedFd;
|
use std::os::fd::OwnedFd;
|
||||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
use std::thread::JoinHandle;
|
use std::thread::JoinHandle;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
@ -80,6 +80,12 @@ pub struct EventLoop {
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
pub fn new() -> Result<EventLoop, EventLoopError> {
|
pub fn new() -> Result<EventLoop, EventLoopError> {
|
||||||
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
// For better cross-platformness.
|
||||||
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
let connection = Connection::connect_to_env().map_err(|err| os_error!(err))?;
|
let connection = Connection::connect_to_env().map_err(|err| os_error!(err))?;
|
||||||
|
|
||||||
let (globals, mut event_queue) =
|
let (globals, mut event_queue) =
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use std::cell::Cell;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::os::windows::io::{AsRawHandle as _, FromRawHandle as _, OwnedHandle, RawHandle};
|
use std::os::windows::io::{AsRawHandle as _, FromRawHandle as _, OwnedHandle, RawHandle};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||||
use std::sync::{Arc, LazyLock, Mutex, MutexGuard};
|
use std::sync::{Arc, LazyLock, Mutex, MutexGuard};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{fmt, mem, panic, ptr};
|
use std::{fmt, mem, panic, ptr};
|
||||||
|
|
@ -195,6 +195,12 @@ impl EventLoop {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
attributes: &mut PlatformSpecificEventLoopAttributes,
|
attributes: &mut PlatformSpecificEventLoopAttributes,
|
||||||
) -> Result<Self, EventLoopError> {
|
) -> Result<Self, EventLoopError> {
|
||||||
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
// For better cross-platformness.
|
||||||
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
let thread_id = unsafe { GetCurrentThreadId() };
|
let thread_id = unsafe { GetCurrentThreadId() };
|
||||||
|
|
||||||
if !attributes.any_thread && thread_id != main_thread_id() {
|
if !attributes.any_thread && thread_id != main_thread_id() {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use std::mem::MaybeUninit;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
|
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
|
||||||
use std::sync::{Arc, LazyLock, Mutex, Weak};
|
use std::sync::{Arc, LazyLock, Mutex, Weak};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
@ -207,6 +208,12 @@ struct EventLoopState {
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
pub fn new() -> Result<EventLoop, EventLoopError> {
|
pub fn new() -> Result<EventLoop, EventLoopError> {
|
||||||
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
// Required?
|
||||||
|
return Err(EventLoopError::RecreationAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
|
let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
|
||||||
Ok(xconn) => xconn.clone(),
|
Ok(xconn) => xconn.clone(),
|
||||||
Err(err) => return Err(os_error!(err.clone()).into()),
|
Err(err) => return Err(os_error!(err.clone()).into()),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue