Commit 73c95809 authored by Robert Knight's avatar Robert Knight
Browse files

* Make both the Screen and the ScreenWindow keep track of lines scrolled.
  The Screen class records lines scrolled in response to output from the terminal
  program.  The ScreenWindow class records lines scrolled in response to the user
  dragging the scrollbar up and down.
  This allows the scrolling optimisation to work for normal shell usage and
  for interactive programs such as man/vim etc.
* Avoid redrawing scrollbar if the value or range has not changed since the
  previous update.
  
* Add debug facility to count lines repainted on each update.
* Remove references to the 'history cursor' from the emulation.
* Some style tidy-up in TerminalDisplay::updateImage()

svn path=/branches/work/konsole-split-view/; revision=645755
parent aa359721
......@@ -263,8 +263,7 @@ void Emulation::onKeyPress( QKeyEvent* ev )
{
if (!listenToKeyPress) return; // someone else gets the keys
emit notifySessionState(NOTIFYNORMAL);
if (currentScreen->getHistCursor() != currentScreen->getHistLines() && !ev->text().isEmpty())
currentScreen->setHistCursor(currentScreen->getHistLines());
if (!ev->text().isEmpty())
{ // A block of text
// Note that the text is proper unicode.
......@@ -504,11 +503,15 @@ bool Emulation::findTextNext( const QString &str, bool forward, bool isCaseSensi
//work out how many lines into the current block of text the search result was found
//- looks a little painful, but it only has to be done once per search.
m_findPos = line + string.left(pos + 1).count(QChar('\n'));
if ( m_findPos > currentScreen->getHistLines() )
currentScreen->setHistCursor(currentScreen->getHistLines());
else
currentScreen->setHistCursor(m_findPos);
//TODO - Reimplement moving active view to focus on current match now that
// that multiple views can show different parts of the screen at the same
// time.
//
// if ( m_findPos > currentScreen->getHistLines() )
// currentScreen->setHistCursor(currentScreen->getHistLines());
// else
// currentScreen->setHistCursor(m_findPos);
//cause target line to be selected
//currentScreen->getHistoryLine(m_findPos);
......@@ -540,6 +543,8 @@ void Emulation::showBulk()
bulk_timer2.stop();
emit updateViews();
currentScreen->resetScrolledLines();
}
void Emulation::bufferedUpdate()
......@@ -587,13 +592,6 @@ QSize Emulation::imageSize()
return QSize(currentScreen->getColumns(), currentScreen->getLines());
}
void Emulation::onHistoryCursorChange(int cursor)
{
currentScreen->setHistCursor(cursor);
bufferedUpdate();
}
void Emulation::setColumns(int columns)
{
//FIXME: this goes strange ways.
......
......@@ -133,8 +133,6 @@ public Q_SLOTS: // signals incoming from TerminalDisplay
/** Change the size of the emulation's image */
virtual void onImageSizeChange(int lines, int columns);
virtual void onHistoryCursorChange(int cursor);
/**
* Interprets a sequence of characters and sends the result to the terminal.
* This is equivalent to calling onKeyPress for each character in @p text in succession.
......
......@@ -71,8 +71,6 @@ Screen::Screen(int l, int c)
columns(c),
screenLines(new ImageLine[lines+1] ),
_scrolledLines(0),
// image(new Character[(lines+1)*columns]),
histCursor(0),
hist(new HistoryScrollNone()),
cuX(0), cuY(0),
cu_re(0),
......@@ -101,7 +99,6 @@ Screen::Screen(int l, int c)
Screen::~Screen()
{
// delete[] image;
delete[] screenLines;
delete[] tabstops;
delete hist;
......@@ -202,7 +199,6 @@ void Screen::setMargins(int top, int bot)
cuX = 0;
cuY = getMode(MODE_Origin) ? top : 0;
resetScrolledLines();
}
int Screen::topMargin() const
......@@ -856,6 +852,8 @@ int Screen::scrolledLines() const
void Screen::resetScrolledLines()
{
//qDebug() << "scrolled lines reset";
_scrolledLines = 0;
}
......@@ -879,6 +877,8 @@ void Screen::scrollUp(int from, int n)
_scrolledLines -= n;
//qDebug() << "Screen::scrollUp( from: " << from << " , n: " << n << ")";
//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin));
clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' ');
......@@ -898,6 +898,8 @@ void Screen::scrollDown(int n)
void Screen::scrollDown(int from, int n)
{
//qDebug() << "Screen::scrollDown( from: " << from << " , n: " << n << ")";
_scrolledLines += n;
//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
......@@ -1042,6 +1044,10 @@ NOTE: moveImage() can only move whole lines.
void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
{
//qDebug() << "moving image from (" << (sourceBegin/columns)
// << "," << (sourceEnd/columns) << ") to " <<
// (dest/columns);
Q_ASSERT( sourceBegin <= sourceEnd );
int lines=(sourceEnd-sourceBegin)/columns;
......@@ -1478,8 +1484,6 @@ QString Screen::getHistoryLine(int no)
void Screen::addHistLine()
{
assert(hasScroll() || histCursor == 0);
// add to hist buffer
// we have to take care about scrolling, too...
......@@ -1494,11 +1498,9 @@ void Screen::addHistLine()
bool beginIsTL = (sel_begin == sel_TL);
// adjust history cursor
// Adjust selection for the new point of reference
if (newHistLines > oldHistLines)
{
histCursor++;
// Adjust selection for the new point of reference
if (sel_begin != -1)
{
sel_TL += columns;
......@@ -1506,14 +1508,6 @@ void Screen::addHistLine()
}
}
// Scroll up if user is looking at the history and we can scroll up
if ((histCursor > 0) && // We can scroll up and...
((histCursor != newHistLines) || // User is looking at history...
sel_busy)) // or user is selecting text.
{
histCursor--;
}
if (sel_begin != -1)
{
// Scroll selection in history up
......@@ -1542,19 +1536,6 @@ void Screen::addHistLine()
}
}
if (!hasScroll()) histCursor = 0; //FIXME: a poor workaround
}
void Screen::setHistCursor(int cursor)
{
_scrolledLines += histCursor-cursor;
histCursor = cursor; //FIXME:rangecheck
}
int Screen::getHistCursor()
{
return histCursor;
}
int Screen::getHistLines()
......@@ -1566,7 +1547,6 @@ void Screen::setScroll(const HistoryType& t)
{
clearSelection();
hist = t.getScroll(hist);
histCursor = hist->getLines();
}
bool Screen::hasScroll()
......
......@@ -207,11 +207,6 @@ public: // these are all `Screen' operations
/*! return the number of columns. */
int getColumns() { return columns; }
/*! set the position of the history cursor. */
void setHistCursor(int cursor);
/*! return the position of the history cursor. */
int getHistCursor();
int getHistLines ();
void setScroll(const HistoryType&);
const HistoryType& getScroll();
......@@ -315,6 +310,8 @@ public: // these are all `Screen' operations
/**
* Returns the number of lines that the image has been scrolled up or down by,
* since the last call to resetScrolledLines().
*
* a positive return value indicates that the image has been scrolled up,
* a negative return value indicates that the image has been scrolled down.
*/
......@@ -382,7 +379,6 @@ private: // helper
// history buffer ---------------
int histCursor; // display position relative to start of the history buffer
HistoryScroll *hist;
// cursor location
......
......@@ -48,6 +48,7 @@ Screen* ScreenWindow::screen() const
Character* ScreenWindow::getImage()
{
return _screen->getCookedImage(_currentLine);
}
......@@ -150,6 +151,8 @@ bool ScreenWindow::trackOutput() const
int ScreenWindow::scrollCount() const
{
// qDebug() << "window returning scroll count of " << _scrollCount;
return _scrollCount;
}
......@@ -160,12 +163,15 @@ void ScreenWindow::resetScrollCount()
void ScreenWindow::notifyOutputChanged()
{
// move window to the bottom of the screen and update scroll count
// if this window is currently tracking the bottom of the screen
if ( _trackOutput )
{
scrollTo( _screen->getHistLines() );
{
_scrollCount -= _screen->scrolledLines();
_currentLine = _screen->getHistLines();
}
emit outputChanged();
emit outputChanged();
}
#include "ScreenWindow.moc"
......@@ -263,8 +263,8 @@ Session* SessionManager::createSession(QString configPath )
session->setTerminalType( info->terminal() );
//temporary
//session->setHistory( HistoryTypeBuffer(1000) );
session->setHistory( HistoryTypeFile() );
session->setHistory( HistoryTypeBuffer(200) );
//session->setHistory( HistoryTypeFile() );
//ask for notification when session dies
connect( session , SIGNAL(done(Session*)) , SLOT(sessionTerminated(Session*)) );
......
......@@ -969,8 +969,9 @@ void TerminalDisplay::processFilters()
void TerminalDisplay::updateImage()
{
// 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
// 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->resetScrollCount();
......@@ -1004,6 +1005,9 @@ void TerminalDisplay::updateImage()
char *dirtyMask = (char *) malloc(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++)
......@@ -1020,8 +1024,11 @@ void TerminalDisplay::updateImage()
// Two extra so that we don't have to have to care about start and end conditions
for (x = 0; x < columnsToUpdate; x++)
{
if ( ( (m_imPreeditLength > 0) && ( ( m_imStartLine == y )
&& ( ( m_imStart < m_imEnd ) && ( ( x > m_imStart ) ) && ( x < m_imEnd ) )
if ( ( (m_imPreeditLength > 0) &&
( ( m_imStartLine == y ) &&
( ( m_imStart < m_imEnd ) &&
( ( x > m_imStart ) ) &&
( x < m_imEnd ) )
|| ( ( m_imSelStart < m_imSelEnd ) && ( ( x > m_imSelStart ) ) ) ) )
|| newLine[x] != currentLine[x])
{
......@@ -1053,12 +1060,17 @@ void TerminalDisplay::updateImage()
int lln = columnsToUpdate - x;
for (len = 1; len < lln; len++)
{
c = newLine[x+len].character;
if (!c)
continue; // Skip trailing part of multi-col chars.
const Character& ch = newLine[x+len];
if (newLine[x+len].foregroundColor != cf || newLine[x+len].backgroundColor != cb || newLine[x+len].rendition != cr ||
!dirtyMask[x+len] || isLineChar(c) != lineDraw || (newLine[x+len+1].character == 0) != doubleWidth)
if (!ch.character)
continue; // Skip trailing part of multi-col chars.
if ( ch.foregroundColor != cf ||
ch.backgroundColor != cb ||
ch.rendition != cr ||
!dirtyMask[x+len] ||
isLineChar(c) != lineDraw ||
(newLine[x+len+1].character == 0) != doubleWidth )
break;
disstrU[p++] = c; //fontMap(c);
......@@ -1068,20 +1080,29 @@ void TerminalDisplay::updateImage()
// for XIM on the spot input style
m_isIMEdit = m_isIMSel = false;
if ( m_imStartLine == y ) {
if ( ( m_imStart < m_imEnd ) && ( x >= m_imStart-1 ) && ( x + int( unistr.length() ) <= m_imEnd ) )
m_isIMEdit = true;
if ( ( m_imSelStart < m_imSelEnd ) && ( x >= m_imStart-1 ) && ( x + int( unistr.length() ) <= m_imEnd ) )
m_isIMSel = true;
}
else if ( m_imStartLine < y ) { // for word worp
if ( ( m_imStart < m_imEnd ) )
if ( m_imStartLine == y )
{
if ( ( m_imStart < m_imEnd ) &&
( x >= m_imStart-1 ) &&
( x + int( unistr.length() ) <= m_imEnd )
)
m_isIMEdit = true;
if ( ( m_imSelStart < m_imSelEnd ) &&
( x >= m_imStart-1 ) &&
( x + int( unistr.length() ) <= m_imEnd )
)
m_isIMSel = true;
}
else if ( m_imStartLine < y )
{ // for word warp
if ( m_imStart < m_imEnd )
m_isIMEdit = true;
if ( ( m_imSelStart < m_imSelEnd ) )
if ( m_imSelStart < m_imSelEnd )
m_isIMSel = true;
}
}
bool save_fixed_font = fixed_font;
if (lineDraw)
......@@ -1098,42 +1119,60 @@ void TerminalDisplay::updateImage()
}
//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
//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++;
QRect dirtyRect = QRect( bX+tLx , bY+tLy+font_h*y , font_w * columnsToUpdate , font_h );
// add the area occupied by this line to the region which needs to be
// repainted
QRect dirtyRect = QRect( bX+tLx ,
bY+tLy+font_h*y ,
font_w * columnsToUpdate ,
font_h );
dirtyRegion |= dirtyRect;
}
dirtyMask--; // Set back
// finally, make `image' become `newimg'.
// 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));
}
// debugging - display a count of the number of lines that will need
// to be repainted
//qDebug() << "dirty line count = " << dirtyLineCount;
// 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( bX+tLx , bY+tLy+font_h*linesToUpdate , font_w * this->columns , font_h * (usedLines-linesToUpdate) );
dirtyRegion |= QRect( bX+tLx ,
bY+tLy+font_h*linesToUpdate ,
font_w * this->columns ,
font_h * (usedLines-linesToUpdate) );
}
usedLines = linesToUpdate;
if ( columnsToUpdate < usedColumns )
{
dirtyRegion |= QRect( bX+tLx+columnsToUpdate*font_w , bY+tLy , font_w * (usedColumns-columnsToUpdate) , font_h * this->lines );
dirtyRegion |= QRect( bX+tLx+columnsToUpdate*font_w ,
bY+tLy ,
font_w * (usedColumns-columnsToUpdate) ,
font_h * this->lines );
}
usedColumns = columnsToUpdate;
// redraw the display
// update the parts of the display which have changed
update(dirtyRegion);
if ( hasBlinker && !blinkT->isActive()) blinkT->start( BLINK_DELAY );
......@@ -1166,7 +1205,7 @@ void TerminalDisplay::showResizeNotification()
mResizeWidget->setFrameShape((QFrame::Shape) (QFrame::Box|QFrame::Raised));
mResizeWidget->setMidLineWidth(2);
QBoxLayout *l = new QVBoxLayout(mResizeWidget);
l->setMargin(10);
l->setMargin(10);
mResizeLabel = new QLabel(i18n("Size: XXX x XXX"), mResizeWidget);
l->addWidget(mResizeLabel, 1, Qt::AlignCenter);
mResizeWidget->setMinimumWidth(mResizeLabel->fontMetrics().width(i18n("Size: XXX x XXX"))+20);
......@@ -1182,7 +1221,6 @@ void TerminalDisplay::showResizeNotification()
mResizeWidget->show();
mResizeTimer->start(3000);
}
}
void TerminalDisplay::setBlinkingCursor(bool blink)
......@@ -1575,16 +1613,25 @@ bool TerminalDisplay::scrollAtEnd()
void TerminalDisplay::setScroll(int cursor, int slines)
{
//kDebug(1211)<<"TerminalDisplay::setScroll() disconnect()"<<endl;
// update scrollbar if the range or value has changed,
// otherwise return
//
// setting the range or value of a scrollbar will always trigger
// a repaint, so it should be avoided if it is not necessary
if ( scrollbar->minimum() == 0 &&
scrollbar->maximum() == slines &&
scrollbar->value() == cursor )
{
//qDebug() << "no change in scrollbar - skipping update";
return;
}
disconnect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
//kDebug(1211)<<"TerminalDisplay::setScroll() setRange()"<<endl;
scrollbar->setRange(0,slines);
//kDebug(1211)<<"TerminalDisplay::setScroll() setSteps()"<<endl;
scrollbar->setSingleStep(1);
scrollbar->setPageStep(lines);
scrollbar->setValue(cursor);
connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
//kDebug(1211)<<"TerminalDisplay::setScroll() done"<<endl;
}
void TerminalDisplay::setScrollbarLocation(int loc)
......
......@@ -1054,12 +1054,6 @@ void Vt102Emulation::onKeyPress( QKeyEvent* ev )
}
}
// revert to non-history when typing
if (currentScreen->getHistCursor() != currentScreen->getHistLines() && (!ev->text().isEmpty()
|| ev->key()==Qt::Key_Down || ev->key()==Qt::Key_Up || ev->key()==Qt::Key_Left || ev->key()==Qt::Key_Right
|| ev->key()==Qt::Key_PageUp || ev->key()==Qt::Key_PageDown))
currentScreen->setHistCursor(currentScreen->getHistLines());
if (cmd==CMD_send) {
if ((ev->modifiers() & Qt::AltModifier) && !metaspecified ) sendString("\033");
emit sendBlock(txt.constData(), txt.length());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment