iOS: Send updated expose events on application background/foregrounding

When an application has background processing enabled, for example for
communicating with an external accessory or getting location updates,
it might trigger code that does UI updates, which will kill the app as
doing UI in the background is not allowed on iOS.

We guard against this by propagating the backgrounding as updated expose
events with a non-exposed region and isExposed() returning false. This
means clients who correctly use QWindow::isExposed() to guard their
drawing code (including the scene-graph), will live to see another day.

Task-number: QTBUG-36956
Change-Id: Ib708394d33093affe68c9f2c7abde7e54be5ec74
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
This commit is contained in:
Tor Arne Vestbø 2014-04-24 15:33:20 +02:00 committed by The Qt Project
parent b619c35d85
commit a3634e4b2b
2 changed files with 28 additions and 5 deletions

View File

@ -88,6 +88,7 @@ public:
WId winId() const { return WId(m_view); };
private:
void applicationStateChanged(Qt::ApplicationState state);
void applyGeometry(const QRect &rect);
QUIView *m_view;

View File

@ -192,12 +192,25 @@
- (void)displayLayer:(CALayer *)layer
{
QSize bounds = fromCGRect(layer.bounds).toRect().size();
Q_UNUSED(layer);
Q_ASSERT(layer == self.layer);
Q_ASSERT(m_qioswindow->geometry().size() == bounds);
Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
[self sendUpdatedExposeEvent];
}
- (void)sendUpdatedExposeEvent
{
QRegion region;
if (m_qioswindow->isExposed()) {
QSize bounds = fromCGRect(self.layer.bounds).toRect().size();
Q_ASSERT(m_qioswindow->geometry().size() == bounds);
Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
region = QRect(QPoint(), bounds);
}
QRegion region = self.hidden ? QRegion() : QRect(QPoint(), bounds);
QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region);
QWindowSystemInterface::flushWindowSystemEvents();
}
@ -334,6 +347,8 @@ QIOSWindow::QIOSWindow(QWindow *window)
, m_view([[QUIView alloc] initWithQIOSWindow:this])
, m_windowLevel(0)
{
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged);
setParent(QPlatformWindow::parent());
// Resolve default window geometry in case it was not set before creating the
@ -471,7 +486,8 @@ void QIOSWindow::applyGeometry(const QRect &rect)
bool QIOSWindow::isExposed() const
{
return window()->isVisible() && !window()->geometry().isEmpty();
return qApp->applicationState() > Qt::ApplicationHidden
&& window()->isVisible() && !window()->geometry().isEmpty();
}
void QIOSWindow::setWindowState(Qt::WindowState state)
@ -593,6 +609,12 @@ void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientatio
[[UIApplication sharedApplication] setStatusBarOrientation:uiOrientation animated:NO];
}
void QIOSWindow::applicationStateChanged(Qt::ApplicationState)
{
if (window()->isExposed() != isExposed())
[m_view sendUpdatedExposeEvent];
}
qreal QIOSWindow::devicePixelRatio() const
{
return m_view.contentScaleFactor;