Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Defer window creation until UIApplicationMain on iOS #1121

Closed
wants to merge 2 commits into from
Closed

Defer window creation until UIApplicationMain on iOS #1121

wants to merge 2 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Aug 25, 2019

Fixes #1120

  • Tested on all platforms changed
  • Compilation warnings were addressed
  • cargo fmt has been run on this branch
  • Added an entry to CHANGELOG.md if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality
  • Updated feature matrix, if new features were added or implemented

@ghost ghost marked this pull request as ready for review August 26, 2019 12:37
@ghost
Copy link
Author

ghost commented Aug 26, 2019

r? @mtak-

@mtak-
Copy link
Contributor

mtak- commented Aug 28, 2019

Looking into this now. There's a lot of other changes here.

Copy link
Contributor

@mtak- mtak- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. I know it was not a small task.

I wonder if we should just panic during window creation if +[UIApplication sharedApplication] == nil. Basically nothing in UIKit is guaranteed to work correctly before UIApplicationMain has been called. In iOS 14 getting the mainScreen before UIApplicationMain could well break. We're trying to fight the platform too much IMO. All windows can just be created during or after StartCause::Init. This is what our code base naturally settled upon after working with winit on iOS for a while.

I'm pretty open to the window size/position changes, as the current situation isn't great. Mostly, I'd want "safe area" awareness to be something that the user opts into, and if they don't, then they get black bars around the safe area.

height: safe_area.size.height as _,
}
}
self.outer_size()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning behind this change?

I agree the current situation is not right, but this fix also isn't ideal. Safe area unaware apps should get the black-bar-under-notch effect that is so common in apps today. IIUC this code defaults to rendering under notches. I could be swayed, tho, that winit shouldn't attempt to solve that problem.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to address the reasoning behind this change in #1122. The return value of this function doesn't necessarily affect rendering. When resizing the swapchain, gfx-hal applications generally call compatibility and use the current_extent (which returns the bounds of the CAMetalLayer) instead of calling out to winit and using the inner_size of the window.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh. Missed that. I agree with everything in #1122. The more I think about the "black bar" solution, the more I think it's specific to CAMetalLayer and CAEAGLLayer. IIUC, UIKit views automatically respond to constraints set by the safe area by default.

Your fix here looks good to me.

assert!(
!view_controller.is_null(),
"Failed to create `UIViewController` instance"
);
let view_controller: id = msg_send![view_controller, init];
view_controller = msg_send![view_controller, init];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the random coding style change? I'm partial to the immutable version.

..
} => queued_windows.push(window),
// `UIApplicationMain` already called, so initialize immediately
_ => (*window).init(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init should be performed after drop(this). Otherwise we get panics stemming from double borrow_mut's on AppState.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also should be queuing up windows during the Launching state to preserve window creation order.

@@ -116,29 +97,36 @@ impl AppState {
RefMut::map(guard, |state| state.as_mut().unwrap())
}

// requires main thread and window is a UIWindow
// retains window
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment explaining why this function is/was unsafe would be good.

drop(this);
}

pub unsafe fn cancel_deferred_window_init(window: *mut WindowInner) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be unnecessary if appstate held onto std::rc::Weak<RefCell<WindowInner>>'s.

let () = msg_send![self.window, setBounds: bounds];
}
pub fn set_outer_position(&self, _position: LogicalPosition) {
warn!("`Window::set_outer_position` is ignored on iOS")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the reasoning behind this change? We can set window positions on iOS. I'm not sure we should remove support for that.

if self.window.is_null() {
view::frame_from_window_attributes(&self.window_attributes.borrow())
} else {
msg_send![self.window, frame]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What problems are solved by not using screen_frame here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that frame already returns the coordinates in screen-space, which would make screen_frame and its associated functions unnecessary, and hence reduce complexity.

if self.window.is_null() {
view::frame_from_window_attributes(&self.window_attributes.borrow())
} else {
msg_send![self.window, frame]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar question about why screen_frame is no longer used here.

@@ -1,6 +1,13 @@
# Unreleased

- On macOS, implement `run_return`.
- On iOS 13.0, fix `NSInternalInconsistencyException` upon touching the screen.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this bug simulator only?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can also reproduce this on my iPhone 6s.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Bummer

- On iOS, `Window::set_outer_position` is now ignored.
- On iOS, `WindowBuilder::with_inner_size` is now ignored (to match behaviour
`Window::set_inner_size`, and additionally when combined with `with_fullscreen` this used to
result in an incorrect size for the window).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*to match the behavior of

@mtak-
Copy link
Contributor

mtak- commented Aug 28, 2019

I am strongly in favor of asserting that there is a current UIApplication on window creation.

assert!(msg_send![class!(UIApplication), sharedApplication].is_null());

@mtak-
Copy link
Contributor

mtak- commented Aug 29, 2019

@Osspial What do you think of what I've suggested here? To summarize, iOS would not allow window creation (and eventually other things like getting monitor handles) until StartCause::Init has been sent out.

The current situation is that iOS implicitly requires a running eventloop for at least two things I'm aware of:

  • listing of the available monitors
  • creating UIWindows before iOS 13 worked, but now does not.

There are likely other things that don't work, and I'm concerned that this is a losing battle with UIKit. Apple is apparently happy to break UIKit code that is run before launch.

@ghost
Copy link
Author

ghost commented Aug 29, 2019

Thank you for the review! I know it wasn't the easiest thing to review, especially as I've combined two separate changes here. This was done just to keep me from rewriting the code twice over.

I am strongly in favor of asserting that there is a current UIApplication on window creation.

I tend to agree. We should probably just bite the bullet and not allow windows to be created before the event loop starts. It's simpler than having to track all of this state. The examples should be updated accordingly.

@ghost
Copy link
Author

ghost commented Aug 30, 2019

@Osspial I noticed there's no way to access available_monitors or primary_monitor inside the closure before a window is created, because the closure gets passed a EventLoopWindowTarget instead of a reference to the EventLoop. I'm curious as to why this is.

@Osspial
Copy link
Contributor

Osspial commented Sep 5, 2019

@aleksijuvani The main reason we expose EventLoopWindowTarget is because doing that makes it possible to implement our APIs on Linux (see #638 (comment)). We should be able to move the monitor listing functions to EventLoopWindowTarget, though.

@Osspial Osspial mentioned this pull request Sep 26, 2019
7 tasks
@ghost
Copy link
Author

ghost commented Oct 7, 2019

Closing due to #1120 (comment).

@ghost ghost closed this Oct 7, 2019
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

NSInternalInconsistencyException upon touching the screen on iOS 13.0
3 participants