1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-04-16 02:28:05 -05:00

Implement lazy horizontal resizing of screen and scrollback.

[originally from svn r1087]
This commit is contained in:
Simon Tatham 2001-04-28 15:32:25 +00:00
parent 9525da2826
commit fc56312b45

View File

@ -5,6 +5,7 @@
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <assert.h>
#include "putty.h" #include "putty.h"
#include "tree234.h" #include "tree234.h"
@ -48,14 +49,14 @@ static int compatibility_level = TM_PUTTY;
static tree234 *scrollback; /* lines scrolled off top of screen */ static tree234 *scrollback; /* lines scrolled off top of screen */
static tree234 *screen; /* lines on primary screen */ static tree234 *screen; /* lines on primary screen */
static tree234 *alt_screen; /* lines on alternate screen */ static tree234 *alt_screen; /* lines on alternate screen */
static int disptop; /* distance scrolled back (0 or negative) */ static int disptop; /* distance scrolled back (0 or -ve) */
static unsigned long *cpos; /* cursor position (convenience) */ static unsigned long *cpos; /* cursor position (convenience) */
static unsigned long *disptext; /* buffer of text on real screen */ static unsigned long *disptext; /* buffer of text on real screen */
static unsigned long *wanttext; /* buffer of text we want on screen */ static unsigned long *wanttext; /* buffer of text we want on screen */
#define VBELL_TIMEOUT 100 /* millisecond duration of visual bell */ #define VBELL_TIMEOUT 100 /* millisecond len of visual bell */
struct beeptime { struct beeptime {
struct beeptime *next; struct beeptime *next;
@ -69,10 +70,7 @@ long lastbeep;
static unsigned char *selspace; /* buffer for building selections in */ static unsigned char *selspace; /* buffer for building selections in */
#define TSIZE (sizeof(unsigned long)) #define TSIZE (sizeof(unsigned long))
#define lineptr(x) ( (unsigned long *) \ #define fix_cpos do { cpos = lineptr(curs.y) + curs.x; } while(0)
((x) >= 0 ? index234(screen, x) : \
index234(scrollback, (x)+count234(scrollback)) ) )
#define fix_cpos do { cpos = lineptr(curs.y) + curs.x; } while(0)
static unsigned long curr_attr, save_attr; static unsigned long curr_attr, save_attr;
static unsigned long erase_char = ERASE_CHAR; static unsigned long erase_char = ERASE_CHAR;
@ -96,7 +94,7 @@ static int insert; /* insert-mode flag */
static int cset; /* 0 or 1: which char set */ static int cset; /* 0 or 1: which char set */
static int save_cset, save_csattr; /* saved with cursor position */ static int save_cset, save_csattr; /* saved with cursor position */
static int rvideo; /* global reverse video flag */ static int rvideo; /* global reverse video flag */
static int rvbell_timeout; /* for explicit (ESC[?5hESC[?5l) vbell */ static int rvbell_timeout; /* for ESC[?5hESC[?5l vbell */
static int cursor_on; /* cursor enabled flag */ static int cursor_on; /* cursor enabled flag */
static int reset_132; /* Flag ESC c resets to 80 cols */ static int reset_132; /* Flag ESC c resets to 80 cols */
static int use_bce; /* Use Background coloured erase */ static int use_bce; /* Use Background coloured erase */
@ -187,6 +185,51 @@ static void deselect (void);
static FILE *lgfp = NULL; static FILE *lgfp = NULL;
static void logtraffic(unsigned char c, int logmode); static void logtraffic(unsigned char c, int logmode);
/*
* Retrieve a line of the screen or of the scrollback, according to
* whether the y coordinate is non-negative or negative
* (respectively).
*/
unsigned long *lineptr(int y, int lineno) {
unsigned long *line, lineattrs;
tree234 *whichtree;
int i, treeindex, oldlen;
if (y >= 0) {
whichtree = screen;
treeindex = y;
} else {
whichtree = scrollback;
treeindex = y + count234(scrollback);
}
line = index234(whichtree, treeindex);
/* We assume that we don't screw up and retrieve something out of range. */
if (line == NULL) {
debug(("line=%d y=%d treeindex=%d\n", lineno, y, treeindex));
debug(("screen:%d scrollback:%d\n", count234(screen), count234(scrollback)));
assert(line != NULL);
}
if (line[0] != cols) {
/*
* This line is the wrong length, which probably means it
* hasn't been accessed since a resize. Resize it now.
*/
oldlen = line[0];
lineattrs = line[oldlen+1];
delpos234(whichtree, treeindex);
line = srealloc(line, TSIZE * (2+cols));
line[0] = cols;
for (i = oldlen; i < cols; i++)
line[i+1] = ERASE_CHAR;
line[cols+1] = lineattrs & LATTR_MODE;
addpos234(whichtree, line, treeindex);
}
return line+1;
}
#define lineptr(x) lineptr(x,__LINE__)
/* /*
* Set up power-on settings for the terminal. * Set up power-on settings for the terminal.
*/ */
@ -299,7 +342,7 @@ void term_size(int newrows, int newcols, int newsavelines) {
tree234 *newsb, *newscreen, *newalt; tree234 *newsb, *newscreen, *newalt;
unsigned long *newdisp, *newwant, *oldline, *line; unsigned long *newdisp, *newwant, *oldline, *line;
int i, j, ccols; int i, j, ccols;
int posn, oldposn, furthest_back, oldsbsize; int sblen;
int save_alt_which = alt_which; int save_alt_which = alt_which;
if (newrows == rows && newcols == cols && newsavelines == savelines) if (newrows == rows && newcols == cols && newsavelines == savelines)
@ -311,48 +354,62 @@ void term_size(int newrows, int newcols, int newsavelines) {
alt_t = marg_t = 0; alt_t = marg_t = 0;
alt_b = marg_b = newrows - 1; alt_b = marg_b = newrows - 1;
newsb = newtree234(NULL); if (rows == -1) {
newscreen = newtree234(NULL); scrollback = newtree234(NULL);
ccols = (cols < newcols ? cols : newcols); screen = newtree234(NULL);
oldsbsize = scrollback ? count234(scrollback) : 0; rows = 0;
furthest_back = newrows - rows - oldsbsize;
if (furthest_back > 0)
furthest_back = 0;
if (furthest_back < -newsavelines)
furthest_back = -newsavelines;
for (posn = newrows; posn-- > furthest_back ;) {
oldposn = posn - newrows + rows;
if (rows == -1 || oldposn < -oldsbsize) {
line = smalloc(TSIZE * (newcols + 1));
for (j = 0; j < newcols; j++)
line[j] = erase_char;
line[newcols] = 0;
} else {
oldline = (oldposn >= 0 ?
delpos234(screen, count234(screen)-1) :
delpos234(scrollback, count234(scrollback)-1));
if (newcols != cols) {
line = smalloc(TSIZE * (newcols + 1));
for (j = 0; j < ccols; j++)
line[j] = oldline[j];
for (j = ccols; j < newcols; j++)
line[j] = erase_char;
line[newcols] = oldline[cols] & LATTR_MODE;
sfree(oldline);
} else {
line = oldline;
}
}
if (posn >= 0)
addpos234(newscreen, line, 0);
else
addpos234(newsb, line, 0);
} }
/*
* Resize the screen and scrollback. We only need to shift
* lines around within our data structures, because lineptr()
* will take care of resizing each individual line if
* necessary. So:
*
* - If the new screen and the old screen differ in length, we
* must shunt some lines in from the scrollback or out to
* the scrollback.
*
* - If doing that fails to provide us with enough material to
* fill the new screen (i.e. the number of rows needed in
* the new screen exceeds the total number in the previous
* screen+scrollback), we must invent some blank lines to
* cover the gap.
*
* - Then, if the new scrollback length is less than the
* amount of scrollback we actually have, we must throw some
* away.
*/
sblen = count234(scrollback);
debug(("resizing rows=%d sblen=%d newrows=%d newsb=%d\n",
rows, sblen, newrows, newsavelines));
if (newrows > rows) {
for (i = rows; i < newrows; i++) {
if (sblen > 0) {
line = delpos234(scrollback, --sblen);
} else {
line = smalloc(TSIZE * (newcols+2));
line[0] = newcols;
for (j = 0; j <= newcols; j++)
line[j+1] = ERASE_CHAR;
}
addpos234(screen, line, 0);
}
} else if (newrows < rows) {
for (i = newrows; i < rows; i++) {
line = delpos234(screen, 0);
addpos234(scrollback, line, sblen++);
}
}
assert(count234(screen) == newrows);
while (sblen > newsavelines) {
line = delpos234(scrollback, 0);
sfree(line);
sblen--;
}
assert(count234(scrollback) <= newsavelines);
debug(("screen:%d scrollback:%d\n", count234(screen), count234(scrollback)));
disptop = 0; disptop = 0;
if (scrollback) freetree234(scrollback);
if (screen) freetree234(screen);
scrollback = newsb;
screen = newscreen;
newdisp = smalloc (newrows*(newcols+1)*TSIZE); newdisp = smalloc (newrows*(newcols+1)*TSIZE);
for (i=0; i<newrows*(newcols+1); i++) for (i=0; i<newrows*(newcols+1); i++)
@ -368,9 +425,10 @@ void term_size(int newrows, int newcols, int newsavelines) {
newalt = newtree234(NULL); newalt = newtree234(NULL);
for (i=0; i<newrows; i++) { for (i=0; i<newrows; i++) {
line = smalloc(TSIZE * (newcols+1)); line = smalloc(TSIZE * (newcols+2));
line[0] = newcols;
for (j = 0; j <= newcols; j++) for (j = 0; j <= newcols; j++)
line[j] = erase_char; line[j+1] = erase_char;
addpos234(newalt, line, i); addpos234(newalt, line, i);
} }
if (alt_screen) { if (alt_screen) {
@ -479,8 +537,8 @@ static void scroll (int topline, int botline, int lines, int sb) {
while (lines < 0) { while (lines < 0) {
line = delpos234(screen, botline); line = delpos234(screen, botline);
for (i = 0; i < cols; i++) for (i = 0; i < cols; i++)
line[i] = erase_char; line[i+1] = erase_char;
line[cols] = 0; line[cols+1] = 0;
addpos234(screen, line, topline); addpos234(screen, line, topline);
if (selstart.y >= topline && selstart.y <= botline) { if (selstart.y >= topline && selstart.y <= botline) {
@ -503,7 +561,7 @@ static void scroll (int topline, int botline, int lines, int sb) {
} else { } else {
while (lines > 0) { while (lines > 0) {
line = delpos234(screen, topline); line = delpos234(screen, topline);
if (sb) { if (sb && savelines > 0) {
int sblen = count234(scrollback); int sblen = count234(scrollback);
/* /*
* We must add this line to the scrollback. We'll * We must add this line to the scrollback. We'll
@ -511,16 +569,18 @@ static void scroll (int topline, int botline, int lines, int sb) {
* replace it, or allocate a new one if the * replace it, or allocate a new one if the
* scrollback isn't full. * scrollback isn't full.
*/ */
if (sblen == savelines) if (sblen == savelines) {
sblen--, line2 = delpos234(scrollback, 0); sblen--, line2 = delpos234(scrollback, 0);
else } else {
line2 = smalloc(TSIZE * (cols+1)); line2 = smalloc(TSIZE * (cols+2));
line2[0] = cols;
}
addpos234(scrollback, line, sblen); addpos234(scrollback, line, sblen);
line = line2; line = line2;
} }
for (i = 0; i < cols; i++) for (i = 0; i < cols; i++)
line[i] = erase_char; line[i+1] = erase_char;
line[cols] = 0; line[cols+1] = 0;
addpos234(screen, line, botline); addpos234(screen, line, botline);
if (selstart.y >= topline && selstart.y <= botline) { if (selstart.y >= topline && selstart.y <= botline) {
@ -633,7 +693,7 @@ static void erase_lots (int line_only, int from_begin, int to_end) {
ldata[start.x] &= ~ATTR_WRAPPED; ldata[start.x] &= ~ATTR_WRAPPED;
else else
ldata[start.x] = erase_char; ldata[start.x] = erase_char;
if (incpos(start)) if (incpos(start) && start.y < rows)
ldata = lineptr(start.y); ldata = lineptr(start.y);
} }
} }