Files
konsole/src/Emulation.cpp
Friedrich W. H. Kossebau 451ed33d63 Add explicit moc includes to sources for moc-covered headers
* speeds up incremental builds as changes to a header will not always
  need the full mocs_compilation.cpp for all the target's headers rebuild,
  while having a moc file sourced into a source file only adds minor
  extra costs, due to small own code and the used headers usually
  already covered by the source file, being for the same class/struct
* seems to not slow down clean builds, due to empty mocs_compilation.cpp
  resulting in those quickly processed, while the minor extra cost of the
  sourced moc files does not outweigh that in summary.
  Measured times actually improved by some percent points.
  (ideally CMake would just skip empty mocs_compilation.cpp & its object
  file one day)
* enables compiler to see all methods of a class in same compilation unit
  to do some sanity checks
* potentially more inlining in general, due to more in the compilation unit
* allows to keep using more forward declarations in the header, as with the
  moc code being sourced into the cpp file there definitions can be ensured
  and often are already for the needs of the normal class methods
2023-07-28 12:17:12 +00:00

335 lines
8.4 KiB
C++

/*
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-FileCopyrightText: 1996 Matthias Ettrich <ettrich@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
// Own
#include "Emulation.h"
// Qt
#include <QKeyEvent>
// Konsole
#include "Screen.h"
#include "ScreenWindow.h"
#include "keyboardtranslator/KeyboardTranslator.h"
#include "keyboardtranslator/KeyboardTranslatorManager.h"
using namespace Konsole;
Emulation::Emulation()
{
// create screens with a default size
_screen[0] = new Screen(40, 80);
_screen[1] = new Screen(40, 80);
_currentScreen = _screen[0];
QObject::connect(&_bulkTimer1, &QTimer::timeout, this, &Konsole::Emulation::showBulk);
QObject::connect(&_bulkTimer2, &QTimer::timeout, this, &Konsole::Emulation::showBulk);
// listen for mouse status changes
connect(this, &Konsole::Emulation::programRequestsMouseTracking, this, &Konsole::Emulation::setUsesMouseTracking);
connect(this, &Konsole::Emulation::programBracketedPasteModeChanged, this, &Konsole::Emulation::bracketedPasteModeChanged);
}
bool Emulation::programUsesMouseTracking() const
{
return _usesMouseTracking;
}
void Emulation::setUsesMouseTracking(bool usesMouseTracking)
{
_usesMouseTracking = usesMouseTracking;
}
bool Emulation::programBracketedPasteMode() const
{
return _bracketedPasteMode;
}
void Emulation::bracketedPasteModeChanged(bool bracketedPasteMode)
{
_bracketedPasteMode = bracketedPasteMode;
}
ScreenWindow *Emulation::createWindow()
{
auto window = new ScreenWindow(_currentScreen);
_windows << window;
connect(window, &Konsole::ScreenWindow::selectionChanged, this, &Konsole::Emulation::bufferedUpdate);
connect(window, &Konsole::ScreenWindow::selectionChanged, this, &Konsole::Emulation::checkSelectedText);
connect(this, &Konsole::Emulation::outputChanged, window, &Konsole::ScreenWindow::notifyOutputChanged);
return window;
}
void Emulation::setCurrentTerminalDisplay(TerminalDisplay *display)
{
_screen[0]->setCurrentTerminalDisplay(display);
_screen[1]->setCurrentTerminalDisplay(display);
}
void Emulation::checkScreenInUse()
{
Q_EMIT primaryScreenInUse(_currentScreen == _screen[0]);
}
void Emulation::checkSelectedText()
{
bool isEmpty = !_currentScreen->hasSelection();
Q_EMIT selectionChanged(isEmpty);
}
Emulation::~Emulation()
{
for (ScreenWindow *window : qAsConst(_windows)) {
delete window;
}
delete _screen[0];
delete _screen[1];
}
void Emulation::setPeekPrimary(const bool doPeek)
{
if (doPeek == _peekingPrimary) {
return;
}
_peekingPrimary = doPeek;
setScreenInternal(doPeek ? 0 : _activeScreenIndex);
Q_EMIT outputChanged();
}
void Emulation::setScreen(int index)
{
_activeScreenIndex = index;
_peekingPrimary = false;
setScreenInternal(_activeScreenIndex);
}
void Emulation::setScreenInternal(int index)
{
Screen *oldScreen = _currentScreen;
_currentScreen = _screen[index & 1];
if (_currentScreen != oldScreen) {
// tell all windows onto this emulation to switch to the newly active screen
for (ScreenWindow *window : qAsConst(_windows)) {
window->setScreen(_currentScreen);
}
checkScreenInUse();
checkSelectedText();
}
}
void Emulation::clearHistory()
{
_screen[0]->setScroll(_screen[0]->getScroll(), false);
}
void Emulation::setHistory(const HistoryType &history)
{
_screen[0]->setScroll(history);
showBulk();
}
const HistoryType &Emulation::history() const
{
return _screen[0]->getScroll();
}
void Emulation::setCodec(const QTextCodec *codec)
{
if (codec != nullptr) {
_codec = codec;
_decoder.reset(_codec->makeDecoder());
Q_EMIT useUtf8Request(utf8());
} else {
#if defined(Q_OS_WIN)
setCodec(Utf8Codec);
#else
setCodec(LocaleCodec);
#endif
}
}
void Emulation::setCodec(EmulationCodec codec)
{
if (codec == Utf8Codec) {
setCodec(QTextCodec::codecForName("utf8"));
} else if (codec == LocaleCodec) {
setCodec(QTextCodec::codecForLocale());
}
}
void Emulation::setKeyBindings(const QString &name)
{
_keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
if (_keyTranslator == nullptr) {
_keyTranslator = KeyboardTranslatorManager::instance()->defaultTranslator();
}
}
QString Emulation::keyBindings() const
{
return _keyTranslator->name();
}
// process application unicode input to terminal
// this is a trivial scanner
void Emulation::receiveChars(const QVector<uint> &chars)
{
for (uint c : chars) {
c &= 0xff;
switch (c) {
case '\b':
_currentScreen->backspace();
break;
case '\t':
_currentScreen->tab();
break;
case '\n':
_currentScreen->newLine();
break;
case '\r':
_currentScreen->toStartOfLine();
break;
case 0x07:
Q_EMIT bell();
break;
default:
_currentScreen->displayCharacter(c);
break;
}
}
}
void Emulation::sendKeyEvent(QKeyEvent *ev)
{
if (!ev->text().isEmpty()) {
// A block of text
// Note that the text is proper unicode.
// We should do a conversion here
Q_EMIT sendData(ev->text().toLocal8Bit());
}
}
void Emulation::receiveData(const char *text, int length)
{
Q_ASSERT(_decoder);
bufferedUpdate();
// send characters to terminal emulator
const QVector<uint> chars = _decoder->toUnicode(text, length).toUcs4();
receiveChars(chars);
// look for z-modem indicator
//-- someone who understands more about z-modems that I do may be able to move
// this check into the above for loop?
auto *found = static_cast<const char *>(memchr(text, '\030', length));
if (found) {
auto startPos = found - text;
if (startPos < 0) {
return;
}
for (int i = startPos; i < length - 4; i++) {
if (text[i] == '\030') {
if (qstrncmp(text + i + 1, "B00", 3) == 0) {
Q_EMIT zmodemDownloadDetected();
} else if (qstrncmp(text + i + 1, "B01", 3) == 0) {
Q_EMIT zmodemUploadDetected();
}
}
}
}
}
void Emulation::writeToStream(TerminalCharacterDecoder *decoder, int startLine, int endLine)
{
_currentScreen->writeLinesToStream(decoder, startLine, endLine);
}
int Emulation::lineCount() const
{
// sum number of lines currently on _screen plus number of lines in history
return _currentScreen->getLines() + _currentScreen->getHistLines();
}
void Emulation::showBulk()
{
_bulkTimer1.stop();
_bulkTimer2.stop();
Q_EMIT outputChanged();
_currentScreen->resetScrolledLines();
_currentScreen->resetDroppedLines();
}
void Emulation::bufferedUpdate()
{
static const int BULK_TIMEOUT1 = 10;
static const int BULK_TIMEOUT2 = 40;
_bulkTimer1.setSingleShot(true);
_bulkTimer1.start(BULK_TIMEOUT1);
if (!_bulkTimer2.isActive()) {
_bulkTimer2.setSingleShot(true);
_bulkTimer2.start(BULK_TIMEOUT2);
}
}
char Emulation::eraseChar() const
{
return '\b';
}
void Emulation::setImageSize(int lines, int columns)
{
if ((lines < 1) || (columns < 1)) {
return;
}
QSize screenSize[2] = {QSize(_screen[0]->getColumns(), _screen[0]->getLines()), //
QSize(_screen[1]->getColumns(), _screen[1]->getLines())};
QSize newSize(columns, lines);
if (newSize == screenSize[0] && newSize == screenSize[1]) {
// If this method is called for the first time, always emit
// SIGNAL(imageSizeChange()), even if the new size is the same as the
// current size. See #176902
if (!_imageSizeInitialized) {
Q_EMIT imageSizeChanged(lines, columns);
}
} else {
_screen[0]->resizeImage(lines, columns);
_screen[1]->resizeImage(lines, columns);
Q_EMIT imageSizeChanged(lines, columns);
bufferedUpdate();
}
if (!_imageSizeInitialized) {
_imageSizeInitialized = true;
Q_EMIT imageSizeInitialized();
}
}
QSize Emulation::imageSize() const
{
return {_currentScreen->getColumns(), _currentScreen->getLines()};
}
#include "moc_Emulation.cpp"