~larryprice/acolyterm/release-0.1

« back to all changes in this revision

Viewing changes to src/plugin/konsole/Emulation.cpp

  • Committer: Larry Price
  • Date: 2016-06-15 14:47:59 UTC
  • Revision ID: larry.price@canonical.com-20160615144759-6wopn0gxwgta3x1n
Updating QMLTermWidget and removing unnecessary konsole codebase

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