• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Konsole

Screen.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of Konsole, an X terminal.
00003 
00004     Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
00005     Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00020     02110-1301  USA.
00021 */
00022 
00023 // Own
00024 #include "Screen.h"
00025 
00026 // Standard
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <assert.h>
00031 #include <string.h>
00032 #include <ctype.h>
00033 
00034 // Qt
00035 #include <QtCore/QTextStream>
00036 #include <QtCore/QDate>
00037 
00038 // KDE
00039 #include <kdebug.h>
00040 
00041 // Konsole
00042 #include "konsole_wcwidth.h"
00043 #include "TerminalCharacterDecoder.h"
00044 
00045 using namespace Konsole;
00046 
00047 //FIXME: this is emulation specific. Use false for xterm, true for ANSI.
00048 //FIXME: see if we can get this from terminfo.
00049 #define BS_CLEARS false
00050 
00051 //Macro to convert x,y position on screen to position within an image.
00052 //
00053 //Originally the image was stored as one large contiguous block of 
00054 //memory, so a position within the image could be represented as an
00055 //offset from the beginning of the block.  For efficiency reasons this
00056 //is no longer the case.  
00057 //Many internal parts of this class still use this representation for parameters and so on,
00058 //notably moveImage() and clearImage().
00059 //This macro converts from an X,Y position into an image offset.
00060 #ifndef loc
00061 #define loc(X,Y) ((Y)*columns+(X))
00062 #endif
00063 
00064 
00065 Character Screen::defaultChar = Character(' ',CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),DEFAULT_RENDITION);
00066 
00067 //#define REVERSE_WRAPPED_LINES  // for wrapped line debug
00068 
00069 Screen::Screen(int l, int c)
00070   : lines(l),
00071     columns(c),
00072     screenLines(new ImageLine[lines+1] ),
00073     _scrolledLines(0),
00074     _droppedLines(0),
00075     hist(new HistoryScrollNone()),
00076     cuX(0), cuY(0),
00077     cu_re(0),
00078     tmargin(0), bmargin(0),
00079     tabstops(0),
00080     sel_begin(0), sel_TL(0), sel_BR(0),
00081     sel_busy(false),
00082     columnmode(false),
00083     ef_fg(CharacterColor()), ef_bg(CharacterColor()), ef_re(0),
00084     sa_cuX(0), sa_cuY(0),
00085     sa_cu_re(0),
00086     lastPos(-1)
00087 {
00088   lineProperties.resize(lines+1);
00089   for (int i=0;i<lines+1;i++)
00090           lineProperties[i]=LINE_DEFAULT;
00091 
00092   initTabStops();
00093   clearSelection();
00094   reset();
00095 }
00096 
00100 Screen::~Screen()
00101 {
00102   delete[] screenLines;
00103   delete[] tabstops;
00104   delete hist;
00105 }
00106 
00107 /* ------------------------------------------------------------------------- */
00108 /*                                                                           */
00109 /* Normalized                    Screen Operations                           */
00110 /*                                                                           */
00111 /* ------------------------------------------------------------------------- */
00112 
00113 // Cursor Setting --------------------------------------------------------------
00114 
00125 void Screen::cursorUp(int n)
00126 //=CUU
00127 {
00128   if (n == 0) n = 1; // Default
00129   int stop = cuY < tmargin ? 0 : tmargin;
00130   cuX = qMin(columns-1,cuX); // nowrap!
00131   cuY = qMax(stop,cuY-n);
00132 }
00133 
00134 void Screen::cursorDown(int n)
00135 //=CUD
00136 {
00137   if (n == 0) n = 1; // Default
00138   int stop = cuY > bmargin ? lines-1 : bmargin;
00139   cuX = qMin(columns-1,cuX); // nowrap!
00140   cuY = qMin(stop,cuY+n);
00141 }
00142 
00143 void Screen::cursorLeft(int n)
00144 //=CUB
00145 {
00146   if (n == 0) n = 1; // Default
00147   cuX = qMin(columns-1,cuX); // nowrap!
00148   cuX = qMax(0,cuX-n);
00149 }
00150 
00151 void Screen::cursorRight(int n)
00152 //=CUF
00153 {
00154   if (n == 0) n = 1; // Default
00155   cuX = qMin(columns-1,cuX+n);
00156 }
00157 
00158 void Screen::setMargins(int top, int bot)
00159 //=STBM
00160 {
00161   if (top == 0) top = 1;      // Default
00162   if (bot == 0) bot = lines;  // Default
00163   top = top - 1;              // Adjust to internal lineno
00164   bot = bot - 1;              // Adjust to internal lineno
00165   if ( !( 0 <= top && top < bot && bot < lines ) )
00166   { kDebug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
00167     return;                   // Default error action: ignore
00168   }
00169   tmargin = top;
00170   bmargin = bot;
00171   cuX = 0;
00172   cuY = getMode(MODE_Origin) ? top : 0;
00173 
00174 }
00175 
00176 int Screen::topMargin() const
00177 {
00178     return tmargin;
00179 }
00180 int Screen::bottomMargin() const
00181 {
00182     return bmargin;
00183 }
00184 
00185 void Screen::index()
00186 //=IND
00187 {
00188   if (cuY == bmargin)
00189   {
00190     scrollUp(1);
00191   }
00192   else if (cuY < lines-1)
00193     cuY += 1;
00194 }
00195 
00196 void Screen::reverseIndex()
00197 //=RI
00198 {
00199   if (cuY == tmargin)
00200      scrollDown(tmargin,1);
00201   else if (cuY > 0)
00202     cuY -= 1;
00203 }
00204 
00205 void Screen::nextLine()
00206 //=NEL
00207 {
00208   toStartOfLine(); index();
00209 }
00210 
00211 void Screen::eraseChars(int n)
00212 {
00213   if (n == 0) n = 1; // Default
00214   int p = qMax(0,qMin(cuX+n-1,columns-1));
00215   clearImage(loc(cuX,cuY),loc(p,cuY),' ');
00216 }
00217 
00218 void Screen::deleteChars(int n)
00219 {
00220   Q_ASSERT( n >= 0 );
00221 
00222   // always delete at least one char
00223   if (n == 0) 
00224       n = 1; 
00225 
00226   // if cursor is beyond the end of the line there is nothing to do
00227   if ( cuX >= screenLines[cuY].count() )
00228       return;
00229 
00230   if ( cuX+n >= screenLines[cuY].count() ) 
00231        n = screenLines[cuY].count() - 1 - cuX;
00232 
00233   Q_ASSERT( n >= 0 );
00234   Q_ASSERT( cuX+n < screenLines[cuY].count() );
00235 
00236   screenLines[cuY].remove(cuX,n);
00237 }
00238 
00239 void Screen::insertChars(int n)
00240 {
00241   if (n == 0) n = 1; // Default
00242 
00243   if ( screenLines[cuY].size() < cuX )
00244     screenLines[cuY].resize(cuX);
00245 
00246   screenLines[cuY].insert(cuX,n,' ');
00247 
00248   if ( screenLines[cuY].count() > columns )
00249       screenLines[cuY].resize(columns);
00250 }
00251 
00252 void Screen::deleteLines(int n)
00253 {
00254   if (n == 0) n = 1; // Default
00255   scrollUp(cuY,n);
00256 }
00257 
00258 void Screen::insertLines(int n)
00259 {
00260   if (n == 0) n = 1; // Default
00261   scrollDown(cuY,n);
00262 }
00263 
00264 // Mode Operations -----------------------------------------------------------
00265 
00266 void Screen::setMode(int m)
00267 {
00268   currParm.mode[m] = true;
00269   switch(m)
00270   {
00271     case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home
00272   }
00273 }
00274 
00275 void Screen::resetMode(int m)
00276 {
00277   currParm.mode[m] = false;
00278   switch(m)
00279   {
00280     case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
00281   }
00282 }
00283 
00284 void Screen::saveMode(int m)
00285 {
00286   saveParm.mode[m] = currParm.mode[m];
00287 }
00288 
00289 void Screen::restoreMode(int m)
00290 {
00291   currParm.mode[m] = saveParm.mode[m];
00292 }
00293 
00294 bool Screen::getMode(int m) const
00295 {
00296   return currParm.mode[m];
00297 }
00298 
00299 void Screen::saveCursor()
00300 {
00301   sa_cuX     = cuX;
00302   sa_cuY     = cuY;
00303   sa_cu_re   = cu_re;
00304   sa_cu_fg   = cu_fg;
00305   sa_cu_bg   = cu_bg;
00306 }
00307 
00308 void Screen::restoreCursor()
00309 {
00310   cuX     = qMin(sa_cuX,columns-1);
00311   cuY     = qMin(sa_cuY,lines-1);
00312   cu_re   = sa_cu_re;
00313   cu_fg   = sa_cu_fg;
00314   cu_bg   = sa_cu_bg;
00315   effectiveRendition();
00316 }
00317 
00318 /* ------------------------------------------------------------------------- */
00319 /*                                                                           */
00320 /*                             Screen Operations                             */
00321 /*                                                                           */
00322 /* ------------------------------------------------------------------------- */
00323 
00324 void Screen::resizeImage(int new_lines, int new_columns)
00325 {
00326   if ((new_lines==lines) && (new_columns==columns)) return;
00327 
00328   if (cuY > new_lines-1)
00329   { // attempt to preserve focus and lines
00330     bmargin = lines-1; //FIXME: margin lost
00331     for (int i = 0; i < cuY-(new_lines-1); i++)
00332     {
00333       addHistLine(); scrollUp(0,1);
00334     }
00335   }
00336 
00337   // create new screen lines and copy from old to new
00338   
00339    ImageLine* newScreenLines = new ImageLine[new_lines+1];
00340    for (int i=0; i < qMin(lines-1,new_lines+1) ;i++)
00341            newScreenLines[i]=screenLines[i];
00342    for (int i=lines;(i > 0) && (i<new_lines+1);i++)
00343            newScreenLines[i].resize( new_columns );
00344    
00345   lineProperties.resize(new_lines+1);
00346   for (int i=lines;(i > 0) && (i<new_lines+1);i++)
00347           lineProperties[i] = LINE_DEFAULT;
00348 
00349   clearSelection();
00350  
00351   delete[] screenLines; 
00352   screenLines = newScreenLines;
00353 
00354   lines = new_lines;
00355   columns = new_columns;
00356   cuX = qMin(cuX,columns-1);
00357   cuY = qMin(cuY,lines-1);
00358 
00359   // FIXME: try to keep values, evtl.
00360   tmargin=0;
00361   bmargin=lines-1;
00362   initTabStops();
00363   clearSelection();
00364 }
00365 
00366 void Screen::setDefaultMargins()
00367 {
00368     tmargin = 0;
00369     bmargin = lines-1;
00370 }
00371 
00372 
00373 /*
00374    Clarifying rendition here and in the display.
00375 
00376    currently, the display's color table is
00377      0       1       2 .. 9    10 .. 17
00378      dft_fg, dft_bg, dim 0..7, intensive 0..7
00379 
00380    cu_fg, cu_bg contain values 0..8;
00381    - 0    = default color
00382    - 1..8 = ansi specified color
00383 
00384    re_fg, re_bg contain values 0..17
00385    due to the TerminalDisplay's color table
00386 
00387    rendition attributes are
00388 
00389       attr           widget screen
00390       -------------- ------ ------
00391       RE_UNDERLINE     XX     XX    affects foreground only
00392       RE_BLINK         XX     XX    affects foreground only
00393       RE_BOLD          XX     XX    affects foreground only
00394       RE_REVERSE       --     XX
00395       RE_TRANSPARENT   XX     --    affects background only
00396       RE_INTENSIVE     XX     --    affects foreground only
00397 
00398    Note that RE_BOLD is used in both widget
00399    and screen rendition. Since xterm/vt102
00400    is to poor to distinguish between bold
00401    (which is a font attribute) and intensive
00402    (which is a color attribute), we translate
00403    this and RE_BOLD in falls eventually appart
00404    into RE_BOLD and RE_INTENSIVE.
00405 */
00406 
00407 void Screen::reverseRendition(Character& p) const
00408 { 
00409     CharacterColor f = p.foregroundColor; 
00410     CharacterColor b = p.backgroundColor;
00411     
00412     p.foregroundColor = b; 
00413     p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
00414 }
00415 
00416 void Screen::effectiveRendition()
00417 // calculate rendition
00418 {
00419   //copy "current rendition" straight into "effective rendition", which is then later copied directly
00420   //into the image[] array which holds the characters and their appearance properties.
00421   //- The old version below filtered out all attributes other than underline and blink at this stage,
00422   //so that they would not be copied into the image[] array and hence would not be visible by TerminalDisplay
00423   //which actually paints the screen using the information from the image[] array.  
00424   //I don't know why it did this, but I'm fairly sure it was the wrong thing to do.  The net result
00425   //was that bold text wasn't printed in bold by Konsole.
00426   ef_re = cu_re;
00427   
00428   //OLD VERSION:
00429   //ef_re = cu_re & (RE_UNDERLINE | RE_BLINK);
00430   
00431   if (cu_re & RE_REVERSE)
00432   {
00433     ef_fg = cu_bg;
00434     ef_bg = cu_fg;
00435   }
00436   else
00437   {
00438     ef_fg = cu_fg;
00439     ef_bg = cu_bg;
00440   }
00441  
00442   if (cu_re & RE_BOLD)
00443     ef_fg.toggleIntensive();
00444 }
00445 
00446 void Screen::copyFromHistory(Character* dest, int startLine, int count) const
00447 {
00448   Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= hist->getLines() );
00449 
00450   for (int line = startLine; line < startLine + count; line++) 
00451   {
00452     const int length = qMin(columns,hist->getLineLen(line));
00453     const int destLineOffset  = (line-startLine)*columns;
00454 
00455     hist->getCells(line,0,length,dest + destLineOffset);
00456 
00457     for (int column = length; column < columns; column++) 
00458         dest[destLineOffset+column] = defaultChar;
00459     
00460     // invert selected text
00461     if (sel_begin !=-1)
00462     {
00463         for (int column = 0; column < columns; column++)
00464         {
00465             if (isSelected(column,line)) 
00466             {
00467                 reverseRendition(dest[destLineOffset + column]); 
00468             }
00469         }
00470     }
00471   }
00472 }
00473 
00474 void Screen::copyFromScreen(Character* dest , int startLine , int count) const
00475 {
00476     Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
00477 
00478     for (int line = startLine; line < (startLine+count) ; line++)
00479     {
00480        int srcLineStartIndex  = line*columns;
00481        int destLineStartIndex = (line-startLine)*columns;
00482 
00483        for (int column = 0; column < columns; column++)
00484        { 
00485          int srcIndex = srcLineStartIndex + column; 
00486          int destIndex = destLineStartIndex + column;
00487 
00488          dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar);
00489 
00490          // invert selected text
00491          if (sel_begin != -1 && isSelected(column,line + hist->getLines()))
00492            reverseRendition(dest[destIndex]); 
00493        }
00494 
00495     }
00496 }
00497 
00498 void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
00499 {
00500   Q_ASSERT( startLine >= 0 ); 
00501   Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
00502 
00503   const int mergedLines = endLine - startLine + 1;
00504 
00505   Q_ASSERT( size >= mergedLines * columns ); 
00506 
00507   const int linesInHistoryBuffer = qBound(0,hist->getLines()-startLine,mergedLines);
00508   const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
00509 
00510   // copy lines from history buffer
00511   if (linesInHistoryBuffer > 0)
00512     copyFromHistory(dest,startLine,linesInHistoryBuffer); 
00513 
00514   // copy lines from screen buffer
00515   if (linesInScreenBuffer > 0)
00516     copyFromScreen(dest + linesInHistoryBuffer*columns,
00517                    startLine + linesInHistoryBuffer - hist->getLines(),
00518                    linesInScreenBuffer);
00519  
00520   // invert display when in screen mode
00521   if (getMode(MODE_Screen))
00522   {
00523     for (int i = 0; i < mergedLines*columns; i++)
00524       reverseRendition(dest[i]); // for reverse display
00525   }
00526 
00527   // mark the character at the current cursor position
00528   int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer);
00529   if(getMode(MODE_Cursor) && cursorIndex < columns*mergedLines)
00530     dest[cursorIndex].rendition |= RE_CURSOR;
00531 }
00532 
00533 QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
00534 {
00535   Q_ASSERT( startLine >= 0 ); 
00536   Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
00537 
00538     const int mergedLines = endLine-startLine+1;
00539     const int linesInHistory = qBound(0,hist->getLines()-startLine,mergedLines);
00540   const int linesInScreen = mergedLines - linesInHistory;
00541 
00542   QVector<LineProperty> result(mergedLines);
00543   int index = 0;
00544 
00545   // copy properties for lines in history
00546   for (int line = startLine; line < startLine + linesInHistory; line++) 
00547   {
00548         //TODO Support for line properties other than wrapped lines
00549       if (hist->isWrappedLine(line))
00550       {
00551         result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
00552       }
00553     index++;
00554   }
00555   
00556   // copy properties for lines in screen buffer
00557   const int firstScreenLine = startLine + linesInHistory - hist->getLines();
00558   for (int line = firstScreenLine; line < firstScreenLine+linesInScreen; line++)
00559     {
00560     result[index]=lineProperties[line];
00561     index++;
00562     }
00563 
00564   return result;
00565 }
00566 
00567 void Screen::reset(bool clearScreen)
00568 {
00569     setMode(MODE_Wrap  ); saveMode(MODE_Wrap  );  // wrap at end of margin
00570   resetMode(MODE_Origin); saveMode(MODE_Origin);  // position refere to [1,1]
00571   resetMode(MODE_Insert); saveMode(MODE_Insert);  // overstroke
00572     setMode(MODE_Cursor);                         // cursor visible
00573   resetMode(MODE_Screen);                         // screen not inverse
00574   resetMode(MODE_NewLine);
00575 
00576   tmargin=0;
00577   bmargin=lines-1;
00578 
00579   setDefaultRendition();
00580   saveCursor();
00581 
00582   if ( clearScreen )
00583     clear();
00584 }
00585 
00586 void Screen::clear()
00587 {
00588   clearEntireScreen();
00589   home();
00590 }
00591 
00592 void Screen::backspace()
00593 {
00594   cuX = qMin(columns-1,cuX); // nowrap!
00595   cuX = qMax(0,cuX-1);
00596  // if (BS_CLEARS) image[loc(cuX,cuY)].character = ' ';
00597 
00598   if (screenLines[cuY].size() < cuX+1)
00599           screenLines[cuY].resize(cuX+1);
00600 
00601   if (BS_CLEARS) screenLines[cuY][cuX].character = ' ';
00602 }
00603 
00604 void Screen::tab(int n)
00605 {
00606   // note that TAB is a format effector (does not write ' ');
00607   if (n == 0) n = 1;
00608   while((n > 0) && (cuX < columns-1))
00609   {
00610     cursorRight(1); while((cuX < columns-1) && !tabstops[cuX]) cursorRight(1);
00611     n--;
00612   }
00613 }
00614 
00615 void Screen::backtab(int n)
00616 {
00617   // note that TAB is a format effector (does not write ' ');
00618   if (n == 0) n = 1;
00619   while((n > 0) && (cuX > 0))
00620   {
00621      cursorLeft(1); while((cuX > 0) && !tabstops[cuX]) cursorLeft(1);
00622      n--;
00623   }
00624 }
00625 
00626 void Screen::clearTabStops()
00627 {
00628   for (int i = 0; i < columns; i++) tabstops[i] = false;
00629 }
00630 
00631 void Screen::changeTabStop(bool set)
00632 {
00633   if (cuX >= columns) return;
00634   tabstops[cuX] = set;
00635 }
00636 
00637 void Screen::initTabStops()
00638 {
00639   delete[] tabstops;
00640   tabstops = new bool[columns];
00641 
00642   // Arrg! The 1st tabstop has to be one longer than the other.
00643   // i.e. the kids start counting from 0 instead of 1.
00644   // Other programs might behave correctly. Be aware.
00645   for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0);
00646 }
00647 
00648 void Screen::newLine()
00649 {
00650   if (getMode(MODE_NewLine)) toStartOfLine();
00651   index();
00652 }
00653 
00654 void Screen::checkSelection(int from, int to)
00655 {
00656   if (sel_begin == -1) return;
00657   int scr_TL = loc(0, hist->getLines());
00658   //Clear entire selection if it overlaps region [from, to]
00659   if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) )
00660   {
00661     clearSelection();
00662   }
00663 }
00664 
00665 void Screen::displayCharacter(unsigned short c)
00666 {
00667   // Note that VT100 does wrapping BEFORE putting the character.
00668   // This has impact on the assumption of valid cursor positions.
00669   // We indicate the fact that a newline has to be triggered by
00670   // putting the cursor one right to the last column of the screen.
00671 
00672   int w = konsole_wcwidth(c);
00673 
00674   if (w <= 0)
00675      return;
00676 
00677   if (cuX+w > columns) {
00678     if (getMode(MODE_Wrap)) {
00679       lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | LINE_WRAPPED);
00680       nextLine();
00681     }
00682     else
00683       cuX = columns-w;
00684   }
00685 
00686   // ensure current line vector has enough elements
00687   int size = screenLines[cuY].size();
00688   if (size == 0 && cuY > 0)
00689   {
00690           screenLines[cuY].resize( qMax(screenLines[cuY-1].size() , cuX+w) );
00691   }
00692   else
00693   {
00694     if (size < cuX+w)
00695     {
00696           screenLines[cuY].resize(cuX+w);
00697     }
00698   }
00699 
00700   if (getMode(MODE_Insert)) insertChars(w);
00701 
00702   lastPos = loc(cuX,cuY);
00703 
00704   // check if selection is still valid.
00705   checkSelection(cuX,cuY);
00706 
00707   Character& currentChar = screenLines[cuY][cuX];
00708 
00709   currentChar.character = c;
00710   currentChar.foregroundColor = ef_fg;
00711   currentChar.backgroundColor = ef_bg;
00712   currentChar.rendition = ef_re;
00713 
00714   int i = 0;
00715   int newCursorX = cuX + w--;
00716   while(w)
00717   {
00718      i++;
00719    
00720      if ( screenLines[cuY].size() < cuX + i + 1 )
00721          screenLines[cuY].resize(cuX+i+1);
00722      
00723      Character& ch = screenLines[cuY][cuX + i];
00724      ch.character = 0;
00725      ch.foregroundColor = ef_fg;
00726      ch.backgroundColor = ef_bg;
00727      ch.rendition = ef_re;
00728 
00729      w--;
00730   }
00731   cuX = newCursorX;
00732 }
00733 
00734 void Screen::compose(const QString& /*compose*/)
00735 {
00736    Q_ASSERT( 0 /*Not implemented yet*/ );
00737 
00738 /*  if (lastPos == -1)
00739      return;
00740      
00741   QChar c(image[lastPos].character);
00742   compose.prepend(c);
00743   //compose.compose(); ### FIXME!
00744   image[lastPos].character = compose[0].unicode();*/
00745 }
00746 
00747 int Screen::scrolledLines() const
00748 {
00749         return _scrolledLines;
00750 }
00751 int Screen::droppedLines() const
00752 {
00753     return _droppedLines;
00754 }
00755 void Screen::resetDroppedLines()
00756 {
00757     _droppedLines = 0;
00758 }
00759 void Screen::resetScrolledLines()
00760 {
00761     _scrolledLines = 0;
00762 }
00763 
00764 // Region commands -------------------------------------------------------------
00765 
00766 void Screen::scrollUp(int n)
00767 {
00768    if (n == 0) n = 1; // Default
00769    if (tmargin == 0) addHistLine(); // hist.history
00770    scrollUp(tmargin, n);
00771 }
00772 
00773 QRect Screen::lastScrolledRegion() const
00774 {
00775     return _lastScrolledRegion;
00776 }
00777 
00778 void Screen::scrollUp(int from, int n)
00779 {
00780   if (n <= 0 || from + n > bmargin) return;
00781 
00782   _scrolledLines -= n;
00783   _lastScrolledRegion = QRect(0,tmargin,columns-1,(bmargin-tmargin));
00784 
00785   //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
00786   moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin));
00787   clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' ');
00788 }
00789 
00790 void Screen::scrollDown(int n)
00791 {
00792    if (n == 0) n = 1; // Default
00793    scrollDown(tmargin, n);
00794 }
00795 
00796 void Screen::scrollDown(int from, int n)
00797 {
00798   _scrolledLines += n;
00799 
00800 //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
00801   if (n <= 0) return;
00802   if (from > bmargin) return;
00803   if (from + n > bmargin) n = bmargin - from;
00804   moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n));
00805   clearImage(loc(0,from),loc(columns-1,from+n-1),' ');
00806 }
00807 
00808 void Screen::setCursorYX(int y, int x)
00809 {
00810   setCursorY(y); setCursorX(x);
00811 }
00812 
00813 void Screen::setCursorX(int x)
00814 {
00815   if (x == 0) x = 1; // Default
00816   x -= 1; // Adjust
00817   cuX = qMax(0,qMin(columns-1, x));
00818 }
00819 
00820 void Screen::setCursorY(int y)
00821 {
00822   if (y == 0) y = 1; // Default
00823   y -= 1; // Adjust
00824   cuY = qMax(0,qMin(lines  -1, y + (getMode(MODE_Origin) ? tmargin : 0) ));
00825 }
00826 
00827 void Screen::home()
00828 {
00829   cuX = 0;
00830   cuY = 0;
00831 }
00832 
00833 void Screen::toStartOfLine()
00834 {
00835   cuX = 0;
00836 }
00837 
00838 int Screen::getCursorX() const
00839 {
00840   return cuX;
00841 }
00842 
00843 int Screen::getCursorY() const
00844 {
00845   return cuY;
00846 }
00847 
00848 // Erasing ---------------------------------------------------------------------
00849 
00850 void Screen::clearImage(int loca, int loce, char c)
00851 { 
00852   int scr_TL=loc(0,hist->getLines());
00853   //FIXME: check positions
00854 
00855   //Clear entire selection if it overlaps region to be moved...
00856   if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) )
00857   {
00858     clearSelection();
00859   }
00860 
00861   int topLine = loca/columns;
00862   int bottomLine = loce/columns;
00863 
00864   Character clearCh(c,cu_fg,cu_bg,DEFAULT_RENDITION);
00865   
00866   //if the character being used to clear the area is the same as the
00867   //default character, the affected lines can simply be shrunk.
00868   bool isDefaultCh = (clearCh == Character());
00869 
00870   for (int y=topLine;y<=bottomLine;y++)
00871   {
00872         lineProperties[y] = 0;
00873 
00874         int endCol = ( y == bottomLine) ? loce%columns : columns-1;
00875         int startCol = ( y == topLine ) ? loca%columns : 0;
00876 
00877         QVector<Character>& line = screenLines[y];
00878 
00879         if ( isDefaultCh && endCol == columns-1 )
00880         {
00881             line.resize(startCol);
00882         }
00883         else
00884         {
00885             if (line.size() < endCol + 1)
00886                 line.resize(endCol+1);
00887 
00888             Character* data = line.data();
00889             for (int i=startCol;i<=endCol;i++)
00890                 data[i]=clearCh;
00891         }
00892   }
00893 }
00894 
00895 void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
00896 {
00897   Q_ASSERT( sourceBegin <= sourceEnd );
00898  
00899   int lines=(sourceEnd-sourceBegin)/columns;
00900 
00901   //move screen image and line properties:
00902   //the source and destination areas of the image may overlap, 
00903   //so it matters that we do the copy in the right order - 
00904   //forwards if dest < sourceBegin or backwards otherwise.
00905   //(search the web for 'memmove implementation' for details)
00906   if (dest < sourceBegin)
00907   {
00908     for (int i=0;i<=lines;i++)
00909     {
00910         screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
00911         lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
00912     }
00913   }
00914   else
00915   {
00916     for (int i=lines;i>=0;i--)
00917     {
00918         screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
00919         lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
00920     }
00921   }
00922 
00923   if (lastPos != -1)
00924   {
00925      int diff = dest - sourceBegin; // Scroll by this amount
00926      lastPos += diff;
00927      if ((lastPos < 0) || (lastPos >= (lines*columns)))
00928         lastPos = -1;
00929   }
00930      
00931   // Adjust selection to follow scroll.
00932   if (sel_begin != -1)
00933   {
00934      bool beginIsTL = (sel_begin == sel_TL);
00935      int diff = dest - sourceBegin; // Scroll by this amount
00936      int scr_TL=loc(0,hist->getLines());
00937      int srca = sourceBegin+scr_TL; // Translate index from screen to global
00938      int srce = sourceEnd+scr_TL; // Translate index from screen to global
00939      int desta = srca+diff;
00940      int deste = srce+diff;
00941 
00942      if ((sel_TL >= srca) && (sel_TL <= srce))
00943         sel_TL += diff;
00944      else if ((sel_TL >= desta) && (sel_TL <= deste))
00945         sel_BR = -1; // Clear selection (see below)
00946 
00947      if ((sel_BR >= srca) && (sel_BR <= srce))
00948         sel_BR += diff;
00949      else if ((sel_BR >= desta) && (sel_BR <= deste))
00950         sel_BR = -1; // Clear selection (see below)
00951 
00952      if (sel_BR < 0)
00953      {
00954         clearSelection();
00955      }
00956      else
00957      {
00958         if (sel_TL < 0)
00959            sel_TL = 0;
00960      }
00961 
00962      if (beginIsTL)
00963         sel_begin = sel_TL;
00964      else
00965         sel_begin = sel_BR;
00966   }
00967 }
00968 
00969 void Screen::clearToEndOfScreen()
00970 {
00971   clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' ');
00972 }
00973 
00974 void Screen::clearToBeginOfScreen()
00975 {
00976   clearImage(loc(0,0),loc(cuX,cuY),' ');
00977 }
00978 
00979 void Screen::clearEntireScreen()
00980 {
00981   // Add entire screen to history
00982   for (int i = 0; i < (lines-1); i++)
00983   {
00984     addHistLine(); scrollUp(0,1);
00985   }
00986 
00987   clearImage(loc(0,0),loc(columns-1,lines-1),' ');
00988 }
00989 
00994 void Screen::helpAlign()
00995 {
00996   clearImage(loc(0,0),loc(columns-1,lines-1),'E');
00997 }
00998 
00999 void Screen::clearToEndOfLine()
01000 {
01001   clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
01002 }
01003 
01004 void Screen::clearToBeginOfLine()
01005 {
01006   clearImage(loc(0,cuY),loc(cuX,cuY),' ');
01007 }
01008 
01009 void Screen::clearEntireLine()
01010 {
01011   clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
01012 }
01013 
01014 void Screen::setRendition(int re)
01015 {
01016   cu_re |= re;
01017   effectiveRendition();
01018 }
01019 
01020 void Screen::resetRendition(int re)
01021 {
01022   cu_re &= ~re;
01023   effectiveRendition();
01024 }
01025 
01026 void Screen::setDefaultRendition()
01027 {
01028   setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
01029   setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
01030   cu_re   = DEFAULT_RENDITION;
01031   effectiveRendition();
01032 }
01033 
01034 void Screen::setForeColor(int space, int color)
01035 {
01036   cu_fg = CharacterColor(space, color);
01037 
01038   if ( cu_fg.isValid() ) 
01039     effectiveRendition();
01040   else 
01041     setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
01042 }
01043 
01044 void Screen::setBackColor(int space, int color)
01045 {
01046   cu_bg = CharacterColor(space, color);
01047 
01048   if ( cu_bg.isValid() ) 
01049     effectiveRendition();
01050   else
01051     setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
01052 }
01053 
01054 /* ------------------------------------------------------------------------- */
01055 /*                                                                           */
01056 /*                            Marking & Selection                            */
01057 /*                                                                           */
01058 /* ------------------------------------------------------------------------- */
01059 
01060 void Screen::clearSelection()
01061 {
01062   sel_BR = -1;
01063   sel_TL = -1;
01064   sel_begin = -1;
01065 }
01066 
01067 void Screen::getSelectionStart(int& column , int& line)
01068 {
01069     if ( sel_TL != -1 )
01070     {
01071         column = sel_TL % columns;
01072         line = sel_TL / columns; 
01073     }
01074     else
01075     {
01076         column = cuX + getHistLines();
01077         line = cuY + getHistLines();
01078     }
01079 }
01080 void Screen::getSelectionEnd(int& column , int& line)
01081 {
01082     if ( sel_BR != -1 )
01083     {
01084         column = sel_BR % columns;
01085         line = sel_BR / columns;
01086     }
01087     else
01088     {
01089         column = cuX + getHistLines();
01090         line = cuY + getHistLines();
01091     } 
01092 }
01093 void Screen::setSelectionStart(const int x, const int y, const bool mode)
01094 {
01095   sel_begin = loc(x,y); 
01096   /* FIXME, HACK to correct for x too far to the right... */
01097   if (x == columns) sel_begin--;
01098 
01099   sel_BR = sel_begin;
01100   sel_TL = sel_begin;
01101   columnmode = mode;
01102 }
01103 
01104 void Screen::setSelectionEnd( const int x, const int y)
01105 {
01106   if (sel_begin == -1) return;
01107   int l =  loc(x,y); 
01108 
01109   if (l < sel_begin)
01110   {
01111     sel_TL = l;
01112     sel_BR = sel_begin;
01113   }
01114   else
01115   {
01116     /* FIXME, HACK to correct for x too far to the right... */
01117     if (x == columns) l--;
01118 
01119     sel_TL = sel_begin;
01120     sel_BR = l;
01121   }
01122 }
01123 
01124 bool Screen::isSelected( const int x,const int y) const
01125 {
01126   if (columnmode) {
01127     int sel_Left,sel_Right;
01128     if ( sel_TL % columns < sel_BR % columns ) {
01129       sel_Left = sel_TL; sel_Right = sel_BR;
01130     } else {
01131       sel_Left = sel_BR; sel_Right = sel_TL;
01132     }
01133     return ( x >= sel_Left % columns ) && ( x <= sel_Right % columns ) &&
01134            ( y >= sel_TL / columns ) && ( y <= sel_BR / columns );
01135   }
01136   else {
01137   int pos = loc(x,y);
01138   return ( pos >= sel_TL && pos <= sel_BR );
01139   }
01140 }
01141 
01142 QString Screen::selectedText(bool preserveLineBreaks)
01143 {
01144   QString result;
01145   QTextStream stream(&result, QIODevice::ReadWrite);
01146   
01147   PlainTextDecoder decoder;
01148   decoder.begin(&stream);
01149   writeSelectionToStream(&decoder , preserveLineBreaks);
01150   decoder.end();
01151   
01152   return result;
01153 }
01154 
01155 bool Screen::isSelectionValid() const
01156 {
01157     return ( sel_TL >= 0 && sel_BR >= 0 );
01158 }
01159 
01160 void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , 
01161                                     bool preserveLineBreaks)
01162 {
01163     // do nothing if selection is invalid
01164     if ( !isSelectionValid() )
01165         return;
01166 
01167     int top = sel_TL / columns; 
01168     int left = sel_TL % columns;
01169 
01170     int bottom = sel_BR / columns;
01171     int right = sel_BR % columns;
01172 
01173     Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
01174 
01175     for (int y=top;y<=bottom;y++)
01176     {
01177             int start = 0;
01178             if ( y == top || columnmode ) start = left;
01179         
01180             int count = -1;
01181             if ( y == bottom || columnmode ) count = right - start + 1;
01182 
01183             const bool appendNewLine = ( y != bottom );
01184             int copied = copyLineToStream( y,
01185                                            start,
01186                                            count,
01187                                            decoder, 
01188                                            appendNewLine,
01189                                            preserveLineBreaks );
01190 
01191             // if the selection goes beyond the end of the last line then
01192             // append a new line character.
01193             //
01194             // this makes it possible to 'select' a trailing new line character after
01195             // the text on a line.  
01196             if ( y == bottom && 
01197                  copied < count )
01198             {
01199                 Character newLineChar('\n');
01200                 decoder->decodeLine(&newLineChar,1,0);
01201             }
01202     }   
01203 }
01204 
01205 int Screen::copyLineToStream(int line , 
01206                               int start, 
01207                               int count,
01208                               TerminalCharacterDecoder* decoder,
01209                               bool appendNewLine,
01210                               bool preserveLineBreaks)
01211 {
01212         //buffer to hold characters for decoding
01213         //the buffer is static to avoid initialising every 
01214         //element on each call to copyLineToStream
01215         //(which is unnecessary since all elements will be overwritten anyway)
01216         static const int MAX_CHARS = 1024;
01217         static Character characterBuffer[MAX_CHARS];
01218         
01219         assert( count < MAX_CHARS );
01220 
01221         LineProperty currentLineProperties = 0;
01222 
01223         //determine if the line is in the history buffer or the screen image
01224         if (line < hist->getLines())
01225         {
01226             const int lineLength = hist->getLineLen(line);
01227 
01228             // ensure that start position is before end of line
01229             start = qMin(start,qMax(0,lineLength-1));
01230 
01231             // retrieve line from history buffer.  It is assumed
01232             // that the history buffer does not store trailing white space
01233             // at the end of the line, so it does not need to be trimmed here 
01234             if (count == -1)
01235             {
01236                     count = lineLength-start;
01237             }
01238             else
01239             {
01240                     count = qMin(start+count,lineLength)-start;
01241             }
01242 
01243             // safety checks
01244             assert( start >= 0 );
01245             assert( count >= 0 );    
01246             assert( (start+count) <= hist->getLineLen(line) );
01247 
01248             hist->getCells(line,start,count,characterBuffer);
01249 
01250             if ( hist->isWrappedLine(line) )
01251                 currentLineProperties |= LINE_WRAPPED;
01252         }
01253         else
01254         {
01255             if ( count == -1 )
01256                     count = columns - start;
01257 
01258             assert( count >= 0 );
01259 
01260             const int screenLine = line-hist->getLines();
01261 
01262             Character* data = screenLines[screenLine].data();
01263             int length = screenLines[screenLine].count();
01264 
01265             // ignore trailing white space at the end of the line
01266             for (int i = length-1; i >= 0; i--)
01267                 if (data[i].character == ' ')
01268                     length--;
01269                 else
01270                     break;
01271 
01272             //retrieve line from screen image
01273             for (int i=start;i < qMin(start+count,length);i++)
01274             {
01275                 characterBuffer[i-start] = data[i];
01276             }
01277 
01278             // count cannot be any greater than length
01279             count = qBound(0,count,length-start);
01280 
01281             Q_ASSERT( screenLine < lineProperties.count() );
01282             currentLineProperties |= lineProperties[screenLine]; 
01283         }
01284 
01285         // add new line character at end
01286         const bool omitLineBreak = (currentLineProperties & LINE_WRAPPED) ||
01287                                    !preserveLineBreaks;
01288 
01289         if ( !omitLineBreak && appendNewLine && (count+1 < MAX_CHARS) )
01290         {
01291             characterBuffer[count] = '\n';
01292             count++;
01293         }
01294 
01295         //decode line and write to text stream  
01296         decoder->decodeLine( (Character*) characterBuffer , 
01297                              count, currentLineProperties );
01298 
01299         return count;
01300 }
01301 
01302 void Screen::writeToStream(TerminalCharacterDecoder* decoder, int from, int to)
01303 {
01304     sel_begin = loc(0,from);
01305     sel_TL = sel_begin;
01306     sel_BR = loc(columns-1,to);
01307     writeSelectionToStream(decoder);
01308     clearSelection();
01309 }
01310 
01311 QString Screen::getHistoryLine(int no)
01312 {
01313   sel_begin = loc(0,no);
01314   sel_TL = sel_begin;
01315   sel_BR = loc(columns-1,no);
01316   return selectedText(false);
01317 }
01318 
01319 void Screen::addHistLine()
01320 {
01321   // add line to history buffer
01322   // we have to take care about scrolling, too...
01323 
01324   if (hasScroll())
01325   {
01326     int oldHistLines = hist->getLines();
01327 
01328     hist->addCellsVector(screenLines[0]);
01329     hist->addLine( lineProperties[0] & LINE_WRAPPED );
01330 
01331     int newHistLines = hist->getLines();
01332 
01333     bool beginIsTL = (sel_begin == sel_TL);
01334 
01335     // If the history is full, increment the count
01336     // of dropped lines
01337     if ( newHistLines == oldHistLines )
01338         _droppedLines++;
01339 
01340     // Adjust selection for the new point of reference
01341     if (newHistLines > oldHistLines)
01342     {
01343        if (sel_begin != -1)
01344        {
01345           sel_TL += columns;
01346           sel_BR += columns;
01347        }
01348     }
01349 
01350     if (sel_begin != -1)
01351     {
01352        // Scroll selection in history up
01353        int top_BR = loc(0, 1+newHistLines);
01354 
01355        if (sel_TL < top_BR)
01356           sel_TL -= columns;
01357 
01358        if (sel_BR < top_BR)
01359           sel_BR -= columns;
01360 
01361        if (sel_BR < 0)
01362        {
01363           clearSelection();
01364        }
01365        else
01366        {
01367           if (sel_TL < 0)
01368              sel_TL = 0;
01369        }
01370 
01371        if (beginIsTL)
01372           sel_begin = sel_TL;
01373        else
01374           sel_begin = sel_BR;
01375     }
01376   }
01377 
01378 }
01379 
01380 int Screen::getHistLines()
01381 {
01382   return hist->getLines();
01383 }
01384 
01385 void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
01386 {
01387   clearSelection();
01388 
01389   if ( copyPreviousScroll )
01390     hist = t.scroll(hist);
01391   else
01392   {
01393       HistoryScroll* oldScroll = hist;
01394       hist = t.scroll(0);
01395       delete oldScroll;
01396   }
01397 }
01398 
01399 bool Screen::hasScroll()
01400 {
01401   return hist->hasScroll();
01402 }
01403 
01404 const HistoryType& Screen::getScroll()
01405 {
01406   return hist->getType();
01407 }
01408 
01409 void Screen::setLineProperty(LineProperty property , bool enable)
01410 {
01411     if ( enable )
01412     {
01413         lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | property);
01414     }
01415     else
01416     {
01417         lineProperties[cuY] = (LineProperty)(lineProperties[cuY] & ~property);
01418     }
01419 }
01420 void Screen::fillWithDefaultChar(Character* dest, int count)
01421 {
01422     for (int i=0;i<count;i++)
01423         dest[i] = defaultChar;
01424 }

Konsole

Skip menu "Konsole"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • Konsole
  • Libraries
  •   libkonq
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal