summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@pelagicore.com>2017-10-24 17:32:28 +0200
committerDominik Holland <dominik.holland@pelagicore.com>2017-11-03 10:13:12 +0000
commite2c4d58dcdd88e560506c8158f39b59ee10ddba7 (patch)
tree56e75ae02b2f6d5408bc62f53eeb827100cef63b /src
parenta2f468bd5a6774023b55007ab008cbd788f77387 (diff)
Fix single-process race condition when emitting windowReady
Make sure that the WindowManager::windowReady signal is only emitted after all QML Component.onCompleted handlers having been dealt with. Since Qt does not provide a suitable API for this, we need to hook into the low-level signal emission. Task-number: AUTOSUITE-134 Change-Id: I5ec4260aca7b4a505b48892dbc255f224e3559d7 Reviewed-by: Dominik Holland <dominik.holland@pelagicore.com>
Diffstat (limited to 'src')
-rw-r--r--src/manager-lib/fakeapplicationmanagerwindow.cpp35
-rw-r--r--src/manager-lib/fakeapplicationmanagerwindow.h4
-rw-r--r--src/manager-lib/manager-lib.pro2
3 files changed, 38 insertions, 3 deletions
diff --git a/src/manager-lib/fakeapplicationmanagerwindow.cpp b/src/manager-lib/fakeapplicationmanagerwindow.cpp
index ca0e96fa..546ee569 100644
--- a/src/manager-lib/fakeapplicationmanagerwindow.cpp
+++ b/src/manager-lib/fakeapplicationmanagerwindow.cpp
@@ -43,6 +43,9 @@
#include "fakeapplicationmanagerwindow.h"
#include "qmlinprocessruntime.h"
#include <QSGSimpleRectNode>
+#include <QQmlComponent>
+#include <private/qqmlcomponentattached_p.h>
+
QT_BEGIN_NAMESPACE_AM
@@ -182,8 +185,36 @@ void FakeApplicationManagerWindow::componentComplete()
prnt = prnt->parent();
}
- if (m_runtime && isVisible())
- m_runtime->addWindow(this);
+ // This part is scary, but we need to make sure that all Component.onComplete: handlers on
+ // the QML side have been run, before we hand this window over to the WindowManager for the
+ // onWindowReady signal. The problem here is that the C++ componentComplete() handler (this
+ // function) is called *before* the QML side, plus, to make matters worse, the QML incubator
+ // could switch back to the event loop a couple of times before finally calling the QML
+ // onCompleted handler(s).
+ // The workaround is to setup watchers for all Component.onCompleted handlers for this object
+ // and wait until the last of them has been dealt with, to finally call our addWindow
+ // function (we are also relying on the signal emission order, so that our lambda is called
+ // after the actual QML handler).
+
+ for (auto a = QQmlComponent::qmlAttachedProperties(this); a; a = a->next) {
+ auto famw = qobject_cast<FakeApplicationManagerWindow *>(a->parent());
+ if (!famw || famw != this)
+ continue;
+
+ m_attachedCompleteHandlers << a;
+
+ connect(a, &QQmlComponentAttached::completed, this, [this, a]() {
+ m_attachedCompleteHandlers.removeAll(a);
+
+ if (m_attachedCompleteHandlers.isEmpty())
+ onVisibleChanged();
+ });
+ }
+
+ // If we do not even have a single Component.onCompleted handler on the QML side, we need to
+ // show the window immediately.
+ if (m_attachedCompleteHandlers.isEmpty())
+ onVisibleChanged();
}
void FakeApplicationManagerWindow::onVisibleChanged()
diff --git a/src/manager-lib/fakeapplicationmanagerwindow.h b/src/manager-lib/fakeapplicationmanagerwindow.h
index 6ef41b2d..a526109b 100644
--- a/src/manager-lib/fakeapplicationmanagerwindow.h
+++ b/src/manager-lib/fakeapplicationmanagerwindow.h
@@ -45,6 +45,8 @@
#include <QQuickItem>
#include <QtAppManCommon/global.h>
+QT_FORWARD_DECLARE_CLASS(QQmlComponentAttached)
+
QT_BEGIN_NAMESPACE_AM
class QmlInProcessRuntime;
@@ -121,6 +123,8 @@ private:
QmlInProcessRuntime *m_runtime = nullptr;
QColor m_color;
+ QVector<QQmlComponentAttached *> m_attachedCompleteHandlers;
+
friend class QmlInProcessRuntime; // for setting the m_runtime member
};
diff --git a/src/manager-lib/manager-lib.pro b/src/manager-lib/manager-lib.pro
index f84f878d..221aa07d 100644
--- a/src/manager-lib/manager-lib.pro
+++ b/src/manager-lib/manager-lib.pro
@@ -5,7 +5,7 @@ MODULE = appman_manager
load(am-config)
QT = core network qml
-!headless:QT *= gui quick
+!headless:QT *= gui quick qml-private
qtHaveModule(dbus):QT *= dbus
QT_FOR_PRIVATE *= \
appman_common-private \