Put prototypes for the functions exported by wcwidth.c in putty.h, and remove
[u/mdw/putty] / terminal.c
index d0a09a3..3fcff47 100644 (file)
@@ -62,17 +62,22 @@ const wchar_t sel_nl[] = SEL_NL;
 /*
  * Internal prototypes.
  */
+static unsigned long *resizeline(unsigned long *, int);
+static unsigned long *lineptr(Terminal *, int, int);
 static void do_paint(Terminal *, Context, int);
 static void erase_lots(Terminal *, int, int, int);
 static void swap_screen(Terminal *, int, int, int);
 static void update_sbar(Terminal *);
 static void deselect(Terminal *);
 static void term_print_finish(Terminal *);
+#ifdef OPTIMISE_SCROLL
+static void scroll_display(Terminal *, int, int, int);
+#endif /* OPTIMISE_SCROLL */
 
 /*
  * Resize a line to make it `cols' columns wide.
  */
-unsigned long *resizeline(unsigned long *line, int cols)
+static unsigned long *resizeline(unsigned long *line, int cols)
 {
     int i, oldlen;
     unsigned long lineattrs;
@@ -99,7 +104,7 @@ unsigned long *resizeline(unsigned long *line, int cols)
  * whether the y coordinate is non-negative or negative
  * (respectively).
  */
-unsigned long *lineptr(Terminal *term, int y, int lineno)
+static unsigned long *lineptr(Terminal *term, int y, int lineno)
 {
     unsigned long *line, *newline;
     tree234 *whichtree;
@@ -147,30 +152,32 @@ static void power_on(Terminal *term)
        for (i = 0; i < term->cols; i++)
            term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
     }
-    term->alt_om = term->dec_om = cfg.dec_om;
-    term->alt_wnext = term->wrapnext = term->alt_ins = term->insert = FALSE;
-    term->alt_wrap = term->wrap = cfg.wrap_mode;
-    term->alt_cset = term->cset = 0;
-    term->alt_utf = term->utf = 0;
-    term->alt_sco_acs = term->sco_acs = 0;
-    term->cset_attr[0] = term->cset_attr[1] = ATTR_ASCII;
+    term->alt_om = term->dec_om = term->cfg->dec_om;
+    term->alt_ins = term->insert = FALSE;
+    term->alt_wnext = term->wrapnext = term->save_wnext = FALSE;
+    term->alt_wrap = term->wrap = term->cfg->wrap_mode;
+    term->alt_cset = term->cset = term->save_cset = 0;
+    term->alt_utf = term->utf = term->save_utf = 0;
+    term->utf_state = 0;
+    term->alt_sco_acs = term->sco_acs = term->save_sco_acs = 0;
+    term->cset_attr[0] = term->cset_attr[1] = term->save_csattr = ATTR_ASCII;
     term->rvideo = 0;
     term->in_vbell = FALSE;
     term->cursor_on = 1;
     term->big_cursor = 0;
     term->save_attr = term->curr_attr = ATTR_DEFAULT;
     term->term_editing = term->term_echoing = FALSE;
-    term->app_cursor_keys = cfg.app_cursor;
-    term->app_keypad_keys = cfg.app_keypad;
-    term->use_bce = cfg.bce;
-    term->blink_is_real = cfg.blinktext;
+    term->app_cursor_keys = term->cfg->app_cursor;
+    term->app_keypad_keys = term->cfg->app_keypad;
+    term->use_bce = term->cfg->bce;
+    term->blink_is_real = term->cfg->blinktext;
     term->erase_char = ERASE_CHAR;
     term->alt_which = 0;
     term_print_finish(term);
     {
        int i;
        for (i = 0; i < 256; i++)
-           term->wordness[i] = cfg.wordness[i];
+           term->wordness[i] = term->cfg->wordness[i];
     }
     if (term->screen) {
        swap_screen(term, 1, FALSE, FALSE);
@@ -186,10 +193,10 @@ static void power_on(Terminal *term)
 void term_update(Terminal *term)
 {
     Context ctx;
-    ctx = get_ctx();
+    ctx = get_ctx(term->frontend);
     if (ctx) {
        int need_sbar_update = term->seen_disp_event;
-       if (term->seen_disp_event && cfg.scroll_on_disp) {
+       if (term->seen_disp_event && term->cfg->scroll_on_disp) {
            term->disptop = 0;         /* return to main screen */
            term->seen_disp_event = 0;
            need_sbar_update = TRUE;
@@ -197,7 +204,7 @@ void term_update(Terminal *term)
        if (need_sbar_update)
            update_sbar(term);
        do_paint(term, ctx, TRUE);
-       sys_cursor(term->curs.x, term->curs.y - term->disptop);
+       sys_cursor(term->frontend, term->curs.x, term->curs.y - term->disptop);
        free_ctx(ctx);
     }
 }
@@ -227,7 +234,7 @@ void term_seen_key_event(Terminal *term)
     /*
      * Reset the scrollback on keypress, if we're doing that.
      */
-    if (cfg.scroll_on_key) {
+    if (term->cfg->scroll_on_key) {
        term->disptop = 0;             /* return to main screen */
        term->seen_disp_event = 1;
     }
@@ -239,7 +246,8 @@ void term_seen_key_event(Terminal *term)
 void term_pwron(Terminal *term)
 {
     power_on(term);
-    ldisc_send(NULL, 0, 0);           /* cause ldisc to notice changes */
+    if (term->ldisc)                  /* cause ldisc to notice changes */
+       ldisc_send(term->ldisc, NULL, 0, 0);
     fix_cpos;
     term->disptop = 0;
     deselect(term);
@@ -254,18 +262,18 @@ void term_pwron(Terminal *term)
  */
 void term_reconfig(Terminal *term)
 {
-    if (cfg.no_alt_screen)
+    if (term->cfg->no_alt_screen)
        swap_screen(term, 0, FALSE, FALSE);
-    if (cfg.no_mouse_rep) {
+    if (term->cfg->no_mouse_rep) {
        term->xterm_mouse = 0;
-       set_raw_mouse_mode(0);
+       set_raw_mouse_mode(term->frontend, 0);
     }
-    if (cfg.no_remote_charset) {
+    if (term->cfg->no_remote_charset) {
        term->cset_attr[0] = term->cset_attr[1] = ATTR_ASCII;
        term->sco_acs = term->alt_sco_acs = 0;
        term->utf = 0;
     }
-    if (!*cfg.printer) {
+    if (!*term->cfg->printer) {
        term_print_finish(term);
     }
 }
@@ -286,7 +294,7 @@ void term_clrsb(Terminal *term)
 /*
  * Initialise the terminal.
  */
-Terminal *term_init(void)
+Terminal *term_init(Config *mycfg, void *frontend)
 {
     Terminal *term;
 
@@ -295,6 +303,9 @@ Terminal *term_init(void)
      * that need it.
      */
     term = smalloc(sizeof(Terminal));
+    term->frontend = frontend;
+    term->cfg = mycfg;
+    term->logctx = NULL;
     term->compatibility_level = TM_PUTTY;
     strcpy(term->id_string, "\033[?6c");
     term->last_blink = term->last_tblink = 0;
@@ -302,6 +313,19 @@ Terminal *term_init(void)
     term->last_paste = 0;
     bufchain_init(&term->inbuf);
     bufchain_init(&term->printer_buf);
+    term->printing = term->only_printing = FALSE;
+    term->print_job = NULL;
+    term->vt52_mode = FALSE;
+    term->cr_lf_return = FALSE;
+    term->seen_disp_event = FALSE;
+    term->xterm_mouse = term->mouse_is_down = FALSE;
+    term->reset_132 = FALSE;
+    term->blinker = term->tblinker = 0;
+    term->has_focus = 1;
+    term->repeat_off = FALSE;
+    term->termstate = TOPLEVEL;
+    term->selstate = NO_SELECTION;
+    term->curstype = 0;
 
     term->screen = term->alt_screen = term->scrollback = NULL;
     term->disptop = 0;
@@ -314,6 +338,9 @@ Terminal *term_init(void)
     term->nbeeps = 0;
     term->lastbeep = FALSE;
     term->beep_overloaded = FALSE;
+    term->attr_mask = 0xffffffff;
+    term->resize_fn = NULL;
+    term->resize_ctx = NULL;
 
     return term;
 }
@@ -441,7 +468,22 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
 
     update_sbar(term);
     term_update(term);
-    back->size();
+    if (term->resize_fn)
+       term->resize_fn(term->resize_ctx, term->cols, term->rows);
+}
+
+/*
+ * Hand a function and context pointer to the terminal which it can
+ * use to notify a back end of resizes.
+ */
+void term_provide_resize_fn(Terminal *term,
+                           void (*resize_fn)(void *, int, int),
+                           void *resize_ctx)
+{
+    term->resize_fn = resize_fn;
+    term->resize_ctx = resize_ctx;
+    if (term->cols > 0 && term->rows > 0)
+       resize_fn(resize_ctx, term->cols, term->rows);
 }
 
 /*
@@ -526,7 +568,8 @@ static void update_sbar(Terminal *term)
 
     nscroll = count234(term->scrollback);
 
-    set_sbar(nscroll + term->rows, nscroll + term->disptop, term->rows);
+    set_sbar(term->frontend, nscroll + term->rows,
+            nscroll + term->disptop, term->rows);
 }
 
 /*
@@ -552,11 +595,13 @@ static void check_selection(Terminal *term, pos from, pos to)
 static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
 {
     unsigned long *line, *line2;
-    int i, seltop;
+    int i, seltop, olddisptop, shift;
 
     if (topline != 0 || term->alt_which != 0)
        sb = FALSE;
 
+    olddisptop = term->disptop;
+    shift = lines;
     if (lines < 0) {
        while (lines < 0) {
            line = delpos234(term->screen, botline);
@@ -665,7 +710,43 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
            lines--;
        }
     }
+#ifdef OPTIMISE_SCROLL
+    shift += term->disptop - olddisptop;
+    if (shift < term->rows && shift > -term->rows && shift != 0)
+       scroll_display(term, topline, botline, shift);
+#endif /* OPTIMISE_SCROLL */
+}
+
+#ifdef OPTIMISE_SCROLL
+/*
+ * Scroll the physical display, and our conception of it in disptext.
+ */
+static void scroll_display(Terminal *term, int topline, int botline, int lines)
+{
+    unsigned long *start, *end;
+    int distance, size, i;
+
+    start = term->disptext + topline * (term->cols + 1);
+    end = term->disptext + (botline + 1) * (term->cols + 1);
+    distance = (lines > 0 ? lines : -lines) * (term->cols + 1);
+    size = end - start - distance;
+    if (lines > 0) {
+       memmove(start, start + distance, size * TSIZE);
+       if (term->dispcurs >= start + distance &&
+           term->dispcurs <= start + distance + size)
+           term->dispcurs -= distance;
+       for (i = 0; i < distance; i++)
+           (start + size)[i] |= ATTR_INVALID;
+    } else {
+       memmove(start + distance, start, size * TSIZE);
+       if (term->dispcurs >= start && term->dispcurs <= start + size)
+           term->dispcurs += distance;
+       for (i = 0; i < distance; i++)
+           start[i] |= ATTR_INVALID;
+    }
+    do_scroll(term->frontend, topline, botline, lines);
 }
+#endif /* OPTIMISE_SCROLL */
 
 /*
  * Move the cursor to a given position, clipping at boundaries. We
@@ -835,13 +916,13 @@ static void toggle_mode(Terminal *term, int mode, int query, int state)
                term->blink_is_real = FALSE;
                term->vt52_bold = FALSE;
            } else {
-               term->blink_is_real = cfg.blinktext;
+               term->blink_is_real = term->cfg->blinktext;
            }
            break;
          case 3:                      /* 80/132 columns */
            deselect(term);
-           if (!cfg.no_remote_resize)
-               request_resize(state ? 132 : 80, term->rows);
+           if (!term->cfg->no_remote_resize)
+               request_resize(term->frontend, state ? 132 : 80, term->rows);
            term->reset_132 = state;
            break;
          case 5:                      /* reverse video */
@@ -884,7 +965,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state)
            break;
          case 10:                     /* set local edit mode */
            term->term_editing = state;
-           ldisc_send(NULL, 0, 0);    /* cause ldisc to notice changes */
+           if (term->ldisc)           /* cause ldisc to notice changes */
+               ldisc_send(term->ldisc, NULL, 0, 0);
            break;
          case 25:                     /* enable/disable cursor */
            compatibility2(OTHER, VT220);
@@ -894,21 +976,21 @@ static void toggle_mode(Terminal *term, int mode, int query, int state)
          case 47:                     /* alternate screen */
            compatibility(OTHER);
            deselect(term);
-           swap_screen(term, cfg.no_alt_screen ? 0 : state, FALSE, FALSE);
+           swap_screen(term, term->cfg->no_alt_screen ? 0 : state, FALSE, FALSE);
            term->disptop = 0;
            break;
          case 1000:                   /* xterm mouse 1 */
            term->xterm_mouse = state ? 1 : 0;
-           set_raw_mouse_mode(state);
+           set_raw_mouse_mode(term->frontend, state);
            break;
          case 1002:                   /* xterm mouse 2 */
            term->xterm_mouse = state ? 2 : 0;
-           set_raw_mouse_mode(state);
+           set_raw_mouse_mode(term->frontend, state);
            break;
          case 1047:                   /* alternate screen */
            compatibility(OTHER);
            deselect(term);
-           swap_screen(term, cfg.no_alt_screen ? 0 : state, TRUE, TRUE);
+           swap_screen(term, term->cfg->no_alt_screen ? 0 : state, TRUE, TRUE);
            term->disptop = 0;
            break;
          case 1048:                   /* save/restore cursor */
@@ -921,7 +1003,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state)
            if (!state) term->seen_disp_event = TRUE;
            compatibility(OTHER);
            deselect(term);
-           swap_screen(term, cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
+           swap_screen(term, term->cfg->no_alt_screen ? 0 : state, TRUE, FALSE);
            if (!state)
                save_cursor(term, state);
            term->disptop = 0;
@@ -934,7 +1016,8 @@ static void toggle_mode(Terminal *term, int mode, int query, int state)
            break;
          case 12:                     /* set echo mode */
            term->term_echoing = !state;
-           ldisc_send(NULL, 0, 0);    /* cause ldisc to notice changes */
+           if (term->ldisc)           /* cause ldisc to notice changes */
+               ldisc_send(term->ldisc, NULL, 0, 0);
            break;
          case 20:                     /* Return sends ... */
            term->cr_lf_return = state;
@@ -959,15 +1042,15 @@ static void do_osc(Terminal *term)
        switch (term->esc_args[0]) {
          case 0:
          case 1:
-           if (!cfg.no_remote_wintitle)
-               set_icon(term->osc_string);
+           if (!term->cfg->no_remote_wintitle)
+               set_icon(term->frontend, term->osc_string);
            if (term->esc_args[0] == 1)
                break;
            /* fall through: parameter 0 means set both */
          case 2:
          case 21:
-           if (!cfg.no_remote_wintitle)
-               set_title(term->osc_string);
+           if (!term->cfg->no_remote_wintitle)
+               set_title(term->frontend, term->osc_string);
            break;
        }
     }
@@ -979,7 +1062,7 @@ static void do_osc(Terminal *term)
 static void term_print_setup(Terminal *term)
 {
     bufchain_clear(&term->printer_buf);
-    term->print_job = printer_start_job(cfg.printer);
+    term->print_job = printer_start_job(term->cfg->printer);
 }
 static void term_print_flush(Terminal *term)
 {
@@ -1053,8 +1136,8 @@ void term_out(Terminal *term)
             * Optionally log the session traffic to a file. Useful for
             * debugging and possibly also useful for actual logging.
             */
-           if (cfg.logtype == LGTYP_DEBUG)
-               logtraffic((unsigned char) c, LGTYP_DEBUG);
+           if (term->cfg->logtype == LGTYP_DEBUG && term->logctx)
+               logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG);
        } else {
            c = unget;
            unget = -1;
@@ -1189,7 +1272,7 @@ void term_out(Terminal *term)
            }
            /* Are we in the nasty ACS mode? Note: no sco in utf mode. */
            else if(term->sco_acs && 
-                   (c!='\033' && c!='\n' && c!='\r' && c!='\b'))
+                   (c!='\033' && c!='\012' && c!='\015' && c!='\b'))
            {
               if (term->sco_acs == 2) c ^= 0x80;
               c |= ATTR_SCOACS;
@@ -1241,7 +1324,7 @@ void term_out(Terminal *term)
                term->curs.x--;
            term->wrapnext = FALSE;
            fix_cpos;
-           if (!cfg.no_dbackspace)    /* destructive bksp might be disabled */
+           if (!term->cfg->no_dbackspace)    /* destructive bksp might be disabled */
                *term->cpos = (' ' | term->curr_attr | ATTR_ASCII);
        } else
            /* Or normal C0 controls. */
@@ -1257,10 +1340,10 @@ void term_out(Terminal *term)
                 * An xterm returns "xterm" (5 characters)
                 */
                compatibility(ANSIMIN);
-               {
+               if (term->ldisc) {
                    char abuf[256], *s, *d;
                    int state = 0;
-                   for (s = cfg.answerback, d = abuf; *s; s++) {
+                   for (s = term->cfg->answerback, d = abuf; *s; s++) {
                        if (state) {
                            if (*s >= 'a' && *s <= 'z')
                                *d++ = (*s - ('a' - 1));
@@ -1275,7 +1358,8 @@ void term_out(Terminal *term)
                        } else
                            *d++ = *s;
                    }
-                   lpage_send(DEFAULT_CODEPAGE, abuf, d - abuf, 0);
+                   lpage_send(term->ldisc, DEFAULT_CODEPAGE,
+                              abuf, d - abuf, 0);
                }
                break;
              case '\007':
@@ -1302,7 +1386,7 @@ void term_out(Terminal *term)
                     * t seconds ago.
                     */
                    while (term->beephead &&
-                          term->beephead->ticks < ticks - cfg.bellovl_t) {
+                          term->beephead->ticks < ticks - term->cfg->bellovl_t) {
                        struct beeptime *tmp = term->beephead;
                        term->beephead = tmp->next;
                        sfree(tmp);
@@ -1311,16 +1395,16 @@ void term_out(Terminal *term)
                        term->nbeeps--;
                    }
 
-                   if (cfg.bellovl && term->beep_overloaded &&
-                       ticks - term->lastbeep >= (unsigned)cfg.bellovl_s) {
+                   if (term->cfg->bellovl && term->beep_overloaded &&
+                       ticks - term->lastbeep >= (unsigned)term->cfg->bellovl_s) {
                        /*
                         * If we're currently overloaded and the
                         * last beep was more than s seconds ago,
                         * leave overload mode.
                         */
                        term->beep_overloaded = FALSE;
-                   } else if (cfg.bellovl && !term->beep_overloaded &&
-                              term->nbeeps >= cfg.bellovl_n) {
+                   } else if (term->cfg->bellovl && !term->beep_overloaded &&
+                              term->nbeeps >= term->cfg->bellovl_n) {
                        /*
                         * Now, if we have n or more beeps
                         * remaining in the queue, go into overload
@@ -1333,13 +1417,13 @@ void term_out(Terminal *term)
                    /*
                     * Perform an actual beep if we're not overloaded.
                     */
-                   if (!cfg.bellovl || !term->beep_overloaded) {
-                       if (cfg.beep == BELL_VISUAL) {
+                   if (!term->cfg->bellovl || !term->beep_overloaded) {
+                       beep(term->frontend, term->cfg->beep);
+                       if (term->cfg->beep == BELL_VISUAL) {
                            term->in_vbell = TRUE;
                            term->vbell_startpoint = ticks;
                            term_update(term);
-                       } else
-                           beep(cfg.beep);
+                       }
                    }
                    term->disptop = 0;
                }
@@ -1374,13 +1458,14 @@ void term_out(Terminal *term)
                    term->esc_query = FALSE;
                }
                break;
-             case '\r':
+             case '\015':
                term->curs.x = 0;
                term->wrapnext = FALSE;
                fix_cpos;
                term->seen_disp_event = TRUE;
                term->paste_hold = 0;
-               logtraffic((unsigned char) c, LGTYP_ASCII);
+               if (term->logctx)
+                   logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
                break;
              case '\014':
                if (has_compat(SCOANSI)) {
@@ -1393,18 +1478,19 @@ void term_out(Terminal *term)
                }
              case '\013':
                compatibility(VT100);
-             case '\n':
+             case '\012':
                if (term->curs.y == term->marg_b)
                    scroll(term, term->marg_t, term->marg_b, 1, TRUE);
                else if (term->curs.y < term->rows - 1)
                    term->curs.y++;
-               if (cfg.lfhascr)
+               if (term->cfg->lfhascr)
                    term->curs.x = 0;
                fix_cpos;
                term->wrapnext = FALSE;
                term->seen_disp_event = 1;
                term->paste_hold = 0;
-               logtraffic((unsigned char) c, LGTYP_ASCII);
+               if (term->logctx)
+                   logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
                break;
              case '\t':
                {
@@ -1452,10 +1538,10 @@ void term_out(Terminal *term)
                    incpos(cursplus);
                    check_selection(term, term->curs, cursplus);
                }
-               if ((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0)
-                   logtraffic((unsigned char) c, LGTYP_ASCII);
+               if (((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0) &&
+                   term->logctx)
+                   logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
                {
-                   extern int wcwidth(wchar_t ucs);
                    int width = 0;
                    if (DIRECT_CHAR(c))
                        width = 1;
@@ -1586,15 +1672,18 @@ void term_out(Terminal *term)
                    break;
                  case 'Z':            /* terminal type query */
                    compatibility(VT100);
-                   ldisc_send(term->id_string, strlen(term->id_string), 0);
+                   if (term->ldisc)
+                       ldisc_send(term->ldisc, term->id_string,
+                                  strlen(term->id_string), 0);
                    break;
                  case 'c':            /* restore power-on settings */
                    compatibility(VT100);
                    power_on(term);
-                   ldisc_send(NULL, 0, 0);/* cause ldisc to notice changes */
+                   if (term->ldisc)   /* cause ldisc to notice changes */
+                       ldisc_send(term->ldisc, NULL, 0, 0);
                    if (term->reset_132) {
-                       if (!cfg.no_remote_resize)
-                           request_resize(80, term->rows);
+                       if (!term->cfg->no_remote_resize)
+                           request_resize(term->frontend, 80, term->rows);
                        term->reset_132 = 0;
                    }
                    fix_cpos;
@@ -1658,55 +1747,55 @@ void term_out(Terminal *term)
 
                  case ANSI('A', '('):
                    compatibility(VT100);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[0] = ATTR_GBCHR;
                    break;
                  case ANSI('B', '('):
                    compatibility(VT100);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[0] = ATTR_ASCII;
                    break;
                  case ANSI('0', '('):
                    compatibility(VT100);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[0] = ATTR_LINEDRW;
                    break;
                  case ANSI('U', '('): 
                    compatibility(OTHER);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[0] = ATTR_SCOACS; 
                    break;
 
                  case ANSI('A', ')'):
                    compatibility(VT100);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[1] = ATTR_GBCHR;
                    break;
                  case ANSI('B', ')'):
                    compatibility(VT100);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[1] = ATTR_ASCII;
                    break;
                  case ANSI('0', ')'):
                    compatibility(VT100);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[1] = ATTR_LINEDRW;
                    break;
                  case ANSI('U', ')'): 
                    compatibility(OTHER);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->cset_attr[1] = ATTR_SCOACS; 
                    break;
 
                  case ANSI('8', '%'):  /* Old Linux code */
                  case ANSI('G', '%'):
                    compatibility(OTHER);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->utf = 1;
                    break;
                  case ANSI('@', '%'):
                    compatibility(OTHER);
-                   if (!cfg.no_remote_charset)
+                   if (!term->cfg->no_remote_charset)
                        term->utf = 0;
                    break;
                }
@@ -1752,7 +1841,8 @@ void term_out(Terminal *term)
                        compatibility(OTHER);
                        /* this reports xterm version 136 so that VIM can
                           use the drag messages from the mouse reporting */
-                       ldisc_send("\033[>0;136;0c", 11, 0);
+                       if (term->ldisc)
+                           ldisc_send(term->ldisc, "\033[>0;136;0c", 11, 0);
                        break;
                      case 'a':       /* move right N cols */
                        compatibility(ANSI);
@@ -1854,17 +1944,20 @@ void term_out(Terminal *term)
                      case 'c':       /* terminal type query */
                        compatibility(VT100);
                        /* This is the response for a VT102 */
-                       ldisc_send(term->id_string,
-                                  strlen(term->id_string), 0);
+                       if (term->ldisc)
+                           ldisc_send(term->ldisc, term->id_string,
+                                      strlen(term->id_string), 0);
                        break;
                      case 'n':       /* cursor position query */
-                       if (term->esc_args[0] == 6) {
-                           char buf[32];
-                           sprintf(buf, "\033[%d;%dR", term->curs.y + 1,
-                                   term->curs.x + 1);
-                           ldisc_send(buf, strlen(buf), 0);
-                       } else if (term->esc_args[0] == 5) {
-                           ldisc_send("\033[0n", 4, 0);
+                       if (term->ldisc) {
+                           if (term->esc_args[0] == 6) {
+                               char buf[32];
+                               sprintf(buf, "\033[%d;%dR", term->curs.y + 1,
+                                       term->curs.x + 1);
+                               ldisc_send(term->ldisc, buf, strlen(buf), 0);
+                           } else if (term->esc_args[0] == 5) {
+                               ldisc_send(term->ldisc, "\033[0n", 4, 0);
+                           }
                        }
                        break;
                      case 'h':       /* toggle modes to high */
@@ -1882,7 +1975,7 @@ void term_out(Terminal *term)
                        compatibility(VT100);
                        {
                            if (term->esc_nargs != 1) break;
-                           if (term->esc_args[0] == 5 && *cfg.printer) {
+                           if (term->esc_args[0] == 5 && *term->cfg->printer) {
                                term->printing = TRUE;
                                term->only_printing = !term->esc_query;
                                term->print_state = 0;
@@ -2004,15 +2097,15 @@ void term_out(Terminal *term)
                                    break;
                                  case 10:      /* SCO acs off */
                                    compatibility(SCOANSI);
-                                   if (cfg.no_remote_charset) break;
+                                   if (term->cfg->no_remote_charset) break;
                                    term->sco_acs = 0; break;
                                  case 11:      /* SCO acs on */
                                    compatibility(SCOANSI);
-                                   if (cfg.no_remote_charset) break;
+                                   if (term->cfg->no_remote_charset) break;
                                    term->sco_acs = 1; break;
                                  case 12:      /* SCO acs on flipped */
                                    compatibility(SCOANSI);
-                                   if (cfg.no_remote_charset) break;
+                                   if (term->cfg->no_remote_charset) break;
                                    term->sco_acs = 2; break;
                                  case 22:      /* disable bold */
                                    compatibility2(OTHER, VT220);
@@ -2091,8 +2184,8 @@ void term_out(Terminal *term)
                            && (term->esc_args[0] < 1 ||
                                term->esc_args[0] >= 24)) {
                            compatibility(VT340TEXT);
-                           if (!cfg.no_remote_resize)
-                               request_resize(term->cols,
+                           if (!term->cfg->no_remote_resize)
+                               request_resize(term->frontend, term->cols,
                                               def(term->esc_args[0], 24));
                            deselect(term);
                        } else if (term->esc_nargs >= 1 &&
@@ -2104,15 +2197,16 @@ void term_out(Terminal *term)
                                int x, y, len;
                                char buf[80], *p;
                              case 1:
-                               set_iconic(FALSE);
+                               set_iconic(term->frontend, FALSE);
                                break;
                              case 2:
-                               set_iconic(TRUE);
+                               set_iconic(term->frontend, TRUE);
                                break;
                              case 3:
                                if (term->esc_nargs >= 3) {
-                                   if (!cfg.no_remote_resize)
-                                       move_window(def(term->esc_args[1], 0),
+                                   if (!term->cfg->no_remote_resize)
+                                       move_window(term->frontend,
+                                                   def(term->esc_args[1], 0),
                                                    def(term->esc_args[2], 0));
                                }
                                break;
@@ -2123,44 +2217,56 @@ void term_out(Terminal *term)
                                 * manage it. */
                                break;
                              case 5:
-                               set_zorder(TRUE);   /* move to top */
+                               /* move to top */
+                               set_zorder(term->frontend, TRUE);
                                break;
                              case 6:
-                               set_zorder(FALSE);  /* move to bottom */
+                               /* move to bottom */
+                               set_zorder(term->frontend, FALSE);
                                break;
                              case 7:
-                               refresh_window();
+                               refresh_window(term->frontend);
                                break;
                              case 8:
                                if (term->esc_nargs >= 3) {
-                                   if (!cfg.no_remote_resize)
-                                       request_resize(def(term->esc_args[2], cfg.width),
-                                                      def(term->esc_args[1], cfg.height));
+                                   if (!term->cfg->no_remote_resize)
+                                       request_resize(term->frontend,
+                                                      def(term->esc_args[2], term->cfg->width),
+                                                      def(term->esc_args[1], term->cfg->height));
                                }
                                break;
                              case 9:
                                if (term->esc_nargs >= 2)
-                                   set_zoomed(term->esc_args[1] ?
+                                   set_zoomed(term->frontend,
+                                              term->esc_args[1] ?
                                               TRUE : FALSE);
                                break;
                              case 11:
-                               ldisc_send(is_iconic() ? "\033[1t" : "\033[2t",
-                                          4, 0);
+                               if (term->ldisc)
+                                   ldisc_send(term->ldisc,
+                                              is_iconic(term->frontend) ?
+                                              "\033[1t" : "\033[2t", 4, 0);
                                break;
                              case 13:
-                               get_window_pos(&x, &y);
-                               len = sprintf(buf, "\033[3;%d;%dt", x, y);
-                               ldisc_send(buf, len, 0);
+                               if (term->ldisc) {
+                                   get_window_pos(term->frontend, &x, &y);
+                                   len = sprintf(buf, "\033[3;%d;%dt", x, y);
+                                   ldisc_send(term->ldisc, buf, len, 0);
+                               }
                                break;
                              case 14:
-                               get_window_pixels(&x, &y);
-                               len = sprintf(buf, "\033[4;%d;%dt", x, y);
-                               ldisc_send(buf, len, 0);
+                               if (term->ldisc) {
+                                   get_window_pixels(term->frontend, &x, &y);
+                                   len = sprintf(buf, "\033[4;%d;%dt", x, y);
+                                   ldisc_send(term->ldisc, buf, len, 0);
+                               }
                                break;
                              case 18:
-                               len = sprintf(buf, "\033[8;%d;%dt",
-                                             term->rows, term->cols);
-                               ldisc_send(buf, len, 0);
+                               if (term->ldisc) {
+                                   len = sprintf(buf, "\033[8;%d;%dt",
+                                                 term->rows, term->cols);
+                                   ldisc_send(term->ldisc, buf, len, 0);
+                               }
                                break;
                              case 19:
                                /*
@@ -2180,18 +2286,22 @@ void term_out(Terminal *term)
                                 */
                                break;
                              case 20:
-                               p = get_window_title(TRUE);
-                               len = strlen(p);
-                               ldisc_send("\033]L", 3, 0);
-                               ldisc_send(p, len, 0);
-                               ldisc_send("\033\\", 2, 0);
+                               if (term->ldisc) {
+                                   p = get_window_title(term->frontend, TRUE);
+                                   len = strlen(p);
+                                   ldisc_send(term->ldisc, "\033]L", 3, 0);
+                                   ldisc_send(term->ldisc, p, len, 0);
+                                   ldisc_send(term->ldisc, "\033\\", 2, 0);
+                               }
                                break;
                              case 21:
-                               p = get_window_title(FALSE);
-                               len = strlen(p);
-                               ldisc_send("\033]l", 3, 0);
-                               ldisc_send(p, len, 0);
-                               ldisc_send("\033\\", 2, 0);
+                               if (term->ldisc) {
+                                   p = get_window_title(term->frontend,FALSE);
+                                   len = strlen(p);
+                                   ldisc_send(term->ldisc, "\033]l", 3, 0);
+                                   ldisc_send(term->ldisc, p, len, 0);
+                                   ldisc_send(term->ldisc, "\033\\", 2, 0);
+                               }
                                break;
                            }
                        }
@@ -2220,10 +2330,10 @@ void term_out(Terminal *term)
                         */
                        compatibility(VT420);
                        if (term->esc_nargs == 1 && term->esc_args[0] > 0) {
-                           if (!cfg.no_remote_resize)
-                               request_resize(term->cols,
+                           if (!term->cfg->no_remote_resize)
+                               request_resize(term->frontend, term->cols,
                                               def(term->esc_args[0],
-                                                  cfg.height));
+                                                  term->cfg->height));
                            deselect(term);
                        }
                        break;
@@ -2234,9 +2344,10 @@ void term_out(Terminal *term)
                         */
                        compatibility(VT340TEXT);
                        if (term->esc_nargs <= 1) {
-                           if (!cfg.no_remote_resize)
-                               request_resize(def(term->esc_args[0],
-                                                  cfg.width), term->rows);
+                           if (!term->cfg->no_remote_resize)
+                               request_resize(term->frontend,
+                                              def(term->esc_args[0],
+                                                  term->cfg->width), term->rows);
                            deselect(term);
                        }
                        break;
@@ -2259,13 +2370,13 @@ void term_out(Terminal *term)
                        break;
                      case 'x':       /* report terminal characteristics */
                        compatibility(VT100);
-                       {
+                       if (term->ldisc) {
                            char buf[32];
                            int i = def(term->esc_args[0], 0);
                            if (i == 0 || i == 1) {
                                strcpy(buf, "\033[2;1;1;112;112;1;0x");
                                buf[2] += i;
-                               ldisc_send(buf, 20, 0);
+                               ldisc_send(term->ldisc, buf, 20, 0);
                            }
                        }
                        break;
@@ -2368,7 +2479,7 @@ void term_out(Terminal *term)
                         * Well we should do a soft reset at this point ...
                         */
                        if (!has_compat(VT420) && has_compat(VT100)) {
-                           if (!cfg.no_remote_resize) {
+                           if (!term->cfg->no_remote_resize) {
                                if (term->reset_132)
                                    request_resize(132, 24);
                                else
@@ -2387,7 +2498,7 @@ void term_out(Terminal *term)
                    term->osc_strlen = 0;
                    break;
                  case 'R':            /* Linux palette reset */
-                   palette_reset();
+                   palette_reset(term->frontend);
                    term_invalidate(term);
                    term->termstate = TOPLEVEL;
                    break;
@@ -2433,7 +2544,7 @@ void term_out(Terminal *term)
                 *
                 * -- RDB
                 */
-               if (c == '\n' || c == '\r') {
+               if (c == '\012' || c == '\015') {
                    term->termstate = TOPLEVEL;
                } else if (c == 0234 || c == '\007') {
                    /*
@@ -2466,7 +2577,7 @@ void term_out(Terminal *term)
                    }
                    term->osc_string[term->osc_strlen++] = val;
                    if (term->osc_strlen >= 7) {
-                       palette_set(term->osc_string[0],
+                       palette_set(term->frontend, term->osc_string[0],
                                    term->osc_string[1] * 16 + term->osc_string[2],
                                    term->osc_string[3] * 16 + term->osc_string[4],
                                    term->osc_string[5] * 16 + term->osc_string[6]);
@@ -2589,7 +2700,8 @@ void term_out(Terminal *term)
                    term->termstate = VT52_Y1;
                    break;
                  case 'Z':
-                   ldisc_send("\033/Z", 3, 0);
+                   if (term->ldisc)
+                       ldisc_send(term->ldisc, "\033/Z", 3, 0);
                    break;
                  case '=':
                    term->app_keypad_keys = TRUE;
@@ -2603,7 +2715,7 @@ void term_out(Terminal *term)
                     *     emulation.
                     */
                    term->vt52_mode = FALSE;
-                   term->blink_is_real = cfg.blinktext;
+                   term->blink_is_real = term->cfg->blinktext;
                    break;
 #if 0
                  case '^':
@@ -2816,7 +2928,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
     /* Has the cursor position or type changed ? */
     if (term->cursor_on) {
        if (term->has_focus) {
-           if (term->blinker || !cfg.blink_cur)
+           if (term->blinker || !term->cfg->blink_cur)
                cursor = TATTR_ACTCURS;
            else
                cursor = 0;
@@ -2887,12 +2999,15 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
                    tattr |= ATTR_WIDE;
 
            /* Video reversing things */
-           if (term->seltype == LEXICOGRAPHIC)
-               selected = (posle(term->selstart, scrpos) &&
-                           poslt(scrpos, term->selend));
-           else
-               selected = (posPle(term->selstart, scrpos) &&
-                           posPlt(scrpos, term->selend));
+           if (term->selstate == DRAGGING || term->selstate == SELECTED) {
+               if (term->seltype == LEXICOGRAPHIC)
+                   selected = (posle(term->selstart, scrpos) &&
+                               poslt(scrpos, term->selend));
+               else
+                   selected = (posPle(term->selstart, scrpos) &&
+                               posPlt(scrpos, term->selend));
+           } else
+               selected = FALSE;
            tattr = (tattr ^ rv
                     ^ (selected ? ATTR_REVERSE : 0));
 
@@ -2912,7 +3027,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
             */
            if ((tchar | tattr) != (term->disptext[idx]& ~ATTR_NARROW)) {
                if ((tattr & ATTR_WIDE) == 0 && 
-                   CharWidth(ctx, (tchar | tattr) & 0xFFFF) == 2)
+                   char_width(ctx, (tchar | tattr) & 0xFFFF) == 2)
                    tattr |= ATTR_NARROW;
            } else if (term->disptext[idx]&ATTR_NARROW)
                tattr |= ATTR_NARROW;
@@ -2926,7 +3041,8 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
            if ((term->disptext[idx] ^ tattr) & ATTR_WIDE)
                dirty_line = TRUE;
 
-           break_run = (tattr != attr || j - start >= sizeof(ch));
+           break_run = (((tattr ^ attr) & term->attr_mask) ||
+               j - start >= sizeof(ch));
 
            /* Special hack for VT100 Linedraw glyphs */
            if ((attr & CSET_MASK) == 0x2300 && tchar >= 0xBA
@@ -3036,7 +3152,7 @@ void term_invalidate(Terminal *term)
  * Paint the window in response to a WM_PAINT message.
  */
 void term_paint(Terminal *term, Context ctx,
-               int left, int top, int right, int bottom)
+               int left, int top, int right, int bottom, int immediately)
 {
     int i, j;
     if (left < 0) left = 0;
@@ -3058,7 +3174,7 @@ void term_paint(Terminal *term, Context ctx,
      * fails to actually do anything when re-sizing ... painting the wrong
      * window perhaps ?
      */
-    if (alt_pressed)
+    if (immediately)
         do_paint (term, ctx, FALSE);
 }
 
@@ -3072,6 +3188,10 @@ void term_paint(Terminal *term, Context ctx,
 void term_scroll(Terminal *term, int rel, int where)
 {
     int sbtop = -count234(term->scrollback);
+#ifdef OPTIMISE_SCROLL
+    int olddisptop = term->disptop;
+    int shift;
+#endif /* OPTIMISE_SCROLL */
 
     term->disptop = (rel < 0 ? 0 : rel > 0 ? sbtop : term->disptop) + where;
     if (term->disptop < sbtop)
@@ -3079,6 +3199,11 @@ void term_scroll(Terminal *term, int rel, int where)
     if (term->disptop > 0)
        term->disptop = 0;
     update_sbar(term);
+#ifdef OPTIMISE_SCROLL
+    shift = (term->disptop - olddisptop);
+    if (shift < term->rows && shift > -term->rows)
+       scroll_display(term, 0, term->rows - 1, shift);
+#endif /* OPTIMISE_SCROLL */
     term_update(term);
 }
 
@@ -3153,7 +3278,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect)
 
            switch (uc & CSET_MASK) {
              case ATTR_LINEDRW:
-               if (!cfg.rawcnp) {
+               if (!term->cfg->rawcnp) {
                    uc = unitab_xterm[uc & 0xFF];
                    break;
                }
@@ -3180,12 +3305,12 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect)
 
            if (DIRECT_FONT(uc)) {
                if (c >= ' ' && c != 0x7F) {
-                   unsigned char buf[4];
+                   char buf[4];
                    WCHAR wbuf[4];
                    int rv;
                    if (is_dbcs_leadbyte(font_codepage, (BYTE) c)) {
                        buf[0] = c;
-                       buf[1] = (unsigned char) ldata[top.x + 1];
+                       buf[1] = (char) (0xFF & ldata[top.x + 1]);
                        rv = mb_to_wc(font_codepage, 0, buf, 2, wbuf, 4);
                        top.x++;
                    } else {
@@ -3228,7 +3353,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect)
     wblen++;
     *wbptr++ = 0;
 #endif
-    write_clip(workbuf, wblen, FALSE); /* transfer to clipboard */
+    write_clip(term->frontend, workbuf, wblen, FALSE); /* transfer to clipbd */
     if (buflen > 0)                   /* indicates we allocated this buffer */
        sfree(workbuf);
 }
@@ -3247,9 +3372,10 @@ void term_copyall(Terminal *term)
  */
 static int wordtype(Terminal *term, int uc)
 {
-    static struct {
+    struct ucsword {
        int start, end, ctype;
-    } *wptr, ucs_words[] = {
+    };
+    static const struct ucsword ucs_words[] = {
        {
        128, 160, 0}, {
        161, 191, 1}, {
@@ -3313,6 +3439,7 @@ static int wordtype(Terminal *term, int uc)
        {
        0, 0, 0}
     };
+    const struct ucsword *wptr;
 
     uc &= (CSET_MASK | CHAR_MASK);
 
@@ -3455,7 +3582,7 @@ void term_do_paste(Terminal *term)
     wchar_t *data;
     int len;
 
-    get_clip(&data, &len);
+    get_clip(term->frontend, &data, &len);
     if (data && len > 0) {
         wchar_t *p, *q;
 
@@ -3482,7 +3609,7 @@ void term_do_paste(Terminal *term)
 
             if (p <= data + len - sel_nl_sz &&
                 !memcmp(p, sel_nl, sizeof(sel_nl))) {
-                term->paste_buffer[term->paste_len++] = '\r';
+                term->paste_buffer[term->paste_len++] = '\015';
                 p += sel_nl_sz;
             }
             q = p;
@@ -3490,14 +3617,15 @@ void term_do_paste(Terminal *term)
 
         /* Assume a small paste will be OK in one go. */
         if (term->paste_len < 256) {
-            luni_send(term->paste_buffer, term->paste_len, 0);
+            if (term->ldisc)
+               luni_send(term->ldisc, term->paste_buffer, term->paste_len, 0);
             if (term->paste_buffer)
                 sfree(term->paste_buffer);
             term->paste_buffer = 0;
             term->paste_pos = term->paste_hold = term->paste_len = 0;
         }
     }
-    get_clip(NULL, NULL);
+    get_clip(term->frontend, NULL, NULL);
 }
 
 void term_mouse(Terminal *term, Mouse_Button b, Mouse_Action a, int x, int y,
@@ -3506,8 +3634,8 @@ void term_mouse(Terminal *term, Mouse_Button b, Mouse_Action a, int x, int y,
     pos selpoint;
     unsigned long *ldata;
     int raw_mouse = (term->xterm_mouse &&
-                    !cfg.no_mouse_rep &&
-                    !(cfg.mouse_override && shift));
+                    !term->cfg->no_mouse_rep &&
+                    !(term->cfg->mouse_override && shift));
     int default_seltype;
 
     if (y < 0) {
@@ -3539,62 +3667,64 @@ void term_mouse(Terminal *term, Mouse_Button b, Mouse_Action a, int x, int y,
     if (raw_mouse) {
        int encstate = 0, r, c;
        char abuf[16];
-       static int is_down = 0;
 
-       switch (b) {
-         case MBT_LEFT:
-           encstate = 0x20;           /* left button down */
-           break;
-         case MBT_MIDDLE:
-           encstate = 0x21;
-           break;
-         case MBT_RIGHT:
-           encstate = 0x22;
-           break;
-         case MBT_WHEEL_UP:
-           encstate = 0x60;
-           break;
-         case MBT_WHEEL_DOWN:
-           encstate = 0x61;
-           break;
-         default: break;              /* placate gcc warning about enum use */
-       }
-       switch (a) {
-         case MA_DRAG:
-           if (term->xterm_mouse == 1)
-               return;
-           encstate += 0x20;
-           break;
-         case MA_RELEASE:
-           encstate = 0x23;
-           is_down = 0;
-           break;
-         case MA_CLICK:
-           if (is_down == b)
-               return;
-           is_down = b;
-           break;
-         default: break;              /* placate gcc warning about enum use */
+       if (term->ldisc) {
+
+           switch (b) {
+             case MBT_LEFT:
+               encstate = 0x20;               /* left button down */
+               break;
+             case MBT_MIDDLE:
+               encstate = 0x21;
+               break;
+             case MBT_RIGHT:
+               encstate = 0x22;
+               break;
+             case MBT_WHEEL_UP:
+               encstate = 0x60;
+               break;
+             case MBT_WHEEL_DOWN:
+               encstate = 0x61;
+               break;
+             default: break;          /* placate gcc warning about enum use */
+           }
+           switch (a) {
+             case MA_DRAG:
+               if (term->xterm_mouse == 1)
+                   return;
+               encstate += 0x20;
+               break;
+             case MA_RELEASE:
+               encstate = 0x23;
+               term->mouse_is_down = 0;
+               break;
+             case MA_CLICK:
+               if (term->mouse_is_down == b)
+                   return;
+               term->mouse_is_down = b;
+               break;
+             default: break;          /* placate gcc warning about enum use */
+           }
+           if (shift)
+               encstate += 0x04;
+           if (ctrl)
+               encstate += 0x10;
+           r = y + 33;
+           c = x + 33;
+
+           sprintf(abuf, "\033[M%c%c%c", encstate, c, r);
+           ldisc_send(term->ldisc, abuf, 6, 0);
        }
-       if (shift)
-           encstate += 0x04;
-       if (ctrl)
-           encstate += 0x10;
-       r = y + 33;
-       c = x + 33;
-
-       sprintf(abuf, "\033[M%c%c%c", encstate, c, r);
-       ldisc_send(abuf, 6, 0);
        return;
     }
 
-    b = translate_button(b);
+    b = translate_button(term->frontend, b);
 
     /*
      * Set the selection type (rectangular or normal) at the start
      * of a selection attempt, from the state of Alt.
      */
-    if (!alt ^ !cfg.rect_select)
+    if (!alt ^ !term->cfg->rect_select)
        default_seltype = RECTANGULAR;
     else
        default_seltype = LEXICOGRAPHIC;
@@ -3699,7 +3829,7 @@ void term_mouse(Terminal *term, Mouse_Button b, Mouse_Action a, int x, int y,
                   || a == MA_2CLK || a == MA_3CLK
 #endif
                   )) {
-       request_paste();
+       request_paste(term->frontend);
     }
 
     term_update(term);
@@ -3710,7 +3840,7 @@ void term_nopaste(Terminal *term)
     if (term->paste_len == 0)
        return;
     sfree(term->paste_buffer);
-    term->paste_buffer = 0;
+    term->paste_buffer = NULL;
     term->paste_len = 0;
 }
 
@@ -3738,10 +3868,11 @@ void term_paste(Terminal *term)
     while (term->paste_pos < term->paste_len) {
        int n = 0;
        while (n + term->paste_pos < term->paste_len) {
-           if (term->paste_buffer[term->paste_pos + n++] == '\r')
+           if (term->paste_buffer[term->paste_pos + n++] == '\015')
                break;
        }
-       luni_send(term->paste_buffer + term->paste_pos, n, 0);
+       if (term->ldisc)
+           luni_send(term->ldisc, term->paste_buffer + term->paste_pos, n, 0);
        term->paste_pos += n;
 
        if (term->paste_pos < term->paste_len) {
@@ -3807,3 +3938,8 @@ int from_backend(void *vterm, int is_stderr, char *data, int len)
      */
     return 0;
 }
+
+void term_provide_logctx(Terminal *term, void *logctx)
+{
+    term->logctx = logctx;
+}