diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 9716adc880..c4923bdf07 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -3,15 +3,6 @@ //! Winit has an OS requirement of iOS 8 or higher, and is regularly tested on //! iOS 9.3. //! -//! ## Window initialization -//! -//! iOS's main `UIApplicationMain` does some init work that's required by all -//! UI-related code (see issue [#1705]). It is best to create your windows -//! inside [`ApplicationHandler::resumed`]. -//! -//! [#1705]: https://github.com/rust-windowing/winit/issues/1705 -//! [`ApplicationHandler::resumed`]: crate::application::ApplicationHandler::resumed -//! //! ## Building app //! //! To build ios app you will need rustc built for this targets: diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 88de5cf212..9aeb0940ba 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -3,20 +3,6 @@ //! Winit has an OS requirement of macOS 10.11 or higher (same as Rust //! itself), and is regularly tested on macOS 10.14. //! -//! ## Window initialization -//! -//! A lot of functionality expects the application to be ready before you -//! start doing anything; this includes creating windows, fetching monitors, -//! drawing, and so on, see issues [#2238], [#2051] and [#2087]. -//! -//! If you encounter problems, you should try doing your initialization inside -//! [`ApplicationHandler::resumed`]. -//! -//! [#2238]: https://github.com/rust-windowing/winit/issues/2238 -//! [#2051]: https://github.com/rust-windowing/winit/issues/2051 -//! [#2087]: https://github.com/rust-windowing/winit/issues/2087 -//! [`ApplicationHandler::resumed`]: crate::application::ApplicationHandler::resumed -//! //! ## Custom `NSApplicationDelegate` //! //! Winit usually handles everything related to the lifecycle events of the application. Sometimes, diff --git a/src/platform_impl/apple/appkit/app_state.rs b/src/platform_impl/apple/appkit/app_state.rs index f65fb8b4ef..1b68717378 100644 --- a/src/platform_impl/apple/appkit/app_state.rs +++ b/src/platform_impl/apple/appkit/app_state.rs @@ -115,7 +115,6 @@ impl AppState { // menu bar is initially unresponsive on macOS 10.15. app.setActivationPolicy(self.activation_policy); - window_activation_hack(&app); #[allow(deprecated)] app.activateIgnoringOtherApps(self.activate_ignoring_other_apps); @@ -387,26 +386,3 @@ impl AppState { fn min_timeout(a: Option, b: Option) -> Option { a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))) } - -/// A hack to make activation of multiple windows work when creating them before -/// `applicationDidFinishLaunching:` / `Event::Event::NewEvents(StartCause::Init)`. -/// -/// Alternative to this would be the user calling `window.set_visible(true)` in -/// `StartCause::Init`. -/// -/// If this becomes too bothersome to maintain, it can probably be removed -/// without too much damage. -fn window_activation_hack(app: &NSApplication) { - // TODO: Proper ordering of the windows - app.windows().into_iter().for_each(|window| { - // Call `makeKeyAndOrderFront` if it was called on the window in `WinitWindow::new` - // This way we preserve the user's desired initial visibility status - // TODO: Also filter on the type/"level" of the window, and maybe other things? - if window.isVisible() { - tracing::trace!("Activating visible window"); - window.makeKeyAndOrderFront(None); - } else { - tracing::trace!("Skipping activating invisible window"); - } - }) -} diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index a38cd0af51..6e58171952 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -558,6 +558,11 @@ fn new_window( masks |= NSWindowStyleMask::FullSizeContentView; } + // NOTE: This should only be created after the application has started launching, + // (`applicationWillFinishLaunching:` at the earliest), otherwise you'll run into very + // confusing issues with the window not being properly activated. + // + // Winit ensures this by not allowing access to `ActiveEventLoop` before handling events. let window: Option> = unsafe { msg_send_id![ super(mtm.alloc().set_ivars(())), diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index 3b9201e886..376f30b827 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -15,8 +15,7 @@ use core_foundation::runloop::{ CFRunLoopTimerInvalidate, CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, }; use objc2::rc::Retained; -use objc2::runtime::AnyObject; -use objc2::{msg_send, sel}; +use objc2::sel; use objc2_foundation::{ CGRect, CGSize, MainThreadMarker, NSInteger, NSObjectProtocol, NSOperatingSystemVersion, NSProcessInfo, @@ -114,7 +113,6 @@ impl Event { #[must_use = "dropping `AppStateImpl` without inspecting it is probably a bug"] enum AppStateImpl { Initial { - queued_windows: Vec>, queued_events: Vec, queued_gpu_redraws: HashSet>, }, @@ -160,7 +158,6 @@ impl AppState { let waker = EventLoopWaker::new(unsafe { CFRunLoopGetMain() }); **guard = Some(AppState { app_state: Some(AppStateImpl::Initial { - queued_windows: Vec::new(), queued_events: Vec::new(), queued_gpu_redraws: HashSet::new(), }), @@ -219,12 +216,10 @@ impl AppState { matches!(self.state(), AppStateImpl::Terminated) } - fn did_finish_launching_transition( - &mut self, - ) -> (Vec>, Vec) { - let (windows, events, queued_gpu_redraws) = match self.take_state() { - AppStateImpl::Initial { queued_windows, queued_events, queued_gpu_redraws } => { - (queued_windows, queued_events, queued_gpu_redraws) + fn did_finish_launching_transition(&mut self) -> Vec { + let (events, queued_gpu_redraws) = match self.take_state() { + AppStateImpl::Initial { queued_events, queued_gpu_redraws } => { + (queued_events, queued_gpu_redraws) }, s => bug!("unexpected state {:?}", s), }; @@ -232,7 +227,7 @@ impl AppState { active_control_flow: self.control_flow, queued_gpu_redraws, }); - (windows, events) + events } fn wakeup_transition(&mut self) -> Option { @@ -393,26 +388,6 @@ impl AppState { } } -pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Retained) { - let mut this = AppState::get_mut(mtm); - match this.state_mut() { - &mut AppStateImpl::Initial { ref mut queued_windows, .. } => { - return queued_windows.push(window.clone()) - }, - &mut AppStateImpl::ProcessingEvents { .. } - | &mut AppStateImpl::InUserCallback { .. } - | &mut AppStateImpl::ProcessingRedraws { .. } => {}, - s @ &mut AppStateImpl::Waiting { .. } | s @ &mut AppStateImpl::PollFinished { .. } => { - bug!("unexpected state {:?}", s) - }, - &mut AppStateImpl::Terminated => { - panic!("Attempt to create a `Window` after the app has terminated") - }, - } - drop(this); - window.makeKeyAndVisible(); -} - pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Retained) { let mut this = AppState::get_mut(mtm); match this.state_mut() { @@ -436,39 +411,13 @@ pub(crate) fn launch(mtm: MainThreadMarker, app: &mut dyn ApplicationHandler, ru pub fn did_finish_launching(mtm: MainThreadMarker) { let mut this = AppState::get_mut(mtm); - let windows = match this.state_mut() { - AppStateImpl::Initial { queued_windows, .. } => mem::take(queued_windows), - s => bug!("unexpected state {:?}", s), - }; this.waker.start(); // have to drop RefMut because the window setup code below can trigger new events drop(this); - for window in windows { - // Do a little screen dance here to account for windows being created before - // `UIApplicationMain` is called. This fixes visual issues such as being - // offcenter and sized incorrectly. Additionally, to fix orientation issues, we - // gotta reset the `rootViewController`. - // - // relevant iOS log: - // ``` - // [ApplicationLifecycle] Windows were created before application initialization - // completed. This may result in incorrect visual appearance. - // ``` - let screen = window.screen(); - let _: () = unsafe { msg_send![&window, setScreen: ptr::null::()] }; - window.setScreen(&screen); - - let controller = window.rootViewController(); - window.setRootViewController(None); - window.setRootViewController(controller.as_deref()); - - window.makeKeyAndVisible(); - } - - let (windows, events) = AppState::get_mut(mtm).did_finish_launching_transition(); + let events = AppState::get_mut(mtm).did_finish_launching_transition(); let events = [ EventWrapper::StaticEvent(Event::NewEvents(StartCause::Init)), @@ -477,12 +426,6 @@ pub fn did_finish_launching(mtm: MainThreadMarker) { .into_iter() .chain(events); handle_nonuser_events(mtm, events); - - // the above window dance hack, could possibly trigger new windows to be created. - // we can just set those windows up normally, as they were created after didFinishLaunching - for window in windows { - window.makeKeyAndVisible(); - } } // AppState::did_finish_launching handles the special transition `Init` diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index d60e79afe5..c96c1a35f6 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -78,6 +78,11 @@ impl WinitUIWindow { frame: CGRect, view_controller: &UIViewController, ) -> Retained { + // NOTE: This should only be created after the application has started launching, + // (`application:willFinishLaunchingWithOptions:` at the earliest), otherwise you'll run + // into very confusing issues with the window not being properly activated. + // + // Winit ensures this by not allowing access to `ActiveEventLoop` before handling events. let this: Retained = unsafe { msg_send_id![mtm.alloc(), initWithFrame: frame] }; this.setRootViewController(Some(view_controller)); @@ -490,8 +495,7 @@ impl Window { let view_controller = WinitViewController::new(mtm, &window_attributes, &view); let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller); - - app_state::set_key_window(mtm, &window); + window.makeKeyAndVisible(); // Like the Windows and macOS backends, we send a `ScaleFactorChanged` and `Resized` // event on window creation if the DPI factor != 1.0