• Skip to content
  • Skip to link menu
KDE 4.1 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 2007-2008 Robert Knight <robertknight@gmail.com> 
00005     Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
00006     Copyright 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   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 // Interpreting Codes ---------------------------------------------------------
00197 
00198 /*
00199    This section deals with decoding the incoming character stream.
00200    Decoding means here, that the stream is first separated into `tokens'
00201    which are then mapped to a `meaning' provided as operations by the
00202    `Screen' class.
00203 */
00204 
00208 void Emulation::receiveChar(int c)
00209 // process application unicode input to terminal
00210 // this is a trivial scanner
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 /*                             Keyboard Handling                             */
00228 /*                                                                           */
00229 /* ------------------------------------------------------------------------- */
00230 
00234 void Emulation::sendKeyEvent( QKeyEvent* ev )
00235 {
00236   emit stateSet(NOTIFYNORMAL);
00237   
00238   if (!ev->text().isEmpty())
00239   { // A block of text
00240     // Note that the text is proper unicode.
00241     // We should do a conversion here, but since this
00242     // routine will never be used, we simply emit plain ascii.
00243     //emit sendBlock(ev->text().toAscii(),ev->text().length());
00244     emit sendData(ev->text().toUtf8(),ev->text().length());
00245   }
00246 }
00247 
00248 void Emulation::sendString(const char*,int)
00249 {
00250     // default implementation does nothing
00251 }
00252 
00253 void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
00254 {
00255     // default implementation does nothing
00256 }
00257 
00258 // Unblocking, Byte to Unicode translation --------------------------------- --
00259 
00260 /*
00261    We are doing code conversion from locale to unicode first.
00262 TODO: Character composition from the old code.  See #96536
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     //send characters to terminal emulator
00274     for (int i=0;i<unicodeText.length();i++)
00275     {
00276         receiveChar(unicodeText[i].unicode());
00277     }
00278 
00279     //look for z-modem indicator
00280     //-- someone who understands more about z-modems that I do may be able to move
00281     //this check into the above for loop?
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 //OLDER VERSION
00293 //This version of onRcvBlock was commented out because
00294 //  a)  It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
00295 //  b)  It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
00296 //      were not printed properly.
00297 //
00298 //There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
00299 //which hasn't been ported into the newer function (above).  Hopefully someone who understands this better
00300 //can find an alternative way of handling the check.  
00301 
00302 
00303 /*void Emulation::onRcvBlock(const char *s, int len)
00304 {
00305   emit notifySessionState(NOTIFYACTIVITY);
00306   
00307   bufferedUpdate();
00308   for (int i = 0; i < len; i++)
00309   {
00310 
00311     QString result = _decoder->toUnicode(&s[i],1);
00312     int reslen = result.length();
00313 
00314     // If we get a control code halfway a multi-byte sequence
00315     // we flush the _decoder and continue with the control code.
00316     if ((s[i] < 32) && (s[i] > 0))
00317     {
00318        // Flush _decoder
00319        while(!result.length())
00320           result = _decoder->toUnicode(&s[i],1);
00321        reslen = 1;
00322        result.resize(reslen);
00323        result[0] = QChar(s[i]);
00324     }
00325 
00326     for (int j = 0; j < reslen; j++)
00327     {
00328       if (result[j].characterategory() == QChar::Mark_NonSpacing)
00329          _currentScreen->compose(result.mid(j,1));
00330       else
00331          onRcvChar(result[j].unicode());
00332     }
00333     if (s[i] == '\030')
00334     {
00335       if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
00336         emit zmodemDetected();
00337     }
00338   }
00339 }*/
00340 
00341 // Selection --------------------------------------------------------------- --
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     // sum number of lines currently on _screen plus number of lines in history
00392     return _currentScreen->getLines() + _currentScreen->getHistLines();
00393 }
00394 
00395 // Refreshing -------------------------------------------------------------- --
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     // compare given length with stored sequence length ( given as the first ushort in the 
00470     // stored buffer ) 
00471     if ( entry == 0 || entry[0] != length ) 
00472        return false;
00473     // if the lengths match, each character must be checked.  the stored buffer starts at
00474     // entry[1]
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     // look for this sequence of points in the table
00485     ushort hash = extendedCharHash(unicodePoints,length);
00486 
00487     // check existing entry for match
00488     while ( extendedCharTable.contains(hash) )
00489     {
00490         if ( extendedCharMatch(hash,unicodePoints,length) )
00491         {
00492             // this sequence already has an entry in the table, 
00493             // return its hash
00494             return hash;
00495         }
00496         else
00497         {
00498             // if hash is already used by another, different sequence of unicode character
00499             // points then try next hash
00500             hash++;
00501         }
00502     }    
00503 
00504     
00505      // add the new sequence to the table and
00506      // return that index
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     // lookup index in table and if found, set the length
00520     // argument and return a pointer to the character sequence
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     // free all allocated character buffers
00541     QHashIterator<ushort,ushort*> iter(extendedCharTable);
00542     while ( iter.hasNext() )
00543     {
00544         iter.next();
00545         delete[] iter.value();
00546     }
00547 }
00548 
00549 // global instance
00550 ExtendedCharTable ExtendedCharTable::instance;
00551 
00552 
00553 #include "Emulation.moc"
00554 

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