void TerminalDisplay::updateImage()
{
if ( !_screenWindow )
return;
// optimization - scroll the existing image where possible and
// avoid expensive text drawing for parts of the image that
// can simply be moved up or down
scrollImage( _screenWindow->scrollCount() ,
_screenWindow->scrollRegion() );
_screenWindow->resetScrollCount();
Character* const newimg = _screenWindow->getImage();
int lines = _screenWindow->windowLines();
int columns = _screenWindow->windowColumns();
setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
if (!_image)
updateImageSize(); // Create _image
Q_ASSERT( this->_usedLines <= this->_lines );
Q_ASSERT( this->_usedColumns <= this->_columns );
int y,x,len;
QPoint tL = contentsRect().topLeft();
int tLx = tL.x();
int tLy = tL.y();
_hasBlinker = false;
CharacterColor cf; // undefined
CharacterColor _clipboard; // undefined
int cr = -1; // undefined
const int linesToUpdate = qMin(this->_lines, qMax(0,lines ));
const int columnsToUpdate = qMin(this->_columns,qMax(0,columns));
QChar *disstrU = new QChar[columnsToUpdate];
char *dirtyMask = new char[columnsToUpdate+2];
QRegion dirtyRegion;
// debugging variable, this records the number of lines that are found to
// be 'dirty' ( ie. have changed from the old _image to the new _image ) and
// which therefore need to be repainted
int dirtyLineCount = 0;
for (y = 0; y < linesToUpdate; y++)
{
const Character* currentLine = &_image[y*this->_columns];
const Character* const newLine = &newimg[y*columns];
bool updateLine = false;
// The dirty mask indicates which characters need repainting. We also
// mark surrounding neighbours dirty, in case the character exceeds
// its cell boundaries
memset(dirtyMask, 0, columnsToUpdate+2);
for( x = 0 ; x < columnsToUpdate ; x++)
{
if ( newLine[x] != currentLine[x] )
{
dirtyMask[x] = true;
}
}
if (!_resizing) // not while _resizing, we're expecting a paintEvent
for (x = 0; x < columnsToUpdate; x++)
{
_hasBlinker |= (newLine[x].rendition & RE_BLINK);
// Start drawing if this character or the next one differs.
// We also take the next one into account to handle the situation
// where characters exceed their cell width.
if (dirtyMask[x])
{
quint16 c = newLine[x+0].character;
if ( !c )
continue;
int p = 0;
disstrU[p++] = c; //fontMap(c);
bool lineDraw = isLineChar(c);
bool doubleWidth = (newLine[x+1].character == 0);
cr = newLine[x].rendition;
_clipboard = newLine[x].backgroundColor;
if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor;
int lln = columnsToUpdate - x;
for (len = 1; len < lln; len++)
{
const Character& ch = newLine[x+len];
if (!ch.character)
continue; // Skip trailing part of multi-col chars.
if ( ch.foregroundColor != cf ||
ch.backgroundColor != _clipboard ||
ch.rendition != cr ||
!dirtyMask[x+len] ||
isLineChar(c) != lineDraw ||
(newLine[x+len+1].character == 0) != doubleWidth )
break;
disstrU[p++] = c; //fontMap(c);
}
QString unistr(disstrU, p);
bool saveFixedFont = _fixedFont;
if (lineDraw)
_fixedFont = false;
if (doubleWidth)
_fixedFont = false;
updateLine = true;
_fixedFont = saveFixedFont;
x += len - 1;
}
}
//both the top and bottom halves of double height _lines must always be redrawn
//although both top and bottom halves contain the same characters, only
//the top one is actually
//drawn.
if (_lineProperties.count() > y)
updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT);
// if the characters on the line are different in the old and the new _image
// then this line must be repainted.
if (updateLine)
{
dirtyLineCount++;
// add the area occupied by this line to the region which needs to be
// repainted
QRect dirtyRect = QRect( _leftMargin+tLx ,
_topMargin+tLy+_fontHeight*y ,
_fontWidth * columnsToUpdate ,
_fontHeight );
dirtyRegion |= dirtyRect;
}
// replace the line of characters in the old _image with the
// current line of the new _image
memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character));
}
// if the new _image is smaller than the previous _image, then ensure that the area
// outside the new _image is cleared
if ( linesToUpdate < _usedLines )
{
dirtyRegion |= QRect( _leftMargin+tLx ,
_topMargin+tLy+_fontHeight*linesToUpdate ,
_fontWidth * this->_columns ,
_fontHeight * (_usedLines-linesToUpdate) );
}
_usedLines = linesToUpdate;
if ( columnsToUpdate < _usedColumns )
{
dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth ,
_topMargin+tLy ,
_fontWidth * (_usedColumns-columnsToUpdate) ,
_fontHeight * this->_lines );
}
_usedColumns = columnsToUpdate;
dirtyRegion |= _inputMethodData.previousPreeditRect;
// update the parts of the display which have changed
update(dirtyRegion);
if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( BLINK_DELAY );
if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; }
delete[] dirtyMask;
delete[] disstrU;
showResizeNotification();
}