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(); }