~verzegnassi-stefano/+junk/ubuntu-terminal-app-uitk13

« back to all changes in this revision

Viewing changes to src/plugin/qmltermwidget/qtermwidget/lib/Emulation.cpp

  • Committer: Filippo Scognamiglio
  • Date: 2014-10-25 04:42:31 UTC
  • Revision ID: flscogna@gmail.com-20141025044231-javjhusbqa171127
Initial reboot commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright 2007-2008 Robert Knight <robertknight@gmail.com> 
 
3
    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
 
4
    Copyright 1996 by Matthias Ettrich <ettrich@kde.org>
 
5
 
 
6
    This program is free software; you can redistribute it and/or modify
 
7
    it under the terms of the GNU General Public License as published by
 
8
    the Free Software Foundation; either version 2 of the License, or
 
9
    (at your option) any later version.
 
10
 
 
11
    This program is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
    GNU General Public License for more details.
 
15
 
 
16
    You should have received a copy of the GNU General Public License
 
17
    along with this program; if not, write to the Free Software
 
18
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
19
    02110-1301  USA.
 
20
*/
 
21
 
 
22
// Own
 
23
#include "Emulation.h"
 
24
 
 
25
// System
 
26
#include <assert.h>
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
 
 
31
// Qt
 
32
#include <QApplication>
 
33
#include <QClipboard>
 
34
#include <QHash>
 
35
#include <QKeyEvent>
 
36
#include <QRegExp>
 
37
#include <QTextStream>
 
38
#include <QThread>
 
39
 
 
40
#include <QTime>
 
41
 
 
42
// KDE
 
43
//#include <kdebug.h>
 
44
 
 
45
// Konsole
 
46
#include "KeyboardTranslator.h"
 
47
#include "Screen.h"
 
48
#include "TerminalCharacterDecoder.h"
 
49
#include "ScreenWindow.h"
 
50
 
 
51
using namespace Konsole;
 
52
 
 
53
Emulation::Emulation() :
 
54
  _currentScreen(0),
 
55
  _codec(0),
 
56
  _decoder(0),
 
57
  _keyTranslator(0),
 
58
  _usesMouse(false)
 
59
{
 
60
  // create screens with a default size
 
61
  _screen[0] = new Screen(40,80);
 
62
  _screen[1] = new Screen(40,80);
 
63
  _currentScreen = _screen[0];
 
64
 
 
65
  QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
 
66
  QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) );
 
67
   
 
68
  // listen for mouse status changes
 
69
  connect( this , SIGNAL(programUsesMouseChanged(bool)) , 
 
70
           SLOT(usesMouseChanged(bool)) );
 
71
}
 
72
 
 
73
bool Emulation::programUsesMouse() const
 
74
{
 
75
    return _usesMouse;
 
76
}
 
77
 
 
78
void Emulation::usesMouseChanged(bool usesMouse)
 
79
{
 
80
    _usesMouse = usesMouse;
 
81
}
 
82
 
 
83
ScreenWindow* Emulation::createWindow()
 
84
{
 
85
    ScreenWindow* window = new ScreenWindow();
 
86
    window->setScreen(_currentScreen);
 
87
    _windows << window;
 
88
 
 
89
    connect(window , SIGNAL(selectionChanged()),
 
90
            this , SLOT(bufferedUpdate()));
 
91
 
 
92
    connect(this , SIGNAL(outputChanged()),
 
93
            window , SLOT(notifyOutputChanged()) );
 
94
    return window;
 
95
}
 
96
 
 
97
Emulation::~Emulation()
 
98
{
 
99
  QListIterator<ScreenWindow*> windowIter(_windows);
 
100
 
 
101
  while (windowIter.hasNext())
 
102
  {
 
103
    delete windowIter.next();
 
104
  }
 
105
 
 
106
  delete _screen[0];
 
107
  delete _screen[1];
 
108
  delete _decoder;
 
109
}
 
110
 
 
111
void Emulation::setScreen(int n)
 
112
{
 
113
  Screen *old = _currentScreen;
 
114
  _currentScreen = _screen[n & 1];
 
115
  if (_currentScreen != old) 
 
116
  {
 
117
     // tell all windows onto this emulation to switch to the newly active screen
 
118
     foreach(ScreenWindow* window,_windows)
 
119
         window->setScreen(_currentScreen);
 
120
  }
 
121
}
 
122
 
 
123
void Emulation::clearHistory()
 
124
{
 
125
    _screen[0]->setScroll( _screen[0]->getScroll() , false );
 
126
}
 
127
void Emulation::setHistory(const HistoryType& t)
 
128
{
 
129
  _screen[0]->setScroll(t);
 
130
 
 
131
  showBulk();
 
132
}
 
133
 
 
134
const HistoryType& Emulation::history() const
 
135
{
 
136
  return _screen[0]->getScroll();
 
137
}
 
138
 
 
139
void Emulation::setCodec(const QTextCodec * qtc)
 
140
{
 
141
  if (qtc)
 
142
      _codec = qtc;
 
143
  else
 
144
     setCodec(LocaleCodec);
 
145
 
 
146
  delete _decoder;
 
147
  _decoder = _codec->makeDecoder();
 
148
 
 
149
  emit useUtf8Request(utf8());
 
150
}
 
151
 
 
152
void Emulation::setCodec(EmulationCodec codec)
 
153
{
 
154
    if ( codec == Utf8Codec )
 
155
        setCodec( QTextCodec::codecForName("utf8") );
 
156
    else if ( codec == LocaleCodec )
 
157
        setCodec( QTextCodec::codecForLocale() );
 
158
}
 
159
 
 
160
void Emulation::setKeyBindings(const QString& name)
 
161
{
 
162
  _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
 
163
  if (!_keyTranslator)
 
164
  {
 
165
      _keyTranslator = KeyboardTranslatorManager::instance()->defaultTranslator();
 
166
  }
 
167
}
 
168
 
 
169
QString Emulation::keyBindings() const
 
170
{
 
171
  return _keyTranslator->name();
 
172
}
 
173
 
 
174
void Emulation::receiveChar(int c)
 
175
// process application unicode input to terminal
 
176
// this is a trivial scanner
 
177
{
 
178
  c &= 0xff;
 
179
  switch (c)
 
180
  {
 
181
    case '\b'      : _currentScreen->backspace();                 break;
 
182
    case '\t'      : _currentScreen->tab();                       break;
 
183
    case '\n'      : _currentScreen->newLine();                   break;
 
184
    case '\r'      : _currentScreen->toStartOfLine();             break;
 
185
    case 0x07      : emit stateSet(NOTIFYBELL);
 
186
                     break;
 
187
    default        : _currentScreen->displayCharacter(c);         break;
 
188
  };
 
189
}
 
190
 
 
191
void Emulation::sendKeyEvent( QKeyEvent* ev )
 
192
{
 
193
  emit stateSet(NOTIFYNORMAL);
 
194
  
 
195
  if (!ev->text().isEmpty())
 
196
  { // A block of text
 
197
    // Note that the text is proper unicode.
 
198
    // We should do a conversion here
 
199
    emit sendData(ev->text().toUtf8(),ev->text().length());
 
200
  }
 
201
}
 
202
 
 
203
void Emulation::sendString(const char*,int)
 
204
{
 
205
    // default implementation does nothing
 
206
}
 
207
 
 
208
void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
 
209
{
 
210
    // default implementation does nothing
 
211
}
 
212
 
 
213
/*
 
214
   We are doing code conversion from locale to unicode first.
 
215
TODO: Character composition from the old code.  See #96536
 
216
*/
 
217
 
 
218
void Emulation::receiveData(const char* text, int length)
 
219
{
 
220
    emit stateSet(NOTIFYACTIVITY);
 
221
 
 
222
    bufferedUpdate();
 
223
        
 
224
    QString unicodeText = _decoder->toUnicode(text,length);
 
225
 
 
226
    //send characters to terminal emulator
 
227
    for (int i=0;i<unicodeText.length();i++)
 
228
        receiveChar(unicodeText[i].unicode());
 
229
 
 
230
    //look for z-modem indicator
 
231
    //-- someone who understands more about z-modems that I do may be able to move
 
232
    //this check into the above for loop?
 
233
    for (int i=0;i<length;i++)
 
234
    {
 
235
        if (text[i] == '\030')
 
236
        {
 
237
            if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0))
 
238
                emit zmodemDetected();
 
239
        }
 
240
    }
 
241
}
 
242
 
 
243
//OLDER VERSION
 
244
//This version of onRcvBlock was commented out because
 
245
//    a)  It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
 
246
//    b)  It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
 
247
//        were not printed properly.
 
248
//
 
249
//There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
 
250
//which hasn't been ported into the newer function (above).  Hopefully someone who understands this better
 
251
//can find an alternative way of handling the check.  
 
252
 
 
253
 
 
254
/*void Emulation::onRcvBlock(const char *s, int len)
 
255
{
 
256
  emit notifySessionState(NOTIFYACTIVITY);
 
257
  
 
258
  bufferedUpdate();
 
259
  for (int i = 0; i < len; i++)
 
260
  {
 
261
 
 
262
    QString result = _decoder->toUnicode(&s[i],1);
 
263
    int reslen = result.length();
 
264
 
 
265
    // If we get a control code halfway a multi-byte sequence
 
266
    // we flush the _decoder and continue with the control code.
 
267
    if ((s[i] < 32) && (s[i] > 0))
 
268
    {
 
269
       // Flush _decoder
 
270
       while(!result.length())
 
271
          result = _decoder->toUnicode(&s[i],1);
 
272
       reslen = 1;
 
273
       result.resize(reslen);
 
274
       result[0] = QChar(s[i]);
 
275
    }
 
276
 
 
277
    for (int j = 0; j < reslen; j++)
 
278
    {
 
279
      if (result[j].characterategory() == QChar::Mark_NonSpacing)
 
280
         _currentScreen->compose(result.mid(j,1));
 
281
      else
 
282
         onRcvChar(result[j].unicode());
 
283
    }
 
284
    if (s[i] == '\030')
 
285
    {
 
286
      if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
 
287
          emit zmodemDetected();
 
288
    }
 
289
  }
 
290
}*/
 
291
 
 
292
void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , 
 
293
                               int startLine ,
 
294
                               int endLine) 
 
295
{
 
296
  _currentScreen->writeLinesToStream(_decoder,startLine,endLine);
 
297
}
 
298
 
 
299
int Emulation::lineCount() const
 
300
{
 
301
    // sum number of lines currently on _screen plus number of lines in history
 
302
    return _currentScreen->getLines() + _currentScreen->getHistLines();
 
303
}
 
304
 
 
305
#define BULK_TIMEOUT1 10
 
306
#define BULK_TIMEOUT2 40
 
307
 
 
308
void Emulation::showBulk()
 
309
{
 
310
    _bulkTimer1.stop();
 
311
    _bulkTimer2.stop();
 
312
 
 
313
    emit outputChanged();
 
314
 
 
315
    _currentScreen->resetScrolledLines();
 
316
    _currentScreen->resetDroppedLines();
 
317
}
 
318
 
 
319
void Emulation::bufferedUpdate()
 
320
{
 
321
   _bulkTimer1.setSingleShot(true);
 
322
   _bulkTimer1.start(BULK_TIMEOUT1);
 
323
   if (!_bulkTimer2.isActive())
 
324
   {
 
325
      _bulkTimer2.setSingleShot(true);
 
326
      _bulkTimer2.start(BULK_TIMEOUT2);
 
327
   }
 
328
}
 
329
 
 
330
char Emulation::eraseChar() const
 
331
{
 
332
  return '\b';
 
333
}
 
334
 
 
335
void Emulation::setImageSize(int lines, int columns)
 
336
{
 
337
  if ((lines < 1) || (columns < 1)) 
 
338
    return;
 
339
 
 
340
  QSize screenSize[2] = { QSize(_screen[0]->getColumns(),
 
341
                                _screen[0]->getLines()),
 
342
                          QSize(_screen[1]->getColumns(),
 
343
                                _screen[1]->getLines()) };
 
344
  QSize newSize(columns,lines);
 
345
 
 
346
  if (newSize == screenSize[0] && newSize == screenSize[1])
 
347
    return;    
 
348
 
 
349
  _screen[0]->resizeImage(lines,columns);
 
350
  _screen[1]->resizeImage(lines,columns);
 
351
 
 
352
  emit imageSizeChanged(lines,columns);
 
353
 
 
354
  bufferedUpdate();
 
355
}
 
356
 
 
357
QSize Emulation::imageSize() const
 
358
{
 
359
  return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
 
360
}
 
361
 
 
362
ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const
 
363
{
 
364
    ushort hash = 0;
 
365
    for ( ushort i = 0 ; i < length ; i++ )
 
366
    {
 
367
        hash = 31*hash + unicodePoints[i];
 
368
    }
 
369
    return hash;
 
370
}
 
371
bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const
 
372
{
 
373
    ushort* entry = extendedCharTable[hash];
 
374
 
 
375
    // compare given length with stored sequence length ( given as the first ushort in the 
 
376
    // stored buffer ) 
 
377
    if ( entry == 0 || entry[0] != length ) 
 
378
       return false;
 
379
    // if the lengths match, each character must be checked.  the stored buffer starts at
 
380
    // entry[1]
 
381
    for ( int i = 0 ; i < length ; i++ )
 
382
    {
 
383
        if ( entry[i+1] != unicodePoints[i] )
 
384
           return false; 
 
385
    } 
 
386
    return true;
 
387
}
 
388
ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length)
 
389
{
 
390
    // look for this sequence of points in the table
 
391
    ushort hash = extendedCharHash(unicodePoints,length);
 
392
 
 
393
    // check existing entry for match
 
394
    while ( extendedCharTable.contains(hash) )
 
395
    {
 
396
        if ( extendedCharMatch(hash,unicodePoints,length) )
 
397
        {
 
398
            // this sequence already has an entry in the table, 
 
399
            // return its hash
 
400
            return hash;
 
401
        }
 
402
        else
 
403
        {
 
404
            // if hash is already used by another, different sequence of unicode character
 
405
            // points then try next hash
 
406
            hash++;
 
407
        }
 
408
    }    
 
409
 
 
410
    
 
411
     // add the new sequence to the table and
 
412
     // return that index
 
413
    ushort* buffer = new ushort[length+1];
 
414
    buffer[0] = length;
 
415
    for ( int i = 0 ; i < length ; i++ )
 
416
       buffer[i+1] = unicodePoints[i]; 
 
417
    
 
418
    extendedCharTable.insert(hash,buffer);
 
419
 
 
420
    return hash;
 
421
}
 
422
 
 
423
ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const
 
424
{
 
425
    // lookup index in table and if found, set the length
 
426
    // argument and return a pointer to the character sequence
 
427
 
 
428
    ushort* buffer = extendedCharTable[hash];
 
429
    if ( buffer )
 
430
    {
 
431
        length = buffer[0];
 
432
        return buffer+1;
 
433
    }
 
434
    else
 
435
    {
 
436
        length = 0;
 
437
        return 0;
 
438
    }
 
439
}
 
440
 
 
441
ExtendedCharTable::ExtendedCharTable()
 
442
{
 
443
}
 
444
ExtendedCharTable::~ExtendedCharTable()
 
445
{
 
446
    // free all allocated character buffers
 
447
    QHashIterator<ushort,ushort*> iter(extendedCharTable);
 
448
    while ( iter.hasNext() )
 
449
    {
 
450
        iter.next();
 
451
        delete[] iter.value();
 
452
    }
 
453
}
 
454
 
 
455
// global instance
 
456
ExtendedCharTable ExtendedCharTable::instance;
 
457
 
 
458
 
 
459
//#include "Emulation.moc"
 
460