CVS commit by sanders: Make as-you-type spell checking work with aspell. Also replace some QTimer::singleShot calls with a standard QTimer, this probably won't change the semantics of the code but I'm paranoid about a race condition causing the slot associated with the timer to be called multiple times (erroneously). I checked to make sure that I didn't break normal spell checking. Basically the problem is that aspell has a habit of emitting spurious white space to stdout. This breaks the inter process communication (IPC) between kspell.cpp and the spell process. The IPC between kspell.cpp and the spell process is fragile. kspell.cpp uses a pair of macros OUTPUT and NOOUTPUT to hook and unhook the readReady signal from the spell process to a slot in kspell.cpp. This is fragile because if the spell process emits data to stdout when the readReady signal is not hooked up to any slot (which happens due to the spurious emissions by aspell) then the KProcIO instance managing the spell process will emit a readyRead signal and then not emit a further readyRead signal until the data that is ready for reading is read by kspell.cpp. Unfortunately due to the fragile logic of kspell.cpp this will never happen (because the emission occurred outside of a OUTPUT/NOOUTPUT connect/disconnect pair). Thus before kspell.cpp pipes a word into the stdin of the spell process for checking it must flush any data that has been written to stdout by the spell process and buffered by KProcIO. M +18 -5 kspell.cpp 1.130 --- kdelibs/kdeui/kspell.cpp #1.129:1.130 @@ -76,4 +76,5 @@ public: bool checking; QValueList unchecked; + QTimer *checkNextTimer; }; @@ -435,5 +436,5 @@ bool KSpell::checkWord( const QString & if ( qs.find (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_ - QTimer::singleShot( 0, this, SLOT(checkNext()) ); + d->checkNextTimer->start( 0, true ); return false; } @@ -450,4 +451,7 @@ bool KSpell::checkWord( const QString & ksdlg->hide(); + QString blank_line; + while (proc->readln( blank_line, true ) != -1); // eat spurious blanks + OUTPUT(checkWord2); // connect (this, SIGNAL (dialog3()), this, SLOT (checkWord3())); @@ -474,5 +478,5 @@ bool KSpell::checkWord( const QString & if ( qs.find (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_ - QTimer::singleShot( 0, this, SLOT(checkNext()) ); + d->checkNextTimer->start( 0, true ); return false; } @@ -490,4 +494,8 @@ bool KSpell::checkWord( const QString & ksdlg->hide(); } + + QString blank_line; + while (proc->readln( blank_line, true ) != -1); // eat spurious blanks + OUTPUT(checkWord2); // connect (this, SIGNAL (dialog3()), this, SLOT (checkWord3())); @@ -523,5 +531,5 @@ void KSpell::checkWord2( KProcIO* ) cwword = word; dialog( word, sugg, SLOT(checkWord3()) ); - QTimer::singleShot( 0, this, SLOT(checkNext()) ); + d->checkNextTimer->start( 0, true ); return; } @@ -534,5 +542,5 @@ void KSpell::checkWord2( KProcIO* ) //so that the calling program knows when the check is complete emit corrected( word, word, 0L ); - QTimer::singleShot( 0, this, SLOT(checkNext()) ); + d->checkNextTimer->start( 0, true ); } @@ -544,4 +552,5 @@ void KSpell::checkNext() BufferedWord buf = d->unchecked.front(); d->unchecked.pop_front(); + if (buf.method == Method1) checkWord( buf.word, buf.useDialog ); @@ -1226,4 +1235,5 @@ KSpell::~KSpell() delete ksconfig; delete ksdlg; + delete d->checkNextTimer; delete d; } @@ -1399,4 +1409,7 @@ void KSpell::initialize( QWidget *_paren d->type = type; d->checking = false; + d->checkNextTimer = new QTimer( this ); + connect( d->checkNextTimer, SIGNAL( timeout() ), + this, SLOT( checkNext() )); autoDelete = false; modaldlg = _modal;