diff --git a/kde/frameworks/tier1/sonnet/ispellchecker.patch b/kde/frameworks/tier1/sonnet/ispellchecker.patch index a509a66e..68095c0f 100644 --- a/kde/frameworks/tier1/sonnet/ispellchecker.patch +++ b/kde/frameworks/tier1/sonnet/ispellchecker.patch @@ -1,49 +1,171 @@ +diff --git a/src/plugins/ispellchecker/ispellcheckerclient.h b/src/plugins/ispellchecker/ispellcheckerclient.h +--- a/src/plugins/ispellchecker/ispellcheckerclient.h ++++ b/src/plugins/ispellchecker/ispellcheckerclient.h +@@ -41,9 +41,8 @@ + } + + private: +- bool m_wasCOMInitialized = false; +- ISpellCheckerFactory* m_spellCheckerFactory = nullptr; +- QStringList m_languages; ++ // we internally keep all spell checker interfaces alive ++ QMap m_languages; + }; + + #endif diff --git a/src/plugins/ispellchecker/ispellcheckerclient.cpp b/src/plugins/ispellchecker/ispellcheckerclient.cpp --- a/src/plugins/ispellchecker/ispellcheckerclient.cpp +++ b/src/plugins/ispellchecker/ispellcheckerclient.cpp -@@ -19,7 +19,7 @@ - m_wasCOMInitialized = SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)); +@@ -15,49 +15,47 @@ + { + qCDebug(SONNET_ISPELLCHECKER) << " ISpellCheckerClient::ISpellCheckerClient"; + +- // init com if needed +- m_wasCOMInitialized = SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)); ++ // init com if needed, use same variant as e.g. Qt in qtbase/src/corelib/io/qfilesystemengine_win.cpp ++ CoInitialize(nullptr); - // get factory +- // get factory - if (SUCCEEDED(CoCreateInstance(__uuidof(SpellCheckerFactory), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_spellCheckerFactory)))) { -+ if (SUCCEEDED(CoCreateInstance(__uuidof(SpellCheckerFactory), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_spellCheckerFactory))) && m_spellCheckerFactory) { ++ // get factory & collect all known languages + instantiate the spell checkers for them ++ ISpellCheckerFactory *spellCheckerFactory = nullptr; ++ if (SUCCEEDED(CoCreateInstance(__uuidof(SpellCheckerFactory), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spellCheckerFactory))) && spellCheckerFactory) { // if we have a factory, cache the language names IEnumString* enumLanguages = nullptr; - if (SUCCEEDED(m_spellCheckerFactory->get_SupportedLanguages(&enumLanguages))) { -@@ -41,15 +41,18 @@ +- if (SUCCEEDED(m_spellCheckerFactory->get_SupportedLanguages(&enumLanguages))) { ++ if (SUCCEEDED(spellCheckerFactory->get_SupportedLanguages(&enumLanguages))) { + HRESULT hr = S_OK; + while (S_OK == hr) { + LPOLESTR string = nullptr; + hr = enumLanguages->Next(1, &string, nullptr); + if (S_OK == hr) { +- m_languages.push_back(QString::fromWCharArray(string)); ++ ISpellChecker *spellChecker = nullptr; ++ if (SUCCEEDED(spellCheckerFactory->CreateSpellChecker(string, &spellChecker)) && spellChecker) { ++ m_languages.insert(QString::fromWCharArray(string), spellChecker); ++ } + CoTaskMemFree(string); + } + } + enumLanguages->Release(); + } +- } else { +- m_spellCheckerFactory = nullptr; ++ spellCheckerFactory->Release(); + } + } ISpellCheckerClient::~ISpellCheckerClient() { - // de-init com if needed - if (m_wasCOMInitialized) { - CoUninitialize(); - } - -+ // leak stuff atm as cleanup crashs.... -+#if 0 - // release factory - if (m_spellCheckerFactory) { - m_spellCheckerFactory->Release(); - } -+ -+ // de-init com if needed after we released the interface! -+ if (m_wasCOMInitialized) { -+ CoUninitialize(); -+ } -+#endif +- // release factory +- if (m_spellCheckerFactory) { +- m_spellCheckerFactory->Release(); +- } ++ // FIXME: we at the moment leak all checkers as sonnet does the cleanup to late for proper com cleanup :/ } SpellerPlugin *ISpellCheckerClient::createSpeller(const QString &language) + { +- // create requested spellchecker, might internally fail to create instance ++ // create requested spellchecker if we know the language + qCDebug(SONNET_ISPELLCHECKER) << " SpellerPlugin *ISpellCheckerClient::createSpeller(const QString &language) ;" << language; +- ISpellCheckerDict *ad = new ISpellCheckerDict(m_spellCheckerFactory, language); +- return ad; ++ const auto it = m_languages.find(language); ++ if (it != m_languages.end()) { ++ return new ISpellCheckerDict(it.value(), language); ++ } ++ return nullptr; + } + + QStringList ISpellCheckerClient::languages() const +diff --git a/src/plugins/ispellchecker/ispellcheckerdict.h b/src/plugins/ispellchecker/ispellcheckerdict.h +--- a/src/plugins/ispellchecker/ispellcheckerdict.h ++++ b/src/plugins/ispellchecker/ispellcheckerdict.h +@@ -14,7 +14,7 @@ + class ISpellCheckerDict : public Sonnet::SpellerPlugin + { + public: +- explicit ISpellCheckerDict(ISpellCheckerFactory *spellCheckerFactory, const QString &language); ++ explicit ISpellCheckerDict(ISpellChecker *spellChecker, const QString &language); + ~ISpellCheckerDict() override; + bool isCorrect(const QString &word) const override; + +@@ -26,8 +26,8 @@ + bool addToSession(const QString &word) override; + + private: +- // spell checker com object +- ISpellChecker *m_spellChecker = nullptr; ++ // spell checker com object, we don't own this ++ ISpellChecker * const m_spellChecker; + }; + + #endif diff --git a/src/plugins/ispellchecker/ispellcheckerdict.cpp b/src/plugins/ispellchecker/ispellcheckerdict.cpp --- a/src/plugins/ispellchecker/ispellcheckerdict.cpp +++ b/src/plugins/ispellchecker/ispellcheckerdict.cpp -@@ -13,7 +13,7 @@ +@@ -9,29 +9,24 @@ + + using namespace Sonnet; + +-ISpellCheckerDict::ISpellCheckerDict(ISpellCheckerFactory *spellCheckerFactory, const QString &language) ++ISpellCheckerDict::ISpellCheckerDict(ISpellChecker *spellChecker, const QString &language) : SpellerPlugin(language) ++ , m_spellChecker(spellChecker) { - // try to init checker +- // try to init checker - if (!SUCCEEDED(spellCheckerFactory->CreateSpellChecker(language.toStdWString().c_str(), &m_spellChecker))) { -+ if (!spellCheckerFactory || !SUCCEEDED(spellCheckerFactory->CreateSpellChecker(language.toStdWString().c_str(), &m_spellChecker))) { - m_spellChecker = nullptr; - } +- m_spellChecker = nullptr; +- } ++ Q_ASSERT(m_spellChecker); + } + + ISpellCheckerDict::~ISpellCheckerDict() + { +- // release com if needed +- if (m_spellChecker) { +- m_spellChecker->Release(); +- } ++ // we don't own m_spellChecker! + } + + bool ISpellCheckerDict::isCorrect(const QString &word) const + { + // check if we are incorrect, we only need to check one enum entry for that, only empty enum means OK + bool ok = true; + IEnumSpellingError* enumSpellingError = nullptr; +- if (m_spellChecker && SUCCEEDED(m_spellChecker->Check(word.toStdWString().c_str(), &enumSpellingError))) { ++ if (SUCCEEDED(m_spellChecker->Check(word.toStdWString().c_str(), &enumSpellingError))) { + ISpellingError *spellingError = nullptr; + if (S_OK == enumSpellingError->Next(&spellingError)) { + ok = false; +@@ -47,7 +42,7 @@ + // query suggestions + QStringList replacements; + IEnumString* words = nullptr; +- if (m_spellChecker && SUCCEEDED(m_spellChecker->Suggest(word.toStdWString().c_str(), &words))) { ++ if (SUCCEEDED(m_spellChecker->Suggest(word.toStdWString().c_str(), &words))) { + HRESULT hr = S_OK; + while (S_OK == hr) { + LPOLESTR string = nullptr; +@@ -73,11 +68,11 @@ + bool ISpellCheckerDict::addToPersonal(const QString &word) + { + // add word "permanently" to the dictionary +- return m_spellChecker && SUCCEEDED(m_spellChecker->Add(word.toStdWString().c_str())); ++ return SUCCEEDED(m_spellChecker->Add(word.toStdWString().c_str())); + } + + bool ISpellCheckerDict::addToSession(const QString &word) + { + // ignore word for this session +- return m_spellChecker && SUCCEEDED(m_spellChecker->Ignore(word.toStdWString().c_str())); ++ return SUCCEEDED(m_spellChecker->Ignore(word.toStdWString().c_str())); } diff --git a/kde/frameworks/tier1/sonnet/sonnet.py b/kde/frameworks/tier1/sonnet/sonnet.py index 5bfda54c..77b37f06 100644 --- a/kde/frameworks/tier1/sonnet/sonnet.py +++ b/kde/frameworks/tier1/sonnet/sonnet.py @@ -1,38 +1,38 @@ import info class subinfo(info.infoclass): def setTargets(self): self.versionInfo.setDefaultValues() self.description = "Spelling framework for Qt, plugin-based." self.patchToApply["5.67.0"] = [ ("ispellchecker.patch", 1), ] - self.patchLevel["5.67.0"] = 4 + self.patchLevel["5.67.0"] = 5 def registerOptions(self): # hunspell just when needed, on Windows(visual studio) or Mac we try with the OS specific checkers self.options.dynamic.registerOption("useHunspell", CraftCore.compiler.isLinux or CraftCore.compiler.isMinGW()) def setDependencies(self): self.buildDependencies["virtual/base"] = None self.buildDependencies["kde/frameworks/extra-cmake-modules"] = None self.runtimeDependencies["libs/qt5/qtbase"] = None if self.options.dynamic.useHunspell: self.runtimeDependencies["libs/hunspell"] = None from Package.CMakePackageBase import * class Package(CMakePackageBase): def __init__(self): CMakePackageBase.__init__(self) # always use just hunspell, if at all! self.subinfo.options.configure.args += " -DCMAKE_DISABLE_FIND_PACKAGE_ASPELL=ON" if not self.subinfo.options.dynamic.useHunspell: self.subinfo.options.configure.args += " -DCMAKE_DISABLE_FIND_PACKAGE_HUNSPELL=ON"