diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index c072ea67fb4..116243ede39 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -957,6 +957,7 @@ void PluginManagerPrivate::nextDelayedInitialize() break; // do next delayedInitialize after a delay } if (delayedInitializeQueue.empty()) { + Utils::setMimeStartupPhase(MimeStartupPhase::UpAndRunning); m_isInitializationDone = true; delete delayedInitializeTimer; delayedInitializeTimer = nullptr; @@ -1370,7 +1371,6 @@ void PluginManagerPrivate::loadPlugins() loadPlugin(spec, PluginSpec::Initialized); } - Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing); { NANOTRACE_SCOPE("ExtensionSystem", "ExtensionsInitialized"); Utils::reverseForeach(queue, [this](PluginSpec *spec) { @@ -1384,8 +1384,8 @@ void PluginManagerPrivate::loadPlugins() }); } emit q->pluginsChanged(); - Utils::setMimeStartupPhase(MimeStartupPhase::UpAndRunning); + Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing); delayedInitializeTimer = new QTimer; delayedInitializeTimer->setInterval(DELAYED_INITIALIZE_INTERVAL); delayedInitializeTimer->setSingleShot(true); diff --git a/src/libs/utils/mimetypes2/mimedatabase.cpp b/src/libs/utils/mimetypes2/mimedatabase.cpp index b4966a952dd..60f3fbf0db5 100644 --- a/src/libs/utils/mimetypes2/mimedatabase.cpp +++ b/src/libs/utils/mimetypes2/mimedatabase.cpp @@ -562,12 +562,9 @@ MimeDatabase::~MimeDatabase() */ MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const { + d->checkInitPhase(nameOrAlias); QMutexLocker locker(&d->mutex); - if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) - qWarning("Accessing MimeDatabase for %s before plugins are initialized", - qPrintable(nameOrAlias)); - return d->mimeTypeForName(nameOrAlias); } @@ -601,12 +598,9 @@ MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const */ MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const { + d->checkInitPhase(fileInfo.filePath()); QMutexLocker locker(&d->mutex); - if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) - qWarning("Accessing MimeDatabase for %s before plugins are initialized", - qPrintable(fileInfo.filePath())); - if (fileInfo.isDir()) return d->mimeTypeForName(QLatin1String("inode/directory")); @@ -659,12 +653,9 @@ MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) const { if (mode == MatchExtension) { + d->checkInitPhase(fileName); QMutexLocker locker(&d->mutex); - if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) - qWarning("Accessing MimeDatabase for %s before plugins are initialized", - qPrintable(fileName)); - const QStringList matches = d->mimeTypeForFileName(fileName); const int matchCount = matches.count(); if (matchCount == 0) { @@ -696,12 +687,9 @@ MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) */ QList MimeDatabase::mimeTypesForFileName(const QString &fileName) const { + d->checkInitPhase(fileName); QMutexLocker locker(&d->mutex); - if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) - qWarning("Accessing MimeDatabase for %s before plugins are initialized", - qPrintable(fileName)); - const QStringList matches = d->mimeTypeForFileName(fileName); QList mimes; mimes.reserve(matches.count()); @@ -731,11 +719,9 @@ QString MimeDatabase::suffixForFileName(const QString &fileName) const */ MimeType MimeDatabase::mimeTypeForData(const QByteArray &data) const { + d->checkInitPhase("data"); QMutexLocker locker(&d->mutex); - if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) - qWarning("Accessing MimeDatabase for data before plugins are initialized"); - int accuracy = 0; return d->findByData(data, &accuracy); } @@ -863,11 +849,9 @@ MimeType MimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, const */ QList MimeDatabase::allMimeTypes() const { + d->checkInitPhase("all mime types"); QMutexLocker locker(&d->mutex); - if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) - qWarning("Accessing MimeDatabase for all mime types before plugins are initialized"); - return d->allMimeTypes(); } @@ -924,4 +908,27 @@ void MimeDatabasePrivate::setGlobPatternsForMimeType(const MimeType &mimeType, } } +void MimeDatabasePrivate::checkInitPhase(const QString &info) +{ + QReadLocker locker(&m_initMutex); + if (m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) { + qWarning("Accessing MimeDatabase for %s before plugins are initialized", qPrintable(info)); + return; + } + // run initialization functions and ensure providers are loaded + // the initializers will call other MIME database functions which "checkInitPhase" again, + // so make sure not to recurse + if (!m_initialized.exchange(true)) { + for (const std::function &f : m_initializers) + f(); + QMutexLocker locker(&mutex); + providers(); + } +} + +void MimeDatabasePrivate::addInitializer(const std::function &init) +{ + m_initializers.append(init); +} + } // namespace Utils diff --git a/src/libs/utils/mimetypes2/mimedatabase_p.h b/src/libs/utils/mimetypes2/mimedatabase_p.h index 8709b2918eb..c816a5c0e5b 100644 --- a/src/libs/utils/mimetypes2/mimedatabase_p.h +++ b/src/libs/utils/mimetypes2/mimedatabase_p.h @@ -25,8 +25,11 @@ #include #include -#include +#include + +#include #include +#include QT_BEGIN_NAMESPACE class QIODevice; @@ -75,6 +78,8 @@ public: void setMagicRulesForMimeType(const MimeType &mimeType, const QMap> &rules); void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns); + void checkInitPhase(const QString &info); + void addInitializer(const std::function &init); private: using Providers = std::vector>; @@ -86,6 +91,7 @@ private: QElapsedTimer m_lastCheck; // added for Qt Creator + QList> m_initializers; QHash m_additionalData; // id -> data bool m_forceLoad = true; @@ -94,6 +100,8 @@ public: QMutex mutex; // added for Qt Creator + QReadWriteLock m_initMutex; + std::atomic_bool m_initialized = false; int m_startupPhase = 0; }; diff --git a/src/libs/utils/mimetypes2/mimeutils.cpp b/src/libs/utils/mimetypes2/mimeutils.cpp index 92aeed56f0c..711dc97187a 100644 --- a/src/libs/utils/mimetypes2/mimeutils.cpp +++ b/src/libs/utils/mimetypes2/mimeutils.cpp @@ -57,7 +57,7 @@ QList allMimeTypes() void setMimeStartupPhase(MimeStartupPhase phase) { auto d = MimeDatabasePrivate::instance(); - QMutexLocker locker(&d->mutex); + QWriteLocker locker(&d->m_initMutex); if (int(phase) != d->m_startupPhase + 1) { qWarning("Unexpected jump in MimedDatabase lifetime from %d to %d", d->m_startupPhase, @@ -69,12 +69,14 @@ void setMimeStartupPhase(MimeStartupPhase phase) void addMimeTypes(const QString &id, const QByteArray &data) { auto d = MimeDatabasePrivate::instance(); - QMutexLocker locker(&d->mutex); - - if (d->m_startupPhase >= int(MimeStartupPhase::PluginsDelayedInitializing)) { - qWarning("Adding items for ID \"%s\" to MimeDatabase after initialization time", - qPrintable(id)); + { + QReadLocker locker(&d->m_initMutex); + if (d->m_startupPhase >= int(MimeStartupPhase::PluginsDelayedInitializing)) { + qWarning("Adding items for ID \"%s\" to MimeDatabase after initialization time", + qPrintable(id)); + } } + QMutexLocker locker(&d->mutex); d->addMimeData(id, data); } @@ -130,4 +132,14 @@ void visitMimeParents(const MimeType &mimeType, } } +/*! + The \a init function will be executed once after the MIME database is first initialized. + It must be thread safe. +*/ +void addMimeInitializer(const std::function &init) +{ + auto d = MimeDatabasePrivate::instance(); + d->addInitializer(init); +} + } // namespace Utils diff --git a/src/libs/utils/mimeutils.h b/src/libs/utils/mimeutils.h index 3fa0fc4ebb9..c5f8b819456 100644 --- a/src/libs/utils/mimeutils.h +++ b/src/libs/utils/mimeutils.h @@ -43,6 +43,7 @@ enum class MimeStartupPhase { }; QTCREATOR_UTILS_EXPORT void setMimeStartupPhase(MimeStartupPhase); +QTCREATOR_UTILS_EXPORT void addMimeInitializer(const std::function &init); QTCREATOR_UTILS_EXPORT void addMimeTypes(const QString &id, const QByteArray &data); QTCREATOR_UTILS_EXPORT QMap> magicRulesForMimeType( const MimeType &mimeType); // priority -> rules diff --git a/src/plugins/coreplugin/mimetypesettings.cpp b/src/plugins/coreplugin/mimetypesettings.cpp index 0e39eaeb3e4..c2bf8202ea4 100644 --- a/src/plugins/coreplugin/mimetypesettings.cpp +++ b/src/plugins/coreplugin/mimetypesettings.cpp @@ -746,19 +746,25 @@ MimeTypeSettingsPrivate::UserMimeTypeHash MimeTypeSettingsPrivate::readUserModif return userMimeTypes; } -void MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(const UserMimeTypeHash &mimeTypes) +static void registerUserModifiedMimeTypes(const MimeTypeSettingsPrivate::UserMimeTypeHash &mimeTypes) { - // register in mime data base, and remember for later for (auto it = mimeTypes.constBegin(); it != mimeTypes.constEnd(); ++it) { Utils::MimeType mt = Utils::mimeTypeForName(it.key()); - if (!mt.isValid()) // loaded from settings + if (!mt.isValid()) continue; - m_userModifiedMimeTypes.insert(it.key(), it.value()); Utils::setGlobPatternsForMimeType(mt, it.value().globPatterns); Utils::setMagicRulesForMimeType(mt, it.value().rules); } } +void MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(const UserMimeTypeHash &mimeTypes) +{ + // register in mime data base, and remember for later + for (auto it = mimeTypes.constBegin(); it != mimeTypes.constEnd(); ++it) + m_userModifiedMimeTypes.insert(it.key(), it.value()); + registerUserModifiedMimeTypes(mimeTypes); +} + // MimeTypeSettingsPage MimeTypeSettings::MimeTypeSettings() @@ -792,8 +798,9 @@ QStringList MimeTypeSettings::keywords() const void MimeTypeSettings::restoreSettings() { MimeTypeSettingsPrivate::UserMimeTypeHash mimetypes - = MimeTypeSettingsPrivate::readUserModifiedMimeTypes(); - MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(mimetypes); + = MimeTypeSettingsPrivate::readUserModifiedMimeTypes(); + MimeTypeSettingsPrivate::m_userModifiedMimeTypes = mimetypes; + Utils::addMimeInitializer([mimetypes] { registerUserModifiedMimeTypes(mimetypes); }); } QWidget *MimeEditorDelegate::createEditor(QWidget *parent, diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 51bd004d1a7..58822a5f71b 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -516,9 +516,7 @@ void CppEditorPlugin::initialize() void CppEditorPlugin::extensionsInitialized() { d->m_fileSettings.fromSettings(ICore::settings()); - if (!d->m_fileSettings.applySuffixesToMimeDB()) - qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n"); - + d->m_fileSettings.addMimeInitializer(); const auto fileNamesPanelFactory = new ProjectPanelFactory; fileNamesPanelFactory->setPriority(99); fileNamesPanelFactory->setDisplayName(Tr::tr("C++ File Naming")); diff --git a/src/plugins/cppeditor/cppfilesettingspage.cpp b/src/plugins/cppeditor/cppfilesettingspage.cpp index a506dff8b8a..3d3014f86b1 100644 --- a/src/plugins/cppeditor/cppfilesettingspage.cpp +++ b/src/plugins/cppeditor/cppfilesettingspage.cpp @@ -93,7 +93,7 @@ void CppFileSettings::fromSettings(QSettings *s) s->endGroup(); } -bool CppFileSettings::applySuffixesToMimeDB() +static bool applySuffixes(const QString &sourceSuffix, const QString &headerSuffix) { Utils::MimeType mt; mt = Utils::mimeTypeForName(QLatin1String(Constants::CPP_SOURCE_MIMETYPE)); @@ -107,6 +107,19 @@ bool CppFileSettings::applySuffixesToMimeDB() return true; } +void CppFileSettings::addMimeInitializer() const +{ + Utils::addMimeInitializer([sourceSuffix = sourceSuffix, headerSuffix = headerSuffix] { + if (!applySuffixes(sourceSuffix, headerSuffix)) + qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n"); + }); +} + +bool CppFileSettings::applySuffixesToMimeDB() +{ + return applySuffixes(sourceSuffix, headerSuffix); +} + bool CppFileSettings::equals(const CppFileSettings &rhs) const { return lowerCaseFiles == rhs.lowerCaseFiles diff --git a/src/plugins/cppeditor/cppfilesettingspage.h b/src/plugins/cppeditor/cppfilesettingspage.h index f4c65fbbc5c..3232ba4d4d5 100644 --- a/src/plugins/cppeditor/cppfilesettingspage.h +++ b/src/plugins/cppeditor/cppfilesettingspage.h @@ -38,6 +38,7 @@ public: void toSettings(QSettings *) const; void fromSettings(QSettings *); + void addMimeInitializer() const; bool applySuffixesToMimeDB(); // Convenience to return a license template completely formatted.