Defer QPlatformWindow creation on setVisible(true) if parent hasn't been created

When a child QWindow is shown by calling setVisible(true), we don't need to
create the platform window immediately if the parent window hasn't been
created yet.

We defer creation until the parent is created, or we're re-parented into
a created parent or made top level.

This optimization is more important now that we create the full parent
hierarchy once we decide that we need to create a child QWindow.

Change-Id: Ia4f0430f0d3709a12f41f6473c1cea6b0ef3c9cd
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
This commit is contained in:
Tor Arne Vestbø 2015-10-16 16:41:34 +02:00
parent ac27f9a83e
commit 73c86fcb40
2 changed files with 83 additions and 13 deletions

View File

@ -406,13 +406,21 @@ void QWindowPrivate::create(bool recursive)
QObjectList childObjects = q->children();
for (int i = 0; i < childObjects.size(); i ++) {
QObject *object = childObjects.at(i);
if (object->isWindowType()) {
QWindow *window = static_cast<QWindow *>(object);
if (recursive)
window->d_func()->create(true);
if (window->d_func()->platformWindow)
window->d_func()->platformWindow->setParent(platformWindow);
}
if (!object->isWindowType())
continue;
QWindow *childWindow = static_cast<QWindow *>(object);
if (recursive)
childWindow->d_func()->create(recursive);
// The child may have had deferred creation due to this window not being created
// at the time setVisible was called, so we re-apply the visible state, which
// may result in creating the child, and emitting the appropriate signals.
if (childWindow->isVisible())
childWindow->setVisible(true);
if (QPlatformWindow *childPlatformWindow = childWindow->d_func()->platformWindow)
childPlatformWindow->setParent(this->platformWindow);
}
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
@ -477,14 +485,23 @@ void QWindow::setVisible(bool visible)
{
Q_D(QWindow);
if (d->visible == visible)
if (d->visible != visible) {
d->visible = visible;
emit visibleChanged(visible);
d->updateVisibility();
} else if (d->platformWindow) {
// Visibility hasn't changed, and the platform window is in sync
return;
d->visible = visible;
emit visibleChanged(visible);
d->updateVisibility();
}
if (!d->platformWindow)
create();
if (!d->platformWindow) {
// If we have a parent window, but the parent hasn't been created yet, we
// can defer creation until the parent is created or we're re-parented.
if (parent() && !parent()->handle())
return;
else
create();
}
if (visible) {
// remove posted quit events when showing a new window
@ -523,6 +540,7 @@ void QWindow::setVisible(bool visible)
if (visible && (d->hasCursor || QGuiApplication::overrideCursor()))
d->applyCursor();
#endif
d->platformWindow->setVisible(visible);
if (!visible) {
@ -619,6 +637,12 @@ void QWindow::setParent(QWindow *parent)
else
d->connectToScreen(newScreen);
// If we were set visible, but not created because we were a child, and we're now
// re-parented into a created parent, or to being a top level, we need re-apply the
// visibility state, which will also create.
if (isVisible() && (!parent || parent->handle()))
setVisible(true);
if (d->platformWindow) {
if (parent)
parent->create();

View File

@ -60,6 +60,7 @@ class tst_QWindow: public QObject
private slots:
void create();
void setParent();
void setVisible();
void eventOrderOnShow();
void resizeEventAfterResize();
void mapGlobal();
@ -186,6 +187,51 @@ void tst_QWindow::setParent()
QVERIFY2(f.handle(), "Making a created window a child of a non-created window should automatically create it");
}
void tst_QWindow::setVisible()
{
QWindow a;
QWindow b(&a);
a.setVisible(true);
QVERIFY2(!b.handle(), "Making a top level window visible doesn't create its children");
QVERIFY2(!b.isVisible(), "Making a top level window visible doesn't make its children visible");
QVERIFY(QTest::qWaitForWindowExposed(&a));
QWindow c;
QWindow d(&c);
d.setVisible(true);
QVERIFY2(!c.handle(), "Making a child window visible doesn't create parent window if parent is hidden");
QVERIFY2(!c.isVisible(), "Making a child window visible doesn't make its parent visible");
QVERIFY2(!d.handle(), "Making a child window visible doesn't create platform window if parent is hidden");
c.create();
QVERIFY(c.handle());
QVERIFY2(d.handle(), "Creating a parent window should automatically create children if they are visible");
QVERIFY2(!c.isVisible(), "Creating a parent window should not make it visible just because it has visible children");
QWindow e;
QWindow f(&e);
f.setVisible(true);
QVERIFY(!f.handle());
QVERIFY(!e.handle());
f.setParent(0);
QVERIFY2(f.handle(), "Making a visible but not created child window top level should create it");
QVERIFY(QTest::qWaitForWindowExposed(&f));
QWindow g;
QWindow h;
QWindow i(&g);
i.setVisible(true);
h.setVisible(true);
QVERIFY(QTest::qWaitForWindowExposed(&h));
QVERIFY(!i.handle());
QVERIFY(!g.handle());
QVERIFY(h.handle());
i.setParent(&h);
QVERIFY2(i.handle(), "Making a visible but not created child window child of a created window should create it");
QVERIFY(QTest::qWaitForWindowExposed(&i));
}
void tst_QWindow::mapGlobal()
{
QWindow a;