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

Konsole

Emulation.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007-2008 Robert Knight <robertknight@gmail.com> 
00003     Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
00004     Copyright 1996 by Matthias Ettrich <ettrich@kde.org>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00019     02110-1301  USA.
00020 */
00021 
00022 // Own
00023 #include "Emulation.h"
00024 
00025 // System
00026 #include <assert.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 
00031 // Qt
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 // KDE
00043 #include <kdebug.h>
00044 
00045 // Konsole
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   // create screens with a default size
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   // listen for mouse status changes
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      // tell all windows onto this emulation to switch to the newly active screen
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 // process application unicode input to terminal
00172 // this is a trivial scanner
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   { // A block of text
00193     // Note that the text is proper unicode.
00194     // We should do a conversion here
00195     emit sendData(ev->text().toUtf8(),ev->text().length());
00196   }
00197 }
00198 
00199 void Emulation::sendString(const char*,int)
00200 {
00201     // default implementation does nothing
00202 }
00203 
00204 void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
00205 {
00206     // default implementation does nothing
00207 }
00208 
00209 /*
00210    We are doing code conversion from locale to unicode first.
00211 TODO: Character composition from the old code.  See #96536
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     //send characters to terminal emulator
00223     for (int i=0;i<unicodeText.length();i++)
00224         receiveChar(unicodeText[i].unicode());
00225 
00226     //look for z-modem indicator
00227     //-- someone who understands more about z-modems that I do may be able to move
00228     //this check into the above for loop?
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 //OLDER VERSION
00240 //This version of onRcvBlock was commented out because
00241 //    a)  It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
00242 //    b)  It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
00243 //        were not printed properly.
00244 //
00245 //There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
00246 //which hasn't been ported into the newer function (above).  Hopefully someone who understands this better
00247 //can find an alternative way of handling the check.  
00248 
00249 
00250 /*void Emulation::onRcvBlock(const char *s, int len)
00251 {
00252   emit notifySessionState(NOTIFYACTIVITY);
00253   
00254   bufferedUpdate();
00255   for (int i = 0; i < len; i++)
00256   {
00257 
00258     QString result = _decoder->toUnicode(&s[i],1);
00259     int reslen = result.length();
00260 
00261     // If we get a control code halfway a multi-byte sequence
00262     // we flush the _decoder and continue with the control code.
00263     if ((s[i] < 32) && (s[i] > 0))
00264     {
00265        // Flush _decoder
00266        while(!result.length())
00267           result = _decoder->toUnicode(&s[i],1);
00268        reslen = 1;
00269        result.resize(reslen);
00270        result[0] = QChar(s[i]);
00271     }
00272 
00273     for (int j = 0; j < reslen; j++)
00274     {
00275       if (result[j].characterategory() == QChar::Mark_NonSpacing)
00276          _currentScreen->compose(result.mid(j,1));
00277       else
00278          onRcvChar(result[j].unicode());
00279     }
00280     if (s[i] == '\030')
00281     {
00282       if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
00283           emit zmodemDetected();
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     // sum number of lines currently on _screen plus number of lines in history
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     // compare given length with stored sequence length ( given as the first ushort in the 
00372     // stored buffer ) 
00373     if ( entry == 0 || entry[0] != length ) 
00374        return false;
00375     // if the lengths match, each character must be checked.  the stored buffer starts at
00376     // entry[1]
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     // look for this sequence of points in the table
00387     ushort hash = extendedCharHash(unicodePoints,length);
00388 
00389     // check existing entry for match
00390     while ( extendedCharTable.contains(hash) )
00391     {
00392         if ( extendedCharMatch(hash,unicodePoints,length) )
00393         {
00394             // this sequence already has an entry in the table, 
00395             // return its hash
00396             return hash;
00397         }
00398         else
00399         {
00400             // if hash is already used by another, different sequence of unicode character
00401             // points then try next hash
00402             hash++;
00403         }
00404     }    
00405 
00406     
00407      // add the new sequence to the table and
00408      // return that index
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     // lookup index in table and if found, set the length
00422     // argument and return a pointer to the character sequence
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     // free all allocated character buffers
00443     QHashIterator<ushort,ushort*> iter(extendedCharTable);
00444     while ( iter.hasNext() )
00445     {
00446         iter.next();
00447         delete[] iter.value();
00448     }
00449 }
00450 
00451 // global instance
00452 ExtendedCharTable ExtendedCharTable::instance;
00453 
00454 
00455 #include "Emulation.moc"
00456 

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.7
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