Commit ff716ffb authored by Matan Ziv-Av's avatar Matan Ziv-Av Committed by Tomaz Canabrava
Browse files

Move graphics related lists from TerminalDisplay to more appropriate classes

- Graphics placements list to Screen
- Kitty image cache to Vt102Emulation
parent 0cc64dcf
......@@ -20,6 +20,7 @@
#include "session/Session.h"
#include "session/SessionController.h"
#include "terminalDisplay/TerminalDisplay.h"
#include "terminalDisplay/TerminalFonts.h"
#include "EscapeSequenceUrlExtractor.h"
#include "characters/ExtendedCharTable.h"
......@@ -90,12 +91,20 @@ Screen::Screen(int lines, int columns)
_escapeSequenceUrlExtractor->setScreen(this);
std::fill(_lineProperties.begin(), _lineProperties.end(), LINE_DEFAULT);
_graphicsPlacements = QVector<TerminalGraphicsPlacement_t *>();
_hasGraphics = false;
initTabStops();
clearSelection();
reset();
}
Screen::~Screen() = default;
Screen::~Screen()
{
for (int i = 0; i < _graphicsPlacements.size(); i++) {
delete _graphicsPlacements[i];
}
}
void Screen::cursorUp(int n)
//=CUU
......@@ -799,8 +808,8 @@ void Screen::reset()
setDefaultRendition();
saveCursor();
if (_currentTerminalDisplay && _currentTerminalDisplay->hasGraphics()) {
_currentTerminalDisplay->delPlacements();
if (_hasGraphics) {
delPlacements();
_currentTerminalDisplay->update();
}
}
......@@ -1064,8 +1073,8 @@ void Screen::scrollUp(int from, int n)
// FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
moveImage(loc(0, from), loc(0, from + n), loc(_columns, _bottomMargin));
clearImage(loc(0, _bottomMargin - n + 1), loc(_columns - 1, _bottomMargin), ' ');
if (_currentTerminalDisplay->hasGraphics()) {
_currentTerminalDisplay->scrollUpVisiblePlacements(n);
if (_hasGraphics) {
scrollUpVisiblePlacements(n);
}
}
......@@ -1284,8 +1293,8 @@ void Screen::clearToBeginOfScreen()
void Screen::clearEntireScreen()
{
clearImage(loc(0, 0), loc(_columns - 1, _lines - 1), ' ');
if (_currentTerminalDisplay && _currentTerminalDisplay->hasGraphics()) {
_currentTerminalDisplay->delPlacements();
if (_hasGraphics) {
delPlacements();
_currentTerminalDisplay->update();
}
}
......@@ -1746,11 +1755,6 @@ int Screen::getHistLines() const
return _history->getLines();
}
int Screen::getHistMaxLines() const
{
return _history->getMaxLines();
}
void Screen::setScroll(const HistoryType &t, bool copyPreviousScroll)
{
clearSelection();
......@@ -1801,3 +1805,180 @@ Konsole::EscapeSequenceUrlExtractor *Konsole::Screen::urlExtractor() const
{
return _escapeSequenceUrlExtractor.get();
}
int Screen::addPlacement(QPixmap pixmap,
int &rows,
int &cols,
int row,
int col,
bool scrolling,
bool moveCursor,
int z,
int id,
int pid,
qreal opacity,
int X,
int Y)
{
if (pixmap.isNull()) {
return -1;
}
TerminalGraphicsPlacement_t *p = new TerminalGraphicsPlacement_t;
if (row == -1) {
row = _cuY;
}
if (col == -1) {
col = _cuX;
}
if (rows == -1) {
rows = (pixmap.height() - 1) / _currentTerminalDisplay->terminalFont()->fontHeight() + 1;
}
if (cols == -1) {
cols = (pixmap.width() - 1) / _currentTerminalDisplay->terminalFont()->fontWidth() + 1;
}
p->pixmap = pixmap;
p->z = z;
p->row = row;
p->col = col;
p->rows = rows;
p->cols = cols;
p->id = id;
p->pid = pid;
p->opacity = opacity;
p->scrolling = scrolling;
p->X = X;
p->Y = Y;
addPlacement(p);
int needScroll = qBound(0, row + rows - _lines + 1, rows);
if (scrolling && needScroll > moveCursor) {
scrollUp(needScroll - moveCursor);
}
if (moveCursor) {
if (rows - needScroll - 1 > 0) {
cursorDown(rows - needScroll - 1);
}
if (_cuX + cols >= _columns) {
toStartOfLine();
newLine();
} else {
cursorRight(cols);
}
}
return qBound(0, row + rows - _lines + 1, rows);
}
void Screen::addPlacement(TerminalGraphicsPlacement_t *p)
{
int i;
// remove placement with the same id and pid, if pid is non zero
if (p->pid >= 0 && p->id >= 0)
for (i = 0; i < _graphicsPlacements.size(); i++) {
TerminalGraphicsPlacement_t *placement = _graphicsPlacements[i];
if (p->id == placement->id && p->pid == placement->pid) {
_graphicsPlacements.remove(i);
delete placement;
break;
}
}
for (i = 0; i < _graphicsPlacements.size() && p->z >= _graphicsPlacements[i]->z; i++)
;
_graphicsPlacements.insert(i, p);
_hasGraphics = true;
// Placements with pid<0 cannot be deleted, so remove those fully covered
// by others.
QRegion covered = QRegion();
for (i = _graphicsPlacements.size() - 1; i >= 0; i--) {
TerminalGraphicsPlacement_t *placement = _graphicsPlacements[i];
if (placement->pid < 0) {
QRect rect(placement->col, placement->row, placement->cols, placement->rows);
if (covered.intersected(rect) == QRegion(rect)) {
_graphicsPlacements.remove(i);
delete placement;
} else {
covered += rect;
}
}
}
}
TerminalGraphicsPlacement_t *Screen::getGraphicsPlacement(int i)
{
if (i >= _graphicsPlacements.size()) {
return nullptr;
}
return _graphicsPlacements[i];
}
void Screen::scrollUpVisiblePlacements(int n)
{
int histMaxLines = _history->getMaxLines();
for (int i = _graphicsPlacements.size() - 1; i >= 0; i--) {
TerminalGraphicsPlacement_t *placement = _graphicsPlacements[i];
if (placement->scrolling) {
placement->row -= n;
if (placement->row + placement->rows < -histMaxLines) {
_graphicsPlacements.remove(i);
delete placement;
}
}
}
}
void Screen::delPlacements(int del, qint64 id, qint64 pid, int x, int y, int z)
{
for (int i = _graphicsPlacements.size() - 1; i >= 0; i--) {
TerminalGraphicsPlacement_t *placement = _graphicsPlacements[i];
bool remove = false;
switch (del) {
case 1:
remove = true;
break;
case 'z':
if (placement->z == z) {
remove = true;
}
break;
case 'x':
if (placement->col <= x && x < placement->col + placement->cols) {
remove = true;
}
break;
case 'y':
if (placement->row <= y && y < placement->row + placement->rows) {
remove = true;
}
break;
case 'p':
if (placement->col <= x && x < placement->col + placement->cols && placement->row <= y && y < placement->row + placement->rows) {
remove = true;
}
break;
case 'q':
if (placement->col <= x && x < placement->col + placement->cols && placement->row <= y && y < placement->row + placement->rows
&& placement->z == z) {
remove = true;
}
break;
case 'a':
if (placement->row + placement->rows > 0) {
remove = true;
}
break;
case 'i':
if (placement->id == id && (pid < 0 || placement->pid == pid)) {
remove = true;
}
break;
}
if (remove) {
_graphicsPlacements.remove(i);
delete placement;
}
}
}
......@@ -31,6 +31,15 @@
#define MODE_AppScreen 6
#define MODES_SCREEN 7
struct TerminalGraphicsPlacement_t {
QPixmap pixmap;
qint64 id;
qint64 pid;
int z, X, Y, col, row, cols, rows;
qreal opacity;
bool scrolling;
};
namespace Konsole
{
class TerminalCharacterDecoder;
......@@ -412,7 +421,6 @@ public:
/** Return the number of lines in the history buffer. */
int getHistLines() const;
int getHistMaxLines() const;
/**
* Sets the type of storage used to keep lines in the history.
* If @p copyPreviousScroll is true then the contents of the previous
......@@ -603,6 +611,29 @@ public:
// Set reflow condition
void setReflowLines(bool enable);
/* Graphics display functions */
int addPlacement(QPixmap pixmap,
int &rows,
int &cols,
int row = -1,
int col = -1,
bool scrolling = true,
bool moveCursor = true,
int z = 1,
int id = -1,
int pid = -1,
qreal opacity = 1.0,
int X = 0,
int Y = 0);
TerminalGraphicsPlacement_t *getGraphicsPlacement(int i);
void scrollUpVisiblePlacements(int n);
void delPlacements(int = 'a', qint64 = 0, qint64 = -1, int = 0, int = 0, int = 0);
bool hasGraphics() const
{
return _hasGraphics;
}
private:
// copies a line of text from the screen or history into a stream using a
// specified character decoder. Returns the number of lines actually copied,
......@@ -771,6 +802,11 @@ private:
// Vt102Emulation defined max argument value that can be passed to a Screen function
const int MAX_SCREEN_ARGUMENT = 40960;
/* Graphics */
void addPlacement(TerminalGraphicsPlacement_t *p);
QVector<TerminalGraphicsPlacement_t *> _graphicsPlacements;
bool _hasGraphics;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Screen::DecodingOptions)
......
......@@ -76,6 +76,8 @@ Vt102Emulation::Vt102Emulation()
imageId = 0;
savedKeys = QMap<char, qint64>();
tokenData = QByteArray();
_graphicsImages = std::map<int, QImage *>();
}
Vt102Emulation::~Vt102Emulation() = default;
......@@ -808,13 +810,12 @@ void Vt102Emulation::processSessionAttributeRequest(int tokenSize)
}
}
QImage image;
image.loadFromData(tokenData);
if (image.isNull()) {
QPixmap pixmap = QPixmap();
pixmap.loadFromData(tokenData);
tokenData.clear();
if (pixmap.isNull()) {
return;
}
QPixmap pixmap = QPixmap::fromImage(image);
if (scaledWidth && scaledHeight) {
pixmap = pixmap.scaled(scaledWidth, scaledHeight, (Qt::AspectRatioMode)keepAspect);
} else {
......@@ -825,19 +826,7 @@ void Vt102Emulation::processSessionAttributeRequest(int tokenSize)
}
}
int rows = -1, cols = -1;
int needScroll = _currentScreen->currentTerminalDisplay()->addPlacement(pixmap, rows, cols);
if (needScroll > 1) {
_currentScreen->scrollUp(needScroll - 1);
}
if (rows - needScroll - 1 > 0) {
_currentScreen->cursorDown(rows - needScroll - 1);
}
if (_currentScreen->getCursorX() + cols >= _currentScreen->getColumns()) {
_currentScreen->toStartOfLine();
_currentScreen->newLine();
} else {
_currentScreen->cursorRight(cols);
}
_currentScreen->addPlacement(pixmap, rows, cols);
}
_pendingSessionAttributesUpdates[attribute] = value;
_sessionAttributesUpdateTimer->start(20);
......@@ -1309,7 +1298,7 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
{
QString value = QString::fromUcs4(&tokenBuffer[3], tokenSize - 4);
QStringList list;
QImage *image = NULL;
QImage *image = nullptr;
int dataPos = value.indexOf(QLatin1Char(';'));
if (dataPos == -1) {
......@@ -1367,7 +1356,7 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
return;
}
if (keys['I']) {
keys['i'] = _currentScreen->currentTerminalDisplay()->getFreeGraphicsImageId();
keys['i'] = getFreeGraphicsImageId();
}
if (imageId != keys['i']) {
imageId = keys['i'];
......@@ -1409,7 +1398,7 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
imageData.append(*out);
}
} else {
out = NULL;
out = nullptr;
}
if (keys['f'] == 24 || keys['f'] == 32) {
enum QImage::Format format = keys['f'] == 24 ? QImage::Format_RGB888 : QImage::Format_RGBA8888;
......@@ -1430,7 +1419,7 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
sendGraphicsReply(params, QString());
} else {
if (keys['i']) {
_currentScreen->currentTerminalDisplay()->setGraphicsImage(keys['i'], image);
_graphicsImages[keys['i']] = image;
}
if (keys['q'] == 0 && keys['a'] == 't') {
QString params = QStringLiteral("i=") + QString::number(keys['i']);
......@@ -1452,7 +1441,11 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
}
if (keys['a'] == 'p' || (keys['a'] == 'T' && keys['m'] == 0)) {
if (keys['i']) {
image = _currentScreen->currentTerminalDisplay()->getGraphicsImage(keys['i']);
if (_graphicsImages.count(keys['i'])) {
image = _graphicsImages[keys['i']];
} else {
image = nullptr;
}
}
if (image) {
QPixmap pixmap = QPixmap::fromImage(*image);
......@@ -1470,22 +1463,8 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
keys['r'] * _currentScreen->currentTerminalDisplay()->terminalFont()->fontHeight());
}
int rows = -1, cols = -1;
int needScroll = _currentScreen->currentTerminalDisplay()
->addPlacement(pixmap, rows, cols, -1, -1, true, keys['z'], keys['i'], keys['p'], keys['A'] / 255.0, keys['X'], keys['Y']);
if (needScroll > 1) {
_currentScreen->scrollUp(needScroll - 1);
}
if (keys['C'] == 0) {
if (rows - needScroll - 1 > 0) {
_currentScreen->cursorDown(rows - needScroll - 1);
}
if (_currentScreen->getCursorX() + cols >= _currentScreen->getColumns()) {
_currentScreen->toStartOfLine();
_currentScreen->newLine();
} else {
_currentScreen->cursorRight(cols);
}
}
_currentScreen
->addPlacement(pixmap, rows, cols, -1, -1, true, keys['C'] == 0, keys['z'], keys['i'], keys['p'], keys['A'] / 255.0, keys['X'], keys['Y']);
if (keys['q'] == 0 && keys['i']) {
QString params = QStringLiteral("i=") + QString::number(keys['i']);
if (keys['I']) {
......@@ -1515,7 +1494,7 @@ void Vt102Emulation::processGraphicsToken(int tokenSize)
x = _currentScreen->getCursorX();
y = _currentScreen->getCursorY();
}
_currentScreen->currentTerminalDisplay()->delPlacements(action, id, pid, x, y, keys['z']);
_currentScreen->delPlacements(action, id, pid, x, y, keys['z']);
}
}
......@@ -1532,7 +1511,7 @@ void Vt102Emulation::sendString(const QByteArray &s)
Q_EMIT sendData(s);
}
void Vt102Emulation::sendGraphicsReply(QString params, QString error)
void Vt102Emulation::sendGraphicsReply(const QString &params, const QString &error)
{
sendString(
(QStringLiteral("\033_G") + params + QStringLiteral(";") + (error.isEmpty() ? QStringLiteral("OK") : error) + QStringLiteral("\033\\")).toLatin1());
......@@ -2040,9 +2019,8 @@ void Vt102Emulation::setMode(int m)
_screen[1]->setDefaultRendition();
_screen[1]->clearSelection();
setScreen(1);
if (_currentScreen->currentTerminalDisplay()) { // We may get here before we have a TerminalDisplay
_currentScreen->currentTerminalDisplay()->selectPlacements(1);
_currentScreen->currentTerminalDisplay()->delPlacements(1);
if (_currentScreen) { // We may get here before we have a TerminalDisplay
_currentScreen->delPlacements(1);
}
break;
}
......@@ -2086,9 +2064,6 @@ void Vt102Emulation::resetMode(int m)
case MODE_AppScreen:
_screen[0]->clearSelection();
setScreen(0);
if (_currentScreen->currentTerminalDisplay()) { // We may get here before we have a TerminalDisplay
_currentScreen->currentTerminalDisplay()->selectPlacements(0);
}
break;
}
// FIXME: Currently this has a redundant condition as MODES_SCREEN is 7
......@@ -2250,11 +2225,8 @@ void Vt102Emulation::SixelModeDisable()
pixmap = pixmap.scaled(pixmap.width(), m_aspect.first * pixmap.height() / m_aspect.second);
}
int rows = -1, cols = -1;
int needScroll = _currentScreen->currentTerminalDisplay()->addPlacement(pixmap, rows, cols, row, col, m_SixelScrolling);
int needScroll = _currentScreen->addPlacement(pixmap, rows, cols, row, col, m_SixelScrolling, false);
if (m_SixelScrolling) {
if (needScroll > 0) {
_currentScreen->scrollUp(needScroll);
}
if (rows - needScroll > 0) {
_currentScreen->cursorDown(rows - needScroll);
}
......@@ -2541,3 +2513,14 @@ bool Vt102Emulation::processSixel(uint cc)
}
return false;
}
int Vt102Emulation::getFreeGraphicsImageId()
{
int i = 1;
while (1) {
if (!_graphicsImages.count(i)) {
return i;
}
i++;
}
}
......@@ -152,7 +152,7 @@ private:
void processChecksumRequest(int argc, int argv[]);
void processGraphicsToken(int tokenSize);
void sendGraphicsReply(QString params, QString error);
void sendGraphicsReply(const QString &params, const QString &error);
void reportTerminalType();
void reportTertiaryAttributes();
void reportSecondaryAttributes();
......@@ -215,6 +215,11 @@ private:
QPair<int, int> m_aspect = qMakePair(1, 1);
bool m_SixelScrolling = true;
QSize m_actualSize; // For efficiency reasons, we keep the image in memory larger than what the end result is
// Kitty
std::map<int, QImage *> _graphicsImages;
// For kitty graphics protocol - image cache
int getFreeGraphicsImageId();
};
}
......
......@@ -75,7 +75,6 @@
#include "TerminalColor.h"
#include "TerminalFonts.h"
#include "TerminalGraphics.h"
#include "TerminalPainter.h"
#include "TerminalScrollBar.h"
......@@ -359,12 +358,6 @@ TerminalDisplay::TerminalDisplay(QWidget *parent)
};
_printManager.reset(new KonsolePrintManager(ldrawBackground, ldrawContents, lgetBackgroundColor));
_graphicsImages = std::map<int, QImage *>();
_graphicsPlacementsArray[0] = QVector<TerminalGraphicsPlacement_t *>();
_graphicsPlacementsArray[1] = QVector<TerminalGraphicsPlacement_t *>();
_graphicsPlacements = &_graphicsPlacementsArray[0];
_hasGraphics = false;
}
TerminalDisplay::~TerminalDisplay()
......@@ -374,11 +367,6 @@ TerminalDisplay::~TerminalDisplay()
delete[] _image;
delete _filterChain;
for (int p = 0; p < 2; p++) {
for (int i = 0; i < _graphicsPlacementsArray[p].size(); i++) {
delete _graphicsPlacementsArray[p][i];
}
}
}
void TerminalDisplay::setupHeaderVisibility()
......@@ -684,7 +672,7 @@ void TerminalDisplay::updateImage()
_screenWindow->resetScrollCount();
// update the parts of the display which have changed
if (_hasGraphics) {
if (_screenWindow->screen()->hasGraphics()) {
update();
} else {
update(dirtyRegion);
......@@ -1028,9 +1016,9 @@ void TerminalDisplay::updateImageSize()
histLines = _screenWindow->screen()->getHistLines();
}
if (histLines) {
scrollUpVisiblePlacements(qMax(-histLines, change));
_screenWindow->screen()->scrollUpVisiblePlacements(qMax(-histLines, change));
} else if (oldLines > _lines && cursorPosition().y() >= oldLines - change) {
scrollUpVisiblePlacements(cursorPosition().y() - _lines + 1);
_screenWindow->screen()->scrollUpVisiblePlacements(cursorPosition().y() - _lines + 1);
}
}
Q_EMIT changedContentSizeSignal(_contentRect.height(), _contentRect.width()); // expose resizeEvent
......@@ -2969,191 +2957,4 @@ int TerminalDisplay::selectionState() const
return _actSel;
}
QImage *TerminalDisplay::getGraphicsImage(int id)
{
if (_graphicsImages.count(id)) {
return _graphicsImages[id];
}
return NULL;
}
void TerminalDisplay::setGraphicsImage(int id, QImage *pixmap)
{
_graphicsImages[id] = pixmap;
}
std::map<int, QImage *>::iterator TerminalDisplay::getGraphicsImagesBegin()
{
return _graphicsImages.begin();
}
std::map<int, QImage *>::iterator TerminalDisplay::getGraphicsImagesEnd()
{
return _graphicsImages.end();
}
int TerminalDisplay::getFreeGraphicsImageId()
{
int i = 1;
while (1) {
if (!_graphicsImages.count(i)) {
return i;
}
i++;
}
}