Merge pull request #11319 from jherico/async_qml_load_crash

Fix potential crash on asynchronous QML loads
This commit is contained in:
Chris Collins 2017-09-07 12:03:10 -07:00 committed by GitHub
commit 12d720805c
5 changed files with 39 additions and 36 deletions

View file

@ -7389,7 +7389,10 @@ void Application::updateDisplayMode() {
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
_displayPlugin = newDisplayPlugin; _displayPlugin = newDisplayPlugin;
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked); auto desktop = offscreenUi->getDesktop();
if (desktop) {
desktop->setProperty("repositionLocked", wasRepositionLocked);
}
} }
bool isHmd = _displayPlugin->isHmd(); bool isHmd = _displayPlugin->isHmd();

View file

@ -169,12 +169,14 @@ void LoginDialog::openUrl(const QString& url) const {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (tablet->getToolbarMode()) { if (tablet->getToolbarMode()) {
auto browser = offscreenUi->load("Browser.qml"); offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
browser->setProperty("url", url); newObject->setProperty("url", url);
});
} else { } else {
if (!hmd->getShouldShowTablet() && !qApp->isHMDMode()) { if (!hmd->getShouldShowTablet() && !qApp->isHMDMode()) {
auto browser = offscreenUi->load("Browser.qml"); offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
browser->setProperty("url", url); newObject->setProperty("url", url);
});
} else { } else {
tablet->gotoWebScreen(url); tablet->gotoWebScreen(url);
} }

View file

@ -554,20 +554,19 @@ void OffscreenUi::createDesktop(const QUrl& url) {
getSurfaceContext()->setContextProperty("DebugQML", QVariant(false)); getSurfaceContext()->setContextProperty("DebugQML", QVariant(false));
#endif #endif
_desktop = dynamic_cast<QQuickItem*>(load(url)); load(url, [=](QQmlContext* context, QObject* newObject) {
Q_ASSERT(_desktop); _desktop = static_cast<QQuickItem*>(newObject);
getSurfaceContext()->setContextProperty("desktop", _desktop); getSurfaceContext()->setContextProperty("desktop", _desktop);
_toolWindow = _desktop->findChild<QQuickItem*>("ToolWindow");
_toolWindow = _desktop->findChild<QQuickItem*>("ToolWindow"); _vrMenu = new VrMenu(this);
for (const auto& menuInitializer : _queuedMenuInitializers) {
menuInitializer(_vrMenu);
}
_vrMenu = new VrMenu(this); new KeyboardFocusHack();
for (const auto& menuInitializer : _queuedMenuInitializers) { connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
menuInitializer(_vrMenu); });
}
new KeyboardFocusHack();
connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
} }
QQuickItem* OffscreenUi::getDesktop() { QQuickItem* OffscreenUi::getDesktop() {

View file

@ -639,7 +639,7 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
_qmlContext->setBaseUrl(baseUrl); _qmlContext->setBaseUrl(baseUrl);
} }
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
qCWarning(uiLogging) << "Called load on a non-surface thread"; qCWarning(uiLogging) << "Called load on a non-surface thread";
} }
@ -662,32 +662,32 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext,
[this, qmlComponent, targetContext, f](QQmlComponent::Status) { [this, qmlComponent, targetContext, f](QQmlComponent::Status) {
finishQmlLoad(qmlComponent, targetContext, f); finishQmlLoad(qmlComponent, targetContext, f);
}); });
return nullptr; return;
} }
return finishQmlLoad(qmlComponent, targetContext, f); finishQmlLoad(qmlComponent, targetContext, f);
} }
QObject* OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
return load(qmlSource, true, f); load(qmlSource, true, f);
} }
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
return load(qmlSource, false, f); load(qmlSource, false, f);
} }
void OffscreenQmlSurface::clearCache() { void OffscreenQmlSurface::clearCache() {
_qmlContext->engine()->clearComponentCache(); _qmlContext->engine()->clearComponentCache();
} }
QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f) {
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (qmlComponent->isError()) { if (qmlComponent->isError()) {
for (const auto& error : qmlComponent->errors()) { for (const auto& error : qmlComponent->errors()) {
qCWarning(uiLogging) << error.url() << error.line() << error; qCWarning(uiLogging) << error.url() << error.line() << error;
} }
qmlComponent->deleteLater(); qmlComponent->deleteLater();
return nullptr; return;
} }
@ -700,7 +700,7 @@ QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlCon
qFatal("Unable to finish loading QML root"); qFatal("Unable to finish loading QML root");
} }
qmlComponent->deleteLater(); qmlComponent->deleteLater();
return nullptr; return;
} }
qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
@ -726,19 +726,19 @@ QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlCon
} }
// If we already have a root, just set a couple of flags and the ancestry // If we already have a root, just set a couple of flags and the ancestry
if (_rootItem) { if (newItem && _rootItem) {
// Allow child windows to be destroyed from JS // Allow child windows to be destroyed from JS
QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership);
newObject->setParent(_rootItem); newObject->setParent(_rootItem);
if (newItem) { if (newItem) {
newItem->setParentItem(_rootItem); newItem->setParentItem(_rootItem);
} }
return newObject; return;
} }
if (!newItem) { if (!newItem) {
qFatal("Could not load object as root item"); qFatal("Could not load object as root item");
return nullptr; return;
} }
connect(newItem, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(QVariant))); connect(newItem, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(QVariant)));
@ -747,7 +747,6 @@ QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlCon
_rootItem = newItem; _rootItem = newItem;
_rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setParentItem(_quickWindow->contentItem());
_rootItem->setSize(_quickWindow->renderTargetSize()); _rootItem->setSize(_quickWindow->renderTargetSize());
return _rootItem;
} }
void OffscreenQmlSurface::updateQuick() { void OffscreenQmlSurface::updateQuick() {

View file

@ -50,10 +50,10 @@ public:
void resize(const QSize& size, bool forceResize = false); void resize(const QSize& size, bool forceResize = false);
QSize size() const; QSize size() const;
Q_INVOKABLE QObject* load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}); Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
Q_INVOKABLE QObject* loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}); Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}); Q_INVOKABLE void load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) { Q_INVOKABLE void load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) {
return load(QUrl(qmlSourceFile), f); return load(QUrl(qmlSourceFile), f);
} }
void clearCache(); void clearCache();
@ -120,7 +120,7 @@ protected:
private: private:
static QOpenGLContext* getSharedContext(); static QOpenGLContext* getSharedContext();
QObject* finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f); void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f);
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
void setupFbo(); void setupFbo();
bool allowNewFrame(uint8_t fps); bool allowNewFrame(uint8_t fps);