X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=terminal.c;h=7570a63b16743fd54b5b8f17cda4c0466ce6c10b;hb=f004bcca17a789356c32527a396b68b71a773db2;hp=ee88974b56326bca9cfcd0d602ef2761011562c6;hpb=7d394fc9e9c705770f6bde26b67df1b00ea82c64;p=PuTTY.git diff --git a/terminal.c b/terminal.c index ee88974b..7570a63b 100644 --- a/terminal.c +++ b/terminal.c @@ -98,6 +98,7 @@ const wchar_t sel_nl[] = SEL_NL; static void resizeline(Terminal *, termline *, int); static termline *lineptr(Terminal *, int, int, int); static void unlineptr(termline *); +static void check_line_size(Terminal *, termline *); static void do_paint(Terminal *, Context, int); static void erase_lots(Terminal *, int, int, int); static int find_last_nonempty_line(Terminal *, tree234 *); @@ -1053,8 +1054,25 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen) } assert(line != NULL); - resizeline(term, line, term->cols); - /* FIXME: should we sort the compressed scrollback out here? */ + /* + * Here we resize lines to _at least_ the right length, but we + * don't truncate them. Truncation is done as a side effect of + * modifying the line. + * + * The point of this policy is to try to arrange that resizing the + * terminal window repeatedly - e.g. successive steps in an X11 + * opaque window-resize drag, or resizing as a side effect of + * retiling by tiling WMs such as xmonad - does not throw away + * data gratuitously. Specifically, we want a sequence of resize + * operations with no terminal output between them to have the + * same effect as a single resize to the ultimate terminal size, + * and also (for the case in which xmonad narrows a window that's + * scrolling things) we want scrolling up new text at the bottom + * of a narrowed window to avoid truncating lines further up when + * the window is re-widened. + */ + if (term->cols > line->cols) + resizeline(term, line, term->cols); return line; } @@ -1062,6 +1080,22 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen) #define lineptr(x) (lineptr)(term,x,__LINE__,FALSE) #define scrlineptr(x) (lineptr)(term,x,__LINE__,TRUE) +/* + * Coerce a termline to the terminal's current width. Unlike the + * optional resize in lineptr() above, this is potentially destructive + * of text, since it can shrink as well as grow the line. + * + * We call this whenever a termline is actually going to be modified. + * Helpfully, putting a single call to this function in check_boundary + * deals with _nearly_ all such cases, leaving only a few things like + * bulk erase and ESC#8 to handle separately. + */ +static void check_line_size(Terminal *term, termline *line) +{ + if (term->cols != line->cols) /* trivial optimisation */ + resizeline(term, line, term->cols); +} + static void term_schedule_tblink(Terminal *term); static void term_schedule_cblink(Terminal *term); @@ -1316,7 +1350,7 @@ void term_pwron(Terminal *term, int clear) { power_on(term, clear); if (term->ldisc) /* cause ldisc to notice changes */ - ldisc_send(term->ldisc, NULL, 0, 0); + ldisc_echoedit_update(term->ldisc); term->disptop = 0; deselect(term); term_update(term); @@ -1493,12 +1527,44 @@ void term_reconfig(Terminal *term, Conf *conf) void term_clrsb(Terminal *term) { unsigned char *line; + int i; + + /* + * Scroll forward to the current screen, if we were back in the + * scrollback somewhere until now. + */ term->disptop = 0; + + /* + * Clear the actual scrollback. + */ while ((line = delpos234(term->scrollback, 0)) != NULL) { sfree(line); /* this is compressed data, not a termline */ } + + /* + * When clearing the scrollback, we also truncate any termlines on + * the current screen which have remembered data from a previous + * larger window size. Rationale: clearing the scrollback is + * sometimes done to protect privacy, so the user intention is + * specifically that we should not retain evidence of what + * previously happened in the terminal, and that ought to include + * evidence to the right as well as evidence above. + */ + for (i = 0; i < term->rows; i++) + check_line_size(term, scrlineptr(i)); + + /* + * There are now no lines of real scrollback which can be pulled + * back into the screen by a resize, and no lines of the alternate + * screen which should be displayed as if part of the scrollback. + */ term->tempsblines = 0; term->alt_sblines = 0; + + /* + * Update the scrollbar to reflect the new state of the world. + */ update_sbar(term); } @@ -2281,6 +2347,7 @@ static void check_boundary(Terminal *term, int x, int y) return; ldata = scrlineptr(y); + check_line_size(term, ldata); if (x == term->cols) { ldata->lattr &= ~LATTR_WRAPPED2; } else { @@ -2351,6 +2418,7 @@ static void erase_lots(Terminal *term, } else { termline *ldata = scrlineptr(start.y); while (poslt(start, end)) { + check_line_size(term, ldata); if (start.x == term->cols) { if (!erase_lattr) ldata->lattr &= ~(LATTR_WRAPPED | LATTR_WRAPPED2); @@ -2506,7 +2574,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 10: /* DECEDM: set local edit mode */ term->term_editing = state; if (term->ldisc) /* cause ldisc to notice changes */ - ldisc_send(term->ldisc, NULL, 0, 0); + ldisc_echoedit_update(term->ldisc); break; case 25: /* DECTCEM: enable/disable cursor */ compatibility2(OTHER, VT220); @@ -2570,7 +2638,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 12: /* SRM: set echo mode */ term->term_echoing = !state; if (term->ldisc) /* cause ldisc to notice changes */ - ldisc_send(term->ldisc, NULL, 0, 0); + ldisc_echoedit_update(term->ldisc); break; case 20: /* LNM: Return sends ... */ term->cr_lf_return = state; @@ -3293,7 +3361,7 @@ static void term_out(Terminal *term) compatibility(VT100); power_on(term, TRUE); if (term->ldisc) /* cause ldisc to notice changes */ - ldisc_send(term->ldisc, NULL, 0, 0); + ldisc_echoedit_update(term->ldisc); if (term->reset_132) { if (!term->no_remote_resize) request_resize(term->frontend, 80, term->rows); @@ -3317,6 +3385,7 @@ static void term_out(Terminal *term) for (i = 0; i < term->rows; i++) { ldata = scrlineptr(i); + check_line_size(term, ldata); for (j = 0; j < term->cols; j++) { copy_termchar(ldata, j, &term->basic_erase_char); @@ -3341,6 +3410,7 @@ static void term_out(Terminal *term) compatibility(VT100); { int nlattr; + termline *ldata; switch (ANSI(c, term->esc_query)) { case ANSI('3', '#'): /* DECDHL: 2*height, top */ @@ -3356,7 +3426,9 @@ static void term_out(Terminal *term) nlattr = LATTR_WIDE; break; } - scrlineptr(term->curs.y)->lattr = nlattr; + ldata = scrlineptr(term->curs.y); + check_line_size(term, ldata); + ldata->lattr = nlattr; } break; /* GZD4: G0 designate 94-set */