21#include "TerminalDisplay.h"
27#include <QAbstractButton>
28#include <QApplication>
39#include <QRegularExpression>
49#include "ScreenWindow.h"
50#include "TerminalCharacterDecoder.h"
51#include "konsole_wcwidth.h"
56inline void initResource()
61using namespace Konsole;
63constexpr auto REPCHAR =
64"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
65"abcdefgjijklmnopqrstuvwxyz"
71bool TerminalDisplay::_antialiasText =
true;
75const QChar LTR_OVERRIDE_CHAR(0x202D);
99 disconnect(_screenWindow,
nullptr,
this,
nullptr);
109 window->setWindowLines(_lines);
120 _colorTable[DEFAULT_BACK_COLOR].color = color;
129 qDebug() <<
"Setting Terminal bg and opacity" << _opacity;
131 p.
setColor(backgroundRole(), _colorTable[DEFAULT_BACK_COLOR].color);
137 Q_EMIT backgroundColorChanged();
140QColor TerminalDisplay::backgroundColor()
const
142 return _colorTable[DEFAULT_BACK_COLOR].color;
147 _colorTable[DEFAULT_FORE_COLOR].color = color;
149 Q_EMIT foregroundColorChanged();
152QColor TerminalDisplay::foregroundColor()
const
154 return _colorTable[DEFAULT_FORE_COLOR].color;
159 _colorTable = std::move(table);
181constexpr bool TerminalDisplay::isLineChar(
QChar c)
const
183 return _drawLineChars && ((c.
unicode() & 0xFF80) == 0x2500);
186constexpr bool TerminalDisplay::isLineCharString(
QStringView string)
const
188 return (
string.size() > 0) && (isLineChar(
string[0]));
191void TerminalDisplay::fontChange(
const QFont &)
193 QFontMetricsF fm(font());
194 _fontHeight = fm.height() + _lineSpacing;
200 _fontWidth = fm.horizontalAdvance(QLatin1String(REPCHAR)) / (qreal)qstrlen(REPCHAR);
204 int fw = fm.horizontalAdvance(QLatin1Char(REPCHAR[0]));
205 for (
unsigned int i = 1; i < qstrlen(REPCHAR); i++) {
206 if (fw != fm.horizontalAdvance(QLatin1Char(REPCHAR[i]))) {
215 _fontAscent = fm.ascent();
217 Q_EMIT changedFontMetricSignal(_fontHeight, _fontWidth);
243 qDebug() <<
"Using a variable-width font in the terminal. This may cause performance degradation and display/alignment errors.";
254 font.setKerning(
false);
263 if (_boldIntense != value) {
264 _boldIntense = value;
265 Q_EMIT boldIntenseChanged();
278, _screenWindow(nullptr)
280, _gridLayout(nullptr)
293, _terminalSizeHint(false)
294, _terminalSizeStartup(true)
297, _disabledBracketedPasteMode(false)
299, _wordSelectionMode(false)
300, _lineSelectionMode(false)
301, _preserveLineBreaks(false)
302, _columnSelectionMode(false)
308, _cursorBlinking(false)
309, _hasBlinkingCursor(false)
310, _allowBlinkingText(true)
314, _possibleTripleClick(false)
315, _resizeWidget(nullptr)
316, _resizeTimer(nullptr)
317, _flowControlWarningEnabled(false)
318, _outputSuspendedLabel(nullptr)
320, _colorsInverted(false)
321, _opacity(static_cast<qreal>(1))
323, _cursorShape(
Emulation::KeyboardCursorShape::BlockCursor)
324, mMotionAfterPasting(NoMoveScreenWindow)
327, m_font(QStringLiteral(
"Monospace"), 12)
329, m_full_cursor_height(false)
330, _drawLineChars(true)
331, m_customColorScheme(new CustomColorScheme(this))
343 _topMargin = _topBaseMargin;
344 _leftMargin = _leftBaseMargin;
346 m_palette = qApp->palette();
363 _blinkTimer =
new QTimer(
this);
364 connect(_blinkTimer, SIGNAL(timeout()),
this, SLOT(blinkEvent()));
365 _blinkCursorTimer =
new QTimer(
this);
371 setBracketedPasteMode(
false);
381 _scrollBar->setVisible(
false);
403TerminalDisplay::~TerminalDisplay()
407 qApp->removeEventFilter(
this);
410 delete _outputSuspendedLabel;
468static void drawLineChar(QPainter &paint,
int x,
int y,
int w,
int h, uint8_t code)
476 quint32 toDraw = LineChars[code];
480 paint.
drawLine(cx - 1, y, cx - 1, cy - 2);
484 paint.
drawLine(cx + 1, y, cx + 1, cy - 2);
488 paint.
drawLine(cx - 1, cy + 2, cx - 1, ey);
492 paint.
drawLine(cx + 1, cy + 2, cx + 1, ey);
496 paint.
drawLine(x, cy - 1, cx - 2, cy - 1);
500 paint.
drawLine(x, cy + 1, cx - 2, cy + 1);
504 paint.
drawLine(cx + 2, cy - 1, ex, cy - 1);
508 paint.
drawLine(cx + 2, cy + 1, ex, cy + 1);
533static void drawOtherChar(QPainter &paint,
int x,
int y,
int w,
int h, uchar code)
536 const int cx = x + w / 2;
537 const int cy = y + h / 2;
538 const int ex = x + w - 1;
539 const int ey = y + h - 1;
542 if (0x4C <= code && code <= 0x4F) {
543 const int xHalfGap = qMax(w / 15, 1);
544 const int yHalfGap = qMax(h / 15, 1);
547 paint.
drawLine(x, cy - 1, cx - xHalfGap - 1, cy - 1);
548 paint.
drawLine(x, cy + 1, cx - xHalfGap - 1, cy + 1);
549 paint.
drawLine(cx + xHalfGap, cy - 1, ex, cy - 1);
550 paint.
drawLine(cx + xHalfGap, cy + 1, ex, cy + 1);
553 paint.
drawLine(x, cy, cx - xHalfGap - 1, cy);
554 paint.
drawLine(cx + xHalfGap, cy, ex, cy);
557 paint.
drawLine(cx - 1, y, cx - 1, cy - yHalfGap - 1);
558 paint.
drawLine(cx + 1, y, cx + 1, cy - yHalfGap - 1);
559 paint.
drawLine(cx - 1, cy + yHalfGap, cx - 1, ey);
560 paint.
drawLine(cx + 1, cy + yHalfGap, cx + 1, ey);
563 paint.
drawLine(cx, y, cx, cy - yHalfGap - 1);
564 paint.
drawLine(cx, cy + yHalfGap, cx, ey);
570 else if (0x6D <= code && code <= 0x70) {
571 const int r = w * 3 / 8;
577 paint.
drawArc(cx, cy, d, d, 90 * 16, 90 * 16);
582 paint.
drawArc(cx - d, cy, d, d, 0 * 16, 90 * 16);
587 paint.
drawArc(cx - d, cy - d, d, d, 270 * 16, 90 * 16);
592 paint.
drawArc(cx, cy - d, d, d, 180 * 16, 90 * 16);
598 else if (0x71 <= code && code <= 0x73) {
614void TerminalDisplay::drawLineCharString(QPainter &painter,
int x,
int y, QStringView str,
const Character *attributes)
const
616 const QPen ¤tPen = painter.
pen();
618 if ((attributes->
rendition & RE_BOLD) && _boldIntense) {
619 QPen boldPen(currentPen);
624 for (qsizetype i = 0; i < str.
size(); i++) {
625 uint8_t code =
static_cast<uint8_t
>(str[i].unicode() & 0xffU);
627 drawLineChar(painter, qRound(
x + (_fontWidth * i)),
y, qRound(_fontWidth), qRound(_fontHeight), code);
629 drawOtherChar(painter, qRound(
x + (_fontWidth * i)),
y, qRound(_fontWidth), qRound(_fontHeight), code);
632 painter.
setPen(currentPen);
637 if (_cursorShape == shape) {
641 _cursorShape = shape;
652 if (useForegroundColor)
659 _cursorColor = color;
668 if (_opacity != backgroundOpacity)
670 _opacity = backgroundOpacity;
672 QColor nColor = backgroundColor();
676 Q_EMIT backgroundOpacityChanged();
680void TerminalDisplay::drawBackground(
QPainter &painter,
const QRect &rect,
const QColor &backgroundColor,
bool useOpacitySetting)
685 if (useOpacitySetting) {
686 QColor color(backgroundColor);
687 color.setAlphaF(_opacity);
694 painter.
fillRect(rect, backgroundColor);
697void TerminalDisplay::drawCursor(QPainter &painter,
699 const QColor &foregroundColor,
701 bool &invertCharacterColor)
703 QRect cursorRect = rect;
705 cursorRect.
setHeight(qRound(_fontHeight) - ((m_full_cursor_height) ? 0 : _lineSpacing - 1));
707 if (!_cursorBlinking) {
708 if (_cursorColor.isValid())
709 painter.
setPen(_cursorColor);
711 painter.
setPen(foregroundColor);
716 float penWidth = qMax(1, painter.
pen().
width());
720 +penWidth / 2 + fmod(penWidth, 2),
721 -penWidth / 2 - fmod(penWidth, 2),
722 -penWidth / 2 - fmod(penWidth, 2)));
726 painter.
fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor);
728 if (!_cursorColor.isValid()) {
731 invertCharacterColor =
true;
741void TerminalDisplay::drawCharacters(QPainter &painter,
const QRect &rect,
const QString &text,
const Character *style,
bool invertCharacterColor)
744 if (_blinking && (style->
rendition & RE_BLINK))
752 bool useBold = ((style->
rendition & RE_BOLD) && _boldIntense) || font().bold();
753 const bool useUnderline = style->
rendition & RE_UNDERLINE || font().underline();
754 const bool useItalic = style->
rendition & RE_ITALIC || font().italic();
755 const bool useStrikeOut = style->
rendition & RE_STRIKEOUT || font().strikeOut();
756 const bool useOverline = style->
rendition & RE_OVERLINE || font().overline();
760 QFont font = painter.
font();
761 if (font.bold() != useBold || font.underline() != useUnderline || font.italic() != useItalic || font.strikeOut() != useStrikeOut
762 || font.overline() != useOverline) {
763 font.setBold(useBold);
764 font.setUnderline(useUnderline);
765 font.setItalic(useItalic);
766 font.setStrikeOut(useStrikeOut);
767 font.setOverline(useOverline);
773 const QColor color = textColor.
color(_colorTable);
774 QPen pen = painter.
pen();
775 if (pen.
color() != color) {
781 if (isLineCharString(text))
782 drawLineCharString(painter, rect.
x(), rect.
y(), text, style);
791 painter.
drawText(rect.
x(), rect.
y() + _fontAscent + _lineSpacing, text);
793 painter.
drawText(rect.
x(), rect.
y() + _fontAscent + _lineSpacing, LTR_OVERRIDE_CHAR + text);
798void TerminalDisplay::drawTextFragment(QPainter &painter,
const QRect &rect,
const QString &text,
const Character *style)
807 if (backgroundColor != this->backgroundColor())
808 drawBackground(painter, rect, backgroundColor,
false );
812 bool invertCharacterColor =
false;
814 drawCursor(painter, rect, foregroundColor, backgroundColor, invertCharacterColor);
817 drawCharacters(painter, rect, text, style, invertCharacterColor);
839void TerminalDisplay::scrollImage(
int lines,
const QRect &screenWindowRegion)
844 if (_outputSuspendedLabel && _outputSuspendedLabel->
isVisible())
851 QRect region = screenWindowRegion;
855 if (lines == 0 || _image.empty() || !region.
isValid() || (region.
top() + abs(lines)) >= region.
bottom() || this->_lines <= region.
height())
859 if (_resizeWidget && _resizeWidget->
isVisible())
860 _resizeWidget->
hide();
872 int scrollBarWidth = _scrollBar->
isHidden() ? 0
874 : _scrollBar->
width();
875 const int SCROLLBAR_CONTENT_GAP = scrollBarWidth == 0 ? 0 : 1;
877 if (_scrollbarLocation == QTermWidget::ScrollBarLeft) {
878 scrollRect.
setLeft(scrollBarWidth + SCROLLBAR_CONTENT_GAP);
882 scrollRect.
setRight(
width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP);
884 void *firstCharPos = &_image[region.
top() * this->_columns];
885 void *lastCharPos = &_image[(region.
top() + abs(lines)) * this->_columns];
887 int top = _topMargin + (region.
top() * qRound(_fontHeight));
888 int linesToMove = region.
height() - abs(lines);
889 int bytesToMove = linesToMove * this->_columns *
sizeof(Character);
891 Q_ASSERT(linesToMove > 0);
892 Q_ASSERT(bytesToMove > 0);
897 Q_ASSERT((
char *)lastCharPos + bytesToMove < (
char *)(_image.data() + (this->_lines * this->_columns)));
899 Q_ASSERT((lines * this->_columns) < _imageSize);
902 memmove(firstCharPos, lastCharPos, bytesToMove);
908 Q_ASSERT((
char *)firstCharPos + bytesToMove < (
char *)(_image.data() + (this->_lines * this->_columns)));
911 memmove(lastCharPos, firstCharPos, bytesToMove);
914 scrollRect.
setTop(top + abs(lines) * qRound(_fontHeight));
916 scrollRect.
setHeight(linesToMove * qRound(_fontHeight));
924QRegion TerminalDisplay::hotSpotRegion()
const
927 const auto hotSpots = _filterChain->hotSpots();
930 if (hotSpot->startLine() == hotSpot->endLine()) {
931 r.
setLeft(hotSpot->startColumn());
932 r.
setTop(hotSpot->startLine());
935 region |= imageToWidget(r);
938 r.
setLeft(hotSpot->startColumn());
939 r.
setTop(hotSpot->startLine());
942 region |= imageToWidget(r);
944 for (
int line = hotSpot->startLine() + 1; line < hotSpot->endLine(); line++) {
949 region |= imageToWidget(r);
953 r.
setTop(hotSpot->endLine());
956 region |= imageToWidget(r);
968 QRegion preUpdateHotSpots = hotSpotRegion();
975 _filterChain->setImage(_screenWindow->getImage(), _screenWindow->windowLines(), _screenWindow->windowColumns(), _screenWindow->getLineProperties());
976 _filterChain->process();
978 QRegion postUpdateHotSpots = hotSpotRegion();
980 update(preUpdateHotSpots | postUpdateHotSpots);
999 if (_image.empty()) {
1005 auto newimg = _screenWindow->getImage();
1006 int lines = _screenWindow->windowLines();
1007 int columns = _screenWindow->windowColumns();
1009 setScroll(_screenWindow->currentLine(), _screenWindow->lineCount());
1011 Q_ASSERT(this->_usedLines <= this->_lines);
1012 Q_ASSERT(this->_usedColumns <= this->_columns);
1016 QPoint tL = contentsRect().topLeft();
1019 _hasBlinker =
false;
1025 const int linesToUpdate = qMin(this->_lines, qMax(0, lines));
1026 const int columnsToUpdate = qMin(this->_columns, qMax(0, columns));
1028 std::vector<QChar> disstrU(columnsToUpdate);
1029 std::vector<char> dirtyMask(columnsToUpdate + 2);
1035 int dirtyLineCount = 0;
1037 for (
y = 0;
y < linesToUpdate; ++
y) {
1038 const Character *currentLine = &_image[
y * _columns];
1039 const Character *
const newLine = &newimg[
y * columns];
1041 bool updateLine =
false;
1046 memset(dirtyMask.data(), 0, columnsToUpdate + 2);
1048 for (
x = 0;
x < columnsToUpdate; ++
x) {
1049 if (newLine[
x] != currentLine[
x]) {
1050 dirtyMask[
x] =
true;
1055 for (
x = 0;
x < columnsToUpdate; ++
x) {
1056 _hasBlinker |= (newLine[
x].
rendition & RE_BLINK);
1067 bool lineDraw = isLineChar(c);
1068 bool doubleWidth = (
x + 1 == columnsToUpdate) ?
false : (newLine[
x + 1].
character.
unicode() == 0);
1071 if (newLine[
x].foregroundColor != cf)
1073 int lln = columnsToUpdate -
x;
1074 for (len = 1; len < lln; ++len) {
1080 bool nextIsDoubleWidth = (
x + len + 1 == columnsToUpdate) ?
false : (newLine[
x + len + 1].
character.
unicode() == 0);
1083 || isLineChar(c) != lineDraw || nextIsDoubleWidth != doubleWidth)
1089 bool saveFixedFont = _fixedFont;
1097 _fixedFont = saveFixedFont;
1106 if (_lineProperties.size() >
y)
1107 updateLine |= (_lineProperties[
y] & LINE_DOUBLEHEIGHT);
1116 QRect dirtyRect =
QRect(_leftMargin + tLx, _topMargin + tLy + qRound(_fontHeight) *
y, _fontWidth * columnsToUpdate, qRound(_fontHeight));
1118 dirtyRegion |= dirtyRect;
1123 memcpy((
void *)currentLine, (
const void *)newLine, columnsToUpdate *
sizeof(
Character));
1128 if (linesToUpdate < _usedLines) {
1129 dirtyRegion |=
QRect(_leftMargin + tLx,
1130 _topMargin + tLy + qRound(_fontHeight) * linesToUpdate,
1131 _fontWidth * this->_columns,
1132 qRound(_fontHeight) * (_usedLines - linesToUpdate));
1134 _usedLines = linesToUpdate;
1136 if (columnsToUpdate < _usedColumns) {
1137 dirtyRegion |=
QRect(_leftMargin + tLx + columnsToUpdate * _fontWidth,
1139 _fontWidth * (_usedColumns - columnsToUpdate),
1140 qRound(_fontHeight) * this->_lines);
1142 _usedColumns = columnsToUpdate;
1144 dirtyRegion |= _inputMethodData.previousPreeditRect;
1147 update(dirtyRegion);
1149 if (_hasBlinker && !_blinkTimer->isActive())
1150 _blinkTimer->start(TEXT_BLINK_DELAY);
1151 if (!_hasBlinker && _blinkTimer->isActive()) {
1152 _blinkTimer->stop();
1157void TerminalDisplay::showResizeNotification()
1163 if (_hasBlinkingCursor != blink)
1164 Q_EMIT blinkingCursorStateChanged();
1166 _hasBlinkingCursor = blink;
1168 if (blink && !_blinkCursorTimer->isActive())
1171 if (!blink && _blinkCursorTimer->isActive()) {
1172 _blinkCursorTimer->stop();
1173 if (_cursorBlinking)
1176 _cursorBlinking =
false;
1182 _allowBlinkingText = blink;
1184 if (blink && !_blinkTimer->isActive())
1185 _blinkTimer->start(TEXT_BLINK_DELAY);
1187 if (!blink && _blinkTimer->isActive()) {
1188 _blinkTimer->stop();
1199 _cursorBlinking =
false;
1202 _blinkCursorTimer->
stop();
1206 _blinkTimer->
stop();
1211 if (_hasBlinkingCursor) {
1212 _blinkCursorTimer->
start();
1217 _blinkTimer->start();
1221void TerminalDisplay::paint(QPainter *painter)
1225 drawContents(*painter, dirtyRect);
1228QPoint TerminalDisplay::cursorPosition()
const
1231 return _screenWindow->cursorPosition();
1236QRect TerminalDisplay::preeditRect()
const
1238 const int preeditLength = string_width(_inputMethodData.preeditString);
1240 if (preeditLength == 0)
1243 return QRect(_leftMargin + qRound(_fontWidth) * cursorPosition().
x(),
1244 _topMargin + qRound(_fontHeight) * cursorPosition().
y(),
1245 qRound(_fontWidth) * preeditLength,
1246 qRound(_fontHeight));
1249void TerminalDisplay::drawInputMethodPreeditString(QPainter &painter,
const QRect &rect)
1251 if (_inputMethodData.preeditString.isEmpty())
1254 const QPoint cursorPos = cursorPosition();
1256 bool invertColors =
false;
1257 const QColor background = _colorTable[DEFAULT_BACK_COLOR].color;
1258 const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color;
1259 const Character *style = &_image[loc(cursorPos.
x(), cursorPos.
y())];
1261 drawBackground(painter, rect, background,
true);
1262 drawCursor(painter, rect, foreground, background, invertColors);
1263 drawCharacters(painter, rect, _inputMethodData.preeditString, style, invertColors);
1265 _inputMethodData.previousPreeditRect = rect;
1270 return _filterChain.get();
1273void TerminalDisplay::paintFilters(
QPainter &painter)
1278 int leftMargin = _leftBaseMargin
1280 ? _scrollBar->
width()
1283 auto charPos = getCharacterPosition(cursorPos);
1284 Character cursorCharacter = _image[loc(charPos.columns, charPos.lines)];
1292 for (
const auto spot : spots) {
1294 if (spot->type() == Filter::HotSpot::Link) {
1296 if (spot->startLine() == spot->endLine()) {
1297 r.
setCoords(spot->startColumn() * qRound(_fontWidth) + 1 + leftMargin,
1298 spot->startLine() * qRound(_fontHeight) + 1 + _topBaseMargin,
1299 spot->endColumn() * qRound(_fontWidth) - 1 + leftMargin,
1300 (spot->endLine() + 1) * qRound(_fontHeight) - 1 + _topBaseMargin);
1303 r.
setCoords(spot->startColumn() * qRound(_fontWidth) + 1 + leftMargin,
1304 spot->startLine() * qRound(_fontHeight) + 1 + _topBaseMargin,
1305 _columns * qRound(_fontWidth) - 1 + leftMargin,
1306 (spot->startLine() + 1) * qRound(_fontHeight) - 1 + _topBaseMargin);
1308 for (
int line = spot->startLine() + 1; line < spot->endLine(); line++) {
1309 r.
setCoords(0 * qRound(_fontWidth) + 1 + leftMargin,
1310 line * qRound(_fontHeight) + 1 + _topBaseMargin,
1311 _columns * qRound(_fontWidth) - 1 + leftMargin,
1312 (line + 1) * qRound(_fontHeight) - 1 + _topBaseMargin);
1315 r.
setCoords(0 * qRound(_fontWidth) + 1 + leftMargin,
1316 spot->endLine() * qRound(_fontHeight) + 1 + _topBaseMargin,
1317 spot->endColumn() * qRound(_fontWidth) - 1 + leftMargin,
1318 (spot->endLine() + 1) * qRound(_fontHeight) - 1 + _topBaseMargin);
1323 for (
int line = spot->startLine(); line <= spot->endLine(); line++) {
1324 int startColumn = 0;
1325 int endColumn = _columns - 1;
1330 while (QChar(_image[loc(endColumn, line)].character).isSpace() && endColumn > 0)
1337 if (line == spot->startLine())
1338 startColumn = spot->startColumn();
1339 if (line == spot->endLine())
1340 endColumn = spot->endColumn();
1352 r.
setCoords(startColumn * qRound(_fontWidth) + 1 + leftMargin,
1353 line * qRound(_fontHeight) + 1 + _topBaseMargin,
1354 endColumn * qRound(_fontWidth) - 1 + leftMargin,
1355 (line + 1) * qRound(_fontHeight) - 1 + _topBaseMargin);
1357 if (spot->type() == Filter::HotSpot::Link) {
1358 QFontMetricsF metrics(font());
1362 qreal baseline = (qreal)r.
bottom() - metrics.descent();
1364 qreal underlinePos = baseline + metrics.underlinePos();
1372 else if (spot->type() == Filter::HotSpot::Marker) {
1374 painter.
fillRect(r, QBrush(QColor(255, 0, 0, 120)));
1380int TerminalDisplay::textWidth(
const int startColumn,
const int length,
const int line)
const
1382 QFontMetricsF fm(font());
1384 for (
int column = 0; column < length; column++) {
1385 result += fm.horizontalAdvance(_image[loc(startColumn + column, line)].character);
1390QRect TerminalDisplay::calculateTextArea(
int topLeftX,
int topLeftY,
int startColumn,
int line,
int length)
1392 int left = _fixedFont ? qRound(_fontWidth) * startColumn : textWidth(0, startColumn, line);
1393 int top = qRound(_fontHeight) * line;
1394 int width = _fixedFont ? qRound(_fontWidth) * length : textWidth(startColumn, length, line);
1395 return {_leftMargin + topLeftX +
left, _topMargin + topLeftY + top,
width, qRound(_fontHeight)};
1398void TerminalDisplay::drawContents(QPainter &paint,
const QRect &rect)
1401 drawBackground(paint, contentsRect(), _colorTable[DEFAULT_BACK_COLOR].color,
true);
1403 QPoint tL = contentsRect().topLeft();
1407 int lux = qMin(_usedColumns - 1, qMax(0, qRound((rect.
left() - tLx - _leftMargin) / _fontWidth)));
1408 int luy = qMin(_usedLines - 1, qMax(0, qRound((rect.
top() - tLy - _topMargin) / _fontHeight)));
1409 int rlx = qMin(_usedColumns - 1, qMax(0, qRound((rect.
right() - tLx - _leftMargin) / _fontWidth)));
1410 int rly = qMin(_usedLines - 1, qMax(0, qRound((rect.
bottom() - tLy - _topMargin) / _fontHeight)));
1412 if (_image.empty()) {
1416 const int bufferSize = _usedColumns;
1419 for (
int y = luy;
y <= rly;
y++) {
1420 char16_t c = _image[loc(lux,
y)].character.unicode();
1424 for (;
x <= rlx;
x++) {
1429 unistr.
resize(bufferSize);
1432 if (_image[loc(
x,
y)].rendition & RE_EXTENDED_CHAR) {
1434 ushort extendedCharLength = 0;
1436 for (
int index = 0; index < extendedCharLength; index++) {
1437 Q_ASSERT(p < bufferSize);
1438 unistr[p++] = chars[index];
1442 c = _image[loc(
x,
y)].character.unicode();
1444 Q_ASSERT(p < bufferSize);
1449 bool lineDraw = isLineChar(c);
1450 bool doubleWidth = (_image[qMin(loc(
x,
y) + 1, _imageSize)].character.unicode() == 0);
1451 CharacterColor currentForeground = _image[loc(
x,
y)].foregroundColor;
1452 CharacterColor currentBackground = _image[loc(
x,
y)].backgroundColor;
1453 quint8 currentRendition = _image[loc(
x,
y)].rendition;
1455 while (
x + len <= rlx && _image[loc(
x + len,
y)].foregroundColor == currentForeground
1456 && _image[loc(
x + len,
y)].backgroundColor == currentBackground && _image[loc(
x + len,
y)].rendition == currentRendition
1457 && (_image[qMin(loc(
x + len,
y) + 1, _imageSize)].character.unicode() == 0) == doubleWidth
1458 && isLineChar(c = _image[loc(
x + len,
y)].character.unicode()) == lineDraw)
1466 if ((
x + len < _usedColumns) && (!_image[loc(
x + len,
y)].character.unicode()))
1469 bool save__fixedFont = _fixedFont;
1475 QTransform textScale;
1477 if (
y < _lineProperties.size()) {
1478 if (_lineProperties[
y] & LINE_DOUBLEWIDTH)
1479 textScale.
scale(2, 1);
1481 if (_lineProperties[
y] & LINE_DOUBLEHEIGHT)
1482 textScale.
scale(1, 2);
1486 paint.setWorldTransform(textScale,
true);
1489 QRect textArea = calculateTextArea(tLx, tLy,
x,
y, len);
1500 drawTextFragment(paint, textArea, unistr, &_image[loc(
x,
y)]);
1504 _fixedFont = save__fixedFont;
1507 paint.setWorldTransform(textScale.
inverted(),
true);
1509 if (
y < _lineProperties.size() - 1) {
1515 if (_lineProperties[
y] & LINE_DOUBLEHEIGHT)
1524void TerminalDisplay::blinkEvent()
1526 if (!_allowBlinkingText)
1529 _blinking = !_blinking;
1537QRect TerminalDisplay::imageToWidget(
const QRect &imageArea)
const
1540 result.
setLeft(_leftMargin + qRound(_fontWidth) * imageArea.
left());
1541 result.
setTop(_topMargin + qRound(_fontHeight) * imageArea.
top());
1548void TerminalDisplay::updateCursor()
1550 QRect cursorRect = imageToWidget(QRect(cursorPosition(), QSize(1, 1)));
1554void TerminalDisplay::blinkCursorEvent()
1556 _cursorBlinking = !_cursorBlinking;
1566void TerminalDisplay::resizeEvent(QResizeEvent *)
1572void TerminalDisplay::propagateSize()
1575 setSize(_columns, _lines);
1578 if (!_image.empty())
1582void TerminalDisplay::updateImageSize()
1584 auto oldimg = _image;
1585 int oldlin = _lines;
1586 int oldcol = _columns;
1591 int lines = qMin(oldlin, _lines);
1592 int columns = qMin(oldcol, _columns);
1594 if (!oldimg.empty()) {
1595 for (
int line = 0; line < lines; line++) {
1596 memcpy((
void *)&_image[_columns * line], (
void *)&oldimg[oldcol * line], columns *
sizeof(Character));
1602 _screenWindow->setWindowLines(_lines);
1604 _resizing = (oldlin != _lines) || (oldcol != _columns);
1607 showResizeNotification();
1608 Q_EMIT changedContentSizeSignal(_contentHeight, _contentWidth);
1619void TerminalDisplay::showEvent(QShowEvent *)
1621 Q_EMIT changedContentSizeSignal(_contentHeight, _contentWidth);
1623void TerminalDisplay::hideEvent(QHideEvent *)
1625 Q_EMIT changedContentSizeSignal(_contentHeight, _contentWidth);
1634void TerminalDisplay::scrollBarPositionChanged(
int)
1639 _screenWindow->scrollTo(_scrollBar->value());
1645 const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum());
1646 _screenWindow->setTrackOutput(atEndOfOutput);
1651 Q_EMIT scrollbarValueChanged();
1661 if (_scrollBar->minimum() == 0 && _scrollBar->maximum() == (slines - _lines) && _scrollBar->value() ==
cursor) {
1666 _scrollBar->setRange(0, slines - _lines);
1667 _scrollBar->setSingleStep(1);
1668 _scrollBar->setPageStep(_lines);
1669 _scrollBar->setValue(
cursor);
1676 _scrollBar->setValue(_scrollBar->maximum());
1679 _screenWindow->scrollTo(_scrollBar->value() + 1);
1680 _screenWindow->setTrackOutput(_screenWindow->atEndOfOutput());
1685 if (_scrollbarLocation == position)
1688 if (position == QTermWidget::NoScrollBar)
1693 _topMargin = _leftMargin = 1;
1694 _scrollbarLocation = position;
1700void TerminalDisplay::mousePressEvent(
QMouseEvent *ev)
1703 mouseTripleClickEvent(ev);
1713 auto charPos = getCharacterPosition(ev->
pos());
1715 auto [charColumn, charLine] = charPos;
1718 _lineSelectionMode =
false;
1719 _wordSelectionMode =
false;
1721 Q_EMIT isBusySelecting(
true);
1723 bool selected =
false;
1729 selected = _screenWindow->isSelected(charColumn, charLine);
1733 dragInfo.state = diPending;
1734 dragInfo.start = ev->
pos();
1737 dragInfo.state = diNone;
1743 _screenWindow->clearSelection();
1746 pos.
ry() += _scrollBar->value();
1747 _iPntSel = _pntSel = pos;
1751 Q_EMIT mouseSignal(0, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum(), 0);
1754 Filter::HotSpot *spot = _filterChain->hotSpotAt(charLine, charColumn);
1755 if (spot && spot->
type() == Filter::HotSpot::Link)
1756 spot->
activate(QLatin1String(
"click-action"));
1762 Q_EMIT mouseSignal(1, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum(), 0);
1767 Q_EMIT mouseSignal(2, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum(), 0);
1773 auto pos = getCharacterPosition(position);
1775 Filter::HotSpot *spot = _filterChain->hotSpotAt(pos.lines, pos.columns);
1780void TerminalDisplay::mouseMoveEvent(
QMouseEvent *ev)
1782 int leftMargin = _leftBaseMargin
1784 ? _scrollBar->
width()
1787 auto charPos = getCharacterPosition(ev->
pos());
1791 Filter::HotSpot *spot = _filterChain->hotSpotAt(charPos.lines, charPos.columns);
1792 if (spot && spot->
type() == Filter::HotSpot::Link) {
1793 QRegion previousHotspotArea = _mouseOverHotspotArea;
1794 _mouseOverHotspotArea =
QRegion();
1798 spot->
startLine() * qRound(_fontHeight) + _topBaseMargin,
1799 spot->
endColumn() * qRound(_fontWidth) + leftMargin,
1800 (spot->
endLine() + 1) * qRound(_fontHeight) - 1 + _topBaseMargin);
1801 _mouseOverHotspotArea |= r;
1804 spot->
startLine() * qRound(_fontHeight) + _topBaseMargin,
1805 _columns * qRound(_fontWidth) - 1 + leftMargin,
1806 (spot->
startLine() + 1) * qRound(_fontHeight) + _topBaseMargin);
1807 _mouseOverHotspotArea |= r;
1808 for (
int line = spot->
startLine() + 1; line < spot->endLine(); line++) {
1809 r.
setCoords(0 * qRound(_fontWidth) + leftMargin,
1810 line * qRound(_fontHeight) + _topBaseMargin,
1811 _columns * qRound(_fontWidth) + leftMargin,
1812 (line + 1) * qRound(_fontHeight) + _topBaseMargin);
1813 _mouseOverHotspotArea |= r;
1815 r.
setCoords(0 * qRound(_fontWidth) + leftMargin,
1816 spot->
endLine() * qRound(_fontHeight) + _topBaseMargin,
1817 spot->
endColumn() * qRound(_fontWidth) + leftMargin,
1818 (spot->
endLine() + 1) * qRound(_fontHeight) + _topBaseMargin);
1819 _mouseOverHotspotArea |= r;
1821 update(_mouseOverHotspotArea | previousHotspotArea);
1822 }
else if (!_mouseOverHotspotArea.isEmpty()) {
1823 update(_mouseOverHotspotArea);
1825 _mouseOverHotspotArea = QRegion();
1844 Q_EMIT mouseSignal(button, charPos.columns + 1, charPos.lines + 1 + _scrollBar->value() - _scrollBar->maximum(), 1);
1849 if (dragInfo.state == diPending) {
1856 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1857 if (ev->
position().
x() > dragInfo.start.x() + distance || ev->
position().
x() < dragInfo.start.x() - distance
1858 || ev->
position().
y() > dragInfo.start.y() + distance || ev->
position().
y() < dragInfo.start.y() - distance)
1860 if (ev->
pos().
x() > dragInfo.start.x() + distance || ev->
pos().
x() < dragInfo.start.x() - distance
1861 || ev->
pos().
y() > dragInfo.start.y() + distance || ev->
pos().
y() < dragInfo.start.y() - distance)
1865 Q_EMIT isBusySelecting(
false);
1867 _screenWindow->clearSelection();
1871 }
else if (dragInfo.state == diDragging) {
1884 extendSelection(ev->
pos());
1887void TerminalDisplay::extendSelection(
const QPoint &position)
1889 QPoint pos = position;
1895 QPoint tL = contentsRect().topLeft();
1898 int scroll = _scrollBar->value();
1904 int linesBeyondWidget = 0;
1906 QRect textBounds(tLx + _leftMargin, tLy + _topMargin, _usedColumns * qRound(_fontWidth) - 1, _usedLines * qRound(_fontHeight) - 1);
1909 QPoint oldpos = pos;
1911 pos.
setX(qBound(textBounds.left(), pos.
x(), textBounds.right()));
1912 pos.
setY(qBound(textBounds.top(), pos.
y(), textBounds.bottom()));
1914 if (oldpos.
y() > textBounds.bottom()) {
1915 linesBeyondWidget = (oldpos.
y() - textBounds.bottom()) / qRound(_fontHeight);
1916 _scrollBar->setValue(_scrollBar->value() + linesBeyondWidget + 1);
1918 if (oldpos.
y() < textBounds.top()) {
1919 linesBeyondWidget = (textBounds.top() - oldpos.
y()) / qRound(_fontHeight);
1920 _scrollBar->setValue(_scrollBar->value() - linesBeyondWidget - 1);
1924 getCharacterPosition(pos);
1926 QPoint _iPntSelCorr = _iPntSel;
1927 _iPntSelCorr.
ry() -= _scrollBar->value();
1928 QPoint _pntSelCorr = _pntSel;
1929 _pntSelCorr.
ry() -= _scrollBar->value();
1930 bool swapping =
false;
1932 if (_wordSelectionMode) {
1937 bool left_not_right = (here.
y() < _iPntSelCorr.
y() || (here.
y() == _iPntSelCorr.
y() && here.
x() < _iPntSelCorr.
x()));
1938 bool old_left_not_right = (_pntSelCorr.
y() < _iPntSelCorr.
y() || (_pntSelCorr.
y() == _iPntSelCorr.
y() && _pntSelCorr.
x() < _iPntSelCorr.
x()));
1939 swapping = left_not_right != old_left_not_right;
1942 QPoint
left = left_not_right ? here : _iPntSelCorr;
1944 if (i >= 0 && i <= _imageSize) {
1945 selClass = charClass(_image[i].character);
1946 while (((
left.x() > 0) || (
left.y() > 0 && (_lineProperties[
left.y() - 1] & LINE_WRAPPED))) && charClass(_image[i - 1].character) == selClass) {
1951 left.rx() = _usedColumns - 1;
1958 QPoint
right = left_not_right ? _iPntSelCorr : here;
1960 if (i >= 0 && i <= _imageSize) {
1961 selClass = charClass(_image[i].character);
1962 while (((
right.x() < _usedColumns - 1) || (
right.y() < _usedLines - 1 && (_lineProperties[
right.y()] & LINE_WRAPPED)))
1963 && charClass(_image[i + 1].character) == selClass) {
1965 if (
right.x() < _usedColumns - 1)
1975 if (left_not_right) {
1985 if (_lineSelectionMode) {
1987 bool above_not_below = (here.
y() < _iPntSelCorr.
y());
1989 QPoint above = above_not_below ? here : _iPntSelCorr;
1990 QPoint below = above_not_below ? _iPntSelCorr : here;
1992 while (above.
y() > 0 && (_lineProperties[above.
y() - 1] & LINE_WRAPPED))
1994 while (below.
y() < _usedLines - 1 && (_lineProperties[below.
y()] & LINE_WRAPPED))
1998 below.
setX(_usedColumns - 1);
2001 if (above_not_below) {
2009 QPoint newSelBegin = QPoint(ohere.
x(), ohere.
y());
2010 swapping = !(_tripleSelBegin == newSelBegin);
2011 _tripleSelBegin = newSelBegin;
2017 if (!_wordSelectionMode && !_lineSelectionMode) {
2021 bool left_not_right = (here.
y() < _iPntSelCorr.
y() || (here.
y() == _iPntSelCorr.
y() && here.
x() < _iPntSelCorr.
x()));
2022 bool old_left_not_right = (_pntSelCorr.
y() < _iPntSelCorr.
y() || (_pntSelCorr.
y() == _iPntSelCorr.
y() && _pntSelCorr.
x() < _iPntSelCorr.
x()));
2023 swapping = left_not_right != old_left_not_right;
2026 QPoint
left = left_not_right ? here : _iPntSelCorr;
2029 QPoint
right = left_not_right ? _iPntSelCorr : here;
2030 if (
right.x() > 0 && !_columnSelectionMode) {
2032 if (i >= 0 && i <= _imageSize) {
2033 selClass = charClass(_image[i - 1].character);
2048 if (left_not_right) {
2059 if ((here == _pntSelCorr) && (scroll == _scrollBar->value()))
2065 if (_actSel < 2 || swapping) {
2066 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
2067 _screenWindow->setSelectionStart(ohere.
x(), ohere.
y(),
true);
2069 _screenWindow->setSelectionStart(ohere.
x() - 1 - offset, ohere.
y(),
false);
2075 _pntSel.
ry() += _scrollBar->value();
2077 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
2078 _screenWindow->setSelectionEnd(here.
x(), here.
y());
2080 _screenWindow->setSelectionEnd(here.
x() + offset, here.
y());
2084void TerminalDisplay::mouseReleaseEvent(QMouseEvent *ev)
2089 auto [charColumn, charLine] = getCharacterPosition(ev->
pos());
2092 Q_EMIT isBusySelecting(
false);
2093 if (dragInfo.state == diPending) {
2095 _screenWindow->clearSelection();
2099 setSelection(_screenWindow->selectedText(_preserveLineBreaks));
2109 Q_EMIT mouseSignal(0, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum(), 2);
2111 dragInfo.state = diNone;
2119CharPos TerminalDisplay::getCharacterPosition(
const QPointF &widgetPoint)
const
2121 int line, column = 0;
2123 line = (widgetPoint.
y() - contentsRect().top() - _topMargin) / qRound(_fontHeight);
2126 if (line >= _usedLines)
2127 line = _usedLines - 1;
2129 int x = widgetPoint.
x() + qRound(_fontWidth) / 2 - contentsRect().left() - _leftMargin;
2131 column =
x / qRound(_fontWidth);
2134 while (column + 1 < _usedColumns &&
x > textWidth(0, column + 1, line))
2146 if (column > _usedColumns)
2147 column = _usedColumns;
2149 return {column, line};
2165 _lineProperties = _screenWindow->getLineProperties();
2168void TerminalDisplay::mouseDoubleClickEvent(
QMouseEvent *ev)
2175 QPoint pos = getCharacterPosition(ev->
pos());
2186 _screenWindow->clearSelection();
2189 int i = loc(bgnSel.
x(), bgnSel.
y());
2191 _iPntSel.
ry() += _scrollBar->
value();
2193 _wordSelectionMode =
true;
2196 QChar selClass = charClass(_image[i].character);
2200 while (((
x > 0) || (bgnSel.
y() > 0 && (_lineProperties[bgnSel.
y() - 1] & LINE_WRAPPED))) && charClass(_image[i - 1].character) == selClass) {
2205 x = _usedColumns - 1;
2211 _screenWindow->setSelectionStart(bgnSel.
x(), bgnSel.
y(),
false);
2214 i = loc(endSel.
x(), endSel.
y());
2216 while (((
x < _usedColumns - 1) || (endSel.
y() < _usedLines - 1 && (_lineProperties[endSel.
y()] & LINE_WRAPPED)))
2217 && charClass(_image[i + 1].character) == selClass) {
2219 if (
x < _usedColumns - 1)
2230 if ((QChar(_image[i].character) == QLatin1Char(
'@')) && ((endSel.
x() - bgnSel.
x()) > 0))
2235 _screenWindow->setSelectionEnd(endSel.
x(), endSel.
y());
2237 setSelection(_screenWindow->selectedText(_preserveLineBreaks));
2240 _possibleTripleClick =
true;
2245void TerminalDisplay::wheelEvent(QWheelEvent *ev)
2255 bool canScroll = _scrollBar->maximum() > 0;
2257 _scrollBar->event(ev);
2269 int linesToScroll = abs(wheelDegrees) / 5;
2273 for (
int i = 0; i < linesToScroll; i++)
2278 auto pos = getCharacterPosition(ev->
position());
2284void TerminalDisplay::tripleClickTimeout()
2286 _possibleTripleClick =
false;
2289void TerminalDisplay::mouseTripleClickEvent(QMouseEvent *ev)
2294 _iPntSel = getCharacterPosition(ev->
pos());
2296 _screenWindow->clearSelection();
2298 _lineSelectionMode =
true;
2299 _wordSelectionMode =
false;
2302 Q_EMIT isBusySelecting(
true);
2304 while (_iPntSel.y() > 0 && (_lineProperties[_iPntSel.y() - 1] & LINE_WRAPPED))
2309 int i = loc(_iPntSel.x(), _iPntSel.y());
2310 QChar selClass = charClass(_image[i].character);
2311 int x = _iPntSel.x();
2313 while (((
x > 0) || (_iPntSel.y() > 0 && (_lineProperties[_iPntSel.y() - 1] & LINE_WRAPPED))) && charClass(_image[i - 1].character) == selClass) {
2323 _screenWindow->setSelectionStart(
x, _iPntSel.y(),
false);
2324 _tripleSelBegin = QPoint(
x, _iPntSel.y());
2326 _screenWindow->setSelectionStart(0, _iPntSel.y(),
false);
2327 _tripleSelBegin = QPoint(0, _iPntSel.y());
2330 while (_iPntSel.y() < _lines - 1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED))
2333 _screenWindow->setSelectionEnd(_columns - 1, _iPntSel.y());
2335 setSelection(_screenWindow->selectedText(_preserveLineBreaks));
2337 _iPntSel.ry() += _scrollBar->value();
2340bool TerminalDisplay::focusNextPrevChild(
bool next)
2349QChar TerminalDisplay::charClass(QChar qch)
const
2352 return QLatin1Char(
' ');
2355 return QLatin1Char(
'a');
2362 _wordCharacters = wc;
2367 if (_mouseMarks != on) {
2370 Q_EMIT usesMouseChanged();
2378void TerminalDisplay::setBracketedPasteMode(
bool on)
2380 _bracketedPasteMode = on;
2382bool TerminalDisplay::bracketedPasteMode()
const
2384 return _bracketedPasteMode;
2395void TerminalDisplay::emitSelection(
bool useXselection,
bool appendReturn)
2406 text.
replace(QLatin1String(
"\r\n"), QLatin1String(
"\n"));
2407 text.
replace(QLatin1Char(
'\n'), QLatin1Char(
'\r'));
2409 if (_trimPastedTrailingNewlines) {
2410 text.
replace(QRegularExpression(QStringLiteral(
"\\r+$")), QString());
2442 text.
append(QLatin1Char(
'\r'));
2448 _screenWindow->clearSelection();
2450 switch (mMotionAfterPasting) {
2451 case MoveStartScreenWindow:
2456 _screenWindow->setTrackOutput(
false);
2457 _screenWindow->scrollTo(0);
2459 case MoveEndScreenWindow:
2462 case NoMoveScreenWindow:
2470 if (bracketedPasteMode() && !_disabledBracketedPasteMode) {
2476void TerminalDisplay::setSelection(
const QString &t)
2482 Q_EMIT isTextSelectedChanged();
2490 QString text = _screenWindow->selectedText(_preserveLineBreaks);
2497 emitSelection(
false,
false);
2502 emitSelection(
true,
false);
2505void TerminalDisplay::setConfirmMultilinePaste(
bool confirmMultilinePaste)
2507 _confirmMultilinePaste = confirmMultilinePaste;
2510void TerminalDisplay::setTrimPastedTrailingNewlines(
bool trimPastedTrailingNewlines)
2512 _trimPastedTrailingNewlines = trimPastedTrailingNewlines;
2523 _flowControlWarningEnabled = enable;
2531void TerminalDisplay::setMotionAfterPasting(MotionAfterPasting action)
2533 mMotionAfterPasting = action;
2536int TerminalDisplay::motionAfterPasting()
2538 return mMotionAfterPasting;
2541void TerminalDisplay::keyPressEvent(QKeyEvent *event)
2546 bool emitKeyPressSignal =
true;
2575 _screenWindow->scrollTo(0);
2582 _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
2588 emitKeyPressSignal =
false;
2595 if (_hasBlinkingCursor) {
2597 if (_cursorBlinking)
2600 _cursorBlinking =
false;
2603 if ( emitKeyPressSignal )
2611 switch(mMotionAfterPasting)
2613 case MoveStartScreenWindow:
2614 _screenWindow->scrollTo(0);
2616 case MoveEndScreenWindow:
2619 case NoMoveScreenWindow:
2632void TerminalDisplay::inputMethodEvent(QInputMethodEvent *event)
2637 _inputMethodData.preeditString =
event->preeditString();
2638 update(preeditRect() | _inputMethodData.previousPreeditRect);
2643void TerminalDisplay::inputMethodQuery(QInputMethodQueryEvent *event)
2652 const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0, 0);
2655 return imageToWidget(QRect(cursorPos.
x(), cursorPos.
y(), 1, 1));
2662 return cursorPos.
x();
2667 QTextStream stream(&lineText);
2668 PlainTextDecoder decoder;
2669 decoder.
begin(&stream);
2670 decoder.
decodeLine(std::span(&_image[loc(0, cursorPos.
y())], _usedColumns), _lineProperties[cursorPos.
y()]);
2684bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent *keyEvent)
2686 int modifiers =
keyEvent->modifiers();
2692 int modifierCount = 0;
2696 if (modifiers & currentModifier)
2698 currentModifier <<= 1;
2700 if (modifierCount < 2) {
2701 bool override =
false;
2712 int keyCode =
keyEvent->key() | modifiers;
2729bool TerminalDisplay::event(QEvent *event)
2731 bool eventHandled =
false;
2732 switch (event->type()) {
2734 eventHandled = handleShortcutOverrideEvent((QKeyEvent *)event);
2741 inputMethodQuery(
static_cast<QInputMethodQueryEvent *
>(event));
2742 eventHandled =
true;
2755void TerminalDisplay::enableBell()
2775 Q_EMIT notifyBell(message);
2783void TerminalDisplay::selectionChanged()
2785 Q_EMIT copyAvailable(_screenWindow->selectedText(
false).isEmpty() ==
false);
2788void TerminalDisplay::swapColorTable()
2791 _colorTable[1] = _colorTable[0];
2792 _colorTable[0] = color;
2793 _colorsInverted = !_colorsInverted;
2797void TerminalDisplay::clearImage()
2800 for (
int i = 0; i <= _imageSize; i++) {
2801 _image[i].character = u
' ';
2802 _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR);
2803 _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR);
2804 _image[i].rendition = DEFAULT_RENDITION;
2808void TerminalDisplay::calcGeometry()
2810 _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().
height());
2812 switch (_scrollbarLocation) {
2813 case QTermWidget::NoScrollBar:
2814 _leftMargin = _leftBaseMargin;
2815 _contentWidth = contentsRect().width() - 2 * _leftBaseMargin;
2817 case QTermWidget::ScrollBarLeft:
2818 _leftMargin = _leftBaseMargin + scrollBarWidth;
2819 _contentWidth = contentsRect().width() - 2 * _leftBaseMargin - scrollBarWidth;
2820 _scrollBar->move(contentsRect().topLeft());
2822 case QTermWidget::ScrollBarRight:
2823 _leftMargin = _leftBaseMargin;
2824 _contentWidth = contentsRect().width() - 2 * _leftBaseMargin - scrollBarWidth;
2825 _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width() - 1, 0));
2829 _topMargin = _topBaseMargin;
2830 _contentHeight = contentsRect().height() - 2 * _topBaseMargin + 1;
2832 if (!_isFixedSize) {
2834 _columns = qMax(1, qRound(_contentWidth / _fontWidth));
2835 _usedColumns = qMin(_usedColumns, _columns);
2838 _lines = qMax(1, _contentHeight / qRound(_fontHeight));
2839 _usedLines = qMin(_usedLines, _lines);
2843void TerminalDisplay::makeImage()
2849 Q_ASSERT(_lines > 0 && _columns > 0);
2850 Q_ASSERT(_usedLines <= _lines && _usedColumns <= _columns);
2852 _imageSize = _lines * _columns;
2856 _image.resize(_imageSize + 1);
2862void TerminalDisplay::setSize(
int columns,
int lines)
2864 int scrollBarWidth =
2865 (_scrollBar->isHidden() || _scrollBar->style()->styleHint(
QStyle::SH_ScrollBar_Transient,
nullptr, _scrollBar)) ? 0 : _scrollBar->sizeHint().width();
2866 int horizontalMargin = 2 * _leftBaseMargin;
2867 int verticalMargin = 2 * _topBaseMargin;
2869 QSize newSize = QSize(horizontalMargin + scrollBarWidth + (columns * _fontWidth), verticalMargin + (lines * qRound(_fontHeight)));
2871 if (newSize != size()) {
2878void TerminalDisplay::setFixedSize(
int cols,
int lins)
2880 _isFixedSize =
true;
2883 _columns = qMax(1, cols);
2884 _lines = qMax(1, lins);
2885 _usedColumns = qMin(_usedColumns, _columns);
2886 _usedLines = qMin(_usedLines, _lines);
2888 if (!_image.empty()) {
2892 setSize(cols, lins);
2896QSize TerminalDisplay::sizeHint()
const
2907void TerminalDisplay::dragEnterEvent(QDragEnterEvent *event)
2909 if (event->mimeData()->hasFormat(QLatin1String(
"text/plain")))
2910 event->acceptProposedAction();
2911 if (event->mimeData()->urls().size())
2912 event->acceptProposedAction();
2915void TerminalDisplay::dropEvent(QDropEvent *event)
2918 QList<QUrl> urls =
event->mimeData()->urls();
2923 qDebug() <<
"TerminalDisplay: handling urls. It can be broken. Report any errors, please";
2924 for (
int i = 0; i < urls.
size(); i++) {
2931 urlText = url.
path();
2939 dropText += urlText;
2941 if (i != urls.
size() - 1)
2942 dropText += QLatin1Char(
' ');
2945 dropText =
event->mimeData()->text();
2951void TerminalDisplay::doDrag()
2953 dragInfo.state = diDragging;
2954 dragInfo.dragObject =
new QDrag(
this);
2955 QMimeData *mimeData =
new QMimeData;
2957 dragInfo.dragObject->setMimeData(mimeData);
2964 _outputSuspendedLabel->setVisible(suspended);
2967uint TerminalDisplay::lineSpacing()
const
2969 return _lineSpacing;
2972void TerminalDisplay::setLineSpacing(uint i)
2974 if (i != _lineSpacing) {
2977 Q_EMIT lineSpacingChanged();
2981int TerminalDisplay::margin()
const
2983 return _topBaseMargin;
2986void TerminalDisplay::setMargin(
int i)
2989 _leftBaseMargin = i;
2994#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2995void TerminalDisplay::geometryChanged(
const QRectF &newGeometry,
const QRectF &oldGeometry)
2997void TerminalDisplay::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
3000 if (newGeometry != oldGeometry) {
3001 resizeEvent(
nullptr);
3005 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
3006 QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry);
3012void TerminalDisplay::update(
const QRegion ®ion)
3025void TerminalDisplay::update()
3030QRect TerminalDisplay::contentsRect()
const
3032 return QRect(0, 0, this->
width(), this->
height());
3035QSize TerminalDisplay::size()
const
3040void TerminalDisplay::setSession(KSession *session)
3049 connect(
this, &TerminalDisplay::copyAvailable, m_session, &KSession::selectionChanged);
3054 m_session->addView(
this);
3062KSession *TerminalDisplay::getSession()
3067QStringList TerminalDisplay::availableColorSchemes()
3071 std::transform(colorSchemes.begin(), colorSchemes.end(), std::back_inserter(ret), [](
auto cs) {
3077void TerminalDisplay::setColorScheme(
const QString &name)
3079 if (name != _colorScheme)
3083 disconnect(m_scheme,
nullptr,
this,
nullptr);
3086 m_scheme = [&,
this]()
3088 if(name ==
"Adaptive")
3090 return m_customColorScheme->getScheme();
3094 if (!availableColorSchemes().
contains(name))
3103 qDebug() <<
"Cannot load color scheme: " <<
name;
3107 connect(m_scheme, SIGNAL(colorChanged(
int)),
this, SLOT(applyColorScheme()));
3110 _colorScheme =
name;
3111 Q_EMIT colorSchemeChanged();
3116void TerminalDisplay::applyColorScheme()
3118 qDebug() <<
"Colors CHANGED";
3121 qDebug() <<
"Cannot apply color scheme";
3129 qDebug() <<
"Colors CHANGED" << m_scheme->backgroundColor() << this->backgroundColor();
3131 QColor nColor = m_scheme->backgroundColor();
3136 Q_EMIT backgroundColorChanged();
3137 Q_EMIT foregroundColorChanged();
3140QString TerminalDisplay::colorScheme()
const
3142 return _colorScheme;
3145void TerminalDisplay::simulateKeyPress(
int key,
int modifiers,
bool pressed, quint32 nativeScanCode,
const QString &text)
3147 Q_UNUSED(nativeScanCode);
3153void TerminalDisplay::simulateKeySequence(
const QKeySequence &keySequence)
3156 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
3163 QKeyEvent eventPress = QKeyEvent(
QEvent::KeyPress, key, modifiers, QString());
3168void TerminalDisplay::simulateWheel(
int x,
int y,
int buttons,
int modifiers, QPoint angleDelta)
3171 QWheelEvent event(QPointF(
x,
y),
3182void TerminalDisplay::simulateMouseMove(
int x,
int y,
int button,
int buttons,
int modifiers)
3185 mouseMoveEvent(&event);
3188void TerminalDisplay::simulateMousePress(
int x,
int y,
int button,
int buttons,
int modifiers)
3191 mousePressEvent(&event);
3194void TerminalDisplay::simulateMouseRelease(
int x,
int y,
int button,
int buttons,
int modifiers)
3197 mouseReleaseEvent(&event);
3200void TerminalDisplay::simulateMouseDoubleClick(
int x,
int y,
int button,
int buttons,
int modifiers)
3203 mouseDoubleClickEvent(&event);
3206QSize TerminalDisplay::getTerminalSize()
3208 return QSize(_lines, _columns);
3211bool TerminalDisplay::getUsesMouse()
3216int TerminalDisplay::getScrollbarValue()
3218 return _scrollBar->value();
3221void TerminalDisplay::setScrollbarValue(
int value)
3223 if (value != _scrollBar->value())
3225 _scrollBar->setValue(value);
3229int TerminalDisplay::getScrollbarMaximum()
3231 return _scrollBar->maximum();
3234int TerminalDisplay::getScrollbarMinimum()
3236 return _scrollBar->minimum();
3239QSize TerminalDisplay::getFontMetrics()
3241 return QSize(qRound(_fontWidth), qRound(_fontHeight));
3244void TerminalDisplay::setFullCursorHeight(
bool val)
3246 if (m_full_cursor_height != val) {
3247 m_full_cursor_height = val;
3248 Q_EMIT fullCursorHeightChanged();
3252bool TerminalDisplay::fullCursorHeight()
const
3254 return m_full_cursor_height;
3257void TerminalDisplay::itemChange(ItemChange change,
const ItemChangeData &value)
3261 if (value.boolValue && _screenWindow) {
3262 if (this->columns() != _screenWindow->columnCount() || this->lines() != _screenWindow->lineCount()) {
3263 Q_EMIT changedContentSizeSignal(_contentHeight, _contentWidth);
3274qreal TerminalDisplay::backgroundOpacity()
const
3281 return m_customColorScheme;
3289void TerminalDisplay::setReadOnly(
bool newReadOnly)
3291 if (m_readOnly == newReadOnly)
3293 m_readOnly = newReadOnly;
3294 Q_EMIT readOnlyChanged();
3297bool TerminalDisplay::isTextSelected()
const
3302 return !_screenWindow->selectedText(
false).isEmpty();
3305QString TerminalDisplay::selectedText()
const
3310 return _screenWindow->selectedText(_preserveLineBreaks);
3313void TerminalDisplay::findNext(
const QString& regexp)
3326void TerminalDisplay::findPrevious(
const QString& regexp)
3330void TerminalDisplay::matchFound(
int startColumn,
int startLine,
int endColumn,
int endLine)
3333 qDebug() <<
"Scroll to" << startLine;
3341void TerminalDisplay::noMatchFound()
void termLostFocus()
termLostFocus
void termGetFocus()
termGetFocus
void termKeyPressed(QKeyEvent *, bool)
termKeyPressed
Describes the color of a single character in the terminal.
constexpr QColor color(std::span< const ColorEntry > palette) const
Returns the color within the specified color palette.
A single character in the terminal which consists of a unicode character value, foreground and backgr...
QChar character
The unicode character value for this character.
CharacterColor foregroundColor
The foreground color used to draw this character.
CharacterColor backgroundColor
The color used to draw this character's background.
quint8 rendition
A combination of RENDITION flags which specify options for drawing the character.
An entry in a terminal display's color palette.
QList< ColorScheme * > allColorSchemes()
Returns a list of the all the available color schemes.
static ColorSchemeManager * instance()
Returns the global color scheme manager instance.
const ColorScheme * defaultColorScheme() const
Returns the default color scheme for Konsole.
const ColorScheme * findColorScheme(const QString &name)
Returns the color scheme with the given name or 0 if no scheme with that name exists.
Base class for terminal emulation back-ends.
KeyboardCursorShape
This enum describes the available shapes for the keyboard cursor.
@ UnderlineCursor
A single flat line which occupies the space at the bottom of the cursor character's area.
@ BlockCursor
A rectangular block which covers the entire area of the cursor character.
@ IBeamCursor
An cursor shaped like the capital letter 'I', similar to the IBeam cursor used in Qt/KDE text editors...
static ExtendedCharTable instance
The global ExtendedCharTable instance.
std::span< const ushort > lookupExtendedChar(ushort hash, ushort &length) const
Looks up and returns a pointer to a sequence of unicode characters which was added to the table using...
A chain which allows a group of filters to be processed as one.
Represents an area of text which matched the pattern a particular filter has been looking for.
virtual void activate(const QString &action=QString())=0
Causes the an action associated with a hotspot to be triggered.
int endLine() const
Returns the line where the hotspot area ends.
int startLine() const
Returns the line when the hotspot area starts.
int endColumn() const
Returns the column on endLine() where the hotspot area ends.
virtual QList< QAction * > actions()
Returns a list of actions associated with the hotspot which can be used in a menu or toolbar.
int startColumn() const
Returns the column on startLine() where the hotspot area starts.
Type type() const
Returns the type of the hotspot.
void decodeLine(std::span< const Character > characters, LineProperty properties) override
Converts a line of terminal characters with associated properties into a text string and writes the s...
void end() override
End decoding.
void begin(QTextStream *output) override
Begin decoding characters.
Provides a window onto a section of a terminal screen.
void setSelectionStart(int column, int line, bool columnMode)
Sets the start of the selection to the given line and column within the window.
void setSelectionEnd(int column, int line)
Sets the end of the selection to the given line and column within the window.
@ ScrollLines
Scroll the window down by a given number of lines.
@ ScrollPages
Scroll the window down by a given number of pages, where one page is windowLines() lines.
void setTrackOutput(bool trackOutput)
Specifies whether the window should automatically move to the bottom of the screen when new output is...
int currentLine() const
Returns the index of the line which is currently at the top of this window.
void clearSelection()
Clears the current selection.
void selectionChanged()
Emitted when the selection is changed.
void notifyOutputChanged()
Notifies the window that the contents of the associated terminal screen have changed.
void scrollTo(int line)
Scrolls the window so that line is at the top of the window.
void outputChanged()
Emitted when the contents of the associated terminal screen (see screen()) changes.
void setKeyboardCursorColor(bool useForegroundColor, const QColor &color)
Sets the color used to draw the keyboard cursor.
CustomColorScheme * customColorScheme
Access to the CustomColorScheme object, which allows to modify manually the colors.
void setUsesMouse(bool usesMouse)
Sets whether the program whoose output is being displayed in the view is interested in mouse events.
bool usesMouse() const
See setUsesMouse()
bool readOnly
A read only mode prevents the user from sending keyevents.
void updateFilters()
Essentially calles processFilters().
void bell(const QString &message)
Shows a notification that a bell event has occurred in the terminal.
void bracketText(QString &text) const
change and wrap text corresponding to paste mode
void outputSuspended(bool suspended)
Causes the widget to display or hide a message informing the user that terminal output has been suspe...
void pasteSelection()
Pastes the content of the selection into the display.
void setBlinkingCursor(bool blink)
Specifies whether or not the cursor blinks.
KSession * session
Register the session to handle.
void setBlinkingTextEnabled(bool blink)
Specifies whether or not text can blink.
void keyPressedSignal(QKeyEvent *e, bool fromPaste)
Emitted when the user presses a key whilst the terminal widget has focus.
void pasteClipboard()
Pastes the content of the clipboard into the display.
void updateLineProperties()
Causes the terminal display to fetch the latest line status flags from the associated terminal screen...
void setWordCharacters(const QString &wc)
Sets which characters, in addition to letters and numbers, are regarded as being part of a word for t...
void setRandomSeed(uint seed)
Sets the seed used to generate random colors for the display (in color schemes that support them).
ScreenWindow * screenWindow() const
Returns the terminal screen section which is displayed in this widget.
void setBellMode(int mode)
Sets the type of effect used to alert the user when a 'bell' occurs in the terminal session.
QColor keyboardCursorColor() const
Returns the color of the keyboard cursor, or an invalid color if the keyboard cursor color is set to ...
TerminalDisplay(QQuickItem *parent=nullptr)
Constructs a new terminal display widget with the specified parent.
void configureRequest(const QPoint &position)
Emitted when the user right clicks on the display, or right-clicks with the Shift key held down if us...
void setForegroundColor(const QColor &color)
Sets the text of the display to the specified color.
void setScrollBarPosition(QTermWidget::ScrollBarPosition position)
Specifies whether the terminal display has a vertical scroll bar, and if so whether it is shown on th...
void setBackgroundColor(const QColor &color)
Sets the background of the display to the specified color.
void setFlowControlWarningEnabled(bool enabled)
Changes whether the flow control warning box should be shown when the flow control stop key (Ctrl+S) ...
void processFilters()
Updates the filters in the display's filter chain.
void scrollToEnd()
Scroll to the bottom of the terminal (reset scrolling).
void setKeyboardCursorShape(Emulation::KeyboardCursorShape shape)
Sets the shape of the keyboard cursor.
@ NotifyBell
KDE notification.
@ SystemBeepBell
A system beep.
@ VisualBell
A silent, visual bell (eg.
@ NoScrollBar
Do not show the scroll bar.
void setBackgroundOpacity(qreal backgroundOpacity)
Sets the backgroundOpacity of the terminal display.
QList< QAction * > filterActions(const QPoint &position)
Returns a list of menu actions created by the filters for the content at the given position.
void updateImage()
Causes the terminal display to fetch the latest character image from the associated terminal screen (...
FilterChain * filterChain() const
Returns the display's filter chain.
void mouseSignal(int button, int column, int line, int eventType)
A mouse event occurred.
void overrideShortcutCheck(QKeyEvent *keyEvent, bool &override)
When a shortcut which is also a valid terminal key sequence is pressed while the terminal widget has ...
@ SelectWholeLine
Select the whole line underneath the cursor.
@ SelectForwardsFromCursor
Select from the current cursor position to the end of the line.
void setColorTable(std::array< ColorEntry, TABLE_COLORS > &&table)
Sets the terminal color palette used by the display.
void setVTFont(const QFont &font)
Sets the font used to draw the display.
void copyClipboard()
Copies the selected text to the clipboard.
void setBoldIntense(bool value)
Specifies whether characters with intense colors should be rendered as bold.
std::span< const ColorEntry > colorTable() const
Returns the terminal color palette used by the display.
Emulation::KeyboardCursorShape keyboardCursorShape() const
Returns the shape of the keyboard cursor.
uint randomSeed() const
Returns the seed used to generate random colors for the display (in color schemes that support them).
void setScroll(int cursor, int lines)
Sets the current position and range of the display's scroll bar.
void setScreenWindow(ScreenWindow *window)
Sets the terminal screen section which is displayed in this widget.
A filter chain which processes character images from terminal displays.
Type type(const QSqlDatabase &db)
void update(Part *part, const QByteArray &data, qint64 dataSize)
QString name(const QVariant &location)
int distance(const GeoCoordinates &coord1, const GeoCoordinates &coord2)
void valueChanged(int value)
QPalette palette(const QWidget *widget)
const char * constData() const const
bool isLetterOrNumber(char32_t ucs4)
bool isSpace(char32_t ucs4)
void setText(const QString &text, Mode mode)
QString text(Mode mode) const const
void setAlphaF(float alpha)
void setStyleStrategy(StyleStrategy s)
bool isEmpty() const const
qsizetype size() const const
void setText(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QRectF clipBoundingRect() const const
void drawArc(const QRect &rectangle, int startAngle, int spanAngle)
void drawLine(const QLine &line)
void drawPoint(const QPoint &position)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
const QPen & pen() const const
void setCompositionMode(CompositionMode mode)
void setFont(const QFont &font)
void setLayoutDirection(Qt::LayoutDirection direction)
void setPen(Qt::PenStyle style)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
QColor color() const const
void setColor(const QColor &color)
QPoint toPoint() const const
QQuickItem(QQuickItem *parent)
bool hasActiveFocus() const const
virtual QRectF clipRect() const const
virtual bool contains(const QPointF &point) const const
QCursor cursor() const const
virtual bool event(QEvent *ev) override
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
QPointF mapFromScene(const QPointF &point) const const
QPointF mapToGlobal(const QPointF &point) const const
void setCursor(const QCursor &cursor)
void setFlags(Flags flags)
QQuickWindow * window() const const
QQuickPaintedItem(QQuickItem *parent)
void setFillColor(const QColor &)
virtual void itemChange(ItemChange change, const ItemChangeData &value) override
void setRenderTarget(RenderTarget target)
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
bool isEmpty() const const
bool isValid() const const
void moveTopLeft(const QPoint &position)
void setCoords(int x1, int y1, int x2, int y2)
void setHeight(int height)
QPoint topLeft() const const
QRect toAlignedRect() const const
QRect boundingRect() const const
bool contains(const QPoint &p) const const
QPointF position() const const
QString & append(QChar ch)
bool isEmpty() const const
QString & prepend(QChar ch)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
void reserve(qsizetype size)
void resize(qsizetype newSize, QChar fillChar)
QByteArray toLocal8Bit() const const
qsizetype size() const const
virtual int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const const=0
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
void keySequence(QWidget *widget, const QKeySequence &keySequence)
bool isLocalFile() const const
QString path(ComponentFormattingOptions options) const const
QString toString(FormattingOptions options) const const
QPoint angleDelta() const const