iOS: Trigger manual layout of root view controller when coming out of background
When rotating the device when the application is in the background iOS will ask the root view controller to layout its views when then foregrounding the application, but at that point the application state is still in the suspended state, meaning we block any view resizing or rendering. To ensure the views are resized correctly, we trigger a manual layout after the application comes out of the suspended state. Task-number: QTBUG-67719 Change-Id: I1ef0a4133d4b94edaac7b0f3cb4e49e367eb76d4 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
a75f25a43f
commit
e0e1c7ec2d
@ -56,8 +56,8 @@ public:
|
|||||||
static Qt::ApplicationState toQtApplicationState(UIApplicationState state);
|
static Qt::ApplicationState toQtApplicationState(UIApplicationState state);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void applicationStateWillChange(Qt::ApplicationState);
|
void applicationStateWillChange(Qt::ApplicationState oldState, Qt::ApplicationState newState);
|
||||||
void applicationStateDidChange(Qt::ApplicationState);
|
void applicationStateDidChange(Qt::ApplicationState oldState, Qt::ApplicationState newState);
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -87,18 +87,18 @@ QIOSApplicationState::QIOSApplicationState()
|
|||||||
|
|
||||||
void QIOSApplicationState::handleApplicationStateChanged(UIApplicationState uiState, const QString &reason)
|
void QIOSApplicationState::handleApplicationStateChanged(UIApplicationState uiState, const QString &reason)
|
||||||
{
|
{
|
||||||
Qt::ApplicationState state = toQtApplicationState(uiState);
|
Qt::ApplicationState oldState = QGuiApplication::applicationState();
|
||||||
qCDebug(lcQpaApplication) << qPrintable(reason)
|
Qt::ApplicationState newState = toQtApplicationState(uiState);
|
||||||
<< "- moving from" << QGuiApplication::applicationState() << "to" << state;
|
qCDebug(lcQpaApplication) << qPrintable(reason) << "- moving from" << oldState << "to" << newState;
|
||||||
|
|
||||||
if (QIOSIntegration *integration = QIOSIntegration::instance()) {
|
if (QIOSIntegration *integration = QIOSIntegration::instance()) {
|
||||||
emit integration->applicationState.applicationStateWillChange(state);
|
emit integration->applicationState.applicationStateWillChange(oldState, newState);
|
||||||
QWindowSystemInterface::handleApplicationStateChanged(state);
|
QWindowSystemInterface::handleApplicationStateChanged(newState);
|
||||||
emit integration->applicationState.applicationStateDidChange(state);
|
emit integration->applicationState.applicationStateDidChange(oldState, newState);
|
||||||
qCDebug(lcQpaApplication) << "done moving to" << state;
|
qCDebug(lcQpaApplication) << "done moving to" << newState;
|
||||||
} else {
|
} else {
|
||||||
qCDebug(lcQpaApplication) << "no platform integration yet, setting state directly";
|
qCDebug(lcQpaApplication) << "no platform integration yet, setting state directly";
|
||||||
QGuiApplicationPrivate::applicationState = state;
|
QGuiApplicationPrivate::applicationState = newState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,29 +301,34 @@ bool QIOSContext::verifyGraphicsHardwareAvailability()
|
|||||||
static dispatch_once_t onceToken = 0;
|
static dispatch_once_t onceToken = 0;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState;
|
QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState;
|
||||||
connect(applicationState, &QIOSApplicationState::applicationStateWillChange, [](Qt::ApplicationState state) {
|
connect(applicationState, &QIOSApplicationState::applicationStateWillChange,
|
||||||
if (applicationBackgrounded && state != Qt::ApplicationSuspended) {
|
[](Qt::ApplicationState oldState, Qt::ApplicationState newState) {
|
||||||
qCDebug(lcQpaGLContext) << "app no longer backgrounded, rendering enabled";
|
Q_UNUSED(oldState);
|
||||||
applicationBackgrounded = false;
|
if (applicationBackgrounded && newState != Qt::ApplicationSuspended) {
|
||||||
|
qCDebug(lcQpaGLContext) << "app no longer backgrounded, rendering enabled";
|
||||||
|
applicationBackgrounded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
connect(applicationState, &QIOSApplicationState::applicationStateDidChange, [](Qt::ApplicationState state) {
|
connect(applicationState, &QIOSApplicationState::applicationStateDidChange,
|
||||||
if (state != Qt::ApplicationSuspended)
|
[](Qt::ApplicationState oldState, Qt::ApplicationState newState) {
|
||||||
return;
|
Q_UNUSED(oldState);
|
||||||
|
if (newState != Qt::ApplicationSuspended)
|
||||||
|
return;
|
||||||
|
|
||||||
qCDebug(lcQpaGLContext) << "app backgrounded, rendering disabled";
|
qCDebug(lcQpaGLContext) << "app backgrounded, rendering disabled";
|
||||||
applicationBackgrounded = true;
|
|
||||||
|
|
||||||
// By the time we receive this signal the application has moved into
|
// By the time we receive this signal the application has moved into
|
||||||
// Qt::ApplactionStateSuspended, and all windows have been obscured,
|
// Qt::ApplactionStateSuspended, and all windows have been obscured,
|
||||||
// which should stop all rendering. If there's still an active GL context,
|
// which should stop all rendering. If there's still an active GL context,
|
||||||
// we follow Apple's advice and call glFinish before making it inactive.
|
// we follow Apple's advice and call glFinish before making it inactive.
|
||||||
if (QOpenGLContext *currentContext = QOpenGLContext::currentContext()) {
|
if (QOpenGLContext *currentContext = QOpenGLContext::currentContext()) {
|
||||||
qCWarning(lcQpaGLContext) << "explicitly glFinishing and deactivating" << currentContext;
|
qCWarning(lcQpaGLContext) << "explicitly glFinishing and deactivating" << currentContext;
|
||||||
glFinish();
|
glFinish();
|
||||||
currentContext->doneCurrent();
|
currentContext->doneCurrent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (applicationBackgrounded) {
|
if (applicationBackgrounded) {
|
||||||
|
@ -62,6 +62,8 @@ public:
|
|||||||
QIOSIntegration();
|
QIOSIntegration();
|
||||||
~QIOSIntegration();
|
~QIOSIntegration();
|
||||||
|
|
||||||
|
void initialize() override;
|
||||||
|
|
||||||
bool hasCapability(Capability cap) const override;
|
bool hasCapability(Capability cap) const override;
|
||||||
|
|
||||||
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
|
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
|
||||||
|
@ -95,7 +95,10 @@ QIOSIntegration::QIOSIntegration()
|
|||||||
|
|
||||||
// Set current directory to app bundle folder
|
// Set current directory to app bundle folder
|
||||||
QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String]));
|
QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QIOSIntegration::initialize()
|
||||||
|
{
|
||||||
UIScreen *mainScreen = [UIScreen mainScreen];
|
UIScreen *mainScreen = [UIScreen mainScreen];
|
||||||
NSMutableArray *screens = [[[UIScreen screens] mutableCopy] autorelease];
|
NSMutableArray *screens = [[[UIScreen screens] mutableCopy] autorelease];
|
||||||
if (![screens containsObject:mainScreen]) {
|
if (![screens containsObject:mainScreen]) {
|
||||||
|
@ -273,6 +273,20 @@
|
|||||||
m_focusWindowChangeConnection = QObject::connect(qApp, &QGuiApplication::focusWindowChanged, [self]() {
|
m_focusWindowChangeConnection = QObject::connect(qApp, &QGuiApplication::focusWindowChanged, [self]() {
|
||||||
[self updateProperties];
|
[self updateProperties];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState;
|
||||||
|
QObject::connect(applicationState, &QIOSApplicationState::applicationStateDidChange,
|
||||||
|
[self](Qt::ApplicationState oldState, Qt::ApplicationState newState) {
|
||||||
|
if (oldState == Qt::ApplicationSuspended && newState != Qt::ApplicationSuspended) {
|
||||||
|
// We may have ignored an earlier layout because the application was suspended,
|
||||||
|
// and we didn't want to render anything at that moment in fear of being killed
|
||||||
|
// due to rendering in the background, so we trigger an explicit layout when
|
||||||
|
// coming out of the suspended state.
|
||||||
|
qCDebug(lcQpaWindow) << "triggering root VC layout when coming out of suspended state";
|
||||||
|
[self.view setNeedsLayout];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
Loading…
Reference in New Issue
Block a user