macOS/iOS: Remove window activation hacks (#3872)
No longer necessary aftera8c7109andfacb809.
This commit is contained in:
parent
a61e7bb4f4
commit
6c4da19197
6 changed files with 18 additions and 113 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<Instant>, b: Option<Instant>) -> Option<Instant> {
|
||||
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");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Retained<WinitWindow>> = unsafe {
|
||||
msg_send_id![
|
||||
super(mtm.alloc().set_ivars(())),
|
||||
|
|
|
|||
|
|
@ -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<Retained<WinitUIWindow>>,
|
||||
queued_events: Vec<EventWrapper>,
|
||||
queued_gpu_redraws: HashSet<Retained<WinitUIWindow>>,
|
||||
},
|
||||
|
|
@ -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<Retained<WinitUIWindow>>, Vec<EventWrapper>) {
|
||||
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<EventWrapper> {
|
||||
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<EventWrapper> {
|
||||
|
|
@ -393,26 +388,6 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Retained<WinitUIWindow>) {
|
||||
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<WinitUIWindow>) {
|
||||
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::<AnyObject>()] };
|
||||
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`
|
||||
|
|
|
|||
|
|
@ -78,6 +78,11 @@ impl WinitUIWindow {
|
|||
frame: CGRect,
|
||||
view_controller: &UIViewController,
|
||||
) -> Retained<Self> {
|
||||
// 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<Self> = 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue