From 83a318800db22408628e60c9e1730578efcfee37 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 1 Nov 2012 01:47:44 -0700 Subject: Thu Nov 1 01:47:04 PDT 2012 --- extra/kdeplasma-addons/PKGBUILD | 14 +- extra/kdeplasma-addons/fix-spell-crash.patch | 267 +++++++++++++++++++++++++++ 2 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 extra/kdeplasma-addons/fix-spell-crash.patch (limited to 'extra/kdeplasma-addons') diff --git a/extra/kdeplasma-addons/PKGBUILD b/extra/kdeplasma-addons/PKGBUILD index e3fa6d221..da60347b4 100644 --- a/extra/kdeplasma-addons/PKGBUILD +++ b/extra/kdeplasma-addons/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 167845 2012-10-03 14:46:47Z andrea $ +# $Id: PKGBUILD 170053 2012-10-31 10:13:04Z andrea $ # Maintainer: Andrea Scarpino # Contributor: Pierre Schmitz @@ -76,17 +76,23 @@ pkgname=('kdeplasma-addons-applets-bball' 'kdeplasma-addons-wallpapers-virus' 'kdeplasma-addons-wallpapers-weather') pkgver=4.9.2 -pkgrel=1 +pkgrel=3 arch=('i686' 'x86_64') url='http://www.kde.org' license=('GPL' 'LGPL') groups=('kde' 'kdeplasma-addons') makedepends=('cmake' 'automoc4' 'kdebase-workspace' 'kdeedu-marble' 'eigen' 'scim' 'qwt' 'boost' 'libkexiv2' 'ibus' 'qoauth' 'qjson') -source=("http://download.kde.org/stable/${pkgver}/src/${pkgbase}-${pkgver}.tar.xz") -sha1sums=('9f6493d52beb2ed723038e60f5f9ab53beec4e44') +source=("http://download.kde.org/stable/${pkgver}/src/${pkgbase}-${pkgver}.tar.xz" + 'fix-spell-crash.patch') +sha1sums=('9f6493d52beb2ed723038e60f5f9ab53beec4e44' + '1ff0e61d73a4fce8ee7f585504a129ff50405ae6') build() { + cd ${pkgbase}-${pkgver} + patch -p1 -i "${srcdir}"/fix-spell-crash.patch + cd ../ + mkdir build cd build cmake ../${pkgbase}-${pkgver} \ diff --git a/extra/kdeplasma-addons/fix-spell-crash.patch b/extra/kdeplasma-addons/fix-spell-crash.patch new file mode 100644 index 000000000..75c26c6ad --- /dev/null +++ b/extra/kdeplasma-addons/fix-spell-crash.patch @@ -0,0 +1,267 @@ +commit 124e35885b8cd1b593b7b83a070bd0bdb5758661 +Author: Simeon Bird +Date: Fri Oct 19 21:16:34 2012 -0400 + + Fix the plasma spellchecker's 'foreign language' support. + Previously this caused segfaults (even if not used) because + it called setLanguage(), which is not thread-safe, in match(). + + Instead, this patch constructs a new speller safely for each new + language, without deleting the old one. Old spellers are instead + deleted on the teardown() signal. + + While we're at it, amend the language detection so that the user + can type natural language names (eg, 'german') and have the + spell-checker find the right language. + + REVIEW: 106244 + BUG: 303831 + BUG: 264779 + FIXED-IN: 4.9.3 + +diff --git a/runners/spellchecker/spellcheck.cpp b/runners/spellchecker/spellcheck.cpp +index 672732d..cc6aeb2 100644 +--- a/runners/spellchecker/spellcheck.cpp ++++ b/runners/spellchecker/spellcheck.cpp +@@ -24,6 +24,7 @@ + // #include + #include + #include ++#include + + SpellCheckRunner::SpellCheckRunner(QObject* parent, const QVariantList &args) + : Plasma::AbstractRunner(parent, args) +@@ -43,13 +44,64 @@ void SpellCheckRunner::init() + { + Plasma::AbstractRunner::init(); + +- //store all language names, makes it posible to type "spell german TERM" if english locale is set ++ //Connect prepare and teardown signals ++ connect(this, SIGNAL(prepare()), this, SLOT(loaddata())); ++ connect(this, SIGNAL(teardown()), this, SLOT(destroydata())); ++} ++ ++//Load a default dictionary and some locale names ++void SpellCheckRunner::loaddata() ++{ ++ //Load the default speller, with the default language ++ if (!m_spellers.contains("")) { ++ m_spellers[""] = QSharedPointer (new Sonnet::Speller("")); ++ } ++ //store all language names, makes it possible to type "spell german TERM" if english locale is set ++ //Need to construct a map between natual language names and names the spell-check recognises. + KLocale *locale = KGlobal::locale(); +- QStringList codes = locale->allLanguagesList(); +- foreach (const QString &code, codes) { +- const QString name = locale->languageCodeToName(code); +- m_languages[name.toLower()] = code; ++ const QStringList avail = m_spellers[""]->availableLanguages(); ++ //We need to filter the available languages so that we associate the natural language ++ //name (eg. 'german') with one sub-code. ++ QSet families; ++ //First get the families ++ foreach (const QString &code, avail) { ++ families +=code.left(2); ++ } ++ //Now for each family figure out which is the main code. ++ foreach (const QString &fcode,families) { ++ QStringList family = avail.filter(fcode); ++ QString code; ++ //If we only have one code, use it. ++ //If a string is the default language, use it ++ if (family.contains(m_spellers[""]->language())) { ++ code = m_spellers[""]->language(); ++ } else if (fcode == QLatin1String("en")) { ++ //If the family is english, default to en_US. ++ if (family.contains("en_US")) { ++ code = QLatin1String("en_US"); ++ } ++ } else if (family.contains(fcode+QLatin1String("_")+fcode.toUpper())) { ++ //If we have a speller of the form xx_XX, try that. ++ //This gets us most European languages with more than one spelling. ++ code = fcode+QLatin1String("_")+fcode.toUpper(); ++ } else { ++ //Otherwise, pick the first value as it is highest priority. ++ code = family.first(); ++ } ++ //Finally, add code to the map. ++ const QString name = locale->languageCodeToName(fcode); ++ if (!name.isEmpty()) { ++ m_languages[name.toLower()] = code; ++ } ++// kDebug() << "SPELL lang: " << fcode<< "::"<< name << " : " << code; + } ++ ++} ++ ++void SpellCheckRunner::destroydata() ++{ ++ //Clear the data arrays to save memory ++ m_spellers.clear(); + } + + void SpellCheckRunner::reloadConfiguration() +@@ -73,13 +125,52 @@ void SpellCheckRunner::reloadConfiguration() + setSyntaxes(syns); + } + ++/* Take the input query, split into a list, and see if it contains a language to spell in. ++ * Return the empty string if we can't match a language. */ ++QString SpellCheckRunner::findlang(const QStringList& terms) ++{ ++ //If first term is a language code (like en_GB), set it as the spell-check language ++ if (terms.count() >= 1 && m_spellers[""]->availableLanguages().contains(terms[0])) { ++ return terms[0]; ++ } ++ //If we have two terms and the first is a language name (eg 'french'), ++ //set it as the available language ++ else if (terms.count() >=2) { ++ QString code; ++ { ++ //Is this a descriptive language name? ++ QMap::const_iterator it = m_languages.constFind(terms[0].toLower()); ++ if (it != m_languages.constEnd()) { ++ code = *it; ++ } ++ //Maybe it is a subset of a language code? ++ else { ++ QStringList codes = QStringList(m_languages.values()).filter(terms[0]); ++ if (!codes.isEmpty()) { ++ code = codes.first(); ++ } ++ } ++ } ++ ++ if (!code.isEmpty()) { ++ //We found a valid language! Check still available ++ const QStringList avail = m_spellers[""]->availableLanguages(); ++ //Does the spell-checker like it? ++ if (avail.contains(code)) { ++ return code; ++ } ++ } ++ //FIXME: Support things like 'british english' or 'canadian french' ++ } ++ return QLatin1String(""); ++} ++ + void SpellCheckRunner::match(Plasma::RunnerContext &context) + { + if (!context.isValid()) { + return; + } + +- + const QString term = context.query(); + QString query = term; + +@@ -88,53 +179,46 @@ void SpellCheckRunner::match(Plasma::RunnerContext &context) + if (query.left(len) != m_triggerWord) { + return; + } +- +- QString language = m_speller.defaultLanguage(); + query = query.mid(len).trimmed(); +- QStringList terms = query.split(' '); +- +- //two terms specified, check if first is a language +- QString customLanguage; +- if (terms.count() == 2) { +- customLanguage = terms[0]; +- query = terms[1]; +- } +- //three terms specified, check if first two are a language, e.g. "american english" +- if (terms.count() == 3) { +- customLanguage = terms[0] + ' ' + terms[1]; +- query = terms[2]; +- } +- +- if (!customLanguage.isEmpty()) { +- language = customLanguage; +- m_speller.setLanguage(language); ++ } + +- //not valid, maybe it is a language name, not a code +- if (!m_speller.isValid()) { +- QHash::const_iterator it = m_languages.constFind(language.toLower()); +- //is a valid language name +- if (it != m_languages.constEnd()) { +- language = *it; ++ //Pointer to speller object with our chosen language ++ QSharedPointer speller = m_spellers[""]; ++ ++ if (speller->isValid()) { ++ QStringList terms = query.split(' ', QString::SkipEmptyParts); ++ QString lang = findlang(terms); ++ //If we found a language, create a new speller object using it. ++ if (!lang.isEmpty()) { ++ //First term is the language ++ terms.removeFirst(); ++ //New speller object if we don't already have one ++ if (!m_spellers.contains(lang)) { ++ QMutexLocker lock (&m_spellLock); ++ //Check nothing happened while we were acquiring the lock ++ if (!m_spellers.contains(lang)) { ++ m_spellers[lang] = QSharedPointer(new Sonnet::Speller(lang)); + } + } ++ speller = m_spellers[lang]; ++ //Rejoin the strings ++ query = terms.join(QLatin1String(" ")); + } +- +- m_speller.setLanguage(language); + } + +- if (query.size() < 3) { ++ if (query.size() < 2) { + return; + } + + Plasma::QueryMatch match(this); + match.setType(Plasma::QueryMatch::InformationalMatch); + +- if (m_speller.isValid()) { ++ if (speller->isValid()) { + QStringList suggestions; +- const bool correct = m_speller.checkAndSuggest(query,suggestions); ++ const bool correct = speller->checkAndSuggest(query,suggestions); + if (correct) { + match.setIcon(KIcon(QLatin1String( "checkbox" ))); +- match.setText(i18n("Correct")); ++ match.setText(i18n("Correct")+QLatin1String(": ")+query); + } else { + match.setIcon(KIcon(QLatin1String( "edit-delete" ))); + const QString recommended = i18n("Suggested words: %1", suggestions.join(i18nc("seperator for a list of words", ", "))); +diff --git a/runners/spellchecker/spellcheck.h b/runners/spellchecker/spellcheck.h +index 492c370..ca65452 100644 +--- a/runners/spellchecker/spellcheck.h ++++ b/runners/spellchecker/spellcheck.h +@@ -22,6 +22,7 @@ + #include + + #include ++#include + + /** + * This checks the spelling of query +@@ -41,12 +42,17 @@ public: + + protected slots: + void init(); ++ void loaddata(); ++ void destroydata(); + + private: ++ QString findlang(const QStringList &terms); ++ + QString m_triggerWord; +- QHash m_languages;//key=language name, value=language code ++ QMap m_languages;//key=language name, value=language code + bool m_requireTriggerWord; +- Sonnet::Speller m_speller; ++ QMap > m_spellers; //spellers ++ QMutex m_spellLock; //Lock held when constructing a new speller + }; + + K_EXPORT_PLASMA_RUNNER(spellcheckrunner, SpellCheckRunner) -- cgit v1.2.3-54-g00ecf