From 6e1851de9595d7e7abe9acdc8c473e792d24c4c2 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 11 Mar 2014 12:51:15 +0100 Subject: Static plugins: support loading static plugins from several engines When loading dynamic plugins, we register them as loaded so that we don't try to register their types several times if using several engines. The same was not done for static plugins. This patch will ensure that we follow the same logic also for static plugins. Task-number: QTBUG-36532 Change-Id: Icc1e089ae5d682c38b2d36bf4808f1c753c122a4 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/qml/qqmlengine.cpp | 2 +- src/qml/qml/qqmlimport.cpp | 64 +++++++++++++++++++++++++++++++++++++--------- src/qml/qml/qqmlimport_p.h | 8 +++--- 3 files changed, 58 insertions(+), 16 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 72de9845c8..d927a8c628 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1983,7 +1983,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths) bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList *errors) { Q_D(QQmlEngine); - return d->importDatabase.importPlugin(filePath, uri, QString(), errors); + return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), errors); } /*! diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 97f82a2e8d..cae8365598 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -191,7 +191,7 @@ void qmlClearEnginePlugins() QMutexLocker lock(&plugins->mutex); foreach (RegisteredPlugin plugin, plugins->values()) { QPluginLoader* loader = plugin.loader; - if (!loader->unload()) + if (loader && !loader->unload()) qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString())); delete loader; } @@ -911,7 +911,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); if (!resolvedFilePath.isEmpty()) { dynamicPluginsFound++; - if (!database->importPlugin(resolvedFilePath, uri, typeNamespace, errors)) { + if (!database->importDynamicPlugin(resolvedFilePath, uri, typeNamespace, errors)) { if (errors) { // XXX TODO: should we leave the import plugin error alone? // Here, we pop it off the top and coalesce it into this error's message. @@ -947,7 +947,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, if (versionUri == metaTagUri.toString()) { staticPluginsFound++; QObject *instance = pair.first.instance(); - if (!database->importPlugin(instance, basePath, uri, typeNamespace, true, errors)) { + if (!database->importStaticPlugin(instance, basePath, uri, typeNamespace, errors)) { if (errors) { QQmlError poppedError = errors->takeFirst(); QQmlError error; @@ -1820,12 +1820,11 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths) /*! \internal */ -bool QQmlImportDatabase::importPlugin(QObject *instance, const QString &basePath, - const QString &uri, const QString &typeNamespace, - bool initEngine, QList *errors) +bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &basePath, + const QString &uri, const QString &typeNamespace, QList *errors) { if (qmlImportTrace()) - qDebug().nospace() << "QQmlImportDatabase::importPluginInstance: " << uri << " from " << basePath; + qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath; QQmlTypesExtensionInterface *iface = qobject_cast(instance); if (!iface) { @@ -1894,20 +1893,61 @@ bool QQmlImportDatabase::importPlugin(QObject *instance, const QString &basePath return false; } - if (initEngine) { + return true; +} + +/*! + \internal +*/ +bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath, + const QString &uri, const QString &typeNamespace, QList *errors) +{ +#ifndef QT_NO_LIBRARY + // Dynamic plugins are differentiated by their filepath. For static plugins we + // don't have that information so we use their address as key instead. + QString uniquePluginID = QString().sprintf("%p", instance); + StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); + QMutexLocker lock(&plugins->mutex); + + // Plugin types are global across all engines and should only be + // registered once. But each engine still needs to be initialized. + bool typesRegistered = plugins->contains(uniquePluginID); + bool engineInitialized = initializedPlugins.contains(uniquePluginID); + + if (typesRegistered) { + Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri, + "QQmlImportDatabase::importStaticPlugin", + "Internal error: Static plugin imported previously with different uri"); + } else { + RegisteredPlugin plugin; + plugin.uri = uri; + plugin.loader = 0; + plugins->insert(uniquePluginID, plugin); + + if (!registerPluginTypes(instance, basePath, uri, typeNamespace, errors)) + return false; + } + + if (!engineInitialized) { + initializedPlugins.insert(uniquePluginID); + if (QQmlExtensionInterface *eiface = qobject_cast(instance)) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - ep->typeLoader.initializeEngine(eiface, moduleId); + ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData()); } } return true; +#else + return false; +#endif } /*! \internal */ -bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &uri, const QString &typeNamespace, QList *errors) +bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri, + const QString &typeNamespace, QList *errors) { #ifndef QT_NO_LIBRARY QFileInfo fileInfo(filePath); @@ -1920,7 +1960,7 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur if (typesRegistered) { Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri, - "QQmlImportDatabase::importPlugin", + "QQmlImportDatabase::importDynamicPlugin", "Internal error: Plugin imported previously with different uri"); } @@ -1961,7 +2001,7 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur plugins->insert(absoluteFilePath, plugin); // Continue with shared code path for dynamic and static plugins: - if (!importPlugin(instance, fileInfo.absolutePath(), uri, typeNamespace, false, errors)) + if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, errors)) return false; } diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index f19f5d4f34..b19e777852 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -151,7 +151,7 @@ public: QQmlImportDatabase(QQmlEngine *); ~QQmlImportDatabase(); - bool importPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, QList *errors); + bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, QList *errors); QStringList importPathList(PathType type = LocalOrRemote) const; void setImportPathList(const QStringList &paths); @@ -170,8 +170,10 @@ private: QString resolvePlugin(QQmlTypeLoader *typeLoader, const QString &qmldirPath, const QString &qmldirPluginPath, const QString &baseName); - bool importPlugin(QObject *instance, const QString &basePath, const QString &uri, - const QString &typeNamespace, bool initEngine, QList *errors); + bool importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri, + const QString &typeNamespace, QList *errors); + bool registerPluginTypes(QObject *instance, const QString &basePath, + const QString &uri, const QString &typeNamespace, QList *errors); struct QmldirCache { int versionMajor; -- cgit v1.2.3