2
This file is part of Konsole, an X terminal.
3
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
5
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35
#include <QtCore/QTextStream>
36
#include <QtCore/QDate>
39
#include "konsole_wcwidth.h"
40
#include "TerminalCharacterDecoder.h"
42
using namespace Konsole;
44
//FIXME: this is emulation specific. Use false for xterm, true for ANSI.
45
//FIXME: see if we can get this from terminfo.
46
#define BS_CLEARS false
48
//Macro to convert x,y position on screen to position within an image.
50
//Originally the image was stored as one large contiguous block of
51
//memory, so a position within the image could be represented as an
52
//offset from the beginning of the block. For efficiency reasons this
53
//is no longer the case.
54
//Many internal parts of this class still use this representation for parameters and so on,
55
//notably moveImage() and clearImage().
56
//This macro converts from an X,Y position into an image offset.
58
#define loc(X,Y) ((Y)*columns+(X))
62
Character Screen::defaultChar = Character( ' ',
63
CharacterColor( COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR ),
64
CharacterColor( COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR ),
67
//#define REVERSE_WRAPPED_LINES // for wrapped line debug
69
Screen::Screen( int l, int c )
72
screenLines( new ImageLine[lines+1] ),
75
hist( new HistoryScrollNone() ),
78
tmargin( 0 ), bmargin( 0 ),
80
sel_begin( 0 ), sel_TL( 0 ), sel_BR( 0 ),
83
ef_fg( CharacterColor() ), ef_bg( CharacterColor() ), ef_re( 0 ),
84
sa_cuX( 0 ), sa_cuY( 0 ),
88
lineProperties.resize( lines + 1 );
89
for ( int i = 0; i < lines + 1; i++ )
90
lineProperties[i] = LINE_DEFAULT;
102
delete[] screenLines;
107
/* ------------------------------------------------------------------------- */
109
/* Normalized Screen Operations */
111
/* ------------------------------------------------------------------------- */
113
// Cursor Setting --------------------------------------------------------------
117
The `cursor' is a location within the screen that is implicitely used in
118
many operations. The operations within this section allow to manipulate
119
the cursor explicitly and to obtain it's value.
121
The position of the cursor is guarantied to be between (including) 0 and
122
`columns-1' and `lines-1'.
128
The cursor will not be moved beyond the top margin.
131
void Screen::cursorUp( int n )
134
if ( n == 0 ) n = 1; // Default
135
int stop = cuY < tmargin ? 0 : tmargin;
136
cuX = qMin( columns - 1, cuX ); // nowrap!
137
cuY = qMax( stop, cuY - n );
141
Move the cursor down.
143
The cursor will not be moved beyond the bottom margin.
146
void Screen::cursorDown( int n )
149
if ( n == 0 ) n = 1; // Default
150
int stop = cuY > bmargin ? lines - 1 : bmargin;
151
cuX = qMin( columns - 1, cuX ); // nowrap!
152
cuY = qMin( stop, cuY + n );
156
Move the cursor left.
158
The cursor will not move beyond the first column.
161
void Screen::cursorLeft( int n )
164
if ( n == 0 ) n = 1; // Default
165
cuX = qMin( columns - 1, cuX ); // nowrap!
166
cuX = qMax( 0, cuX - n );
170
Move the cursor left.
172
The cursor will not move beyond the rightmost column.
175
void Screen::cursorRight( int n )
178
if ( n == 0 ) n = 1; // Default
179
cuX = qMin( columns - 1, cuX + n );
182
void Screen::setMargins( int top, int bot )
185
if ( top == 0 ) top = 1; // Default
186
if ( bot == 0 ) bot = lines; // Default
187
top = top - 1; // Adjust to internal lineno
188
bot = bot - 1; // Adjust to internal lineno
189
if ( !( 0 <= top && top < bot && bot < lines ) )
191
qDebug() << " setRegion(" << top << "," << bot << ") : bad range.";
192
return; // Default error action: ignore
197
cuY = getMode( MODE_Origin ) ? top : 0;
201
int Screen::topMargin() const
205
int Screen::bottomMargin() const
213
if ( cuY == bmargin )
217
else if ( cuY < lines - 1 )
221
void Screen::reverseIndex()
224
if ( cuY == tmargin )
225
scrollDown( tmargin, 1 );
231
Move the cursor to the begin of the next line.
233
If cursor is on bottom margin, the region between the
234
actual top and bottom margin is scrolled up.
237
void Screen::NextLine()
243
void Screen::eraseChars( int n )
245
if ( n == 0 ) n = 1; // Default
246
int p = qMax( 0, qMin( cuX + n - 1, columns - 1 ) );
247
clearImage( loc( cuX, cuY ), loc( p, cuY ), ' ' );
250
void Screen::deleteChars( int n )
254
// always delete at least one char
258
// if cursor is beyond the end of the line there is nothing to do
259
if ( cuX >= screenLines[cuY].count() )
262
if ( cuX + n >= screenLines[cuY].count() )
263
n = screenLines[cuY].count() - 1 - cuX;
266
Q_ASSERT( cuX + n < screenLines[cuY].count() );
268
screenLines[cuY].remove( cuX, n );
271
void Screen::insertChars( int n )
273
if ( n == 0 ) n = 1; // Default
275
if ( screenLines[cuY].size() < cuX )
276
screenLines[cuY].resize( cuX );
278
screenLines[cuY].insert( cuX, n, ' ' );
280
if ( screenLines[cuY].count() > columns )
281
screenLines[cuY].resize( columns );
284
void Screen::deleteLines( int n )
286
if ( n == 0 ) n = 1; // Default
290
/*! insert `n' lines at the cursor position.
292
The cursor is not moved by the operation.
295
void Screen::insertLines( int n )
297
if ( n == 0 ) n = 1; // Default
298
scrollDown( cuY, n );
301
// Mode Operations -----------------------------------------------------------
303
/*! Set a specific mode. */
305
void Screen::setMode( int m )
307
currParm.mode[m] = true;
310
case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home
314
/*! Reset a specific mode. */
316
void Screen::resetMode( int m )
318
currParm.mode[m] = false;
321
case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
325
/*! Save a specific mode. */
327
void Screen::saveMode( int m )
329
saveParm.mode[m] = currParm.mode[m];
332
/*! Restore a specific mode. */
334
void Screen::restoreMode( int m )
336
currParm.mode[m] = saveParm.mode[m];
339
bool Screen::getMode( int m ) const
341
return currParm.mode[m];
344
void Screen::saveCursor()
353
void Screen::restoreCursor()
355
cuX = qMin( sa_cuX, columns - 1 );
356
cuY = qMin( sa_cuY, lines - 1 );
360
effectiveRendition();
363
/* ------------------------------------------------------------------------- */
365
/* Screen Operations */
367
/* ------------------------------------------------------------------------- */
369
/*! Resize the screen image
371
The topmost left position is maintained, while lower lines
372
or right hand side columns might be removed or filled with
373
spaces to fit the new size.
375
The region setting is reset to the whole screen and the
376
tab positions reinitialized.
378
If the new image is narrower than the old image then text on lines
379
which extends past the end of the new image is preserved so that it becomes
380
visible again if the screen is later resized to make it larger.
383
void Screen::resizeImage( int new_lines, int new_columns )
385
if (( new_lines == lines ) && ( new_columns == columns ) ) return;
387
if ( cuY > new_lines - 1 )
388
{ // attempt to preserve focus and lines
389
bmargin = lines - 1; //FIXME: margin lost
390
for ( int i = 0; i < cuY - ( new_lines - 1 ); i++ )
392
addHistLine(); scrollUp( 0, 1 );
396
// create new screen lines and copy from old to new
398
ImageLine* newScreenLines = new ImageLine[new_lines+1];
399
for ( int i = 0; i < qMin( lines - 1, new_lines + 1 ) ; i++ )
400
newScreenLines[i] = screenLines[i];
401
for ( int i = lines; ( i > 0 ) && ( i < new_lines + 1 ); i++ )
402
newScreenLines[i].resize( new_columns );
404
lineProperties.resize( new_lines + 1 );
405
for ( int i = lines; ( i > 0 ) && ( i < new_lines + 1 ); i++ )
406
lineProperties[i] = LINE_DEFAULT;
410
delete[] screenLines;
411
screenLines = newScreenLines;
414
columns = new_columns;
415
cuX = qMin( cuX, columns - 1 );
416
cuY = qMin( cuY, lines - 1 );
418
// FIXME: try to keep values, evtl.
425
void Screen::setDefaultMargins()
433
Clarifying rendition here and in the display.
435
currently, the display's color table is
437
dft_fg, dft_bg, dim 0..7, intensive 0..7
439
cu_fg, cu_bg contain values 0..8;
441
- 1..8 = ansi specified color
443
re_fg, re_bg contain values 0..17
444
due to the TerminalDisplay's color table
446
rendition attributes are
449
-------------- ------ ------
450
RE_UNDERLINE XX XX affects foreground only
451
RE_BLINK XX XX affects foreground only
452
RE_BOLD XX XX affects foreground only
454
RE_TRANSPARENT XX -- affects background only
455
RE_INTENSIVE XX -- affects foreground only
457
Note that RE_BOLD is used in both widget
458
and screen rendition. Since xterm/vt102
459
is to poor to distinguish between bold
460
(which is a font attribute) and intensive
461
(which is a color attribute), we translate
462
this and RE_BOLD in falls eventually appart
463
into RE_BOLD and RE_INTENSIVE.
466
void Screen::reverseRendition( Character& p ) const
468
CharacterColor f = p.foregroundColor;
469
CharacterColor b = p.backgroundColor;
471
p.foregroundColor = b;
472
p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
475
void Screen::effectiveRendition()
476
// calculate rendition
478
//copy "current rendition" straight into "effective rendition", which is then later copied directly
479
//into the image[] array which holds the characters and their appearance properties.
480
//- The old version below filtered out all attributes other than underline and blink at this stage,
481
//so that they would not be copied into the image[] array and hence would not be visible by TerminalDisplay
482
//which actually paints the screen using the information from the image[] array.
483
//I don't know why it did this, but I'm fairly sure it was the wrong thing to do. The net result
484
//was that bold text wasn't printed in bold by Konsole.
488
//ef_re = cu_re & (RE_UNDERLINE | RE_BLINK);
490
if ( cu_re & RE_REVERSE )
501
if ( cu_re & RE_BOLD )
502
ef_fg.toggleIntensive();
508
Get the size of the image by \sa getLines and \sa getColumns.
510
NOTE that the image returned by this function must later be
515
void Screen::copyFromHistory( Character* dest, int startLine, int count ) const
517
Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= hist->getLines() );
519
for ( int line = startLine; line < startLine + count; line++ )
521
const int length = qMin( columns, hist->getLineLen( line ) );
522
const int destLineOffset = ( line - startLine ) * columns;
524
hist->getCells( line, 0, length, dest + destLineOffset );
526
for ( int column = length; column < columns; column++ )
527
dest[destLineOffset+column] = defaultChar;
529
// invert selected text
530
if ( sel_begin != -1 )
532
for ( int column = 0; column < columns; column++ )
534
if ( isSelected( column, line ) )
536
reverseRendition( dest[destLineOffset + column] );
543
void Screen::copyFromScreen( Character* dest , int startLine , int count ) const
545
Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
547
for ( int line = startLine; line < ( startLine + count ) ; line++ )
549
int srcLineStartIndex = line * columns;
550
int destLineStartIndex = ( line - startLine ) * columns;
552
for ( int column = 0; column < columns; column++ )
554
int srcIndex = srcLineStartIndex + column;
555
int destIndex = destLineStartIndex + column;
557
dest[destIndex] = screenLines[srcIndex/columns].value( srcIndex % columns, defaultChar );
559
// invert selected text
560
if ( sel_begin != -1 && isSelected( column, line + hist->getLines() ) )
561
reverseRendition( dest[destIndex] );
567
void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
569
Q_ASSERT( startLine >= 0 );
570
Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
572
const int mergedLines = endLine - startLine + 1;
574
Q_ASSERT( size >= mergedLines * columns );
576
const int linesInHistoryBuffer = qBound( 0, hist->getLines() - startLine, mergedLines );
577
const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
579
// copy lines from history buffer
580
if ( linesInHistoryBuffer > 0 )
582
copyFromHistory( dest, startLine, linesInHistoryBuffer );
585
// copy lines from screen buffer
586
if ( linesInScreenBuffer > 0 )
588
copyFromScreen( dest + linesInHistoryBuffer*columns,
589
startLine + linesInHistoryBuffer - hist->getLines(),
590
linesInScreenBuffer );
593
// invert display when in screen mode
594
if ( getMode( MODE_Screen ) )
596
for ( int i = 0; i < mergedLines*columns; i++ )
597
reverseRendition( dest[i] ); // for reverse display
600
// mark the character at the current cursor position
601
int cursorIndex = loc( cuX, cuY + linesInHistoryBuffer );
602
if ( getMode( MODE_Cursor ) && cursorIndex < columns*mergedLines )
603
dest[cursorIndex].rendition |= RE_CURSOR;
606
QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
608
Q_ASSERT( startLine >= 0 );
609
Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
611
const int mergedLines = endLine - startLine + 1;
612
const int linesInHistory = qBound( 0, hist->getLines() - startLine, mergedLines );
613
const int linesInScreen = mergedLines - linesInHistory;
615
QVector<LineProperty> result( mergedLines );
618
// copy properties for lines in history
619
for ( int line = startLine; line < startLine + linesInHistory; line++ )
621
//TODO Support for line properties other than wrapped lines
622
if ( hist->isWrappedLine( line ) )
624
result[index] = ( LineProperty )( result[index] | LINE_WRAPPED );
629
// copy properties for lines in screen buffer
630
const int firstScreenLine = startLine + linesInHistory - hist->getLines();
631
for ( int line = firstScreenLine; line < firstScreenLine + linesInScreen; line++ )
633
result[index] = lineProperties[line];
643
void Screen::reset( bool clearScreen )
645
setMode( MODE_Wrap ); saveMode( MODE_Wrap ); // wrap at end of margin
646
resetMode( MODE_Origin ); saveMode( MODE_Origin ); // position refere to [1,1]
647
resetMode( MODE_Insert ); saveMode( MODE_Insert ); // overstroke
648
setMode( MODE_Cursor ); // cursor visible
649
resetMode( MODE_Screen ); // screen not inverse
650
resetMode( MODE_NewLine );
655
setDefaultRendition();
662
/*! Clear the entire screen and home the cursor.
671
void Screen::BackSpace()
673
cuX = qMin( columns - 1, cuX ); // nowrap!
674
cuX = qMax( 0, cuX - 1 );
675
// if (BS_CLEARS) image[loc(cuX,cuY)].character = ' ';
677
if ( screenLines[cuY].size() < cuX + 1 )
678
screenLines[cuY].resize( cuX + 1 );
680
if ( BS_CLEARS ) screenLines[cuY][cuX].character = ' ';
683
void Screen::Tabulate( int n )
685
// note that TAB is a format effector (does not write ' ');
687
while (( n > 0 ) && ( cuX < columns - 1 ) )
689
cursorRight( 1 ); while (( cuX < columns - 1 ) && !tabstops[cuX] ) cursorRight( 1 );
694
void Screen::backTabulate( int n )
696
// note that TAB is a format effector (does not write ' ');
698
while (( n > 0 ) && ( cuX > 0 ) )
700
cursorLeft( 1 ); while (( cuX > 0 ) && !tabstops[cuX] ) cursorLeft( 1 );
705
void Screen::clearTabStops()
707
for ( int i = 0; i < columns; i++ ) tabstops[i] = false;
710
void Screen::changeTabStop( bool set )
712
if ( cuX >= columns ) return;
716
void Screen::initTabStops()
719
tabstops = new bool[columns];
721
// Arrg! The 1st tabstop has to be one longer than the other.
722
// i.e. the kids start counting from 0 instead of 1.
723
// Other programs might behave correctly. Be aware.
724
for ( int i = 0; i < columns; i++ ) tabstops[i] = ( i % 8 == 0 && i != 0 );
728
This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine)
729
depending on the NewLine Mode (LNM). This mode also
730
affects the key sequence returned for newline ([CR]LF).
733
void Screen::NewLine()
735
if ( getMode( MODE_NewLine ) ) Return();
739
/*! put `c' literally onto the screen at the current cursor position.
741
VT100 uses the convention to produce an automatic newline (am)
742
with the *first* character that would fall onto the next line (xenl).
745
void Screen::checkSelection( int from, int to )
747
if ( sel_begin == -1 ) return;
748
int scr_TL = loc( 0, hist->getLines() );
749
//Clear entire selection if it overlaps region [from, to]
750
if (( sel_BR > ( from + scr_TL ) ) && ( sel_TL < ( to + scr_TL ) ) )
756
void Screen::ShowCharacter( unsigned short c )
758
// Note that VT100 does wrapping BEFORE putting the character.
759
// This has impact on the assumption of valid cursor positions.
760
// We indicate the fact that a newline has to be triggered by
761
// putting the cursor one right to the last column of the screen.
763
int w = konsole_wcwidth( c );
768
if ( cuX + w > columns )
770
if ( getMode( MODE_Wrap ) )
772
lineProperties[cuY] = ( LineProperty )( lineProperties[cuY] | LINE_WRAPPED );
779
// ensure current line vector has enough elements
780
int size = screenLines[cuY].size();
781
if ( size == 0 && cuY > 0 )
783
screenLines[cuY].resize( qMax( screenLines[cuY-1].size() , cuX + w ) );
787
if ( size < cuX + w )
789
screenLines[cuY].resize( cuX + w );
793
if ( getMode( MODE_Insert ) ) insertChars( w );
795
lastPos = loc( cuX, cuY );
797
// check if selection is still valid.
798
checkSelection( cuX, cuY );
800
Character& currentChar = screenLines[cuY][cuX];
802
currentChar.character = c;
803
currentChar.foregroundColor = ef_fg;
804
currentChar.backgroundColor = ef_bg;
805
currentChar.rendition = ef_re;
808
int newCursorX = cuX + w--;
813
if ( screenLines[cuY].size() < cuX + i + 1 )
814
screenLines[cuY].resize( cuX + i + 1 );
816
Character& ch = screenLines[cuY][cuX + i];
818
ch.foregroundColor = ef_fg;
819
ch.backgroundColor = ef_bg;
820
ch.rendition = ef_re;
827
void Screen::compose( const QString& /*compose*/ )
829
Q_ASSERT( 0 /*Not implemented yet*/ );
831
/* if (lastPos == -1)
834
QChar c(image[lastPos].character);
836
//compose.compose(); ### FIXME!
837
image[lastPos].character = compose[0].unicode();*/
840
int Screen::scrolledLines() const
842
return _scrolledLines;
844
int Screen::droppedLines() const
846
return _droppedLines;
848
void Screen::resetDroppedLines()
852
void Screen::resetScrolledLines()
854
//kDebug() << "scrolled lines reset";
859
// Region commands -------------------------------------------------------------
861
void Screen::scrollUp( int n )
863
if ( n == 0 ) n = 1; // Default
864
if ( tmargin == 0 ) addHistLine(); // hist.history
865
scrollUp( tmargin, n );
868
/*! scroll up `n' lines within current region.
869
The `n' new lines are cleared.
870
\sa setRegion \sa scrollDown
873
QRect Screen::lastScrolledRegion() const
875
return _lastScrolledRegion;
878
void Screen::scrollUp( int from, int n )
880
if ( n <= 0 || from + n > bmargin ) return;
883
_lastScrolledRegion = QRect( 0, tmargin, columns - 1, ( bmargin - tmargin ) );
885
//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
886
moveImage( loc( 0, from ), loc( 0, from + n ), loc( columns - 1, bmargin ) );
887
clearImage( loc( 0, bmargin - n + 1 ), loc( columns - 1, bmargin ), ' ' );
890
void Screen::scrollDown( int n )
892
if ( n == 0 ) n = 1; // Default
893
scrollDown( tmargin, n );
896
/*! scroll down `n' lines within current region.
897
The `n' new lines are cleared.
898
\sa setRegion \sa scrollUp
901
void Screen::scrollDown( int from, int n )
904
//kDebug() << "Screen::scrollDown( from: " << from << " , n: " << n << ")";
908
//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
909
if ( n <= 0 ) return;
910
if ( from > bmargin ) return;
911
if ( from + n > bmargin ) n = bmargin - from;
912
moveImage( loc( 0, from + n ), loc( 0, from ), loc( columns - 1, bmargin - n ) );
913
clearImage( loc( 0, from ), loc( columns - 1, from + n - 1 ), ' ' );
916
void Screen::setCursorYX( int y, int x )
918
setCursorY( y ); setCursorX( x );
921
void Screen::setCursorX( int x )
923
if ( x == 0 ) x = 1; // Default
925
cuX = qMax( 0, qMin( columns - 1, x ) );
928
void Screen::setCursorY( int y )
930
if ( y == 0 ) y = 1; // Default
932
cuY = qMax( 0, qMin( lines - 1, y + ( getMode( MODE_Origin ) ? tmargin : 0 ) ) );
941
void Screen::Return()
946
int Screen::getCursorX() const
951
int Screen::getCursorY() const
956
// Erasing ---------------------------------------------------------------------
960
This group of operations erase parts of the screen contents by filling
961
it with spaces colored due to the current rendition settings.
963
Althought the cursor position is involved in most of these operations,
964
it is never modified by them.
967
/*! fill screen between (including) `loca' (start) and `loce' (end) with spaces.
969
This is an internal helper functions. The parameter types are internal
970
addresses of within the screen image and make use of the way how the
971
screen matrix is mapped to the image vector.
974
void Screen::clearImage( int loca, int loce, char c )
976
int scr_TL = loc( 0, hist->getLines() );
977
//FIXME: check positions
979
//Clear entire selection if it overlaps region to be moved...
980
if (( sel_BR > ( loca + scr_TL ) ) && ( sel_TL < ( loce + scr_TL ) ) )
985
int topLine = loca / columns;
986
int bottomLine = loce / columns;
988
Character clearCh( c, cu_fg, cu_bg, DEFAULT_RENDITION );
990
//if the character being used to clear the area is the same as the
991
//default character, the affected lines can simply be shrunk.
992
bool isDefaultCh = ( clearCh == Character() );
994
for ( int y = topLine; y <= bottomLine; y++ )
996
lineProperties[y] = 0;
998
int endCol = ( y == bottomLine ) ? loce % columns : columns - 1;
999
int startCol = ( y == topLine ) ? loca % columns : 0;
1001
QVector<Character>& line = screenLines[y];
1003
if ( isDefaultCh && endCol == columns - 1 )
1005
line.resize( startCol );
1009
if ( line.size() < endCol + 1 )
1010
line.resize( endCol + 1 );
1012
Character* data = line.data();
1013
for ( int i = startCol; i <= endCol; i++ )
1019
/*! move image between (including) `sourceBegin' and `sourceEnd' to 'dest'.
1021
The 'dest', 'sourceBegin' and 'sourceEnd' parameters can be generated using
1022
the loc(column,line) macro.
1024
NOTE: moveImage() can only move whole lines.
1026
This is an internal helper functions. The parameter types are internal
1027
addresses of within the screen image and make use of the way how the
1028
screen matrix is mapped to the image vector.
1031
void Screen::moveImage( int dest, int sourceBegin, int sourceEnd )
1033
//kDebug() << "moving image from (" << (sourceBegin/columns)
1034
// << "," << (sourceEnd/columns) << ") to " <<
1037
Q_ASSERT( sourceBegin <= sourceEnd );
1039
int lines = ( sourceEnd - sourceBegin ) / columns;
1041
//move screen image and line properties:
1042
//the source and destination areas of the image may overlap,
1043
//so it matters that we do the copy in the right order -
1044
//forwards if dest < sourceBegin or backwards otherwise.
1045
//(search the web for 'memmove implementation' for details)
1046
if ( dest < sourceBegin )
1048
for ( int i = 0; i <= lines; i++ )
1050
screenLines[( dest/columns )+i ] = screenLines[( sourceBegin/columns )+i ];
1051
lineProperties[( dest/columns )+i] = lineProperties[( sourceBegin/columns )+i];
1056
for ( int i = lines; i >= 0; i-- )
1058
screenLines[( dest/columns )+i ] = screenLines[( sourceBegin/columns )+i ];
1059
lineProperties[( dest/columns )+i] = lineProperties[( sourceBegin/columns )+i];
1063
if ( lastPos != -1 )
1065
int diff = dest - sourceBegin; // Scroll by this amount
1067
if (( lastPos < 0 ) || ( lastPos >= ( lines*columns ) ) )
1071
// Adjust selection to follow scroll.
1072
if ( sel_begin != -1 )
1074
bool beginIsTL = ( sel_begin == sel_TL );
1075
int diff = dest - sourceBegin; // Scroll by this amount
1076
int scr_TL = loc( 0, hist->getLines() );
1077
int srca = sourceBegin + scr_TL; // Translate index from screen to global
1078
int srce = sourceEnd + scr_TL; // Translate index from screen to global
1079
int desta = srca + diff;
1080
int deste = srce + diff;
1082
if (( sel_TL >= srca ) && ( sel_TL <= srce ) )
1084
else if (( sel_TL >= desta ) && ( sel_TL <= deste ) )
1085
sel_BR = -1; // Clear selection (see below)
1087
if (( sel_BR >= srca ) && ( sel_BR <= srce ) )
1089
else if (( sel_BR >= desta ) && ( sel_BR <= deste ) )
1090
sel_BR = -1; // Clear selection (see below)
1109
void Screen::clearToEndOfScreen()
1111
clearImage( loc( cuX, cuY ), loc( columns - 1, lines - 1 ), ' ' );
1114
void Screen::clearToBeginOfScreen()
1116
clearImage( loc( 0, 0 ), loc( cuX, cuY ), ' ' );
1119
void Screen::clearEntireScreen()
1121
// Add entire screen to history
1122
for ( int i = 0; i < ( lines - 1 ); i++ )
1124
addHistLine(); scrollUp( 0, 1 );
1127
clearImage( loc( 0, 0 ), loc( columns - 1, lines - 1 ), ' ' );
1130
/*! fill screen with 'E'
1131
This is to aid screen alignment
1134
void Screen::helpAlign()
1136
clearImage( loc( 0, 0 ), loc( columns - 1, lines - 1 ), 'E' );
1139
void Screen::clearToEndOfLine()
1141
clearImage( loc( cuX, cuY ), loc( columns - 1, cuY ), ' ' );
1144
void Screen::clearToBeginOfLine()
1146
clearImage( loc( 0, cuY ), loc( cuX, cuY ), ' ' );
1149
void Screen::clearEntireLine()
1151
clearImage( loc( 0, cuY ), loc( columns - 1, cuY ), ' ' );
1154
void Screen::setRendition( int re )
1157
effectiveRendition();
1160
void Screen::resetRendition( int re )
1163
effectiveRendition();
1166
void Screen::setDefaultRendition()
1168
setForeColor( COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR );
1169
setBackColor( COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR );
1170
cu_re = DEFAULT_RENDITION;
1171
effectiveRendition();
1174
void Screen::setForeColor( int space, int color )
1176
cu_fg = CharacterColor( space, color );
1178
if ( cu_fg.isValid() )
1179
effectiveRendition();
1181
setForeColor( COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR );
1184
void Screen::setBackColor( int space, int color )
1186
cu_bg = CharacterColor( space, color );
1188
if ( cu_bg.isValid() )
1189
effectiveRendition();
1191
setBackColor( COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR );
1194
/* ------------------------------------------------------------------------- */
1196
/* Marking & Selection */
1198
/* ------------------------------------------------------------------------- */
1200
void Screen::clearSelection()
1207
void Screen::getSelectionStart( int& column , int& line )
1211
column = sel_TL % columns;
1212
line = sel_TL / columns;
1216
column = cuX + getHistLines();
1217
line = cuY + getHistLines();
1220
void Screen::getSelectionEnd( int& column , int& line )
1224
column = sel_BR % columns;
1225
line = sel_BR / columns;
1229
column = cuX + getHistLines();
1230
line = cuY + getHistLines();
1233
void Screen::setSelectionStart( /*const ScreenCursor& viewCursor ,*/ const int x, const int y, const bool mode )
1235
// kDebug(1211) << "setSelBeginXY(" << x << "," << y << ")";
1236
sel_begin = loc( x, y ); //+histCursor) ;
1238
/* FIXME, HACK to correct for x too far to the right... */
1239
if ( x == columns ) sel_begin--;
1246
void Screen::setSelectionEnd( const int x, const int y )
1248
// kDebug(1211) << "setSelExtentXY(" << x << "," << y << ")";
1249
if ( sel_begin == -1 ) return;
1250
int l = loc( x, y ); // + histCursor);
1252
if ( l < sel_begin )
1259
/* FIXME, HACK to correct for x too far to the right... */
1260
if ( x == columns ) l--;
1267
bool Screen::isSelected( const int x, const int y ) const
1271
int sel_Left, sel_Right;
1272
if ( sel_TL % columns < sel_BR % columns )
1274
sel_Left = sel_TL; sel_Right = sel_BR;
1278
sel_Left = sel_BR; sel_Right = sel_TL;
1280
return ( x >= sel_Left % columns ) && ( x <= sel_Right % columns ) &&
1281
( y >= sel_TL / columns ) && ( y <= sel_BR / columns );
1282
//( y+histCursor >= sel_TL / columns ) && ( y+histCursor <= sel_BR / columns );
1286
//int pos = loc(x,y+histCursor);
1287
int pos = loc( x, y );
1288
return ( pos >= sel_TL && pos <= sel_BR );
1292
QString Screen::selectedText( bool preserveLineBreaks )
1295
QTextStream stream( &result, QIODevice::ReadWrite );
1297
PlainTextDecoder decoder;
1298
decoder.begin( &stream );
1299
writeSelectionToStream( &decoder , preserveLineBreaks );
1305
bool Screen::isSelectionValid() const
1307
return ( sel_TL >= 0 && sel_BR >= 0 );
1310
void Screen::writeSelectionToStream( TerminalCharacterDecoder* decoder ,
1311
bool preserveLineBreaks )
1313
// do nothing if selection is invalid
1314
if ( !isSelectionValid() )
1317
int top = sel_TL / columns;
1318
int left = sel_TL % columns;
1320
int bottom = sel_BR / columns;
1321
int right = sel_BR % columns;
1323
Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
1325
//kDebug() << "sel_TL = " << sel_TL;
1326
//kDebug() << "columns = " << columns;
1328
for ( int y = top; y <= bottom; y++ )
1331
if ( y == top || columnmode ) start = left;
1334
if ( y == bottom || columnmode ) count = right - start + 1;
1336
const bool appendNewLine = ( y != bottom );
1337
copyLineToStream( y,
1342
preserveLineBreaks );
1347
void Screen::copyLineToStream( int line ,
1350
TerminalCharacterDecoder* decoder,
1352
bool preserveLineBreaks )
1354
//buffer to hold characters for decoding
1355
//the buffer is static to avoid initialising every
1356
//element on each call to copyLineToStream
1357
//(which is unnecessary since all elements will be overwritten anyway)
1358
static const int MAX_CHARS = 1024;
1359
static Character characterBuffer[MAX_CHARS];
1361
assert( count < MAX_CHARS );
1363
LineProperty currentLineProperties = 0;
1365
//determine if the line is in the history buffer or the screen image
1366
if ( line < hist->getLines() )
1368
const int lineLength = hist->getLineLen( line );
1370
// ensure that start position is before end of line
1371
start = qMin( start, qMax( 0, lineLength - 1 ) );
1373
//retrieve line from history buffer
1376
count = lineLength - start;
1380
count = qMin( start + count, lineLength ) - start;
1384
assert( start >= 0 );
1385
assert( count >= 0 );
1386
assert(( start + count ) <= hist->getLineLen( line ) );
1388
hist->getCells( line, start, count, characterBuffer );
1390
if ( hist->isWrappedLine( line ) )
1391
currentLineProperties |= LINE_WRAPPED;
1396
count = columns - start;
1398
assert( count >= 0 );
1400
const int screenLine = line - hist->getLines();
1402
Character* data = screenLines[screenLine].data();
1403
int length = screenLines[screenLine].count();
1405
//retrieve line from screen image
1406
for ( int i = start; i < qMin( start + count, length ); i++ )
1408
characterBuffer[i-start] = data[i];
1411
// count cannot be any greater than length
1412
count = qBound( 0, count, length - start );
1414
Q_ASSERT( screenLine < lineProperties.count() );
1415
currentLineProperties |= lineProperties[screenLine];
1418
//do not decode trailing whitespace characters
1419
for ( int i = count - 1 ; i >= 0; i-- )
1420
if ( QChar( characterBuffer[i].character ).isSpace() )
1425
// add new line character at end
1426
const bool omitLineBreak = ( currentLineProperties & LINE_WRAPPED ) ||
1427
!preserveLineBreaks;
1429
if ( !omitLineBreak && appendNewLine && ( count + 1 < MAX_CHARS ) )
1431
characterBuffer[count] = '\n';
1435
//decode line and write to text stream
1436
decoder->decodeLine(( Character* ) characterBuffer ,
1437
count, currentLineProperties );
1440
// Method below has been removed because of its reliance on 'histCursor'
1441
// and I want to restrict the methods which have knowledge of the scroll position
1442
// to just those which deal with selection and supplying final screen images.
1444
/*void Screen::writeToStream(QTextStream* stream , TerminalCharacterDecoder* decoder) {
1448
setSelectionEnd(columns-1,lines-1+hist->getLines()-histCursor);
1450
writeSelectionToStream(stream,decoder);
1455
void Screen::writeToStream( TerminalCharacterDecoder* decoder, int from, int to )
1457
sel_begin = loc( 0, from );
1459
sel_BR = loc( columns - 1, to );
1460
writeSelectionToStream( decoder );
1464
QString Screen::getHistoryLine( int no )
1466
sel_begin = loc( 0, no );
1468
sel_BR = loc( columns - 1, no );
1469
return selectedText( false );
1472
void Screen::addHistLine()
1474
// add line to history buffer
1475
// we have to take care about scrolling, too...
1479
int oldHistLines = hist->getLines();
1481
hist->addCellsVector( screenLines[0] );
1482
hist->addLine( lineProperties[0] & LINE_WRAPPED );
1484
int newHistLines = hist->getLines();
1486
bool beginIsTL = ( sel_begin == sel_TL );
1488
// If the history is full, increment the count
1490
if ( newHistLines == oldHistLines )
1493
// Adjust selection for the new point of reference
1494
if ( newHistLines > oldHistLines )
1496
if ( sel_begin != -1 )
1503
if ( sel_begin != -1 )
1505
// Scroll selection in history up
1506
int top_BR = loc( 0, 1 + newHistLines );
1508
if ( sel_TL < top_BR )
1511
if ( sel_BR < top_BR )
1533
int Screen::getHistLines()
1535
return hist->getLines();
1538
void Screen::setScroll( const HistoryType& t , bool copyPreviousScroll )
1542
if ( copyPreviousScroll )
1543
hist = t.scroll( hist );
1546
HistoryScroll* oldScroll = hist;
1547
hist = t.scroll( 0 );
1552
bool Screen::hasScroll()
1554
return hist->hasScroll();
1557
const HistoryType& Screen::getScroll()
1559
return hist->getType();
1562
void Screen::setLineProperty( LineProperty property , bool enable )
1566
lineProperties[cuY] = ( LineProperty )( lineProperties[cuY] | property );
1570
lineProperties[cuY] = ( LineProperty )( lineProperties[cuY] & ~property );
1573
void Screen::fillWithDefaultChar( Character* dest, int count )
1575
for ( int i = 0; i < count; i++ )
1576
dest[i] = defaultChar;