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