• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Konsole

Emulation.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of Konsole, an X terminal.
00003 
00004     Copyright (C) 2007 Robert Knight <robertknight@gmail.com> 
00005     Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
00006     Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00021     02110-1301  USA.
00022 */
00023 
00024 // Own
00025 #include "Emulation.h"
00026 
00027 // System
00028 #include <assert.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 
00033 // Qt
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 // KDE
00045 #include <kdebug.h>
00046 
00047 // Konsole
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 /*                               Emulation                                  */
00058 /*                                                                           */
00059 /* ------------------------------------------------------------------------- */
00060 
00061 //#define CNTL(c) ((c)-'@')
00062 
00066 Emulation::Emulation() :
00067   _currentScreen(0),
00068   _codec(0),
00069   _decoder(0),
00070   _keyTranslator(0),
00071   _usesMouse(false)
00072 {
00073 
00074   // create screens with a default size
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   // listen for mouse status changes
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      // tell all windows onto this emulation to switch to the newly active _screen
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 // Interpreting Codes ---------------------------------------------------------
00195 
00196 /*
00197    This section deals with decoding the incoming character stream.
00198    Decoding means here, that the stream is first separated into `tokens'
00199    which are then mapped to a `meaning' provided as operations by the
00200    `Screen' class.
00201 */
00202 
00206 void Emulation::receiveChar(int c)
00207 // process application unicode input to terminal
00208 // this is a trivial scanner
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 /*                             Keyboard Handling                             */
00226 /*                                                                           */
00227 /* ------------------------------------------------------------------------- */
00228 
00232 void Emulation::sendKeyEvent( QKeyEvent* ev )
00233 {
00234   emit stateSet(NOTIFYNORMAL);
00235   
00236   if (!ev->text().isEmpty())
00237   { // A block of text
00238     // Note that the text is proper unicode.
00239     // We should do a conversion here, but since this
00240     // routine will never be used, we simply emit plain ascii.
00241     //emit sendBlock(ev->text().toAscii(),ev->text().length());
00242     emit sendData(ev->text().toUtf8(),ev->text().length());
00243   }
00244 }
00245 
00246 void Emulation::sendString(const char*,int)
00247 {
00248     // default implementation does nothing
00249 }
00250 
00251 void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
00252 {
00253     // default implementation does nothing
00254 }
00255 
00256 // Unblocking, Byte to Unicode translation --------------------------------- --
00257 
00258 /*
00259    We are doing code conversion from locale to unicode first.
00260 TODO: Character composition from the old code.  See #96536
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     //send characters to terminal emulator
00272     for (int i=0;i<unicodeText.length();i++)
00273     {
00274         receiveChar(unicodeText[i].unicode());
00275     }
00276 
00277     //look for z-modem indicator
00278     //-- someone who understands more about z-modems that I do may be able to move
00279     //this check into the above for loop?
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 //OLDER VERSION
00291 //This version of onRcvBlock was commented out because
00292 //  a)  It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
00293 //  b)  It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
00294 //      were not printed properly.
00295 //
00296 //There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
00297 //which hasn't been ported into the newer function (above).  Hopefully someone who understands this better
00298 //can find an alternative way of handling the check.  
00299 
00300 
00301 /*void Emulation::onRcvBlock(const char *s, int len)
00302 {
00303   emit notifySessionState(NOTIFYACTIVITY);
00304   
00305   bufferedUpdate();
00306   for (int i = 0; i < len; i++)
00307   {
00308 
00309     QString result = _decoder->toUnicode(&s[i],1);
00310     int reslen = result.length();
00311 
00312     // If we get a control code halfway a multi-byte sequence
00313     // we flush the _decoder and continue with the control code.
00314     if ((s[i] < 32) && (s[i] > 0))
00315     {
00316        // Flush _decoder
00317        while(!result.length())
00318           result = _decoder->toUnicode(&s[i],1);
00319        reslen = 1;
00320        result.resize(reslen);
00321        result[0] = QChar(s[i]);
00322     }
00323 
00324     for (int j = 0; j < reslen; j++)
00325     {
00326       if (result[j].characterategory() == QChar::Mark_NonSpacing)
00327          _currentScreen->compose(result.mid(j,1));
00328       else
00329          onRcvChar(result[j].unicode());
00330     }
00331     if (s[i] == '\030')
00332     {
00333       if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
00334         emit zmodemDetected();
00335     }
00336   }
00337 }*/
00338 
00339 // Selection --------------------------------------------------------------- --
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     // sum number of lines currently on _screen plus number of lines in history
00390     return _currentScreen->getLines() + _currentScreen->getHistLines();
00391 }
00392 
00393 // Refreshing -------------------------------------------------------------- --
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   //kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
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     // compare given length with stored sequence length ( given as the first ushort in the 
00460     // stored buffer ) 
00461     if ( entry == 0 || entry[0] != length ) 
00462        return false;
00463     // if the lengths match, each character must be checked.  the stored buffer starts at
00464     // entry[1]
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     // look for this sequence of points in the table
00475     ushort hash = extendedCharHash(unicodePoints,length);
00476 
00477     // check existing entry for match
00478     while ( extendedCharTable.contains(hash) )
00479     {
00480         if ( extendedCharMatch(hash,unicodePoints,length) )
00481         {
00482             // this sequence already has an entry in the table, 
00483             // return its hash
00484             return hash;
00485         }
00486         else
00487         {
00488             // if hash is already used by another, different sequence of unicode character
00489             // points then try next hash
00490             hash++;
00491         }
00492     }    
00493 
00494     
00495      // add the new sequence to the table and
00496      // return that index
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     // lookup index in table and if found, set the length
00510     // argument and return a pointer to the character sequence
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     // free all allocated character buffers
00531     QHashIterator<ushort,ushort*> iter(extendedCharTable);
00532     while ( iter.hasNext() )
00533     {
00534         iter.next();
00535         delete[] iter.value();
00536     }
00537 }
00538 
00539 // global instance
00540 ExtendedCharTable ExtendedCharTable::instance;
00541 
00542 
00543 #include "Emulation.moc"
00544 

Konsole

Skip menu "Konsole"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • Konsole
  • Libraries
  •   libkonq
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal