2
This file is part of Konsole, an X terminal.
4
Copyright (C) 2007 Robert Knight <robertknight@gmail.com>
5
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
6
Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org>
8
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27
#include "Emulation.h"
36
#include <QtGui/QApplication>
37
#include <QtGui/QClipboard>
38
#include <QtCore/QHash>
39
#include <QtGui/QKeyEvent>
40
#include <QtCore/QRegExp>
41
#include <QtCore/QTextStream>
42
#include <QtCore/QThread>
44
#include <QtCore/QTime>
47
#include "KeyboardTranslator.h"
49
#include "TerminalCharacterDecoder.h"
50
#include "ScreenWindow.h"
52
using namespace Konsole;
54
/* ------------------------------------------------------------------------- */
58
/* ------------------------------------------------------------------------- */
60
//#define CNTL(c) ((c)-'@')
65
Emulation::Emulation() :
73
// create screens with a default size
74
_screen[0] = new Screen( 40, 80 );
75
_screen[1] = new Screen( 40, 80 );
76
_currentScreen = _screen[0];
78
QObject::connect( &_bulkTimer1, SIGNAL( timeout() ), this, SLOT( showBulk() ) );
79
QObject::connect( &_bulkTimer2, SIGNAL( timeout() ), this, SLOT( showBulk() ) );
81
// listen for mouse status changes
82
connect( this , SIGNAL( programUsesMouseChanged( bool ) ) ,
83
SLOT( usesMouseChanged( bool ) ) );
86
bool Emulation::programUsesMouse() const
91
void Emulation::usesMouseChanged( bool usesMouse )
93
_usesMouse = usesMouse;
96
ScreenWindow* Emulation::createWindow()
98
ScreenWindow* window = new ScreenWindow();
99
window->setScreen( _currentScreen );
102
connect( window , SIGNAL( selectionChanged() ),
103
this , SLOT( bufferedUpdate() ) );
105
connect( this , SIGNAL( outputChanged() ),
106
window , SLOT( notifyOutputChanged() ) );
113
Emulation::~Emulation()
115
QListIterator<ScreenWindow*> windowIter( _windows );
117
while ( windowIter.hasNext() )
119
delete windowIter.next();
127
/*! change between primary and alternate _screen
130
void Emulation::setScreen( int n )
132
Screen *old = _currentScreen;
133
_currentScreen = _screen[n&1];
134
if ( _currentScreen != old )
136
old->setBusySelecting( false );
138
// tell all windows onto this emulation to switch to the newly active _screen
139
QListIterator<ScreenWindow*> windowIter( _windows );
140
while ( windowIter.hasNext() )
142
windowIter.next()->setScreen( _currentScreen );
147
void Emulation::clearHistory()
149
_screen[0]->setScroll( _screen[0]->getScroll() , false );
151
void Emulation::setHistory( const HistoryType& t )
153
_screen[0]->setScroll( t );
158
const HistoryType& Emulation::history()
160
return _screen[0]->getScroll();
163
void Emulation::setCodec( const QTextCodec * qtc )
169
_decoder = _codec->makeDecoder();
171
emit useUtf8Request( utf8() );
174
void Emulation::setCodec( EmulationCodec codec )
176
if ( codec == Utf8Codec )
177
setCodec( QTextCodec::codecForName( "utf8" ) );
178
else if ( codec == LocaleCodec )
179
setCodec( QTextCodec::codecForLocale() );
182
void Emulation::setKeyBindings( const QString& name )
184
_keyTranslator = KeyboardTranslatorManager::instance()->findTranslator( name );
187
QString Emulation::keyBindings()
189
return _keyTranslator->name();
193
// Interpreting Codes ---------------------------------------------------------
196
This section deals with decoding the incoming character stream.
197
Decoding means here, that the stream is first separated into `tokens'
198
which are then mapped to a `meaning' provided as operations by the
205
void Emulation::receiveChar( int c )
206
// process application unicode input to terminal
207
// this is a trivial scanner
212
case '\b' : _currentScreen->BackSpace(); break;
213
case '\t' : _currentScreen->Tabulate(); break;
214
case '\n' : _currentScreen->NewLine(); break;
215
case '\r' : _currentScreen->Return(); break;
216
case 0x07 : emit stateSet( NOTIFYBELL );
218
default : _currentScreen->ShowCharacter( c ); break;
222
/* ------------------------------------------------------------------------- */
224
/* Keyboard Handling */
226
/* ------------------------------------------------------------------------- */
231
void Emulation::sendKeyEvent( QKeyEvent* ev )
233
emit stateSet( NOTIFYNORMAL );
235
if ( !ev->text().isEmpty() )
237
// Note that the text is proper unicode.
238
// We should do a conversion here, but since this
239
// routine will never be used, we simply emit plain ascii.
240
//emit sendBlock(ev->text().toAscii(),ev->text().length());
241
emit sendData( ev->text().toUtf8(), ev->text().length() );
245
void Emulation::sendString( const char*, int )
247
// default implementation does nothing
250
void Emulation::sendMouseEvent( int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/ )
252
// default implementation does nothing
255
// Unblocking, Byte to Unicode translation --------------------------------- --
258
We are doing code conversion from locale to unicode first.
259
TODO: Character composition from the old code. See #96536
262
void Emulation::receiveData( const char* text, int length )
264
emit stateSet( NOTIFYACTIVITY );
268
QString unicodeText = _decoder->toUnicode( text, length );
270
//send characters to terminal emulator
271
for ( int i = 0; i < unicodeText.length(); i++ )
273
receiveChar( unicodeText[i].unicode() );
276
//look for z-modem indicator
277
//-- someone who understands more about z-modems that I do may be able to move
278
//this check into the above for loop?
279
for ( int i = 0; i < length; i++ )
281
if ( text[i] == '\030' )
283
if (( length - i - 1 > 3 ) && ( strncmp( text + i + 1, "B00", 3 ) == 0 ) )
284
emit zmodemDetected();
290
//This version of onRcvBlock was commented out because
291
// a) It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
292
// b) It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
293
// were not printed properly.
295
//There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
296
//which hasn't been ported into the newer function (above). Hopefully someone who understands this better
297
//can find an alternative way of handling the check.
300
/*void Emulation::onRcvBlock(const char *s, int len)
302
emit notifySessionState(NOTIFYACTIVITY);
305
for (int i = 0; i < len; i++)
308
QString result = _decoder->toUnicode(&s[i],1);
309
int reslen = result.length();
311
// If we get a control code halfway a multi-byte sequence
312
// we flush the _decoder and continue with the control code.
313
if ((s[i] < 32) && (s[i] > 0))
316
while(!result.length())
317
result = _decoder->toUnicode(&s[i],1);
319
result.resize(reslen);
320
result[0] = QChar(s[i]);
323
for (int j = 0; j < reslen; j++)
325
if (result[j].characterategory() == QChar::Mark_NonSpacing)
326
_currentScreen->compose(result.mid(j,1));
328
onRcvChar(result[j].unicode());
332
if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
333
emit zmodemDetected();
338
// Selection --------------------------------------------------------------- --
341
void Emulation::onSelectionBegin( const int x, const int y, const bool columnmode )
343
if ( !connected ) return;
344
_currentScreen->setSelectionStart( x, y, columnmode );
348
void Emulation::onSelectionExtend( const int x, const int y )
350
if ( !connected ) return;
351
_currentScreen->setSelectionEnd( x, y );
355
void Emulation::setSelection( const bool preserve_line_breaks )
357
if ( !connected ) return;
358
QString t = _currentScreen->selectedText( preserve_line_breaks );
361
QListIterator< TerminalDisplay* > viewIter( _views );
363
while ( viewIter.hasNext() )
364
viewIter.next()->setSelection( t );
368
void Emulation::testIsSelected( const int x, const int y, bool &selected )
370
if ( !connected ) return;
371
selected = _currentScreen->isSelected( x, y );
374
void Emulation::clearSelection()
376
if ( !connected ) return;
377
_currentScreen->clearSelection();
383
void Emulation::writeToStream( TerminalCharacterDecoder* _decoder ,
387
_currentScreen->writeToStream( _decoder, startLine, endLine );
390
int Emulation::lineCount()
392
// sum number of lines currently on _screen plus number of lines in history
393
return _currentScreen->getLines() + _currentScreen->getHistLines();
396
// Refreshing -------------------------------------------------------------- --
398
#define BULK_TIMEOUT1 10
399
#define BULK_TIMEOUT2 40
403
void Emulation::showBulk()
408
emit outputChanged();
410
_currentScreen->resetScrolledLines();
411
_currentScreen->resetDroppedLines();
414
void Emulation::bufferedUpdate()
416
_bulkTimer1.setSingleShot( true );
417
_bulkTimer1.start( BULK_TIMEOUT1 );
418
if ( !_bulkTimer2.isActive() )
420
_bulkTimer2.setSingleShot( true );
421
_bulkTimer2.start( BULK_TIMEOUT2 );
425
char Emulation::getErase() const
430
void Emulation::setImageSize( int lines, int columns )
432
//kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
433
Q_ASSERT( lines > 0 );
434
Q_ASSERT( columns > 0 );
436
_screen[0]->resizeImage( lines, columns );
437
_screen[1]->resizeImage( lines, columns );
439
emit imageSizeChanged( lines, columns );
444
QSize Emulation::imageSize()
446
return QSize( _currentScreen->getColumns(), _currentScreen->getLines() );
449
ushort ExtendedCharTable::extendedCharHash( ushort* unicodePoints , ushort length ) const
452
for ( ushort i = 0 ; i < length ; i++ )
454
hash = 31 * hash + unicodePoints[i];
458
bool ExtendedCharTable::extendedCharMatch( ushort hash , ushort* unicodePoints , ushort length ) const
460
ushort* entry = extendedCharTable[hash];
462
// compare given length with stored sequence length ( given as the first ushort in the
464
if ( entry == 0 || entry[0] != length )
466
// if the lengths match, each character must be checked. the stored buffer starts at
468
for ( int i = 0 ; i < length ; i++ )
470
if ( entry[i+1] != unicodePoints[i] )
475
ushort ExtendedCharTable::createExtendedChar( ushort* unicodePoints , ushort length )
477
// look for this sequence of points in the table
478
ushort hash = extendedCharHash( unicodePoints, length );
480
// check existing entry for match
481
while ( extendedCharTable.contains( hash ) )
483
if ( extendedCharMatch( hash, unicodePoints, length ) )
485
// this sequence already has an entry in the table,
491
// if hash is already used by another, different sequence of unicode character
492
// points then try next hash
498
// add the new sequence to the table and
500
ushort* buffer = new ushort[length+1];
502
for ( int i = 0 ; i < length ; i++ )
503
buffer[i+1] = unicodePoints[i];
505
extendedCharTable.insert( hash, buffer );
510
ushort* ExtendedCharTable::lookupExtendedChar( ushort hash , ushort& length ) const
512
// lookup index in table and if found, set the length
513
// argument and return a pointer to the character sequence
515
ushort* buffer = extendedCharTable[hash];
528
ExtendedCharTable::ExtendedCharTable()
531
ExtendedCharTable::~ExtendedCharTable()
533
// free all allocated character buffers
534
QHashIterator<ushort, ushort*> iter( extendedCharTable );
535
while ( iter.hasNext() )
538
delete[] iter.value();
543
ExtendedCharTable ExtendedCharTable::instance;
546
//#include "moc_Emulation.cpp"