]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - terminal.c
Giant const-correctness patch of doom!
[PuTTY.git] / terminal.c
index ee88974b56326bca9cfcd0d602ef2761011562c6..dc727238a8236a7644b5e88469dc3fed7f8456e7 100644 (file)
@@ -65,7 +65,7 @@
 
 #define has_compat(x) ( ((CL_##x)&term->compatibility_level) != 0 )
 
-char *EMPTY_WINDOW_TITLE = "";
+const char *EMPTY_WINDOW_TITLE = "";
 
 const char sco2ansicolour[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 
@@ -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 */
@@ -3868,7 +3940,8 @@ static void term_out(Terminal *term)
 
                            switch (term->esc_args[0]) {
                                int x, y, len;
-                               char buf[80], *p;
+                               char buf[80];
+                                const char *p;
                              case 1:
                                set_iconic(term->frontend, FALSE);
                                break;
@@ -3923,7 +3996,9 @@ static void term_out(Terminal *term)
                              case 13:
                                if (term->ldisc) {
                                    get_window_pos(term->frontend, &x, &y);
-                                   len = sprintf(buf, "\033[3;%d;%dt", x, y);
+                                   len = sprintf(buf, "\033[3;%u;%ut",
+                                                  (unsigned)x,
+                                                  (unsigned)y);
                                    ldisc_send(term->ldisc, buf, len, 0);
                                }
                                break;
@@ -6245,7 +6320,7 @@ void term_set_focus(Terminal *term, int has_focus)
  */
 char *term_get_ttymode(Terminal *term, const char *mode)
 {
-    char *val = NULL;
+    const char *val = NULL;
     if (strcmp(mode, "ERASE") == 0) {
        val = term->bksp_is_delete ? "^?" : "^H";
     }
@@ -6265,7 +6340,7 @@ struct term_userpass_state {
  * input.
  */
 int term_get_userpass_input(Terminal *term, prompts_t *p,
-                           unsigned char *in, int inlen)
+                           const unsigned char *in, int inlen)
 {
     struct term_userpass_state *s = (struct term_userpass_state *)p->data;
     if (!s) {