X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=terminal.c;h=7570a63b16743fd54b5b8f17cda4c0466ce6c10b;hb=f004bcca17a789356c32527a396b68b71a773db2;hp=bd77f2397878d085a6646ca508a80acb1405c448;hpb=7a53bd65d70fad73dbd6832497965fa11b2a357b;p=PuTTY.git diff --git a/terminal.c b/terminal.c index bd77f239..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); @@ -2517,7 +2585,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) compatibility(OTHER); deselect(term); swap_screen(term, term->no_alt_screen ? 0 : state, FALSE, FALSE); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; break; case 1000: /* xterm mouse 1 (normal) */ term->xterm_mouse = state ? 1 : 0; @@ -2537,7 +2606,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) compatibility(OTHER); deselect(term); swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, TRUE); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; break; case 1048: /* save/restore cursor */ if (!term->no_alt_screen) @@ -2553,7 +2623,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, FALSE); if (!state && !term->no_alt_screen) save_cursor(term, state); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; break; case 2004: /* xterm bracketed paste */ term->bracketed_paste = state ? TRUE : FALSE; @@ -2567,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; @@ -3015,7 +3086,8 @@ static void term_out(Terminal *term) if (has_compat(SCOANSI)) { move(term, 0, 0, 0); erase_lots(term, FALSE, FALSE, TRUE); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; term->wrapnext = FALSE; seen_disp_event(term); break; @@ -3289,13 +3361,14 @@ 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); term->reset_132 = 0; } - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; seen_disp_event(term); break; case 'H': /* HTS: set a tab */ @@ -3312,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); @@ -3319,7 +3393,8 @@ static void term_out(Terminal *term) } ldata->lattr = LATTR_NORM; } - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; seen_disp_event(term); scrtop.x = scrtop.y = 0; scrbot.x = 0; @@ -3335,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 */ @@ -3350,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 */ @@ -3517,7 +3595,8 @@ static void term_out(Terminal *term) erase_lots(term, FALSE, !!(i & 2), !!(i & 1)); } } - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; seen_disp_event(term); break; case 'K': /* EL: erase line or parts of it */ @@ -4424,7 +4503,8 @@ static void term_out(Terminal *term) break; case 'J': erase_lots(term, FALSE, FALSE, TRUE); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; break; case 'K': erase_lots(term, TRUE, FALSE, TRUE); @@ -4479,7 +4559,8 @@ static void term_out(Terminal *term) /* compatibility(ATARI) */ move(term, 0, 0, 0); erase_lots(term, FALSE, FALSE, TRUE); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; break; case 'L': /* compatibility(ATARI) */ @@ -4502,7 +4583,8 @@ static void term_out(Terminal *term) case 'd': /* compatibility(ATARI) */ erase_lots(term, FALSE, TRUE, FALSE); - term->disptop = 0; + if (term->scroll_on_disp) + term->disptop = 0; break; case 'e': /* compatibility(ATARI) */ @@ -5886,7 +5968,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, */ if (raw_mouse && (term->selstate != ABOUT_TO) && (term->selstate != DRAGGING)) { - int encstate = 0, r, c; + int encstate = 0, r, c, wheel; char abuf[32]; int len = 0; @@ -5895,22 +5977,35 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, switch (braw) { case MBT_LEFT: encstate = 0x00; /* left button down */ + wheel = FALSE; break; case MBT_MIDDLE: encstate = 0x01; + wheel = FALSE; break; case MBT_RIGHT: encstate = 0x02; + wheel = FALSE; break; case MBT_WHEEL_UP: encstate = 0x40; + wheel = TRUE; break; case MBT_WHEEL_DOWN: encstate = 0x41; + wheel = TRUE; break; - default: break; /* placate gcc warning about enum use */ + default: + return; } - switch (a) { + if (wheel) { + /* For mouse wheel buttons, we only ever expect to see + * MA_CLICK actions, and we don't try to keep track of + * the buttons being 'pressed' (since without matching + * click/release pairs that's pointless). */ + if (a != MA_CLICK) + return; + } else switch (a) { case MA_DRAG: if (term->xterm_mouse == 1) return; @@ -5927,7 +6022,8 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, return; term->mouse_is_down = braw; break; - default: break; /* placate gcc warning about enum use */ + default: + return; } if (shift) encstate += 0x04;