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 if (qtc)
00167 _codec = qtc;
00168 else
00169 setCodec(LocaleCodec);
00170
00171 delete _decoder;
00172 _decoder = _codec->makeDecoder();
00173
00174 emit useUtf8Request(utf8());
00175 }
00176
00177 void Emulation::setCodec(EmulationCodec codec)
00178 {
00179 if ( codec == Utf8Codec )
00180 setCodec( QTextCodec::codecForName("utf8") );
00181 else if ( codec == LocaleCodec )
00182 setCodec( QTextCodec::codecForLocale() );
00183 }
00184
00185 void Emulation::setKeyBindings(const QString& name)
00186 {
00187 _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
00188 }
00189
00190 QString Emulation::keyBindings()
00191 {
00192 return _keyTranslator->name();
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00208 void Emulation::receiveChar(int c)
00209
00210
00211 {
00212 c &= 0xff;
00213 switch (c)
00214 {
00215 case '\b' : _currentScreen->backspace(); break;
00216 case '\t' : _currentScreen->tab(); break;
00217 case '\n' : _currentScreen->newLine(); break;
00218 case '\r' : _currentScreen->toStartOfLine(); break;
00219 case 0x07 : emit stateSet(NOTIFYBELL);
00220 break;
00221 default : _currentScreen->displayCharacter(c); break;
00222 };
00223 }
00224
00225
00226
00227
00228
00229
00230
00234 void Emulation::sendKeyEvent( QKeyEvent* ev )
00235 {
00236 emit stateSet(NOTIFYNORMAL);
00237
00238 if (!ev->text().isEmpty())
00239 {
00240
00241
00242
00243
00244 emit sendData(ev->text().toUtf8(),ev->text().length());
00245 }
00246 }
00247
00248 void Emulation::sendString(const char*,int)
00249 {
00250
00251 }
00252
00253 void Emulation::sendMouseEvent(int , int , int , int )
00254 {
00255
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265 void Emulation::receiveData(const char* text, int length)
00266 {
00267 emit stateSet(NOTIFYACTIVITY);
00268
00269 bufferedUpdate();
00270
00271 QString unicodeText = _decoder->toUnicode(text,length);
00272
00273
00274 for (int i=0;i<unicodeText.length();i++)
00275 {
00276 receiveChar(unicodeText[i].unicode());
00277 }
00278
00279
00280
00281
00282 for (int i=0;i<length;i++)
00283 {
00284 if (text[i] == '\030')
00285 {
00286 if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0))
00287 emit zmodemDetected();
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
00342
00343 #if 0
00344 void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode) {
00345 if (!connected) return;
00346 _currentScreen->setSelectionStart( x,y,columnmode);
00347 showBulk();
00348 }
00349
00350 void Emulation::onSelectionExtend(const int x, const int y) {
00351 if (!connected) return;
00352 _currentScreen->setSelectionEnd(x,y);
00353 showBulk();
00354 }
00355
00356 void Emulation::setSelection(const bool preserve_line_breaks) {
00357 if (!connected) return;
00358 QString t = _currentScreen->selectedText(preserve_line_breaks);
00359 if (!t.isNull())
00360 {
00361 QListIterator< TerminalDisplay* > viewIter(_views);
00362
00363 while (viewIter.hasNext())
00364 viewIter.next()->setSelection(t);
00365 }
00366 }
00367
00368 void Emulation::testIsSelected(const int x, const int y, bool &selected)
00369 {
00370 if (!connected) return;
00371 selected=_currentScreen->isSelected(x,y);
00372 }
00373
00374 void Emulation::clearSelection() {
00375 if (!connected) return;
00376 _currentScreen->clearSelection();
00377 showBulk();
00378 }
00379
00380 #endif
00381
00382 void Emulation::writeToStream( TerminalCharacterDecoder* _decoder ,
00383 int startLine ,
00384 int endLine)
00385 {
00386 _currentScreen->writeToStream(_decoder,startLine,endLine);
00387 }
00388
00389 int Emulation::lineCount()
00390 {
00391
00392 return _currentScreen->getLines() + _currentScreen->getHistLines();
00393 }
00394
00395
00396
00397 #define BULK_TIMEOUT1 10
00398 #define BULK_TIMEOUT2 40
00399
00402 void Emulation::showBulk()
00403 {
00404 _bulkTimer1.stop();
00405 _bulkTimer2.stop();
00406
00407 emit outputChanged();
00408
00409 _currentScreen->resetScrolledLines();
00410 _currentScreen->resetDroppedLines();
00411 }
00412
00413 void Emulation::bufferedUpdate()
00414 {
00415 _bulkTimer1.setSingleShot(true);
00416 _bulkTimer1.start(BULK_TIMEOUT1);
00417 if (!_bulkTimer2.isActive())
00418 {
00419 _bulkTimer2.setSingleShot(true);
00420 _bulkTimer2.start(BULK_TIMEOUT2);
00421 }
00422 }
00423
00424 char Emulation::getErase() const
00425 {
00426 return '\b';
00427 }
00428
00429 void Emulation::setImageSize(int lines, int columns)
00430 {
00431 Q_ASSERT( lines > 0 );
00432 Q_ASSERT( columns > 0 );
00433
00434 QSize screenSize[2] = { QSize(_screen[0]->getColumns(),
00435 _screen[0]->getLines()),
00436 QSize(_screen[1]->getColumns(),
00437 _screen[1]->getLines()) };
00438 QSize newSize(columns,lines);
00439
00440 if (newSize == screenSize[0] && newSize == screenSize[1])
00441 return;
00442
00443 _screen[0]->resizeImage(lines,columns);
00444 _screen[1]->resizeImage(lines,columns);
00445
00446 emit imageSizeChanged(lines,columns);
00447
00448 bufferedUpdate();
00449 }
00450
00451 QSize Emulation::imageSize()
00452 {
00453 return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
00454 }
00455
00456 ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const
00457 {
00458 ushort hash = 0;
00459 for ( ushort i = 0 ; i < length ; i++ )
00460 {
00461 hash = 31*hash + unicodePoints[i];
00462 }
00463 return hash;
00464 }
00465 bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const
00466 {
00467 ushort* entry = extendedCharTable[hash];
00468
00469
00470
00471 if ( entry == 0 || entry[0] != length )
00472 return false;
00473
00474
00475 for ( int i = 0 ; i < length ; i++ )
00476 {
00477 if ( entry[i+1] != unicodePoints[i] )
00478 return false;
00479 }
00480 return true;
00481 }
00482 ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length)
00483 {
00484
00485 ushort hash = extendedCharHash(unicodePoints,length);
00486
00487
00488 while ( extendedCharTable.contains(hash) )
00489 {
00490 if ( extendedCharMatch(hash,unicodePoints,length) )
00491 {
00492
00493
00494 return hash;
00495 }
00496 else
00497 {
00498
00499
00500 hash++;
00501 }
00502 }
00503
00504
00505
00506
00507 ushort* buffer = new ushort[length+1];
00508 buffer[0] = length;
00509 for ( int i = 0 ; i < length ; i++ )
00510 buffer[i+1] = unicodePoints[i];
00511
00512 extendedCharTable.insert(hash,buffer);
00513
00514 return hash;
00515 }
00516
00517 ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const
00518 {
00519
00520
00521
00522 ushort* buffer = extendedCharTable[hash];
00523 if ( buffer )
00524 {
00525 length = buffer[0];
00526 return buffer+1;
00527 }
00528 else
00529 {
00530 length = 0;
00531 return 0;
00532 }
00533 }
00534
00535 ExtendedCharTable::ExtendedCharTable()
00536 {
00537 }
00538 ExtendedCharTable::~ExtendedCharTable()
00539 {
00540
00541 QHashIterator<ushort,ushort*> iter(extendedCharTable);
00542 while ( iter.hasNext() )
00543 {
00544 iter.next();
00545 delete[] iter.value();
00546 }
00547 }
00548
00549
00550 ExtendedCharTable ExtendedCharTable::instance;
00551
00552
00553 #include "Emulation.moc"
00554