00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "Emulation.h"
00026
00027
00028 #include <assert.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032
00033
00034 #include <QtGui/QApplication>
00035 #include <QtGui/QClipboard>
00036 #include <QtCore/QHash>
00037 #include <QtGui/QKeyEvent>
00038 #include <QtCore/QRegExp>
00039 #include <QtCore/QTextStream>
00040 #include <QtCore/QThread>
00041
00042 #include <QtCore/QTime>
00043
00044
00045 #include <kdebug.h>
00046
00047
00048 #include "KeyboardTranslator.h"
00049 #include "Screen.h"
00050 #include "TerminalCharacterDecoder.h"
00051 #include "ScreenWindow.h"
00052
00053 using namespace Konsole;
00054
00055
00056
00057
00058
00059
00060
00061
00062
00066 Emulation::Emulation() :
00067 _currentScreen(0),
00068 _codec(0),
00069 _decoder(0),
00070 _keyTranslator(0),
00071 _usesMouse(false)
00072 {
00073
00074
00075 _screen[0] = new Screen(40,80);
00076 _screen[1] = new Screen(40,80);
00077 _currentScreen = _screen[0];
00078
00079 QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
00080 QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) );
00081
00082
00083 connect( this , SIGNAL(programUsesMouseChanged(bool)) ,
00084 SLOT(usesMouseChanged(bool)) );
00085 }
00086
00087 bool Emulation::programUsesMouse() const
00088 {
00089 return _usesMouse;
00090 }
00091
00092 void Emulation::usesMouseChanged(bool usesMouse)
00093 {
00094 _usesMouse = usesMouse;
00095 }
00096
00097 ScreenWindow* Emulation::createWindow()
00098 {
00099 ScreenWindow* window = new ScreenWindow();
00100 window->setScreen(_currentScreen);
00101 _windows << window;
00102
00103 connect(window , SIGNAL(selectionChanged()),
00104 this , SLOT(bufferedUpdate()));
00105
00106 connect(this , SIGNAL(outputChanged()),
00107 window , SLOT(notifyOutputChanged()) );
00108 return window;
00109 }
00110
00114 Emulation::~Emulation()
00115 {
00116 QListIterator<ScreenWindow*> windowIter(_windows);
00117
00118 while (windowIter.hasNext())
00119 {
00120 delete windowIter.next();
00121 }
00122
00123 delete _screen[0];
00124 delete _screen[1];
00125 delete _decoder;
00126 }
00127
00131 void Emulation::setScreen(int n)
00132 {
00133 Screen *old = _currentScreen;
00134 _currentScreen = _screen[n&1];
00135 if (_currentScreen != old)
00136 {
00137 old->setBusySelecting(false);
00138
00139
00140 QListIterator<ScreenWindow*> windowIter(_windows);
00141 while ( windowIter.hasNext() )
00142 {
00143 windowIter.next()->setScreen(_currentScreen);
00144 }
00145 }
00146 }
00147
00148 void Emulation::clearHistory()
00149 {
00150 _screen[0]->setScroll( _screen[0]->getScroll() , false );
00151 }
00152 void Emulation::setHistory(const HistoryType& t)
00153 {
00154 _screen[0]->setScroll(t);
00155
00156 showBulk();
00157 }
00158
00159 const HistoryType& Emulation::history()
00160 {
00161 return _screen[0]->getScroll();
00162 }
00163
00164 void Emulation::setCodec(const QTextCodec * qtc)
00165 {
00166 Q_ASSERT( qtc );
00167
00168 _codec = qtc;
00169 delete _decoder;
00170 _decoder = _codec->makeDecoder();
00171
00172 emit useUtf8Request(utf8());
00173 }
00174
00175 void Emulation::setCodec(EmulationCodec codec)
00176 {
00177 if ( codec == Utf8Codec )
00178 setCodec( QTextCodec::codecForName("utf8") );
00179 else if ( codec == LocaleCodec )
00180 setCodec( QTextCodec::codecForLocale() );
00181 }
00182
00183 void Emulation::setKeyBindings(const QString& name)
00184 {
00185 _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
00186 }
00187
00188 QString Emulation::keyBindings()
00189 {
00190 return _keyTranslator->name();
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00206 void Emulation::receiveChar(int c)
00207
00208
00209 {
00210 c &= 0xff;
00211 switch (c)
00212 {
00213 case '\b' : _currentScreen->BackSpace(); break;
00214 case '\t' : _currentScreen->Tabulate(); break;
00215 case '\n' : _currentScreen->NewLine(); break;
00216 case '\r' : _currentScreen->Return(); break;
00217 case 0x07 : emit stateSet(NOTIFYBELL);
00218 break;
00219 default : _currentScreen->ShowCharacter(c); break;
00220 };
00221 }
00222
00223
00224
00225
00226
00227
00228
00232 void Emulation::sendKeyEvent( QKeyEvent* ev )
00233 {
00234 emit stateSet(NOTIFYNORMAL);
00235
00236 if (!ev->text().isEmpty())
00237 {
00238
00239
00240
00241
00242 emit sendData(ev->text().toUtf8(),ev->text().length());
00243 }
00244 }
00245
00246 void Emulation::sendString(const char*,int)
00247 {
00248
00249 }
00250
00251 void Emulation::sendMouseEvent(int , int , int , int )
00252 {
00253
00254 }
00255
00256
00257
00258
00259
00260
00261
00262
00263 void Emulation::receiveData(const char* text, int length)
00264 {
00265 emit stateSet(NOTIFYACTIVITY);
00266
00267 bufferedUpdate();
00268
00269 QString unicodeText = _decoder->toUnicode(text,length);
00270
00271
00272 for (int i=0;i<unicodeText.length();i++)
00273 {
00274 receiveChar(unicodeText[i].unicode());
00275 }
00276
00277
00278
00279
00280 for (int i=0;i<length;i++)
00281 {
00282 if (text[i] == '\030')
00283 {
00284 if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0))
00285 emit zmodemDetected();
00286 }
00287 }
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 #if 0
00342 void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode) {
00343 if (!connected) return;
00344 _currentScreen->setSelectionStart( x,y,columnmode);
00345 showBulk();
00346 }
00347
00348 void Emulation::onSelectionExtend(const int x, const int y) {
00349 if (!connected) return;
00350 _currentScreen->setSelectionEnd(x,y);
00351 showBulk();
00352 }
00353
00354 void Emulation::setSelection(const bool preserve_line_breaks) {
00355 if (!connected) return;
00356 QString t = _currentScreen->selectedText(preserve_line_breaks);
00357 if (!t.isNull())
00358 {
00359 QListIterator< TerminalDisplay* > viewIter(_views);
00360
00361 while (viewIter.hasNext())
00362 viewIter.next()->setSelection(t);
00363 }
00364 }
00365
00366 void Emulation::testIsSelected(const int x, const int y, bool &selected)
00367 {
00368 if (!connected) return;
00369 selected=_currentScreen->isSelected(x,y);
00370 }
00371
00372 void Emulation::clearSelection() {
00373 if (!connected) return;
00374 _currentScreen->clearSelection();
00375 showBulk();
00376 }
00377
00378 #endif
00379
00380 void Emulation::writeToStream( TerminalCharacterDecoder* _decoder ,
00381 int startLine ,
00382 int endLine)
00383 {
00384 _currentScreen->writeToStream(_decoder,startLine,endLine);
00385 }
00386
00387 int Emulation::lineCount()
00388 {
00389
00390 return _currentScreen->getLines() + _currentScreen->getHistLines();
00391 }
00392
00393
00394
00395 #define BULK_TIMEOUT1 10
00396 #define BULK_TIMEOUT2 40
00397
00400 void Emulation::showBulk()
00401 {
00402 _bulkTimer1.stop();
00403 _bulkTimer2.stop();
00404
00405 emit outputChanged();
00406
00407 _currentScreen->resetScrolledLines();
00408 _currentScreen->resetDroppedLines();
00409 }
00410
00411 void Emulation::bufferedUpdate()
00412 {
00413 _bulkTimer1.setSingleShot(true);
00414 _bulkTimer1.start(BULK_TIMEOUT1);
00415 if (!_bulkTimer2.isActive())
00416 {
00417 _bulkTimer2.setSingleShot(true);
00418 _bulkTimer2.start(BULK_TIMEOUT2);
00419 }
00420 }
00421
00422 char Emulation::getErase() const
00423 {
00424 return '\b';
00425 }
00426
00427 void Emulation::setImageSize(int lines, int columns)
00428 {
00429
00430 Q_ASSERT( lines > 0 );
00431 Q_ASSERT( columns > 0 );
00432
00433 _screen[0]->resizeImage(lines,columns);
00434 _screen[1]->resizeImage(lines,columns);
00435
00436 emit imageSizeChanged(lines,columns);
00437
00438 bufferedUpdate();
00439 }
00440
00441 QSize Emulation::imageSize()
00442 {
00443 return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
00444 }
00445
00446 ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const
00447 {
00448 ushort hash = 0;
00449 for ( ushort i = 0 ; i < length ; i++ )
00450 {
00451 hash = 31*hash + unicodePoints[i];
00452 }
00453 return hash;
00454 }
00455 bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const
00456 {
00457 ushort* entry = extendedCharTable[hash];
00458
00459
00460
00461 if ( entry == 0 || entry[0] != length )
00462 return false;
00463
00464
00465 for ( int i = 0 ; i < length ; i++ )
00466 {
00467 if ( entry[i+1] != unicodePoints[i] )
00468 return false;
00469 }
00470 return true;
00471 }
00472 ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length)
00473 {
00474
00475 ushort hash = extendedCharHash(unicodePoints,length);
00476
00477
00478 while ( extendedCharTable.contains(hash) )
00479 {
00480 if ( extendedCharMatch(hash,unicodePoints,length) )
00481 {
00482
00483
00484 return hash;
00485 }
00486 else
00487 {
00488
00489
00490 hash++;
00491 }
00492 }
00493
00494
00495
00496
00497 ushort* buffer = new ushort[length+1];
00498 buffer[0] = length;
00499 for ( int i = 0 ; i < length ; i++ )
00500 buffer[i+1] = unicodePoints[i];
00501
00502 extendedCharTable.insert(hash,buffer);
00503
00504 return hash;
00505 }
00506
00507 ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const
00508 {
00509
00510
00511
00512 ushort* buffer = extendedCharTable[hash];
00513 if ( buffer )
00514 {
00515 length = buffer[0];
00516 return buffer+1;
00517 }
00518 else
00519 {
00520 length = 0;
00521 return 0;
00522 }
00523 }
00524
00525 ExtendedCharTable::ExtendedCharTable()
00526 {
00527 }
00528 ExtendedCharTable::~ExtendedCharTable()
00529 {
00530
00531 QHashIterator<ushort,ushort*> iter(extendedCharTable);
00532 while ( iter.hasNext() )
00533 {
00534 iter.next();
00535 delete[] iter.value();
00536 }
00537 }
00538
00539
00540 ExtendedCharTable ExtendedCharTable::instance;
00541
00542
00543 #include "Emulation.moc"
00544