source: ogBrowser-Git/qtermwidget/lib/Emulation.cpp @ c0cec9d

jenkinsmain
Last change on this file since c0cec9d was fedf2a2, checked in by Vadim Troshchinskiy Shmelev <vtroshchinskiy@…>, 18 months ago

Update Qtermwidget to Qt6 version
Remove build files

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