Major destabilisation, phase 1. In this phase I've moved (I think)
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 22 Oct 2002 16:11:33 +0000 (16:11 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 22 Oct 2002 16:11:33 +0000 (16:11 +0000)
all the global and function-static variables out of terminal.c into
a dynamically allocated data structure. Note that this does not yet
confer the ability to run more than one of them in the same process,
because other things (the line discipline, the back end) are still
global, and also in particular the address of the dynamically
allocated terminal-data structure is held in a global variable
`term'. But what I've got here represents a reasonable stopping
point at which to check things in. In _theory_ this should all still
work happily, on both Unix and Windows. In practice, who knows?

git-svn-id: svn://svn.tartarus.org/sgt/putty@2115 cda61777-01e9-0310-a592-d414129be87e

15 files changed:
ldisc.c
plink.c
psftp.c
putty.h
raw.c
rlogin.c
scp.c
ssh.c
telnet.c
terminal.c
unicode.c
unix/pterm.c
unix/pty.c
unix/uxucs.c
window.c

diff --git a/ldisc.c b/ldisc.c
index e6a110b..ceafa41 100644 (file)
--- a/ldisc.c
+++ b/ldisc.c
@@ -9,17 +9,18 @@
 #include <ctype.h>
 
 #include "putty.h"
+#include "terminal.h"
 
 #define ECHOING (cfg.localecho == LD_YES || \
                  (cfg.localecho == LD_BACKEND && \
-                      (back->ldisc(LD_ECHO) || term_ldisc(LD_ECHO))))
+                      (back->ldisc(LD_ECHO) || term_ldisc(term, LD_ECHO))))
 #define EDITING (cfg.localedit == LD_YES || \
                  (cfg.localedit == LD_BACKEND && \
-                      (back->ldisc(LD_EDIT) || term_ldisc(LD_EDIT))))
+                      (back->ldisc(LD_EDIT) || term_ldisc(term, LD_EDIT))))
 
 static void c_write(char *buf, int len)
 {
-    from_backend(0, buf, len);
+    from_backend(term, 0, buf, len);
 }
 
 static char *term_buf = NULL;
@@ -27,7 +28,7 @@ static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0;
 
 static int plen(unsigned char c)
 {
-    if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf))
+    if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(term)))
        return 1;
     else if (c < 128)
        return 2;                      /* ^x for some x */
@@ -37,7 +38,7 @@ static int plen(unsigned char c)
 
 static void pwrite(unsigned char c)
 {
-    if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf)) {
+    if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(term))) {
        c_write(&c, 1);
     } else if (c < 128) {
        char cc[2];
@@ -70,6 +71,7 @@ void ldisc_send(char *buf, int len, int interactive)
     if (len == 0) {
        void ldisc_update(int echo, int edit);
        ldisc_update(ECHOING, EDITING);
+       return;
     }
     /*
      * Less than zero means null terminated special string.
diff --git a/plink.c b/plink.c
index 589de1a..5ac8b21 100644 (file)
--- a/plink.c
+++ b/plink.c
@@ -69,7 +69,7 @@ DWORD orig_console_mode;
 
 WSAEVENT netevent;
 
-int term_ldisc(int mode)
+int term_ldisc(Terminal *term, int mode)
 {
     return FALSE;
 }
@@ -164,7 +164,7 @@ void try_output(int is_stderr)
     }
 }
 
-int from_backend(int is_stderr, char *data, int len)
+int from_backend(void *frontend_handle, int is_stderr, char *data, int len)
 {
     HANDLE h = (is_stderr ? errhandle : outhandle);
     int osize, esize;
@@ -529,7 +529,7 @@ int main(int argc, char **argv)
        int nodelay = cfg.tcp_nodelay &&
            (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);
 
-       error = back->init(cfg.host, cfg.port, &realhost, nodelay);
+       error = back->init(NULL, cfg.host, cfg.port, &realhost, nodelay);
        if (error) {
            fprintf(stderr, "Unable to open connection:\n%s", error);
            return 1;
diff --git a/psftp.c b/psftp.c
index 32d24f7..f3f4c5b 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -1522,7 +1522,7 @@ static unsigned char *outptr;            /* where to put the data */
 static unsigned outlen;                       /* how much data required */
 static unsigned char *pending = NULL;  /* any spare data */
 static unsigned pendlen = 0, pendsize = 0;     /* length and phys. size of buffer */
-int from_backend(int is_stderr, char *data, int datalen)
+int from_backend(void *frontend, int is_stderr, char *data, int datalen)
 {
     unsigned char *p = (unsigned char *) data;
     unsigned len = (unsigned) datalen;
@@ -1822,7 +1822,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
 
     back = &ssh_backend;
 
-    err = back->init(cfg.host, cfg.port, &realhost, 0);
+    err = back->init(NULL, cfg.host, cfg.port, &realhost, 0);
     if (err != NULL) {
        fprintf(stderr, "ssh_init: %s\n", err);
        return 1;
diff --git a/putty.h b/putty.h
index 4b151de..646761f 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -18,6 +18,7 @@
 
 typedef struct config_tag Config;
 typedef struct backend_tag Backend;
+typedef struct terminal_tag Terminal;
 
 #include "puttyps.h"
 #include "network.h"
@@ -99,23 +100,10 @@ typedef struct backend_tag Backend;
 #define ATTR_CUR_AND (~(ATTR_BOLD|ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS))
 #define ATTR_CUR_XOR 0x00BA0000UL
 
-GLOBAL int rows, cols, savelines;
-
-GLOBAL int has_focus;
-
-GLOBAL int in_vbell;
-GLOBAL unsigned long vbell_startpoint;
-
-GLOBAL int app_cursor_keys, app_keypad_keys, vt52_mode;
-GLOBAL int repeat_off, cr_lf_return;
-
-GLOBAL int seen_disp_event;
 GLOBAL int alt_pressed;
 
 GLOBAL int session_closed;
 
-GLOBAL int big_cursor;
-
 GLOBAL char *help_path;
 GLOBAL int help_has_contents;
 
@@ -133,7 +121,6 @@ GLOBAL wchar_t unitab_font[256];
 GLOBAL wchar_t unitab_xterm[256];
 GLOBAL wchar_t unitab_oemcp[256];
 GLOBAL unsigned char unitab_ctrl[256];
-#define in_utf (utf || line_codepage==CP_UTF8)
 
 #define LGXF_OVR  1                   /* existing logfile overwrite */
 #define LGXF_APN  0                   /* existing logfile append */
@@ -201,7 +188,8 @@ enum {
 };
 
 struct backend_tag {
-    char *(*init) (char *host, int port, char **realhost, int nodelay);
+    char *(*init) (void *frontend_handle,
+                  char *host, int port, char **realhost, int nodelay);
     /* back->send() returns the current amount of buffered data. */
     int (*send) (char *buf, int len);
     /* back->sendbuffer() does the same thing but without attempting a send */
@@ -410,6 +398,8 @@ GLOBAL Config cfg;
 GLOBAL int default_protocol;
 GLOBAL int default_port;
 
+GLOBAL Terminal *term;                /* temporary while changes are made */
+
 struct RSAKey;                        /* be a little careful of scope */
 
 /*
@@ -476,33 +466,33 @@ void registry_cleanup(void);
  * Exports from terminal.c.
  */
 
-void term_init(void);
-void term_size(int, int, int);
-void term_out(void);
-void term_paint(Context, int, int, int, int);
-void term_scroll(int, int);
-void term_pwron(void);
-void term_clrsb(void);
-void term_mouse(Mouse_Button, Mouse_Action, int, int, int, int, int);
-void term_deselect(void);
-void term_update(void);
-void term_invalidate(void);
-void term_blink(int set_cursor);
-void term_do_paste(void);
-int term_paste_pending(void);
-void term_paste(void);
-void term_nopaste(void);
-int term_ldisc(int option);
-int from_backend(int is_stderr, char *data, int len);
-void logfopen(void);
-void logfclose(void);
-void term_copyall(void);
-void term_reconfig(void);
-void term_seen_key_event(void);
+Terminal *term_init(void);
+void term_size(Terminal *, int, int, int);
+void term_out(Terminal *);
+void term_paint(Terminal *, Context, int, int, int, int);
+void term_scroll(Terminal *, int, int);
+void term_pwron(Terminal *);
+void term_clrsb(Terminal *);
+void term_mouse(Terminal *, Mouse_Button, Mouse_Action, int,int,int,int,int);
+void term_deselect(Terminal *);
+void term_update(Terminal *);
+void term_invalidate(Terminal *);
+void term_blink(Terminal *, int set_cursor);
+void term_do_paste(Terminal *);
+int term_paste_pending(Terminal *);
+void term_paste(Terminal *);
+void term_nopaste(Terminal *);
+int term_ldisc(Terminal *, int option);
+void term_copyall(Terminal *);
+void term_reconfig(Terminal *);
+void term_seen_key_event(Terminal *); 
+int from_backend(void *, int is_stderr, char *data, int len);
 
 /*
  * Exports from logging.c.
  */
+void logfopen();
+void logfclose();
 void logtraffic(unsigned char c, int logmode);
 enum { PKT_INCOMING, PKT_OUTGOING };
 void log_eventlog(char *string);
diff --git a/raw.c b/raw.c
index 20732dd..406dc43 100644 (file)
--- a/raw.c
+++ b/raw.c
 
 static Socket s = NULL;
 static int raw_bufsize;
+static void *frontend;
 
 static void raw_size(void);
 
 static void c_write(char *buf, int len)
 {
-    int backlog = from_backend(0, buf, len);
+    int backlog = from_backend(frontend, 0, buf, len);
     sk_set_frozen(s, backlog > RAW_MAX_BACKLOG);
 }
 
@@ -58,7 +59,8 @@ static void raw_sent(Plug plug, int bufsize)
  * Also places the canonical host name into `realhost'. It must be
  * freed by the caller.
  */
-static char *raw_init(char *host, int port, char **realhost, int nodelay)
+static char *raw_init(void *frontend_handle, char *host, int port,
+                     char **realhost, int nodelay)
 {
     static struct plug_function_table fn_table = {
        raw_closing,
@@ -69,6 +71,8 @@ static char *raw_init(char *host, int port, char **realhost, int nodelay)
     SockAddr addr;
     char *err;
 
+    frontend = frontend_handle;
+
     /*
      * Try to find host.
      */
index 2ef2d71..4baada7 100644 (file)
--- a/rlogin.c
+++ b/rlogin.c
@@ -4,6 +4,7 @@
 #include <ctype.h>
 
 #include "putty.h"
+#include "terminal.h"
 
 #ifndef FALSE
 #define FALSE 0
 
 static Socket s = NULL;
 static int rlogin_bufsize;
+static void *frontend;
 
 static void rlogin_size(void);
 
 static void c_write(char *buf, int len)
 {
-    int backlog = from_backend(0, buf, len);
+    int backlog = from_backend(frontend, 0, buf, len);
     sk_set_frozen(s, backlog > RLOGIN_MAX_BACKLOG);
 }
 
@@ -88,7 +90,8 @@ static void rlogin_sent(Plug plug, int bufsize)
  * Also places the canonical host name into `realhost'. It must be
  * freed by the caller.
  */
-static char *rlogin_init(char *host, int port, char **realhost, int nodelay)
+static char *rlogin_init(void *frontend_handle,
+                        char *host, int port, char **realhost, int nodelay)
 {
     static struct plug_function_table fn_table = {
        rlogin_closing,
@@ -99,6 +102,8 @@ static char *rlogin_init(char *host, int port, char **realhost, int nodelay)
     SockAddr addr;
     char *err;
 
+    frontend = frontend_handle;
+
     /*
      * Try to find host.
      */
@@ -179,13 +184,13 @@ static void rlogin_size(void)
 {
     char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 };
 
-    if (s == NULL)
+    if (s == NULL || term == NULL)
        return;
     
-    b[6] = cols >> 8;
-    b[7] = cols & 0xFF;
-    b[4] = rows >> 8;
-    b[5] = rows & 0xFF;
+    b[6] = term->cols >> 8;
+    b[7] = term->cols & 0xFF;
+    b[4] = term->rows >> 8;
+    b[5] = term->rows & 0xFF;
     rlogin_bufsize = sk_write(s, b, 12);
     return;
 }
diff --git a/scp.c b/scp.c
index e8df3a4..ec3575b 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -308,7 +308,7 @@ static unsigned char *outptr;              /* where to put the data */
 static unsigned outlen;                       /* how much data required */
 static unsigned char *pending = NULL;  /* any spare data */
 static unsigned pendlen = 0, pendsize = 0;     /* length and phys. size of buffer */
-int from_backend(int is_stderr, char *data, int datalen)
+int from_backend(void *frontend, int is_stderr, char *data, int datalen)
 {
     unsigned char *p = (unsigned char *) data;
     unsigned len = (unsigned) datalen;
@@ -565,7 +565,7 @@ static void do_cmd(char *host, char *user, char *cmd)
 
     back = &ssh_backend;
 
-    err = back->init(cfg.host, cfg.port, &realhost, 0);
+    err = back->init(NULL, cfg.host, cfg.port, &realhost, 0);
     if (err != NULL)
        bump("ssh_init: %s", err);
     ssh_scp_init();
diff --git a/ssh.c b/ssh.c
index 3e8396f..31d4cc4 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -5,6 +5,7 @@
 #include <assert.h>
 
 #include "putty.h"
+#include "terminal.h"
 #include "tree234.h"
 #include "ssh.h"
 
@@ -533,6 +534,8 @@ static int savedport;
 static int ssh_send_ok;
 static int ssh_echoing, ssh_editing;
 
+static void *frontend;
+
 static tree234 *ssh_channels;         /* indexed by local id */
 static struct ssh_channel *mainchan;   /* primary session channel */
 static int ssh_exitcode = -1;
@@ -688,7 +691,7 @@ static void c_write(char *buf, int len)
                fputc(buf[i], stderr);
        return;
     }
-    from_backend(1, buf, len);
+    from_backend(frontend, 1, buf, len);
 }
 
 static void c_write_untrusted(char *buf, int len)
@@ -3124,7 +3127,8 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
     if (!cfg.nopty) {
        send_packet(SSH1_CMSG_REQUEST_PTY,
                    PKT_STR, cfg.termtype,
-                   PKT_INT, rows, PKT_INT, cols,
+                   PKT_INT, term ? term->rows : 24,
+                   PKT_INT, term ? term->cols : 80,
                    PKT_INT, 0, PKT_INT, 0, PKT_CHAR, 0, PKT_END);
        ssh_state = SSH_STATE_INTERMED;
        do {
@@ -3198,7 +3202,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
                pktin.type == SSH1_SMSG_STDERR_DATA) {
                long len = GET_32BIT(pktin.body);
                int bufsize =
-                   from_backend(pktin.type == SSH1_SMSG_STDERR_DATA,
+                   from_backend(frontend, pktin.type == SSH1_SMSG_STDERR_DATA,
                                 pktin.body + 4, len);
                if (!ssh1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
                    ssh1_stdout_throttling = 1;
@@ -5142,8 +5146,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
        ssh2_pkt_addstring("pty-req");
        ssh2_pkt_addbool(1);           /* want reply */
        ssh2_pkt_addstring(cfg.termtype);
-       ssh2_pkt_adduint32(cols);
-       ssh2_pkt_adduint32(rows);
+       ssh2_pkt_adduint32(term ? term->cols : 80);
+       ssh2_pkt_adduint32(term ? term->rows : 24);
        ssh2_pkt_adduint32(0);         /* pixel width */
        ssh2_pkt_adduint32(0);         /* pixel height */
        ssh2_pkt_addstring_start();
@@ -5281,7 +5285,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                    switch (c->type) {
                      case CHAN_MAINSESSION:
                        bufsize =
-                           from_backend(pktin.type ==
+                           from_backend(frontend, pktin.type ==
                                         SSH2_MSG_CHANNEL_EXTENDED_DATA,
                                         data, length);
                        break;
@@ -5706,7 +5710,8 @@ static void ssh2_protocol(unsigned char *in, int inlen, int ispkt)
  *
  * Returns an error message, or NULL on success.
  */
-static char *ssh_init(char *host, int port, char **realhost, int nodelay)
+static char *ssh_init(void *frontend_handle,
+                     char *host, int port, char **realhost, int nodelay)
 {
     char *p;
 
@@ -5715,6 +5720,8 @@ static char *ssh_init(char *host, int port, char **realhost, int nodelay)
        return "Microsoft high encryption pack not installed!";
 #endif
 
+    frontend = frontend_handle;
+
     ssh_send_ok = 0;
     ssh_editing = 0;
     ssh_echoing = 0;
@@ -5787,17 +5794,19 @@ static void ssh_size(void)
        break;
       case SSH_STATE_SESSION:
        if (!cfg.nopty) {
+           if (!term)
+               return;
            if (ssh_version == 1) {
                send_packet(SSH1_CMSG_WINDOW_SIZE,
-                           PKT_INT, rows, PKT_INT, cols,
+                           PKT_INT, term->rows, PKT_INT, term->cols,
                            PKT_INT, 0, PKT_INT, 0, PKT_END);
            } else {
                ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
                ssh2_pkt_adduint32(mainchan->remoteid);
                ssh2_pkt_addstring("window-change");
                ssh2_pkt_addbool(0);
-               ssh2_pkt_adduint32(cols);
-               ssh2_pkt_adduint32(rows);
+               ssh2_pkt_adduint32(term->cols);
+               ssh2_pkt_adduint32(term->rows);
                ssh2_pkt_adduint32(0);
                ssh2_pkt_adduint32(0);
                ssh2_pkt_send();
index 8ce3cf4..9aba9ea 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 
 #include "putty.h"
+#include "terminal.h"
 
 #ifndef FALSE
 #define FALSE 0
@@ -13,6 +14,8 @@
 
 static Socket s = NULL;
 
+static void *frontend;
+
 #define        IAC     255                    /* interpret as command: */
 #define        DONT    254                    /* you are not to use option */
 #define        DO      253                    /* please, you use option */
@@ -189,7 +192,7 @@ static void c_write1(int c)
 {
     int backlog;
     char cc = (char) c;
-    backlog = from_backend(0, &cc, 1);
+    backlog = from_backend(frontend, 0, &cc, 1);
     sk_set_frozen(s, backlog > TELNET_MAX_BACKLOG);
 }
 
@@ -451,9 +454,9 @@ static void process_subneg(void)
 }
 
 static enum {
-    TOPLEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
+    TOP_LEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
     SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR
-} telnet_state = TOPLEVEL;
+} telnet_state = TOP_LEVEL;
 
 static void do_telnet_read(char *buf, int len)
 {
@@ -462,10 +465,10 @@ static void do_telnet_read(char *buf, int len)
        int c = (unsigned char) *buf++;
 
        switch (telnet_state) {
-         case TOPLEVEL:
+         case TOP_LEVEL:
          case SEENCR:
            if (c == NUL && telnet_state == SEENCR)
-               telnet_state = TOPLEVEL;
+               telnet_state = TOP_LEVEL;
            else if (c == IAC)
                telnet_state = SEENIAC;
            else {
@@ -487,7 +490,7 @@ static void do_telnet_read(char *buf, int len)
                if (c == CR)
                    telnet_state = SEENCR;
                else
-                   telnet_state = TOPLEVEL;
+                   telnet_state = TOP_LEVEL;
            }
            break;
          case SEENIAC:
@@ -503,30 +506,30 @@ static void do_telnet_read(char *buf, int len)
                telnet_state = SEENSB;
            else if (c == DM) {
                in_synch = 0;
-               telnet_state = TOPLEVEL;
+               telnet_state = TOP_LEVEL;
            } else {
                /* ignore everything else; print it if it's IAC */
                if (c == IAC) {
                    c_write1(c);
                }
-               telnet_state = TOPLEVEL;
+               telnet_state = TOP_LEVEL;
            }
            break;
          case SEENWILL:
            proc_rec_opt(WILL, c);
-           telnet_state = TOPLEVEL;
+           telnet_state = TOP_LEVEL;
            break;
          case SEENWONT:
            proc_rec_opt(WONT, c);
-           telnet_state = TOPLEVEL;
+           telnet_state = TOP_LEVEL;
            break;
          case SEENDO:
            proc_rec_opt(DO, c);
-           telnet_state = TOPLEVEL;
+           telnet_state = TOP_LEVEL;
            break;
          case SEENDONT:
            proc_rec_opt(DONT, c);
-           telnet_state = TOPLEVEL;
+           telnet_state = TOP_LEVEL;
            break;
          case SEENSB:
            sb_opt = c;
@@ -559,7 +562,7 @@ static void do_telnet_read(char *buf, int len)
                goto subneg_addchar;   /* yes, it's a hack, I know, but... */
            else {
                process_subneg();
-               telnet_state = TOPLEVEL;
+               telnet_state = TOP_LEVEL;
            }
            break;
        }
@@ -602,7 +605,8 @@ static void telnet_sent(Plug plug, int bufsize)
  * Also places the canonical host name into `realhost'. It must be
  * freed by the caller.
  */
-static char *telnet_init(char *host, int port, char **realhost, int nodelay)
+static char *telnet_init(void *frontend_handle,
+                        char *host, int port, char **realhost, int nodelay)
 {
     static struct plug_function_table fn_table = {
        telnet_closing,
@@ -613,6 +617,8 @@ static char *telnet_init(char *host, int port, char **realhost, int nodelay)
     SockAddr addr;
     char *err;
 
+    frontend = frontend_handle;
+
     /*
      * Try to find host.
      */
@@ -718,15 +724,15 @@ static void telnet_size(void)
     unsigned char b[16];
     char logbuf[50];
 
-    if (s == NULL || o_naws.state != ACTIVE)
+    if (s == NULL || term == NULL || o_naws.state != ACTIVE)
        return;
     b[0] = IAC;
     b[1] = SB;
     b[2] = TELOPT_NAWS;
-    b[3] = cols >> 8;
-    b[4] = cols & 0xFF;
-    b[5] = rows >> 8;
-    b[6] = rows & 0xFF;
+    b[3] = term->cols >> 8;
+    b[4] = term->cols & 0xFF;
+    b[5] = term->rows >> 8;
+    b[6] = term->rows & 0xFF;
     b[7] = IAC;
     b[8] = SE;
     telnet_bufsize = sk_write(s, b, 9);
index 2785689..d0a09a3 100644 (file)
@@ -5,7 +5,19 @@
 #include <time.h>
 #include <assert.h>
 #include "putty.h"
-#include "tree234.h"
+#include "terminal.h"
+
+#define poslt(p1,p2) ( (p1).y < (p2).y || ( (p1).y == (p2).y && (p1).x < (p2).x ) )
+#define posle(p1,p2) ( (p1).y < (p2).y || ( (p1).y == (p2).y && (p1).x <= (p2).x ) )
+#define poseq(p1,p2) ( (p1).y == (p2).y && (p1).x == (p2).x )
+#define posdiff(p1,p2) ( ((p1).y - (p2).y) * (term->cols+1) + (p1).x - (p2).x )
+
+/* Product-order comparisons for rectangular block selection. */
+#define posPlt(p1,p2) ( (p1).y <= (p2).y && (p1).x < (p2).x )
+#define posPle(p1,p2) ( (p1).y <= (p2).y && (p1).x <= (p2).x )
+
+#define incpos(p) ( (p).x == term->cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
+#define decpos(p) ( (p).x == 0 ? ((p).x = term->cols, (p).y--, 1) : ((p).x--, 0) )
 
 #define VT52_PLUS
 
 #define TM_PUTTY       (0xFFFF)
 
 #define compatibility(x) \
-    if ( ((CL_##x)&compatibility_level) == 0 ) {       \
-       termstate=TOPLEVEL;                             \
+    if ( ((CL_##x)&term->compatibility_level) == 0 ) {         \
+       term->termstate=TOPLEVEL;                       \
        break;                                          \
     }
 #define compatibility2(x,y) \
-    if ( ((CL_##x|CL_##y)&compatibility_level) == 0 ) { \
-       termstate=TOPLEVEL;                             \
+    if ( ((CL_##x|CL_##y)&term->compatibility_level) == 0 ) { \
+       term->termstate=TOPLEVEL;                       \
        break;                                          \
     }
 
-#define has_compat(x) ( ((CL_##x)&compatibility_level) != 0 )
-
-static int compatibility_level = TM_PUTTY;
-
-static tree234 *scrollback;           /* lines scrolled off top of screen */
-static tree234 *screen;                       /* lines on primary screen */
-static tree234 *alt_screen;           /* lines on alternate screen */
-static int disptop;                   /* distance scrolled back (0 or -ve) */
-
-static unsigned long *cpos;           /* cursor position (convenience) */
-
-static unsigned long *disptext;               /* buffer of text on real screen */
-static unsigned long *dispcurs;               /* location of cursor on real screen */
-static unsigned long curstype;        /* type of cursor on real screen */
-
-#define VBELL_TIMEOUT (TICKSPERSEC/10) /* visual bell lasts 1/10 sec */
-
-struct beeptime {
-    struct beeptime *next;
-    unsigned long ticks;
-};
-static struct beeptime *beephead, *beeptail;
-int nbeeps;
-int beep_overloaded;
-long lastbeep;
-
-#define TSIZE (sizeof(unsigned long))
-#define fix_cpos do { cpos = lineptr(curs.y) + curs.x; } while(0)
-
-static unsigned long curr_attr, save_attr;
-static unsigned long erase_char = ERASE_CHAR;
-
-typedef struct {
-    int y, x;
-} pos;
-#define poslt(p1,p2) ( (p1).y < (p2).y || ( (p1).y == (p2).y && (p1).x < (p2).x ) )
-#define posle(p1,p2) ( (p1).y < (p2).y || ( (p1).y == (p2).y && (p1).x <= (p2).x ) )
-#define poseq(p1,p2) ( (p1).y == (p2).y && (p1).x == (p2).x )
-#define posdiff(p1,p2) ( ((p1).y - (p2).y) * (cols+1) + (p1).x - (p2).x )
-#define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
-#define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
-
-/* Product-order comparisons for rectangular block selection. */
-#define posPlt(p1,p2) ( (p1).y <= (p2).y && (p1).x < (p2).x )
-#define posPle(p1,p2) ( (p1).y <= (p2).y && (p1).x <= (p2).x )
-
-static bufchain inbuf;                /* terminal input buffer */
-static pos curs;                      /* cursor */
-static pos savecurs;                  /* saved cursor position */
-static int marg_t, marg_b;            /* scroll margins */
-static int dec_om;                    /* DEC origin mode flag */
-static int wrap, wrapnext;            /* wrap flags */
-static int insert;                    /* insert-mode flag */
-static int cset;                      /* 0 or 1: which char set */
-static int save_cset, save_csattr;     /* saved with cursor position */
-static int save_utf, save_wnext;       /* saved with cursor position */
-static int rvideo;                    /* global reverse video flag */
-static unsigned long rvbell_startpoint;/* for ESC[?5hESC[?5l vbell */
-static int cursor_on;                 /* cursor enabled flag */
-static int reset_132;                 /* Flag ESC c resets to 80 cols */
-static int use_bce;                   /* Use Background coloured erase */
-static int blinker;                   /* When blinking is the cursor on ? */
-static int tblinker;                  /* When the blinking text is on */
-static int blink_is_real;             /* Actually blink blinking text */
-static int term_echoing;              /* Does terminal want local echo? */
-static int term_editing;              /* Does terminal want local edit? */
-static int sco_acs, save_sco_acs;      /* CSI 10,11,12m -> OEM charset */
-static int vt52_bold;                 /* Force bold on non-bold colours */
-static int utf_state;                 /* Is there a pending UTF-8 character */
-static int utf_char;                  /* and what is it so far. */
-static int utf_size;                  /* The size of the UTF character. */
-static int printing, only_printing;    /* Are we doing ANSI printing? */
-static int print_state;                       /* state of print-end-sequence scan */
-static bufchain printer_buf;          /* buffered data for printer */
-static printer_job *print_job;
-
-static int xterm_mouse;                       /* send mouse messages to app */
-
-static unsigned long cset_attr[2];
-
-/*
- * Saved settings on the alternate screen.
- */
-static int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins, alt_cset, alt_sco_acs, alt_utf;
-static int alt_t, alt_b;
-static int alt_which;
-
-#define ARGS_MAX 32                   /* max # of esc sequence arguments */
-#define ARG_DEFAULT 0                 /* if an arg isn't specified */
-#define def(a,d) ( (a) == ARG_DEFAULT ? (d) : (a) )
-static int esc_args[ARGS_MAX];
-static int esc_nargs;
-static int esc_query;
-#define ANSI(x,y)      ((x)+((y)<<8))
-#define ANSI_QUE(x)    ANSI(x,TRUE)
-
-#define OSC_STR_MAX 2048
-static int osc_strlen;
-static char osc_string[OSC_STR_MAX + 1];
-static int osc_w;
-
-static char id_string[1024] = "\033[?6c";
-
-static unsigned char *tabs;
-
-static enum {
-    TOPLEVEL,
-    SEEN_ESC,
-    SEEN_CSI,
-    SEEN_OSC,
-    SEEN_OSC_W,
-
-    DO_CTRLS,
-
-    SEEN_OSC_P,
-    OSC_STRING, OSC_MAYBE_ST,
-    VT52_ESC,
-    VT52_Y1,
-    VT52_Y2,
-    VT52_FG,
-    VT52_BG
-} termstate;
-
-static enum {
-    NO_SELECTION, ABOUT_TO, DRAGGING, SELECTED
-} selstate;
-static enum {
-    LEXICOGRAPHIC, RECTANGULAR
-} seltype;
-static enum {
-    SM_CHAR, SM_WORD, SM_LINE
-} selmode;
-static pos selstart, selend, selanchor;
-
-static short wordness[256] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,           /* 01 */
-    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 1, 1, 1, 1, 1, 1,           /* 23 */
-    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 1, 1, 1, 1, 2,           /* 45 */
-    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 1, 1, 1, 1, 1,           /* 67 */
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1,           /* 89 */
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1,           /* AB */
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-    2, 2, 2, 2, 2, 2, 2, 2,           /* CD */
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-    2, 2, 2, 2, 2, 2, 2, 2,           /* EF */
-};
+#define has_compat(x) ( ((CL_##x)&term->compatibility_level) != 0 )
 
 #define sel_nl_sz  (sizeof(sel_nl)/sizeof(wchar_t))
-static wchar_t sel_nl[] = SEL_NL;
-static wchar_t *paste_buffer = 0;
-static int paste_len, paste_pos, paste_hold;
+const wchar_t sel_nl[] = SEL_NL;
 
 /*
  * Internal prototypes.
  */
-static void do_paint(Context, int);
-static void erase_lots(int, int, int);
-static void swap_screen(int, int, int);
-static void update_sbar(void);
-static void deselect(void);
-static void term_print_finish(void);
+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 *);
 
 /*
  * Resize a line to make it `cols' columns wide.
@@ -240,25 +99,25 @@ unsigned long *resizeline(unsigned long *line, int cols)
  * whether the y coordinate is non-negative or negative
  * (respectively).
  */
-unsigned long *lineptr(int y, int lineno)
+unsigned long *lineptr(Terminal *term, int y, int lineno)
 {
     unsigned long *line, *newline;
     tree234 *whichtree;
     int treeindex;
 
     if (y >= 0) {
-       whichtree = screen;
+       whichtree = term->screen;
        treeindex = y;
     } else {
-       whichtree = scrollback;
-       treeindex = y + count234(scrollback);
+       whichtree = term->scrollback;
+       treeindex = y + count234(term->scrollback);
     }
     line = index234(whichtree, treeindex);
 
     /* We assume that we don't screw up and retrieve something out of range. */
     assert(line != NULL);
 
-    newline = resizeline(line, cols);
+    newline = resizeline(line, term->cols);
     if (newline != line) {
        delpos234(whichtree, treeindex);
        addpos234(whichtree, newline, treeindex);
@@ -268,75 +127,77 @@ unsigned long *lineptr(int y, int lineno)
     return line + 1;
 }
 
-#define lineptr(x) lineptr(x,__LINE__)
+#define lineptr(x) lineptr(term,x,__LINE__)
+
 /*
  * Set up power-on settings for the terminal.
  */
-static void power_on(void)
+static void power_on(Terminal *term)
 {
-    curs.x = curs.y = alt_x = alt_y = savecurs.x = savecurs.y = 0;
-    alt_t = marg_t = 0;
-    if (rows != -1)
-       alt_b = marg_b = rows - 1;
+    term->curs.x = term->curs.y = 0;
+    term->alt_x = term->alt_y = 0;
+    term->savecurs.x = term->savecurs.y = 0;
+    term->alt_t = term->marg_t = 0;
+    if (term->rows != -1)
+       term->alt_b = term->marg_b = term->rows - 1;
     else
-       alt_b = marg_b = 0;
-    if (cols != -1) {
+       term->alt_b = term->marg_b = 0;
+    if (term->cols != -1) {
        int i;
-       for (i = 0; i < cols; i++)
-           tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
+       for (i = 0; i < term->cols; i++)
+           term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
     }
-    alt_om = dec_om = cfg.dec_om;
-    alt_wnext = wrapnext = alt_ins = insert = FALSE;
-    alt_wrap = wrap = cfg.wrap_mode;
-    alt_cset = cset = 0;
-    alt_utf = utf = 0;
-    alt_sco_acs = sco_acs = 0;
-    cset_attr[0] = cset_attr[1] = ATTR_ASCII;
-    rvideo = 0;
-    in_vbell = FALSE;
-    cursor_on = 1;
-    big_cursor = 0;
-    save_attr = curr_attr = ATTR_DEFAULT;
-    term_editing = term_echoing = FALSE;
-    ldisc_send(NULL, 0, 0);           /* cause ldisc to notice changes */
-    app_cursor_keys = cfg.app_cursor;
-    app_keypad_keys = cfg.app_keypad;
-    use_bce = cfg.bce;
-    blink_is_real = cfg.blinktext;
-    erase_char = ERASE_CHAR;
-    alt_which = 0;
-    term_print_finish();
+    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->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->erase_char = ERASE_CHAR;
+    term->alt_which = 0;
+    term_print_finish(term);
     {
        int i;
        for (i = 0; i < 256; i++)
-           wordness[i] = cfg.wordness[i];
+           term->wordness[i] = cfg.wordness[i];
     }
-    if (screen) {
-       swap_screen(1, FALSE, FALSE);
-       erase_lots(FALSE, TRUE, TRUE);
-       swap_screen(0, FALSE, FALSE);
-       erase_lots(FALSE, TRUE, TRUE);
+    if (term->screen) {
+       swap_screen(term, 1, FALSE, FALSE);
+       erase_lots(term, FALSE, TRUE, TRUE);
+       swap_screen(term, 0, FALSE, FALSE);
+       erase_lots(term, FALSE, TRUE, TRUE);
     }
 }
 
 /*
  * Force a screen update.
  */
-void term_update(void)
+void term_update(Terminal *term)
 {
     Context ctx;
     ctx = get_ctx();
     if (ctx) {
-       int need_sbar_update = seen_disp_event;
-       if (seen_disp_event && cfg.scroll_on_disp) {
-           disptop = 0;               /* return to main screen */
-           seen_disp_event = 0;
+       int need_sbar_update = term->seen_disp_event;
+       if (term->seen_disp_event && cfg.scroll_on_disp) {
+           term->disptop = 0;         /* return to main screen */
+           term->seen_disp_event = 0;
            need_sbar_update = TRUE;
        }
        if (need_sbar_update)
-           update_sbar();
-       do_paint(ctx, TRUE);
-       sys_cursor(curs.x, curs.y - disptop);
+           update_sbar(term);
+       do_paint(term, ctx, TRUE);
+       sys_cursor(term->curs.x, term->curs.y - term->disptop);
        free_ctx(ctx);
     }
 }
@@ -345,7 +206,7 @@ void term_update(void)
  * Called from front end when a keypress occurs, to trigger
  * anything magical that needs to happen in that situation.
  */
-void term_seen_key_event(void)
+void term_seen_key_event(Terminal *term)
 {
     /*
      * On any keypress, clear the bell overload mechanism
@@ -354,34 +215,35 @@ void term_seen_key_event(void)
      * to be intended (e.g. beeps from filename completion
      * blocking repeatedly).
      */
-    beep_overloaded = FALSE;
-    while (beephead) {
-       struct beeptime *tmp = beephead;
-       beephead = tmp->next;
+    term->beep_overloaded = FALSE;
+    while (term->beephead) {
+       struct beeptime *tmp = term->beephead;
+       term->beephead = tmp->next;
        sfree(tmp);
     }
-    beeptail = NULL;
-    nbeeps = 0;
+    term->beeptail = NULL;
+    term->nbeeps = 0;
 
     /*
      * Reset the scrollback on keypress, if we're doing that.
      */
     if (cfg.scroll_on_key) {
-       disptop = 0;                   /* return to main screen */
-       seen_disp_event = 1;
+       term->disptop = 0;             /* return to main screen */
+       term->seen_disp_event = 1;
     }
 }
 
 /*
  * Same as power_on(), but an external function.
  */
-void term_pwron(void)
+void term_pwron(Terminal *term)
 {
-    power_on();
+    power_on(term);
+    ldisc_send(NULL, 0, 0);           /* cause ldisc to notice changes */
     fix_cpos;
-    disptop = 0;
-    deselect();
-    term_update();
+    term->disptop = 0;
+    deselect(term);
+    term_update(term);
 }
 
 /*
@@ -390,79 +252,97 @@ void term_pwron(void)
  * user has disabled mouse reporting, and abandon a print job if
  * the user has disabled printing.
  */
-void term_reconfig(void)
+void term_reconfig(Terminal *term)
 {
     if (cfg.no_alt_screen)
-       swap_screen(0, FALSE, FALSE);
+       swap_screen(term, 0, FALSE, FALSE);
     if (cfg.no_mouse_rep) {
-       xterm_mouse = 0;
+       term->xterm_mouse = 0;
        set_raw_mouse_mode(0);
     }
     if (cfg.no_remote_charset) {
-       cset_attr[0] = cset_attr[1] = ATTR_ASCII;
-       sco_acs = alt_sco_acs = 0;
-       utf = 0;
+       term->cset_attr[0] = term->cset_attr[1] = ATTR_ASCII;
+       term->sco_acs = term->alt_sco_acs = 0;
+       term->utf = 0;
     }
     if (!*cfg.printer) {
-       term_print_finish();
+       term_print_finish(term);
     }
 }
 
 /*
  * Clear the scrollback.
  */
-void term_clrsb(void)
+void term_clrsb(Terminal *term)
 {
     unsigned long *line;
-    disptop = 0;
-    while ((line = delpos234(scrollback, 0)) != NULL) {
+    term->disptop = 0;
+    while ((line = delpos234(term->scrollback, 0)) != NULL) {
        sfree(line);
     }
-    update_sbar();
+    update_sbar(term);
 }
 
 /*
  * Initialise the terminal.
  */
-void term_init(void)
+Terminal *term_init(void)
 {
-    screen = alt_screen = scrollback = NULL;
-    disptop = 0;
-    disptext = dispcurs = NULL;
-    tabs = NULL;
-    deselect();
-    rows = cols = -1;
-    power_on();
-    beephead = beeptail = NULL;
-    nbeeps = 0;
-    lastbeep = FALSE;
-    beep_overloaded = FALSE;
+    Terminal *term;
+
+    /*
+     * Allocate a new Terminal structure and initialise the fields
+     * that need it.
+     */
+    term = smalloc(sizeof(Terminal));
+    term->compatibility_level = TM_PUTTY;
+    strcpy(term->id_string, "\033[?6c");
+    term->last_blink = term->last_tblink = 0;
+    term->paste_buffer = NULL;
+    term->last_paste = 0;
+    bufchain_init(&term->inbuf);
+    bufchain_init(&term->printer_buf);
+
+    term->screen = term->alt_screen = term->scrollback = NULL;
+    term->disptop = 0;
+    term->disptext = term->dispcurs = NULL;
+    term->tabs = NULL;
+    deselect(term);
+    term->rows = term->cols = -1;
+    power_on(term);
+    term->beephead = term->beeptail = NULL;
+    term->nbeeps = 0;
+    term->lastbeep = FALSE;
+    term->beep_overloaded = FALSE;
+
+    return term;
 }
 
 /*
  * Set up the terminal for a given size.
  */
-void term_size(int newrows, int newcols, int newsavelines)
+void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
 {
     tree234 *newalt;
     unsigned long *newdisp, *line;
     int i, j;
     int sblen;
-    int save_alt_which = alt_which;
+    int save_alt_which = term->alt_which;
 
-    if (newrows == rows && newcols == cols && newsavelines == savelines)
+    if (newrows == term->rows && newcols == term->cols &&
+       newsavelines == term->savelines)
        return;                        /* nothing to do */
 
-    deselect();
-    swap_screen(0, FALSE, FALSE);
+    deselect(term);
+    swap_screen(term, 0, FALSE, FALSE);
 
-    alt_t = marg_t = 0;
-    alt_b = marg_b = newrows - 1;
+    term->alt_t = term->marg_t = 0;
+    term->alt_b = term->marg_b = newrows - 1;
 
-    if (rows == -1) {
-       scrollback = newtree234(NULL);
-       screen = newtree234(NULL);
-       rows = 0;
+    if (term->rows == -1) {
+       term->scrollback = newtree234(NULL);
+       term->screen = newtree234(NULL);
+       term->rows = 0;
     }
 
     /*
@@ -485,82 +365,82 @@ void term_size(int newrows, int newcols, int newsavelines)
      *    amount of scrollback we actually have, we must throw some
      *    away.
      */
-    sblen = count234(scrollback);
+    sblen = count234(term->scrollback);
     /* Do this loop to expand the screen if newrows > rows */
-    for (i = rows; i < newrows; i++) {
+    for (i = term->rows; i < newrows; i++) {
        if (sblen > 0) {
-           line = delpos234(scrollback, --sblen);
+           line = delpos234(term->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);
+       addpos234(term->screen, line, 0);
     }
     /* Do this loop to shrink the screen if newrows < rows */
-    for (i = newrows; i < rows; i++) {
-       line = delpos234(screen, 0);
-       addpos234(scrollback, line, sblen++);
+    for (i = newrows; i < term->rows; i++) {
+       line = delpos234(term->screen, 0);
+       addpos234(term->scrollback, line, sblen++);
     }
-    assert(count234(screen) == newrows);
+    assert(count234(term->screen) == newrows);
     while (sblen > newsavelines) {
-       line = delpos234(scrollback, 0);
+       line = delpos234(term->scrollback, 0);
        sfree(line);
        sblen--;
     }
-    assert(count234(scrollback) <= newsavelines);
-    disptop = 0;
+    assert(count234(term->scrollback) <= newsavelines);
+    term->disptop = 0;
 
     newdisp = smalloc(newrows * (newcols + 1) * TSIZE);
     for (i = 0; i < newrows * (newcols + 1); i++)
        newdisp[i] = ATTR_INVALID;
-    sfree(disptext);
-    disptext = newdisp;
-    dispcurs = NULL;
+    sfree(term->disptext);
+    term->disptext = newdisp;
+    term->dispcurs = NULL;
 
     newalt = newtree234(NULL);
     for (i = 0; i < newrows; i++) {
        line = smalloc(TSIZE * (newcols + 2));
        line[0] = newcols;
        for (j = 0; j <= newcols; j++)
-           line[j + 1] = erase_char;
+           line[j + 1] = term->erase_char;
        addpos234(newalt, line, i);
     }
-    if (alt_screen) {
-       while (NULL != (line = delpos234(alt_screen, 0)))
+    if (term->alt_screen) {
+       while (NULL != (line = delpos234(term->alt_screen, 0)))
            sfree(line);
-       freetree234(alt_screen);
+       freetree234(term->alt_screen);
     }
-    alt_screen = newalt;
+    term->alt_screen = newalt;
 
-    tabs = srealloc(tabs, newcols * sizeof(*tabs));
+    term->tabs = srealloc(term->tabs, newcols * sizeof(*term->tabs));
     {
        int i;
-       for (i = (cols > 0 ? cols : 0); i < newcols; i++)
-           tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
+       for (i = (term->cols > 0 ? term->cols : 0); i < newcols; i++)
+           term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
     }
 
-    if (rows > 0)
-       curs.y += newrows - rows;
-    if (curs.y < 0)
-       curs.y = 0;
-    if (curs.y >= newrows)
-       curs.y = newrows - 1;
-    if (curs.x >= newcols)
-       curs.x = newcols - 1;
-    alt_x = alt_y = 0;
-    wrapnext = alt_wnext = FALSE;
-
-    rows = newrows;
-    cols = newcols;
-    savelines = newsavelines;
+    if (term->rows > 0)
+       term->curs.y += newrows - term->rows;
+    if (term->curs.y < 0)
+       term->curs.y = 0;
+    if (term->curs.y >= newrows)
+       term->curs.y = newrows - 1;
+    if (term->curs.x >= newcols)
+       term->curs.x = newcols - 1;
+    term->alt_x = term->alt_y = 0;
+    term->wrapnext = term->alt_wnext = FALSE;
+
+    term->rows = newrows;
+    term->cols = newcols;
+    term->savelines = newsavelines;
     fix_cpos;
 
-    swap_screen(save_alt_which, FALSE, FALSE);
+    swap_screen(term, save_alt_which, FALSE, FALSE);
 
-    update_sbar();
-    term_update();
+    update_sbar(term);
+    term_update(term);
     back->size();
 }
 
@@ -571,7 +451,7 @@ void term_size(int newrows, int newcols, int newsavelines)
  * alternate screen completely. (This is even true if we're already
  * on it! Blame xterm.)
  */
-static void swap_screen(int which, int reset, int keep_cur_pos)
+static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos)
 {
     int t;
     tree234 *ttr;
@@ -579,84 +459,84 @@ static void swap_screen(int which, int reset, int keep_cur_pos)
     if (!which)
        reset = FALSE;                 /* do no weird resetting if which==0 */
 
-    if (which != alt_which) {
-       alt_which = which;
+    if (which != term->alt_which) {
+       term->alt_which = which;
 
-       ttr = alt_screen;
-       alt_screen = screen;
-       screen = ttr;
-       t = curs.x;
+       ttr = term->alt_screen;
+       term->alt_screen = term->screen;
+       term->screen = ttr;
+       t = term->curs.x;
        if (!reset && !keep_cur_pos)
-           curs.x = alt_x;
-       alt_x = t;
-       t = curs.y;
+           term->curs.x = term->alt_x;
+       term->alt_x = t;
+       t = term->curs.y;
        if (!reset && !keep_cur_pos)
-           curs.y = alt_y;
-       alt_y = t;
-       t = marg_t;
-       if (!reset) marg_t = alt_t;
-       alt_t = t;
-       t = marg_b;
-       if (!reset) marg_b = alt_b;
-       alt_b = t;
-       t = dec_om;
-       if (!reset) dec_om = alt_om;
-       alt_om = t;
-       t = wrap;
-       if (!reset) wrap = alt_wrap;
-       alt_wrap = t;
-       t = wrapnext;
-       if (!reset) wrapnext = alt_wnext;
-       alt_wnext = t;
-       t = insert;
-       if (!reset) insert = alt_ins;
-       alt_ins = t;
-       t = cset;
-       if (!reset) cset = alt_cset;
-       alt_cset = t;
-       t = utf;
-       if (!reset) utf = alt_utf;
-       alt_utf = t;
-       t = sco_acs;
-       if (!reset) sco_acs = alt_sco_acs;
-       alt_sco_acs = t;
+           term->curs.y = term->alt_y;
+       term->alt_y = t;
+       t = term->marg_t;
+       if (!reset) term->marg_t = term->alt_t;
+       term->alt_t = t;
+       t = term->marg_b;
+       if (!reset) term->marg_b = term->alt_b;
+       term->alt_b = t;
+       t = term->dec_om;
+       if (!reset) term->dec_om = term->alt_om;
+       term->alt_om = t;
+       t = term->wrap;
+       if (!reset) term->wrap = term->alt_wrap;
+       term->alt_wrap = t;
+       t = term->wrapnext;
+       if (!reset) term->wrapnext = term->alt_wnext;
+       term->alt_wnext = t;
+       t = term->insert;
+       if (!reset) term->insert = term->alt_ins;
+       term->alt_ins = t;
+       t = term->cset;
+       if (!reset) term->cset = term->alt_cset;
+       term->alt_cset = t;
+       t = term->utf;
+       if (!reset) term->utf = term->alt_utf;
+       term->alt_utf = t;
+       t = term->sco_acs;
+       if (!reset) term->sco_acs = term->alt_sco_acs;
+       term->alt_sco_acs = t;
     }
 
-    if (reset && screen) {
+    if (reset && term->screen) {
        /*
         * Yes, this _is_ supposed to honour background-colour-erase.
         */
-       erase_lots(FALSE, TRUE, TRUE);
+       erase_lots(term, FALSE, TRUE, TRUE);
     }
 
     /*
      * This might not be possible if we're called during
      * initialisation.
      */
-    if (screen)
+    if (term->screen)
        fix_cpos;
 }
 
 /*
  * Update the scroll bar.
  */
-static void update_sbar(void)
+static void update_sbar(Terminal *term)
 {
     int nscroll;
 
-    nscroll = count234(scrollback);
+    nscroll = count234(term->scrollback);
 
-    set_sbar(nscroll + rows, nscroll + disptop, rows);
+    set_sbar(nscroll + term->rows, nscroll + term->disptop, term->rows);
 }
 
 /*
  * Check whether the region bounded by the two pointers intersects
  * the scroll region, and de-select the on-screen selection if so.
  */
-static void check_selection(pos from, pos to)
+static void check_selection(Terminal *term, pos from, pos to)
 {
-    if (poslt(from, selend) && poslt(selstart, to))
-       deselect();
+    if (poslt(from, term->selend) && poslt(term->selstart, to))
+       deselect(term);
 }
 
 /*
@@ -669,35 +549,35 @@ static void check_selection(pos from, pos to)
  * after calling scroll() and before doing anything else that
  * uses the cpos shortcut pointer.
  */
-static void scroll(int topline, int botline, int lines, int sb)
+static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
 {
     unsigned long *line, *line2;
     int i, seltop;
 
-    if (topline != 0 || alt_which != 0)
+    if (topline != 0 || term->alt_which != 0)
        sb = FALSE;
 
     if (lines < 0) {
        while (lines < 0) {
-           line = delpos234(screen, botline);
-            line = resizeline(line, cols);
-           for (i = 0; i < cols; i++)
-               line[i + 1] = erase_char;
-           line[cols + 1] = 0;
-           addpos234(screen, line, topline);
-
-           if (selstart.y >= topline && selstart.y <= botline) {
-               selstart.y++;
-               if (selstart.y > botline) {
-                   selstart.y = botline;
-                   selstart.x = 0;
+           line = delpos234(term->screen, botline);
+            line = resizeline(line, term->cols);
+           for (i = 0; i < term->cols; i++)
+               line[i + 1] = term->erase_char;
+           line[term->cols + 1] = 0;
+           addpos234(term->screen, line, topline);
+
+           if (term->selstart.y >= topline && term->selstart.y <= botline) {
+               term->selstart.y++;
+               if (term->selstart.y > botline) {
+                   term->selstart.y = botline;
+                   term->selstart.x = 0;
                }
            }
-           if (selend.y >= topline && selend.y <= botline) {
-               selend.y++;
-               if (selend.y > botline) {
-                   selend.y = botline;
-                   selend.x = 0;
+           if (term->selend.y >= topline && term->selend.y <= botline) {
+               term->selend.y++;
+               if (term->selend.y > botline) {
+                   term->selend.y = botline;
+                   term->selend.x = 0;
                }
            }
 
@@ -705,22 +585,22 @@ static void scroll(int topline, int botline, int lines, int sb)
        }
     } else {
        while (lines > 0) {
-           line = delpos234(screen, topline);
-           if (sb && savelines > 0) {
-               int sblen = count234(scrollback);
+           line = delpos234(term->screen, topline);
+           if (sb && term->savelines > 0) {
+               int sblen = count234(term->scrollback);
                /*
                 * We must add this line to the scrollback. We'll
                 * remove a line from the top of the scrollback to
                 * replace it, or allocate a new one if the
                 * scrollback isn't full.
                 */
-               if (sblen == savelines) {
-                   sblen--, line2 = delpos234(scrollback, 0);
+               if (sblen == term->savelines) {
+                   sblen--, line2 = delpos234(term->scrollback, 0);
                } else {
-                   line2 = smalloc(TSIZE * (cols + 2));
-                   line2[0] = cols;
+                   line2 = smalloc(TSIZE * (term->cols + 2));
+                   line2[0] = term->cols;
                }
-               addpos234(scrollback, line, sblen);
+               addpos234(term->scrollback, line, sblen);
                line = line2;
 
                /*
@@ -737,14 +617,14 @@ static void scroll(int topline, int botline, int lines, int sb)
                 * Thanks to Jan Holmen Holsten for the idea and
                 * initial implementation.
                 */
-               if (disptop > -savelines && disptop < 0)
-                   disptop--;
+               if (term->disptop > -term->savelines && term->disptop < 0)
+                   term->disptop--;
            }
-            line = resizeline(line, cols);
-           for (i = 0; i < cols; i++)
-               line[i + 1] = erase_char;
-           line[cols + 1] = 0;
-           addpos234(screen, line, botline);
+            line = resizeline(line, term->cols);
+           for (i = 0; i < term->cols; i++)
+               line[i + 1] = term->erase_char;
+           line[term->cols + 1] = 0;
+           addpos234(term->screen, line, botline);
 
            /*
             * If the selection endpoints move into the scrollback,
@@ -757,27 +637,28 @@ static void scroll(int topline, int botline, int lines, int sb)
             * selection), and also selanchor (for one being
             * selected as we speak).
             */
-           seltop = sb ? -savelines : topline;
-
-           if (selstart.y >= seltop && selstart.y <= botline) {
-               selstart.y--;
-               if (selstart.y < seltop) {
-                   selstart.y = seltop;
-                   selstart.x = 0;
+           seltop = sb ? -term->savelines : topline;
+
+           if (term->selstart.y >= seltop &&
+               term->selstart.y <= botline) {
+               term->selstart.y--;
+               if (term->selstart.y < seltop) {
+                   term->selstart.y = seltop;
+                   term->selstart.x = 0;
                }
            }
-           if (selend.y >= seltop && selend.y <= botline) {
-               selend.y--;
-               if (selend.y < seltop) {
-                   selend.y = seltop;
-                   selend.x = 0;
+           if (term->selend.y >= seltop && term->selend.y <= botline) {
+               term->selend.y--;
+               if (term->selend.y < seltop) {
+                   term->selend.y = seltop;
+                   term->selend.x = 0;
                }
            }
-           if (selanchor.y >= seltop && selanchor.y <= botline) {
-               selanchor.y--;
-               if (selanchor.y < seltop) {
-                   selanchor.y = seltop;
-                   selanchor.x = 0;
+           if (term->selanchor.y >= seltop && term->selanchor.y <= botline) {
+               term->selanchor.y--;
+               if (term->selanchor.y < seltop) {
+                   term->selanchor.y = seltop;
+                   term->selanchor.x = 0;
                }
            }
 
@@ -792,65 +673,68 @@ static void scroll(int topline, int botline, int lines, int sb)
  * not to, 1 to disallow _passing_ the margins, and 2 to disallow
  * even _being_ outside the margins.
  */
-static void move(int x, int y, int marg_clip)
+static void move(Terminal *term, int x, int y, int marg_clip)
 {
     if (x < 0)
        x = 0;
-    if (x >= cols)
-       x = cols - 1;
+    if (x >= term->cols)
+       x = term->cols - 1;
     if (marg_clip) {
-       if ((curs.y >= marg_t || marg_clip == 2) && y < marg_t)
-           y = marg_t;
-       if ((curs.y <= marg_b || marg_clip == 2) && y > marg_b)
-           y = marg_b;
+       if ((term->curs.y >= term->marg_t || marg_clip == 2) &&
+           y < term->marg_t)
+           y = term->marg_t;
+       if ((term->curs.y <= term->marg_b || marg_clip == 2) &&
+           y > term->marg_b)
+           y = term->marg_b;
     }
     if (y < 0)
        y = 0;
-    if (y >= rows)
-       y = rows - 1;
-    curs.x = x;
-    curs.y = y;
+    if (y >= term->rows)
+       y = term->rows - 1;
+    term->curs.x = x;
+    term->curs.y = y;
     fix_cpos;
-    wrapnext = FALSE;
+    term->wrapnext = FALSE;
 }
 
 /*
  * Save or restore the cursor and SGR mode.
  */
-static void save_cursor(int save)
+static void save_cursor(Terminal *term, int save)
 {
     if (save) {
-       savecurs = curs;
-       save_attr = curr_attr;
-       save_cset = cset;
-       save_utf = utf;
-       save_wnext = wrapnext;
-       save_csattr = cset_attr[cset];
-       save_sco_acs = sco_acs;
+       term->savecurs = term->curs;
+       term->save_attr = term->curr_attr;
+       term->save_cset = term->cset;
+       term->save_utf = term->utf;
+       term->save_wnext = term->wrapnext;
+       term->save_csattr = term->cset_attr[term->cset];
+       term->save_sco_acs = term->sco_acs;
     } else {
-       curs = savecurs;
+       term->curs = term->savecurs;
        /* Make sure the window hasn't shrunk since the save */
-       if (curs.x >= cols)
-           curs.x = cols - 1;
-       if (curs.y >= rows)
-           curs.y = rows - 1;
-
-       curr_attr = save_attr;
-       cset = save_cset;
-       utf = save_utf;
-       wrapnext = save_wnext;
+       if (term->curs.x >= term->cols)
+           term->curs.x = term->cols - 1;
+       if (term->curs.y >= term->rows)
+           term->curs.y = term->rows - 1;
+
+       term->curr_attr = term->save_attr;
+       term->cset = term->save_cset;
+       term->utf = term->save_utf;
+       term->wrapnext = term->save_wnext;
        /*
         * wrapnext might reset to False if the x position is no
         * longer at the rightmost edge.
         */
-       if (wrapnext && curs.x < cols-1)
-           wrapnext = FALSE;
-       cset_attr[cset] = save_csattr;
-       sco_acs = save_sco_acs;
+       if (term->wrapnext && term->curs.x < term->cols-1)
+           term->wrapnext = FALSE;
+       term->cset_attr[term->cset] = term->save_csattr;
+       term->sco_acs = term->save_sco_acs;
        fix_cpos;
-       if (use_bce)
-           erase_char = (' ' | ATTR_ASCII |
-                        (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
+       if (term->use_bce)
+           term->erase_char = (' ' | ATTR_ASCII |
+                               (term->curr_attr &
+                                (ATTR_FGMASK | ATTR_BGMASK)));
     }
 }
 
@@ -858,45 +742,46 @@ static void save_cursor(int save)
  * Erase a large portion of the screen: the whole screen, or the
  * whole line, or parts thereof.
  */
-static void erase_lots(int line_only, int from_begin, int to_end)
+static void erase_lots(Terminal *term,
+                      int line_only, int from_begin, int to_end)
 {
     pos start, end;
     int erase_lattr;
     unsigned long *ldata;
 
     if (line_only) {
-       start.y = curs.y;
+       start.y = term->curs.y;
        start.x = 0;
-       end.y = curs.y + 1;
+       end.y = term->curs.y + 1;
        end.x = 0;
        erase_lattr = FALSE;
     } else {
        start.y = 0;
        start.x = 0;
-       end.y = rows;
+       end.y = term->rows;
        end.x = 0;
        erase_lattr = TRUE;
     }
     if (!from_begin) {
-       start = curs;
+       start = term->curs;
     }
     if (!to_end) {
-       end = curs;
+       end = term->curs;
        incpos(end);
     }
-    check_selection(start, end);
+    check_selection(term, start, end);
 
     /* Clear screen also forces a full window redraw, just in case. */
-    if (start.y == 0 && start.x == 0 && end.y == rows)
-       term_invalidate();
+    if (start.y == 0 && start.x == 0 && end.y == term->rows)
+       term_invalidate(term);
 
     ldata = lineptr(start.y);
     while (poslt(start, end)) {
-       if (start.x == cols && !erase_lattr)
+       if (start.x == term->cols && !erase_lattr)
            ldata[start.x] &= ~LATTR_WRAPPED;
        else
-           ldata[start.x] = erase_char;
-       if (incpos(start) && start.y < rows)
+           ldata[start.x] = term->erase_char;
+       if (incpos(start) && start.y < term->rows)
            ldata = lineptr(start.y);
     }
 }
@@ -905,7 +790,7 @@ static void erase_lots(int line_only, int from_begin, int to_end)
  * Insert or delete characters within the current line. n is +ve if
  * insertion is desired, and -ve for deletion.
  */
-static void insch(int n)
+static void insch(Terminal *term, int n)
 {
     int dir = (n < 0 ? -1 : +1);
     int m;
@@ -913,21 +798,21 @@ static void insch(int n)
     unsigned long *ldata;
 
     n = (n < 0 ? -n : n);
-    if (n > cols - curs.x)
-       n = cols - curs.x;
-    m = cols - curs.x - n;
-    cursplus.y = curs.y;
-    cursplus.x = curs.x + n;
-    check_selection(curs, cursplus);
-    ldata = lineptr(curs.y);
+    if (n > term->cols - term->curs.x)
+       n = term->cols - term->curs.x;
+    m = term->cols - term->curs.x - n;
+    cursplus.y = term->curs.y;
+    cursplus.x = term->curs.x + n;
+    check_selection(term, term->curs, cursplus);
+    ldata = lineptr(term->curs.y);
     if (dir < 0) {
-       memmove(ldata + curs.x, ldata + curs.x + n, m * TSIZE);
+       memmove(ldata + term->curs.x, ldata + term->curs.x + n, m * TSIZE);
        while (n--)
-           ldata[curs.x + m++] = erase_char;
+           ldata[term->curs.x + m++] = term->erase_char;
     } else {
-       memmove(ldata + curs.x + n, ldata + curs.x, m * TSIZE);
+       memmove(ldata + term->curs.x + n, ldata + term->curs.x, m * TSIZE);
        while (n--)
-           ldata[curs.x + n] = erase_char;
+           ldata[term->curs.x + n] = term->erase_char;
     }
 }
 
@@ -935,29 +820,29 @@ static void insch(int n)
  * Toggle terminal mode `mode' to state `state'. (`query' indicates
  * whether the mode is a DEC private one or a normal one.)
  */
-static void toggle_mode(int mode, int query, int state)
+static void toggle_mode(Terminal *term, int mode, int query, int state)
 {
     unsigned long ticks;
 
     if (query)
        switch (mode) {
          case 1:                      /* application cursor keys */
-           app_cursor_keys = state;
+           term->app_cursor_keys = state;
            break;
          case 2:                      /* VT52 mode */
-           vt52_mode = !state;
-           if (vt52_mode) {
-               blink_is_real = FALSE;
-               vt52_bold = FALSE;
+           term->vt52_mode = !state;
+           if (term->vt52_mode) {
+               term->blink_is_real = FALSE;
+               term->vt52_bold = FALSE;
            } else {
-               blink_is_real = cfg.blinktext;
+               term->blink_is_real = cfg.blinktext;
            }
            break;
          case 3:                      /* 80/132 columns */
-           deselect();
+           deselect(term);
            if (!cfg.no_remote_resize)
-               request_resize(state ? 132 : 80, rows);
-           reset_132 = state;
+               request_resize(state ? 132 : 80, term->rows);
+           term->reset_132 = state;
            break;
          case 5:                      /* reverse video */
            /*
@@ -968,119 +853,121 @@ static void toggle_mode(int mode, int query, int state)
             */
            ticks = GETTICKCOUNT();
            /* turn off a previous vbell to avoid inconsistencies */
-           if (ticks - vbell_startpoint >= VBELL_TIMEOUT)
-               in_vbell = FALSE;
-           if (rvideo && !state &&    /* we're turning it off... */
-               (ticks - rvbell_startpoint) < VBELL_TIMEOUT) {  /* ...soon */
+           if (ticks - term->vbell_startpoint >= VBELL_TIMEOUT)
+               term->in_vbell = FALSE;
+           if (term->rvideo && !state &&    /* we're turning it off... */
+               (ticks - term->rvbell_startpoint) < VBELL_TIMEOUT) {/*...soon*/
                /* If there's no vbell timeout already, or this one lasts
                 * longer, replace vbell_timeout with ours. */
-               if (!in_vbell ||
-                   (rvbell_startpoint - vbell_startpoint < VBELL_TIMEOUT))
-                   vbell_startpoint = rvbell_startpoint;
-               in_vbell = TRUE;       /* we may clear rvideo but we set in_vbell */
-           } else if (!rvideo && state) {
+               if (!term->in_vbell ||
+                   (term->rvbell_startpoint - term->vbell_startpoint <
+                    VBELL_TIMEOUT))
+                   term->vbell_startpoint = term->rvbell_startpoint;
+               term->in_vbell = TRUE; /* may clear rvideo but set in_vbell */
+           } else if (!term->rvideo && state) {
                /* This is an ON, so we notice the time and save it. */
-               rvbell_startpoint = ticks;
+               term->rvbell_startpoint = ticks;
            }
-           rvideo = state;
-           seen_disp_event = TRUE;
+           term->rvideo = state;
+           term->seen_disp_event = TRUE;
            if (state)
-               term_update();
+               term_update(term);
            break;
          case 6:                      /* DEC origin mode */
-           dec_om = state;
+           term->dec_om = state;
            break;
          case 7:                      /* auto wrap */
-           wrap = state;
+           term->wrap = state;
            break;
          case 8:                      /* auto key repeat */
-           repeat_off = !state;
+           term->repeat_off = !state;
            break;
          case 10:                     /* set local edit mode */
-           term_editing = state;
+           term->term_editing = state;
            ldisc_send(NULL, 0, 0);    /* cause ldisc to notice changes */
            break;
          case 25:                     /* enable/disable cursor */
            compatibility2(OTHER, VT220);
-           cursor_on = state;
-           seen_disp_event = TRUE;
+           term->cursor_on = state;
+           term->seen_disp_event = TRUE;
            break;
          case 47:                     /* alternate screen */
            compatibility(OTHER);
-           deselect();
-           swap_screen(cfg.no_alt_screen ? 0 : state, FALSE, FALSE);
-           disptop = 0;
+           deselect(term);
+           swap_screen(term, cfg.no_alt_screen ? 0 : state, FALSE, FALSE);
+           term->disptop = 0;
            break;
          case 1000:                   /* xterm mouse 1 */
-           xterm_mouse = state ? 1 : 0;
+           term->xterm_mouse = state ? 1 : 0;
            set_raw_mouse_mode(state);
            break;
          case 1002:                   /* xterm mouse 2 */
-           xterm_mouse = state ? 2 : 0;
+           term->xterm_mouse = state ? 2 : 0;
            set_raw_mouse_mode(state);
            break;
          case 1047:                   /* alternate screen */
            compatibility(OTHER);
-           deselect();
-           swap_screen(cfg.no_alt_screen ? 0 : state, TRUE, TRUE);
-           disptop = 0;
+           deselect(term);
+           swap_screen(term, cfg.no_alt_screen ? 0 : state, TRUE, TRUE);
+           term->disptop = 0;
            break;
          case 1048:                   /* save/restore cursor */
-           save_cursor(state);
-           if (!state) seen_disp_event = TRUE;
+           save_cursor(term, state);
+           if (!state) term->seen_disp_event = TRUE;
            break;
          case 1049:                   /* cursor & alternate screen */
            if (state)
-               save_cursor(state);
-           if (!state) seen_disp_event = TRUE;
+               save_cursor(term, state);
+           if (!state) term->seen_disp_event = TRUE;
            compatibility(OTHER);
-           deselect();
-           swap_screen(cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
+           deselect(term);
+           swap_screen(term, cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
            if (!state)
-               save_cursor(state);
-           disptop = 0;
+               save_cursor(term, state);
+           term->disptop = 0;
            break;
     } else
        switch (mode) {
          case 4:                      /* set insert mode */
            compatibility(VT102);
-           insert = state;
+           term->insert = state;
            break;
          case 12:                     /* set echo mode */
-           term_echoing = !state;
+           term->term_echoing = !state;
            ldisc_send(NULL, 0, 0);    /* cause ldisc to notice changes */
            break;
          case 20:                     /* Return sends ... */
-           cr_lf_return = state;
+           term->cr_lf_return = state;
            break;
          case 34:                     /* Make cursor BIG */
            compatibility2(OTHER, VT220);
-           big_cursor = !state;
+           term->big_cursor = !state;
        }
 }
 
 /*
  * Process an OSC sequence: set window title or icon name.
  */
-static void do_osc(void)
+static void do_osc(Terminal *term)
 {
-    if (osc_w) {
-       while (osc_strlen--)
-           wordness[(unsigned char) osc_string[osc_strlen]] = esc_args[0];
+    if (term->osc_w) {
+       while (term->osc_strlen--)
+           term->wordness[(unsigned char)
+               term->osc_string[term->osc_strlen]] = term->esc_args[0];
     } else {
-       osc_string[osc_strlen] = '\0';
-       switch (esc_args[0]) {
+       term->osc_string[term->osc_strlen] = '\0';
+       switch (term->esc_args[0]) {
          case 0:
          case 1:
            if (!cfg.no_remote_wintitle)
-               set_icon(osc_string);
-           if (esc_args[0] == 1)
+               set_icon(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(osc_string);
+               set_title(term->osc_string);
            break;
        }
     }
@@ -1089,48 +976,48 @@ static void do_osc(void)
 /*
  * ANSI printing routines.
  */
-static void term_print_setup(void)
+static void term_print_setup(Terminal *term)
 {
-    bufchain_clear(&printer_buf);
-    print_job = printer_start_job(cfg.printer);
+    bufchain_clear(&term->printer_buf);
+    term->print_job = printer_start_job(cfg.printer);
 }
-static void term_print_flush(void)
+static void term_print_flush(Terminal *term)
 {
     void *data;
     int len;
     int size;
-    while ((size = bufchain_size(&printer_buf)) > 5) {
-       bufchain_prefix(&printer_buf, &data, &len);
+    while ((size = bufchain_size(&term->printer_buf)) > 5) {
+       bufchain_prefix(&term->printer_buf, &data, &len);
        if (len > size-5)
            len = size-5;
-       printer_job_data(print_job, data, len);
-       bufchain_consume(&printer_buf, len);
+       printer_job_data(term->print_job, data, len);
+       bufchain_consume(&term->printer_buf, len);
     }
 }
-static void term_print_finish(void)
+static void term_print_finish(Terminal *term)
 {
     void *data;
     int len, size;
     char c;
 
-    if (!printing && !only_printing)
+    if (!term->printing && !term->only_printing)
        return;                        /* we need do nothing */
 
-    term_print_flush();
-    while ((size = bufchain_size(&printer_buf)) > 0) {
-       bufchain_prefix(&printer_buf, &data, &len);
+    term_print_flush(term);
+    while ((size = bufchain_size(&term->printer_buf)) > 0) {
+       bufchain_prefix(&term->printer_buf, &data, &len);
        c = *(char *)data;
        if (c == '\033' || c == '\233') {
-           bufchain_consume(&printer_buf, size);
+           bufchain_consume(&term->printer_buf, size);
            break;
        } else {
-           printer_job_data(print_job, &c, 1);
-           bufchain_consume(&printer_buf, 1);
+           printer_job_data(term->print_job, &c, 1);
+           bufchain_consume(&term->printer_buf, 1);
        }
     }
-    printer_finish_job(print_job);
-    print_job = NULL;
-    printing = only_printing = FALSE;
+    printer_finish_job(term->print_job);
+    term->print_job = NULL;
+    term->printing = term->only_printing = FALSE;
 }
 
 /*
@@ -1138,7 +1025,7 @@ static void term_print_finish(void)
  * in-memory display. There's a big state machine in here to
  * process escape sequences...
  */
-void term_out(void)
+void term_out(Terminal *term)
 {
     int c, unget;
     unsigned char localbuf[256], *chars;
@@ -1147,15 +1034,15 @@ void term_out(void)
     unget = -1;
 
     chars = NULL;                     /* placate compiler warnings */
-    while (nchars > 0 || bufchain_size(&inbuf) > 0) {
+    while (nchars > 0 || bufchain_size(&term->inbuf) > 0) {
        if (unget == -1) {
            if (nchars == 0) {
                void *ret;
-               bufchain_prefix(&inbuf, &ret, &nchars);
+               bufchain_prefix(&term->inbuf, &ret, &nchars);
                if (nchars > sizeof(localbuf))
                    nchars = sizeof(localbuf);
                memcpy(localbuf, ret, nchars);
-               bufchain_consume(&inbuf, nchars);
+               bufchain_consume(&term->inbuf, nchars);
                chars = localbuf;
                assert(chars != NULL);
            }
@@ -1182,38 +1069,38 @@ void term_out(void)
         * If we're printing, add the character to the printer
         * buffer.
         */
-       if (printing) {
-           bufchain_add(&printer_buf, &c, 1);
+       if (term->printing) {
+           bufchain_add(&term->printer_buf, &c, 1);
 
            /*
             * If we're in print-only mode, we use a much simpler
             * state machine designed only to recognise the ESC[4i
             * termination sequence.
             */
-           if (only_printing) {
+           if (term->only_printing) {
                if (c == '\033')
-                   print_state = 1;
+                   term->print_state = 1;
                else if (c == (unsigned char)'\233')
-                   print_state = 2;
-               else if (c == '[' && print_state == 1)
-                   print_state = 2;
-               else if (c == '4' && print_state == 2)
-                   print_state = 3;
-               else if (c == 'i' && print_state == 3)
-                   print_state = 4;
+                   term->print_state = 2;
+               else if (c == '[' && term->print_state == 1)
+                   term->print_state = 2;
+               else if (c == '4' && term->print_state == 2)
+                   term->print_state = 3;
+               else if (c == 'i' && term->print_state == 3)
+                   term->print_state = 4;
                else
-                   print_state = 0;
-               if (print_state == 4) {
-                   term_print_finish();
+                   term->print_state = 0;
+               if (term->print_state == 4) {
+                   term_print_finish(term);
                }
                continue;
            }
        }
 
        /* First see about all those translations. */
-       if (termstate == TOPLEVEL) {
-           if (in_utf)
-               switch (utf_state) {
+       if (term->termstate == TOPLEVEL) {
+           if (in_utf(term))
+               switch (term->utf_state) {
                  case 0:
                    if (c < 0x80) {
                        /* UTF-8 must be stateless so we ignore iso2022. */
@@ -1222,20 +1109,20 @@ void term_out(void)
                        else c = ((unsigned char)c) | ATTR_ASCII;
                        break;
                    } else if ((c & 0xe0) == 0xc0) {
-                       utf_size = utf_state = 1;
-                       utf_char = (c & 0x1f);
+                       term->utf_size = term->utf_state = 1;
+                       term->utf_char = (c & 0x1f);
                    } else if ((c & 0xf0) == 0xe0) {
-                       utf_size = utf_state = 2;
-                       utf_char = (c & 0x0f);
+                       term->utf_size = term->utf_state = 2;
+                       term->utf_char = (c & 0x0f);
                    } else if ((c & 0xf8) == 0xf0) {
-                       utf_size = utf_state = 3;
-                       utf_char = (c & 0x07);
+                       term->utf_size = term->utf_state = 3;
+                       term->utf_char = (c & 0x07);
                    } else if ((c & 0xfc) == 0xf8) {
-                       utf_size = utf_state = 4;
-                       utf_char = (c & 0x03);
+                       term->utf_size = term->utf_state = 4;
+                       term->utf_char = (c & 0x03);
                    } else if ((c & 0xfe) == 0xfc) {
-                       utf_size = utf_state = 5;
-                       utf_char = (c & 0x01);
+                       term->utf_size = term->utf_state = 5;
+                       term->utf_char = (c & 0x01);
                    } else {
                        c = UCSERR;
                        break;
@@ -1249,21 +1136,21 @@ void term_out(void)
                    if ((c & 0xC0) != 0x80) {
                        unget = c;
                        c = UCSERR;
-                       utf_state = 0;
+                       term->utf_state = 0;
                        break;
                    }
-                   utf_char = (utf_char << 6) | (c & 0x3f);
-                   if (--utf_state)
+                   term->utf_char = (term->utf_char << 6) | (c & 0x3f);
+                   if (--term->utf_state)
                        continue;
 
-                   c = utf_char;
+                   c = term->utf_char;
 
                    /* Is somebody trying to be evil! */
                    if (c < 0x80 ||
-                       (c < 0x800 && utf_size >= 2) ||
-                       (c < 0x10000 && utf_size >= 3) ||
-                       (c < 0x200000 && utf_size >= 4) ||
-                       (c < 0x4000000 && utf_size >= 5))
+                       (c < 0x800 && term->utf_size >= 2) ||
+                       (c < 0x10000 && term->utf_size >= 3) ||
+                       (c < 0x200000 && term->utf_size >= 4) ||
+                       (c < 0x4000000 && term->utf_size >= 5))
                        c = UCSERR;
 
                    /* Unicode line separator and paragraph separator are CR-LF */
@@ -1301,13 +1188,13 @@ void term_out(void)
                    break;
            }
            /* Are we in the nasty ACS mode? Note: no sco in utf mode. */
-           else if(sco_acs && 
+           else if(term->sco_acs && 
                    (c!='\033' && c!='\n' && c!='\r' && c!='\b'))
            {
-              if (sco_acs == 2) c ^= 0x80;
+              if (term->sco_acs == 2) c ^= 0x80;
               c |= ATTR_SCOACS;
            } else {
-               switch (cset_attr[cset]) {
+               switch (term->cset_attr[term->cset]) {
                    /* 
                     * Linedraw characters are different from 'ESC ( B'
                     * only for a small range. For ones outside that
@@ -1341,24 +1228,24 @@ void term_out(void)
        }
 
        /* How about C1 controls ? */
-       if ((c & -32) == 0x80 && termstate < DO_CTRLS && !vt52_mode &&
-           has_compat(VT220)) {
-           termstate = SEEN_ESC;
-           esc_query = FALSE;
+       if ((c & -32) == 0x80 && term->termstate < DO_CTRLS &&
+           !term->vt52_mode && has_compat(VT220)) {
+           term->termstate = SEEN_ESC;
+           term->esc_query = FALSE;
            c = '@' + (c & 0x1F);
        }
 
        /* Or the GL control. */
-       if (c == '\177' && termstate < DO_CTRLS && has_compat(OTHER)) {
-           if (curs.x && !wrapnext)
-               curs.x--;
-           wrapnext = FALSE;
+       if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) {
+           if (term->curs.x && !term->wrapnext)
+               term->curs.x--;
+           term->wrapnext = FALSE;
            fix_cpos;
            if (!cfg.no_dbackspace)    /* destructive bksp might be disabled */
-               *cpos = (' ' | curr_attr | ATTR_ASCII);
+               *term->cpos = (' ' | term->curr_attr | ATTR_ASCII);
        } else
            /* Or normal C0 controls. */
-       if ((c & -32) == 0 && termstate < DO_CTRLS) {
+       if ((c & -32) == 0 && term->termstate < DO_CTRLS) {
            switch (c) {
              case '\005':             /* terminal type query */
                /* Strictly speaking this is VT100 but a VT100 defaults to
@@ -1398,168 +1285,172 @@ void term_out(void)
 
                    ticks = GETTICKCOUNT();
 
-                   if (!beep_overloaded) {
+                   if (!term->beep_overloaded) {
                        newbeep = smalloc(sizeof(struct beeptime));
                        newbeep->ticks = ticks;
                        newbeep->next = NULL;
-                       if (!beephead)
-                           beephead = newbeep;
+                       if (!term->beephead)
+                           term->beephead = newbeep;
                        else
-                           beeptail->next = newbeep;
-                       beeptail = newbeep;
-                       nbeeps++;
+                           term->beeptail->next = newbeep;
+                       term->beeptail = newbeep;
+                       term->nbeeps++;
                    }
 
                    /*
                     * Throw out any beeps that happened more than
                     * t seconds ago.
                     */
-                   while (beephead &&
-                          beephead->ticks < ticks - cfg.bellovl_t) {
-                       struct beeptime *tmp = beephead;
-                       beephead = tmp->next;
+                   while (term->beephead &&
+                          term->beephead->ticks < ticks - cfg.bellovl_t) {
+                       struct beeptime *tmp = term->beephead;
+                       term->beephead = tmp->next;
                        sfree(tmp);
-                       if (!beephead)
-                           beeptail = NULL;
-                       nbeeps--;
+                       if (!term->beephead)
+                           term->beeptail = NULL;
+                       term->nbeeps--;
                    }
 
-                   if (cfg.bellovl && beep_overloaded &&
-                       ticks - lastbeep >= (unsigned)cfg.bellovl_s) {
+                   if (cfg.bellovl && term->beep_overloaded &&
+                       ticks - term->lastbeep >= (unsigned)cfg.bellovl_s) {
                        /*
                         * If we're currently overloaded and the
                         * last beep was more than s seconds ago,
                         * leave overload mode.
                         */
-                       beep_overloaded = FALSE;
-                   } else if (cfg.bellovl && !beep_overloaded &&
-                              nbeeps >= cfg.bellovl_n) {
+                       term->beep_overloaded = FALSE;
+                   } else if (cfg.bellovl && !term->beep_overloaded &&
+                              term->nbeeps >= cfg.bellovl_n) {
                        /*
                         * Now, if we have n or more beeps
                         * remaining in the queue, go into overload
                         * mode.
                         */
-                       beep_overloaded = TRUE;
+                       term->beep_overloaded = TRUE;
                    }
-                   lastbeep = ticks;
+                   term->lastbeep = ticks;
 
                    /*
                     * Perform an actual beep if we're not overloaded.
                     */
-                   if (!cfg.bellovl || !beep_overloaded) {
+                   if (!cfg.bellovl || !term->beep_overloaded) {
                        if (cfg.beep == BELL_VISUAL) {
-                           in_vbell = TRUE;
-                           vbell_startpoint = ticks;
-                           term_update();
+                           term->in_vbell = TRUE;
+                           term->vbell_startpoint = ticks;
+                           term_update(term);
                        } else
                            beep(cfg.beep);
                    }
-                   disptop = 0;
+                   term->disptop = 0;
                }
                break;
              case '\b':
-               if (curs.x == 0 && (curs.y == 0 || wrap == 0));
-               else if (curs.x == 0 && curs.y > 0)
-                   curs.x = cols - 1, curs.y--;
-               else if (wrapnext)
-                   wrapnext = FALSE;
+               if (term->curs.x == 0 &&
+                   (term->curs.y == 0 || term->wrap == 0))
+                   /* do nothing */ ;
+               else if (term->curs.x == 0 && term->curs.y > 0)
+                   term->curs.x = term->cols - 1, term->curs.y--;
+               else if (term->wrapnext)
+                   term->wrapnext = FALSE;
                else
-                   curs.x--;
+                   term->curs.x--;
                fix_cpos;
-               seen_disp_event = TRUE;
+               term->seen_disp_event = TRUE;
                break;
              case '\016':
                compatibility(VT100);
-               cset = 1;
+               term->cset = 1;
                break;
              case '\017':
                compatibility(VT100);
-               cset = 0;
+               term->cset = 0;
                break;
              case '\033':
-               if (vt52_mode)
-                   termstate = VT52_ESC;
+               if (term->vt52_mode)
+                   term->termstate = VT52_ESC;
                else {
                    compatibility(ANSIMIN);
-                   termstate = SEEN_ESC;
-                   esc_query = FALSE;
+                   term->termstate = SEEN_ESC;
+                   term->esc_query = FALSE;
                }
                break;
              case '\r':
-               curs.x = 0;
-               wrapnext = FALSE;
+               term->curs.x = 0;
+               term->wrapnext = FALSE;
                fix_cpos;
-               seen_disp_event = TRUE;
-               paste_hold = 0;
+               term->seen_disp_event = TRUE;
+               term->paste_hold = 0;
                logtraffic((unsigned char) c, LGTYP_ASCII);
                break;
              case '\014':
                if (has_compat(SCOANSI)) {
-                   move(0, 0, 0);
-                   erase_lots(FALSE, FALSE, TRUE);
-                   disptop = 0;
-                   wrapnext = FALSE;
-                   seen_disp_event = 1;
+                   move(term, 0, 0, 0);
+                   erase_lots(term, FALSE, FALSE, TRUE);
+                   term->disptop = 0;
+                   term->wrapnext = FALSE;
+                   term->seen_disp_event = 1;
                    break;
                }
              case '\013':
                compatibility(VT100);
              case '\n':
-               if (curs.y == marg_b)
-                   scroll(marg_t, marg_b, 1, TRUE);
-               else if (curs.y < rows - 1)
-                   curs.y++;
+               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)
-                   curs.x = 0;
+                   term->curs.x = 0;
                fix_cpos;
-               wrapnext = FALSE;
-               seen_disp_event = 1;
-               paste_hold = 0;
+               term->wrapnext = FALSE;
+               term->seen_disp_event = 1;
+               term->paste_hold = 0;
                logtraffic((unsigned char) c, LGTYP_ASCII);
                break;
              case '\t':
                {
-                   pos old_curs = curs;
-                   unsigned long *ldata = lineptr(curs.y);
+                   pos old_curs = term->curs;
+                   unsigned long *ldata = lineptr(term->curs.y);
 
                    do {
-                       curs.x++;
-                   } while (curs.x < cols - 1 && !tabs[curs.x]);
+                       term->curs.x++;
+                   } while (term->curs.x < term->cols - 1 &&
+                            !term->tabs[term->curs.x]);
 
-                   if ((ldata[cols] & LATTR_MODE) != LATTR_NORM) {
-                       if (curs.x >= cols / 2)
-                           curs.x = cols / 2 - 1;
+                   if ((ldata[term->cols] & LATTR_MODE) != LATTR_NORM) {
+                       if (term->curs.x >= term->cols / 2)
+                           term->curs.x = term->cols / 2 - 1;
                    } else {
-                       if (curs.x >= cols)
-                           curs.x = cols - 1;
+                       if (term->curs.x >= term->cols)
+                           term->curs.x = term->cols - 1;
                    }
 
                    fix_cpos;
-                   check_selection(old_curs, curs);
+                   check_selection(term, old_curs, term->curs);
                }
-               seen_disp_event = TRUE;
+               term->seen_disp_event = TRUE;
                break;
            }
        } else
-           switch (termstate) {
+           switch (term->termstate) {
              case TOPLEVEL:
-               /* Only graphic characters get this far, ctrls are stripped above */
-               if (wrapnext && wrap) {
-                   cpos[1] |= LATTR_WRAPPED;
-                   if (curs.y == marg_b)
-                       scroll(marg_t, marg_b, 1, TRUE);
-                   else if (curs.y < rows - 1)
-                       curs.y++;
-                   curs.x = 0;
+               /* Only graphic characters get this far;
+                * ctrls are stripped above */
+               if (term->wrapnext && term->wrap) {
+                   term->cpos[1] |= LATTR_WRAPPED;
+                   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++;
+                   term->curs.x = 0;
                    fix_cpos;
-                   wrapnext = FALSE;
+                   term->wrapnext = FALSE;
                }
-               if (insert)
-                   insch(1);
-               if (selstate != NO_SELECTION) {
-                   pos cursplus = curs;
+               if (term->insert)
+                   insch(term, 1);
+               if (term->selstate != NO_SELECTION) {
+                   pos cursplus = term->curs;
                    incpos(cursplus);
-                   check_selection(curs, cursplus);
+                   check_selection(term, term->curs, cursplus);
                }
                if ((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0)
                    logtraffic((unsigned char) c, LGTYP_ASCII);
@@ -1572,42 +1463,43 @@ void term_out(void)
                        width = wcwidth((wchar_t) c);
                    switch (width) {
                      case 2:
-                       *cpos++ = c | curr_attr;
-                       if (++curs.x == cols) {
-                           *cpos |= LATTR_WRAPPED;
-                           if (curs.y == marg_b)
-                               scroll(marg_t, marg_b, 1, TRUE);
-                           else if (curs.y < rows - 1)
-                               curs.y++;
-                           curs.x = 0;
+                       *term->cpos++ = c | term->curr_attr;
+                       if (++term->curs.x == term->cols) {
+                           *term->cpos |= LATTR_WRAPPED;
+                           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++;
+                           term->curs.x = 0;
                            fix_cpos;
                        }
-                       *cpos++ = UCSWIDE | curr_attr;
+                       *term->cpos++ = UCSWIDE | term->curr_attr;
                        break;
                      case 1:
-                       *cpos++ = c | curr_attr;
+                       *term->cpos++ = c | term->curr_attr;
                        break;
                      default:
                        continue;
                    }
                }
-               curs.x++;
-               if (curs.x == cols) {
-                   cpos--;
-                   curs.x--;
-                   wrapnext = TRUE;
-                   if (wrap && vt52_mode) {
-                       cpos[1] |= LATTR_WRAPPED;
-                       if (curs.y == marg_b)
-                           scroll(marg_t, marg_b, 1, TRUE);
-                       else if (curs.y < rows - 1)
-                           curs.y++;
-                       curs.x = 0;
+               term->curs.x++;
+               if (term->curs.x == term->cols) {
+                   term->cpos--;
+                   term->curs.x--;
+                   term->wrapnext = TRUE;
+                   if (term->wrap && term->vt52_mode) {
+                       term->cpos[1] |= LATTR_WRAPPED;
+                       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++;
+                       term->curs.x = 0;
                        fix_cpos;
-                       wrapnext = FALSE;
+                       term->wrapnext = FALSE;
                    }
                }
-               seen_disp_event = 1;
+               term->seen_disp_event = 1;
                break;
 
              case OSC_MAYBE_ST:
@@ -1617,100 +1509,101 @@ void term_out(void)
                 * and _if_ we see a backslash, we process it.
                 */
                if (c == '\\') {
-                   do_osc();
-                   termstate = TOPLEVEL;
+                   do_osc(term);
+                   term->termstate = TOPLEVEL;
                    break;
                }
                /* else fall through */
              case SEEN_ESC:
                if (c >= ' ' && c <= '/') {
-                   if (esc_query)
-                       esc_query = -1;
+                   if (term->esc_query)
+                       term->esc_query = -1;
                    else
-                       esc_query = c;
+                       term->esc_query = c;
                    break;
                }
-               termstate = TOPLEVEL;
-               switch (ANSI(c, esc_query)) {
+               term->termstate = TOPLEVEL;
+               switch (ANSI(c, term->esc_query)) {
                  case '[':            /* enter CSI mode */
-                   termstate = SEEN_CSI;
-                   esc_nargs = 1;
-                   esc_args[0] = ARG_DEFAULT;
-                   esc_query = FALSE;
+                   term->termstate = SEEN_CSI;
+                   term->esc_nargs = 1;
+                   term->esc_args[0] = ARG_DEFAULT;
+                   term->esc_query = FALSE;
                    break;
                  case ']':            /* xterm escape sequences */
                    /* Compatibility is nasty here, xterm, linux, decterm yuk! */
                    compatibility(OTHER);
-                   termstate = SEEN_OSC;
-                   esc_args[0] = 0;
+                   term->termstate = SEEN_OSC;
+                   term->esc_args[0] = 0;
                    break;
                  case '7':            /* save cursor */
                    compatibility(VT100);
-                   save_cursor(TRUE);
+                   save_cursor(term, TRUE);
                    break;
                  case '8':            /* restore cursor */
                    compatibility(VT100);
-                   save_cursor(FALSE);
-                   seen_disp_event = TRUE;
+                   save_cursor(term, FALSE);
+                   term->seen_disp_event = TRUE;
                    break;
                  case '=':
                    compatibility(VT100);
-                   app_keypad_keys = TRUE;
+                   term->app_keypad_keys = TRUE;
                    break;
                  case '>':
                    compatibility(VT100);
-                   app_keypad_keys = FALSE;
+                   term->app_keypad_keys = FALSE;
                    break;
                  case 'D':            /* exactly equivalent to LF */
                    compatibility(VT100);
-                   if (curs.y == marg_b)
-                       scroll(marg_t, marg_b, 1, TRUE);
-                   else if (curs.y < rows - 1)
-                       curs.y++;
+                   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++;
                    fix_cpos;
-                   wrapnext = FALSE;
-                   seen_disp_event = TRUE;
+                   term->wrapnext = FALSE;
+                   term->seen_disp_event = TRUE;
                    break;
                  case 'E':            /* exactly equivalent to CR-LF */
                    compatibility(VT100);
-                   curs.x = 0;
-                   if (curs.y == marg_b)
-                       scroll(marg_t, marg_b, 1, TRUE);
-                   else if (curs.y < rows - 1)
-                       curs.y++;
+                   term->curs.x = 0;
+                   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++;
                    fix_cpos;
-                   wrapnext = FALSE;
-                   seen_disp_event = TRUE;
+                   term->wrapnext = FALSE;
+                   term->seen_disp_event = TRUE;
                    break;
                  case 'M':            /* reverse index - backwards LF */
                    compatibility(VT100);
-                   if (curs.y == marg_t)
-                       scroll(marg_t, marg_b, -1, TRUE);
-                   else if (curs.y > 0)
-                       curs.y--;
+                   if (term->curs.y == term->marg_t)
+                       scroll(term, term->marg_t, term->marg_b, -1, TRUE);
+                   else if (term->curs.y > 0)
+                       term->curs.y--;
                    fix_cpos;
-                   wrapnext = FALSE;
-                   seen_disp_event = TRUE;
+                   term->wrapnext = FALSE;
+                   term->seen_disp_event = TRUE;
                    break;
                  case 'Z':            /* terminal type query */
                    compatibility(VT100);
-                   ldisc_send(id_string, strlen(id_string), 0);
+                   ldisc_send(term->id_string, strlen(term->id_string), 0);
                    break;
                  case 'c':            /* restore power-on settings */
                    compatibility(VT100);
-                   power_on();
-                   if (reset_132) {
+                   power_on(term);
+                   ldisc_send(NULL, 0, 0);/* cause ldisc to notice changes */
+                   if (term->reset_132) {
                        if (!cfg.no_remote_resize)
-                           request_resize(80, rows);
-                       reset_132 = 0;
+                           request_resize(80, term->rows);
+                       term->reset_132 = 0;
                    }
                    fix_cpos;
-                   disptop = 0;
-                   seen_disp_event = TRUE;
+                   term->disptop = 0;
+                   term->seen_disp_event = TRUE;
                    break;
                  case 'H':            /* set a tab */
                    compatibility(VT100);
-                   tabs[curs.x] = TRUE;
+                   term->tabs[term->curs.x] = TRUE;
                    break;
 
                  case ANSI('8', '#'):  /* ESC # 8 fills screen with Es :-) */
@@ -1720,18 +1613,18 @@ void term_out(void)
                        int i, j;
                        pos scrtop, scrbot;
 
-                       for (i = 0; i < rows; i++) {
+                       for (i = 0; i < term->rows; i++) {
                            ldata = lineptr(i);
-                           for (j = 0; j < cols; j++)
+                           for (j = 0; j < term->cols; j++)
                                ldata[j] = ATTR_DEFAULT | 'E';
-                           ldata[cols] = 0;
+                           ldata[term->cols] = 0;
                        }
-                       disptop = 0;
-                       seen_disp_event = TRUE;
+                       term->disptop = 0;
+                       term->seen_disp_event = TRUE;
                        scrtop.x = scrtop.y = 0;
                        scrbot.x = 0;
-                       scrbot.y = rows;
-                       check_selection(scrtop, scrbot);
+                       scrbot.y = term->rows;
+                       check_selection(term, scrtop, scrbot);
                    }
                    break;
 
@@ -1743,7 +1636,7 @@ void term_out(void)
                    {
                        unsigned long nlattr;
                        unsigned long *ldata;
-                       switch (ANSI(c, esc_query)) {
+                       switch (ANSI(c, term->esc_query)) {
                          case ANSI('3', '#'):
                            nlattr = LATTR_TOP;
                            break;
@@ -1757,101 +1650,103 @@ void term_out(void)
                            nlattr = LATTR_WIDE;
                            break;
                        }
-                       ldata = lineptr(curs.y);
-                       ldata[cols] &= ~LATTR_MODE;
-                       ldata[cols] |= nlattr;
+                       ldata = lineptr(term->curs.y);
+                       ldata[term->cols] &= ~LATTR_MODE;
+                       ldata[term->cols] |= nlattr;
                    }
                    break;
 
                  case ANSI('A', '('):
                    compatibility(VT100);
                    if (!cfg.no_remote_charset)
-                       cset_attr[0] = ATTR_GBCHR;
+                       term->cset_attr[0] = ATTR_GBCHR;
                    break;
                  case ANSI('B', '('):
                    compatibility(VT100);
                    if (!cfg.no_remote_charset)
-                       cset_attr[0] = ATTR_ASCII;
+                       term->cset_attr[0] = ATTR_ASCII;
                    break;
                  case ANSI('0', '('):
                    compatibility(VT100);
                    if (!cfg.no_remote_charset)
-                       cset_attr[0] = ATTR_LINEDRW;
+                       term->cset_attr[0] = ATTR_LINEDRW;
                    break;
                  case ANSI('U', '('): 
                    compatibility(OTHER);
                    if (!cfg.no_remote_charset)
-                       cset_attr[0] = ATTR_SCOACS; 
+                       term->cset_attr[0] = ATTR_SCOACS; 
                    break;
 
                  case ANSI('A', ')'):
                    compatibility(VT100);
                    if (!cfg.no_remote_charset)
-                       cset_attr[1] = ATTR_GBCHR;
+                       term->cset_attr[1] = ATTR_GBCHR;
                    break;
                  case ANSI('B', ')'):
                    compatibility(VT100);
                    if (!cfg.no_remote_charset)
-                       cset_attr[1] = ATTR_ASCII;
+                       term->cset_attr[1] = ATTR_ASCII;
                    break;
                  case ANSI('0', ')'):
                    compatibility(VT100);
                    if (!cfg.no_remote_charset)
-                       cset_attr[1] = ATTR_LINEDRW;
+                       term->cset_attr[1] = ATTR_LINEDRW;
                    break;
                  case ANSI('U', ')'): 
                    compatibility(OTHER);
                    if (!cfg.no_remote_charset)
-                       cset_attr[1] = ATTR_SCOACS; 
+                       term->cset_attr[1] = ATTR_SCOACS; 
                    break;
 
                  case ANSI('8', '%'):  /* Old Linux code */
                  case ANSI('G', '%'):
                    compatibility(OTHER);
                    if (!cfg.no_remote_charset)
-                       utf = 1;
+                       term->utf = 1;
                    break;
                  case ANSI('@', '%'):
                    compatibility(OTHER);
                    if (!cfg.no_remote_charset)
-                       utf = 0;
+                       term->utf = 0;
                    break;
                }
                break;
              case SEEN_CSI:
-               termstate = TOPLEVEL;  /* default */
+               term->termstate = TOPLEVEL;  /* default */
                if (isdigit(c)) {
-                   if (esc_nargs <= ARGS_MAX) {
-                       if (esc_args[esc_nargs - 1] == ARG_DEFAULT)
-                           esc_args[esc_nargs - 1] = 0;
-                       esc_args[esc_nargs - 1] =
-                           10 * esc_args[esc_nargs - 1] + c - '0';
+                   if (term->esc_nargs <= ARGS_MAX) {
+                       if (term->esc_args[term->esc_nargs - 1] == ARG_DEFAULT)
+                           term->esc_args[term->esc_nargs - 1] = 0;
+                       term->esc_args[term->esc_nargs - 1] =
+                           10 * term->esc_args[term->esc_nargs - 1] + c - '0';
                    }
-                   termstate = SEEN_CSI;
+                   term->termstate = SEEN_CSI;
                } else if (c == ';') {
-                   if (++esc_nargs <= ARGS_MAX)
-                       esc_args[esc_nargs - 1] = ARG_DEFAULT;
-                   termstate = SEEN_CSI;
+                   if (++term->esc_nargs <= ARGS_MAX)
+                       term->esc_args[term->esc_nargs - 1] = ARG_DEFAULT;
+                   term->termstate = SEEN_CSI;
                } else if (c < '@') {
-                   if (esc_query)
-                       esc_query = -1;
+                   if (term->esc_query)
+                       term->esc_query = -1;
                    else if (c == '?')
-                       esc_query = TRUE;
+                       term->esc_query = TRUE;
                    else
-                       esc_query = c;
-                   termstate = SEEN_CSI;
+                       term->esc_query = c;
+                   term->termstate = SEEN_CSI;
                } else
-                   switch (ANSI(c, esc_query)) {
+                   switch (ANSI(c, term->esc_query)) {
                      case 'A':       /* move up N lines */
-                       move(curs.x, curs.y - def(esc_args[0], 1), 1);
-                       seen_disp_event = TRUE;
+                       move(term, term->curs.x,
+                            term->curs.y - def(term->esc_args[0], 1), 1);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'e':       /* move down N lines */
                        compatibility(ANSI);
                        /* FALLTHROUGH */
                      case 'B':
-                       move(curs.x, curs.y + def(esc_args[0], 1), 1);
-                       seen_disp_event = TRUE;
+                       move(term, term->curs.x,
+                            term->curs.y + def(term->esc_args[0], 1), 1);
+                       term->seen_disp_event = TRUE;
                        break;
                      case ANSI('c', '>'):      /* report xterm version */
                        compatibility(OTHER);
@@ -1863,105 +1758,112 @@ void term_out(void)
                        compatibility(ANSI);
                        /* FALLTHROUGH */
                      case 'C':
-                       move(curs.x + def(esc_args[0], 1), curs.y, 1);
-                       seen_disp_event = TRUE;
+                       move(term, term->curs.x + def(term->esc_args[0], 1),
+                            term->curs.y, 1);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'D':       /* move left N cols */
-                       move(curs.x - def(esc_args[0], 1), curs.y, 1);
-                       seen_disp_event = TRUE;
+                       move(term, term->curs.x - def(term->esc_args[0], 1),
+                            term->curs.y, 1);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'E':       /* move down N lines and CR */
                        compatibility(ANSI);
-                       move(0, curs.y + def(esc_args[0], 1), 1);
-                       seen_disp_event = TRUE;
+                       move(term, 0,
+                            term->curs.y + def(term->esc_args[0], 1), 1);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'F':       /* move up N lines and CR */
                        compatibility(ANSI);
-                       move(0, curs.y - def(esc_args[0], 1), 1);
-                       seen_disp_event = TRUE;
+                       move(term, 0,
+                            term->curs.y - def(term->esc_args[0], 1), 1);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'G':
                      case '`':       /* set horizontal posn */
                        compatibility(ANSI);
-                       move(def(esc_args[0], 1) - 1, curs.y, 0);
-                       seen_disp_event = TRUE;
+                       move(term, def(term->esc_args[0], 1) - 1,
+                            term->curs.y, 0);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'd':       /* set vertical posn */
                        compatibility(ANSI);
-                       move(curs.x,
-                            (dec_om ? marg_t : 0) + def(esc_args[0],
-                                                        1) - 1,
-                            (dec_om ? 2 : 0));
-                       seen_disp_event = TRUE;
+                       move(term, term->curs.x,
+                            ((term->dec_om ? term->marg_t : 0) +
+                             def(term->esc_args[0], 1) - 1),
+                            (term->dec_om ? 2 : 0));
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'H':
                      case 'f':       /* set horz and vert posns at once */
-                       if (esc_nargs < 2)
-                           esc_args[1] = ARG_DEFAULT;
-                       move(def(esc_args[1], 1) - 1,
-                            (dec_om ? marg_t : 0) + def(esc_args[0],
-                                                        1) - 1,
-                            (dec_om ? 2 : 0));
-                       seen_disp_event = TRUE;
+                       if (term->esc_nargs < 2)
+                           term->esc_args[1] = ARG_DEFAULT;
+                       move(term, def(term->esc_args[1], 1) - 1,
+                            ((term->dec_om ? term->marg_t : 0) +
+                             def(term->esc_args[0], 1) - 1),
+                            (term->dec_om ? 2 : 0));
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'J':       /* erase screen or parts of it */
                        {
-                           unsigned int i = def(esc_args[0], 0) + 1;
+                           unsigned int i = def(term->esc_args[0], 0) + 1;
                            if (i > 3)
                                i = 0;
-                           erase_lots(FALSE, !!(i & 2), !!(i & 1));
+                           erase_lots(term, FALSE, !!(i & 2), !!(i & 1));
                        }
-                       disptop = 0;
-                       seen_disp_event = TRUE;
+                       term->disptop = 0;
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'K':       /* erase line or parts of it */
                        {
-                           unsigned int i = def(esc_args[0], 0) + 1;
+                           unsigned int i = def(term->esc_args[0], 0) + 1;
                            if (i > 3)
                                i = 0;
-                           erase_lots(TRUE, !!(i & 2), !!(i & 1));
+                           erase_lots(term, TRUE, !!(i & 2), !!(i & 1));
                        }
-                       seen_disp_event = TRUE;
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'L':       /* insert lines */
                        compatibility(VT102);
-                       if (curs.y <= marg_b)
-                           scroll(curs.y, marg_b, -def(esc_args[0], 1),
-                                  FALSE);
+                       if (term->curs.y <= term->marg_b)
+                           scroll(term, term->curs.y, term->marg_b,
+                                  -def(term->esc_args[0], 1), FALSE);
                        fix_cpos;
-                       seen_disp_event = TRUE;
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'M':       /* delete lines */
                        compatibility(VT102);
-                       if (curs.y <= marg_b)
-                           scroll(curs.y, marg_b, def(esc_args[0], 1),
+                       if (term->curs.y <= term->marg_b)
+                           scroll(term, term->curs.y, term->marg_b,
+                                  def(term->esc_args[0], 1),
                                   TRUE);
                        fix_cpos;
-                       seen_disp_event = TRUE;
+                       term->seen_disp_event = TRUE;
                        break;
                      case '@':       /* insert chars */
                        /* XXX VTTEST says this is vt220, vt510 manual says vt102 */
                        compatibility(VT102);
-                       insch(def(esc_args[0], 1));
-                       seen_disp_event = TRUE;
+                       insch(term, def(term->esc_args[0], 1));
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'P':       /* delete chars */
                        compatibility(VT102);
-                       insch(-def(esc_args[0], 1));
-                       seen_disp_event = TRUE;
+                       insch(term, -def(term->esc_args[0], 1));
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'c':       /* terminal type query */
                        compatibility(VT100);
                        /* This is the response for a VT102 */
-                       ldisc_send(id_string, strlen(id_string), 0);
+                       ldisc_send(term->id_string,
+                                  strlen(term->id_string), 0);
                        break;
                      case 'n':       /* cursor position query */
-                       if (esc_args[0] == 6) {
+                       if (term->esc_args[0] == 6) {
                            char buf[32];
-                           sprintf(buf, "\033[%d;%dR", curs.y + 1,
-                                   curs.x + 1);
+                           sprintf(buf, "\033[%d;%dR", term->curs.y + 1,
+                                   term->curs.x + 1);
                            ldisc_send(buf, strlen(buf), 0);
-                       } else if (esc_args[0] == 5) {
+                       } else if (term->esc_args[0] == 5) {
                            ldisc_send("\033[0n", 4, 0);
                        }
                        break;
@@ -1970,22 +1872,24 @@ void term_out(void)
                        compatibility(VT100);
                        {
                            int i;
-                           for (i = 0; i < esc_nargs; i++)
-                               toggle_mode(esc_args[i], esc_query, TRUE);
+                           for (i = 0; i < term->esc_nargs; i++)
+                               toggle_mode(term, term->esc_args[i],
+                                           term->esc_query, TRUE);
                        }
                        break;
                      case 'i':
                      case ANSI_QUE('i'):
                        compatibility(VT100);
                        {
-                           if (esc_nargs != 1) break;
-                           if (esc_args[0] == 5 && *cfg.printer) {
-                               printing = TRUE;
-                               only_printing = !esc_query;
-                               print_state = 0;
-                               term_print_setup();
-                           } else if (esc_args[0] == 4 && printing) {
-                               term_print_finish();
+                           if (term->esc_nargs != 1) break;
+                           if (term->esc_args[0] == 5 && *cfg.printer) {
+                               term->printing = TRUE;
+                               term->only_printing = !term->esc_query;
+                               term->print_state = 0;
+                               term_print_setup(term);
+                           } else if (term->esc_args[0] == 4 &&
+                                      term->printing) {
+                               term_print_finish(term);
                            }
                        }
                        break;                  
@@ -1994,126 +1898,137 @@ void term_out(void)
                        compatibility(VT100);
                        {
                            int i;
-                           for (i = 0; i < esc_nargs; i++)
-                               toggle_mode(esc_args[i], esc_query, FALSE);
+                           for (i = 0; i < term->esc_nargs; i++)
+                               toggle_mode(term, term->esc_args[i],
+                                           term->esc_query, FALSE);
                        }
                        break;
                      case 'g':       /* clear tabs */
                        compatibility(VT100);
-                       if (esc_nargs == 1) {
-                           if (esc_args[0] == 0) {
-                               tabs[curs.x] = FALSE;
-                           } else if (esc_args[0] == 3) {
+                       if (term->esc_nargs == 1) {
+                           if (term->esc_args[0] == 0) {
+                               term->tabs[term->curs.x] = FALSE;
+                           } else if (term->esc_args[0] == 3) {
                                int i;
-                               for (i = 0; i < cols; i++)
-                                   tabs[i] = FALSE;
+                               for (i = 0; i < term->cols; i++)
+                                   term->tabs[i] = FALSE;
                            }
                        }
                        break;
                      case 'r':       /* set scroll margins */
                        compatibility(VT100);
-                       if (esc_nargs <= 2) {
+                       if (term->esc_nargs <= 2) {
                            int top, bot;
-                           top = def(esc_args[0], 1) - 1;
-                           bot = (esc_nargs <= 1
-                                  || esc_args[1] ==
-                                  0 ? rows : def(esc_args[1], rows)) - 1;
-                           if (bot >= rows)
-                               bot = rows - 1;
+                           top = def(term->esc_args[0], 1) - 1;
+                           bot = (term->esc_nargs <= 1
+                                  || term->esc_args[1] == 0 ?
+                                  term->rows :
+                                  def(term->esc_args[1], term->rows)) - 1;
+                           if (bot >= term->rows)
+                               bot = term->rows - 1;
                            /* VTTEST Bug 9 - if region is less than 2 lines
                             * don't change region.
                             */
                            if (bot - top > 0) {
-                               marg_t = top;
-                               marg_b = bot;
-                               curs.x = 0;
+                               term->marg_t = top;
+                               term->marg_b = bot;
+                               term->curs.x = 0;
                                /*
                                 * I used to think the cursor should be
                                 * placed at the top of the newly marginned
                                 * area. Apparently not: VMS TPU falls over
                                 * if so.
                                 *
-                                * Well actually it should for Origin mode - RDB
+                                * Well actually it should for
+                                * Origin mode - RDB
                                 */
-                               curs.y = (dec_om ? marg_t : 0);
+                               term->curs.y = (term->dec_om ?
+                                               term->marg_t : 0);
                                fix_cpos;
-                               seen_disp_event = TRUE;
+                               term->seen_disp_event = TRUE;
                            }
                        }
                        break;
                      case 'm':       /* set graphics rendition */
                        {
                            /* 
-                            * A VT100 without the AVO only had one attribute, either
-                            * underline or reverse video depending on the cursor type,
-                            * this was selected by CSI 7m.
+                            * A VT100 without the AVO only had one
+                            * attribute, either underline or
+                            * reverse video depending on the
+                            * cursor type, this was selected by
+                            * CSI 7m.
                             *
                             * case 2:
-                            *  This is sometimes DIM, eg on the GIGI and Linux
+                            *  This is sometimes DIM, eg on the
+                            *  GIGI and Linux
                             * case 8:
                             *  This is sometimes INVIS various ANSI.
                             * case 21:
                             *  This like 22 disables BOLD, DIM and INVIS
                             *
-                            * The ANSI colours appear on any terminal that has colour
-                            * (obviously) but the interaction between sgr0 and the
-                            * colours varies but is usually related to the background
-                            * colour erase item.
-                            * The interaction between colour attributes and the mono
-                            * ones is also very implementation dependent.
+                            * The ANSI colours appear on any
+                            * terminal that has colour (obviously)
+                            * but the interaction between sgr0 and
+                            * the colours varies but is usually
+                            * related to the background colour
+                            * erase item. The interaction between
+                            * colour attributes and the mono ones
+                            * is also very implementation
+                            * dependent.
                             *
-                            * The 39 and 49 attributes are likely to be unimplemented.
+                            * The 39 and 49 attributes are likely
+                            * to be unimplemented.
                             */
                            int i;
-                           for (i = 0; i < esc_nargs; i++) {
-                               switch (def(esc_args[i], 0)) {
+                           for (i = 0; i < term->esc_nargs; i++) {
+                               switch (def(term->esc_args[i], 0)) {
                                  case 0:       /* restore defaults */
-                                   curr_attr = ATTR_DEFAULT;
+                                   term->curr_attr = ATTR_DEFAULT;
                                    break;
                                  case 1:       /* enable bold */
                                    compatibility(VT100AVO);
-                                   curr_attr |= ATTR_BOLD;
+                                   term->curr_attr |= ATTR_BOLD;
                                    break;
                                  case 21:      /* (enable double underline) */
                                    compatibility(OTHER);
                                  case 4:       /* enable underline */
                                    compatibility(VT100AVO);
-                                   curr_attr |= ATTR_UNDER;
+                                   term->curr_attr |= ATTR_UNDER;
                                    break;
                                  case 5:       /* enable blink */
                                    compatibility(VT100AVO);
-                                   curr_attr |= ATTR_BLINK;
+                                   term->curr_attr |= ATTR_BLINK;
                                    break;
                                  case 7:       /* enable reverse video */
-                                   curr_attr |= ATTR_REVERSE;
+                                   term->curr_attr |= ATTR_REVERSE;
                                    break;
                                  case 10:      /* SCO acs off */
                                    compatibility(SCOANSI);
                                    if (cfg.no_remote_charset) break;
-                                   sco_acs = 0; break;
+                                   term->sco_acs = 0; break;
                                  case 11:      /* SCO acs on */
                                    compatibility(SCOANSI);
                                    if (cfg.no_remote_charset) break;
-                                   sco_acs = 1; break;
+                                   term->sco_acs = 1; break;
                                  case 12:      /* SCO acs on flipped */
                                    compatibility(SCOANSI);
                                    if (cfg.no_remote_charset) break;
-                                   sco_acs = 2; break;
+                                   term->sco_acs = 2; break;
                                  case 22:      /* disable bold */
                                    compatibility2(OTHER, VT220);
-                                   curr_attr &= ~ATTR_BOLD;
+                                   term->curr_attr &= ~ATTR_BOLD;
                                    break;
                                  case 24:      /* disable underline */
                                    compatibility2(OTHER, VT220);
-                                   curr_attr &= ~ATTR_UNDER;
+                                   term->curr_attr &= ~ATTR_UNDER;
                                    break;
                                  case 25:      /* disable blink */
                                    compatibility2(OTHER, VT220);
-                                   curr_attr &= ~ATTR_BLINK;
+                                   term->curr_attr &= ~ATTR_BLINK;
                                    break;
                                  case 27:      /* disable reverse video */
                                    compatibility2(OTHER, VT220);
-                                   curr_attr &= ~ATTR_REVERSE;
+                                   term->curr_attr &= ~ATTR_REVERSE;
                                    break;
                                  case 30:
                                  case 31:
@@ -2124,13 +2039,13 @@ void term_out(void)
                                  case 36:
                                  case 37:
                                    /* foreground */
-                                   curr_attr &= ~ATTR_FGMASK;
-                                   curr_attr |=
-                                       (esc_args[i] - 30) << ATTR_FGSHIFT;
+                                   term->curr_attr &= ~ATTR_FGMASK;
+                                   term->curr_attr |=
+                                       (term->esc_args[i] - 30)<<ATTR_FGSHIFT;
                                    break;
                                  case 39:      /* default-foreground */
-                                   curr_attr &= ~ATTR_FGMASK;
-                                   curr_attr |= ATTR_DEFFG;
+                                   term->curr_attr &= ~ATTR_FGMASK;
+                                   term->curr_attr |= ATTR_DEFFG;
                                    break;
                                  case 40:
                                  case 41:
@@ -2141,28 +2056,29 @@ void term_out(void)
                                  case 46:
                                  case 47:
                                    /* background */
-                                   curr_attr &= ~ATTR_BGMASK;
-                                   curr_attr |=
-                                       (esc_args[i] - 40) << ATTR_BGSHIFT;
+                                   term->curr_attr &= ~ATTR_BGMASK;
+                                   term->curr_attr |=
+                                       (term->esc_args[i] - 40)<<ATTR_BGSHIFT;
                                    break;
                                  case 49:      /* default-background */
-                                   curr_attr &= ~ATTR_BGMASK;
-                                   curr_attr |= ATTR_DEFBG;
+                                   term->curr_attr &= ~ATTR_BGMASK;
+                                   term->curr_attr |= ATTR_DEFBG;
                                    break;
                                }
                            }
-                           if (use_bce)
-                               erase_char = (' ' | ATTR_ASCII |
-                                            (curr_attr & 
-                                             (ATTR_FGMASK | ATTR_BGMASK)));
+                           if (term->use_bce)
+                               term->erase_char = (' ' | ATTR_ASCII |
+                                                   (term->curr_attr & 
+                                                    (ATTR_FGMASK |
+                                                     ATTR_BGMASK)));
                        }
                        break;
                      case 's':       /* save cursor */
-                       save_cursor(TRUE);
+                       save_cursor(term, TRUE);
                        break;
                      case 'u':       /* restore cursor */
-                       save_cursor(FALSE);
-                       seen_disp_event = TRUE;
+                       save_cursor(term, FALSE);
+                       term->seen_disp_event = TRUE;
                        break;
                      case 't':       /* set page size - ie window height */
                        /*
@@ -2171,18 +2087,20 @@ void term_out(void)
                         * illegal values (eg first arg 1..9) for window changing 
                         * and reports.
                         */
-                       if (esc_nargs <= 1
-                           && (esc_args[0] < 1 || esc_args[0] >= 24)) {
+                       if (term->esc_nargs <= 1
+                           && (term->esc_args[0] < 1 ||
+                               term->esc_args[0] >= 24)) {
                            compatibility(VT340TEXT);
                            if (!cfg.no_remote_resize)
-                               request_resize(cols, def(esc_args[0], 24));
-                           deselect();
-                       } else if (esc_nargs >= 1 &&
-                                  esc_args[0] >= 1 &&
-                                  esc_args[0] < 24) {
+                               request_resize(term->cols,
+                                              def(term->esc_args[0], 24));
+                           deselect(term);
+                       } else if (term->esc_nargs >= 1 &&
+                                  term->esc_args[0] >= 1 &&
+                                  term->esc_args[0] < 24) {
                            compatibility(OTHER);
 
-                           switch (esc_args[0]) {
+                           switch (term->esc_args[0]) {
                                int x, y, len;
                                char buf[80], *p;
                              case 1:
@@ -2192,10 +2110,10 @@ void term_out(void)
                                set_iconic(TRUE);
                                break;
                              case 3:
-                               if (esc_nargs >= 3) {
+                               if (term->esc_nargs >= 3) {
                                    if (!cfg.no_remote_resize)
-                                       move_window(def(esc_args[1], 0),
-                                                   def(esc_args[2], 0));
+                                       move_window(def(term->esc_args[1], 0),
+                                                   def(term->esc_args[2], 0));
                                }
                                break;
                              case 4:
@@ -2214,15 +2132,16 @@ void term_out(void)
                                refresh_window();
                                break;
                              case 8:
-                               if (esc_nargs >= 3) {
+                               if (term->esc_nargs >= 3) {
                                    if (!cfg.no_remote_resize)
-                                       request_resize(def(esc_args[2], cfg.width),
-                                                      def(esc_args[1], cfg.height));
+                                       request_resize(def(term->esc_args[2], cfg.width),
+                                                      def(term->esc_args[1], cfg.height));
                                }
                                break;
                              case 9:
-                               if (esc_nargs >= 2)
-                                   set_zoomed(esc_args[1] ? TRUE : FALSE);
+                               if (term->esc_nargs >= 2)
+                                   set_zoomed(term->esc_args[1] ?
+                                              TRUE : FALSE);
                                break;
                              case 11:
                                ldisc_send(is_iconic() ? "\033[1t" : "\033[2t",
@@ -2240,7 +2159,7 @@ void term_out(void)
                                break;
                              case 18:
                                len = sprintf(buf, "\033[8;%d;%dt",
-                                             rows, cols);
+                                             term->rows, term->cols);
                                ldisc_send(buf, len, 0);
                                break;
                              case 19:
@@ -2279,17 +2198,19 @@ void term_out(void)
                        break;
                      case 'S':
                        compatibility(SCOANSI);
-                       scroll(marg_t, marg_b, def(esc_args[0], 1), TRUE);
+                       scroll(term, term->marg_t, term->marg_b,
+                              def(term->esc_args[0], 1), TRUE);
                        fix_cpos;
-                       wrapnext = FALSE;
-                       seen_disp_event = TRUE;
+                       term->wrapnext = FALSE;
+                       term->seen_disp_event = TRUE;
                        break;
                      case 'T':
                        compatibility(SCOANSI);
-                       scroll(marg_t, marg_b, -def(esc_args[0], 1), TRUE);
+                       scroll(term, term->marg_t, term->marg_b,
+                              -def(term->esc_args[0], 1), TRUE);
                        fix_cpos;
-                       wrapnext = FALSE;
-                       seen_disp_event = TRUE;
+                       term->wrapnext = FALSE;
+                       term->seen_disp_event = TRUE;
                        break;
                      case ANSI('|', '*'):
                        /* VT420 sequence DECSNLS
@@ -2298,10 +2219,12 @@ void term_out(void)
                         * reasonable range (24..49 AIUI) with no default specified.
                         */
                        compatibility(VT420);
-                       if (esc_nargs == 1 && esc_args[0] > 0) {
+                       if (term->esc_nargs == 1 && term->esc_args[0] > 0) {
                            if (!cfg.no_remote_resize)
-                               request_resize(cols, def(esc_args[0], cfg.height));
-                           deselect();
+                               request_resize(term->cols,
+                                              def(term->esc_args[0],
+                                                  cfg.height));
+                           deselect(term);
                        }
                        break;
                      case ANSI('|', '$'):
@@ -2310,34 +2233,35 @@ void term_out(void)
                         * Docs imply range is only 80 or 132, but I'll allow any.
                         */
                        compatibility(VT340TEXT);
-                       if (esc_nargs <= 1) {
+                       if (term->esc_nargs <= 1) {
                            if (!cfg.no_remote_resize)
-                               request_resize(def(esc_args[0], cfg.width), rows);
-                           deselect();
+                               request_resize(def(term->esc_args[0],
+                                                  cfg.width), term->rows);
+                           deselect(term);
                        }
                        break;
                      case 'X':       /* write N spaces w/o moving cursor */
                        /* XXX VTTEST says this is vt220, vt510 manual says vt100 */
                        compatibility(ANSIMIN);
                        {
-                           int n = def(esc_args[0], 1);
+                           int n = def(term->esc_args[0], 1);
                            pos cursplus;
-                           unsigned long *p = cpos;
-                           if (n > cols - curs.x)
-                               n = cols - curs.x;
-                           cursplus = curs;
+                           unsigned long *p = term->cpos;
+                           if (n > term->cols - term->curs.x)
+                               n = term->cols - term->curs.x;
+                           cursplus = term->curs;
                            cursplus.x += n;
-                           check_selection(curs, cursplus);
+                           check_selection(term, term->curs, cursplus);
                            while (n--)
-                               *p++ = erase_char;
-                           seen_disp_event = TRUE;
+                               *p++ = term->erase_char;
+                           term->seen_disp_event = TRUE;
                        }
                        break;
                      case 'x':       /* report terminal characteristics */
                        compatibility(VT100);
                        {
                            char buf[32];
-                           int i = def(esc_args[0], 0);
+                           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;
@@ -2348,91 +2272,96 @@ void term_out(void)
                      case 'Z':         /* BackTab for xterm */
                        compatibility(OTHER);
                        {
-                           int i = def(esc_args[0], 1);
-                           pos old_curs = curs;
+                           int i = def(term->esc_args[0], 1);
+                           pos old_curs = term->curs;
 
-                           for(;i>0 && curs.x>0; i--) {
+                           for(;i>0 && term->curs.x>0; i--) {
                                do {
-                                   curs.x--;
-                               } while (curs.x >0 && !tabs[curs.x]);
+                                   term->curs.x--;
+                               } while (term->curs.x >0 &&
+                                        !term->tabs[term->curs.x]);
                            }
                            fix_cpos;
-                           check_selection(old_curs, curs);
+                           check_selection(term, old_curs, term->curs);
                        }
                        break;
                      case ANSI('L', '='):
                        compatibility(OTHER);
-                       use_bce = (esc_args[0] <= 0);
-                       erase_char = ERASE_CHAR;
-                       if (use_bce)
-                           erase_char = (' ' | ATTR_ASCII |
-                                        (curr_attr & 
-                                         (ATTR_FGMASK | ATTR_BGMASK)));
+                       term->use_bce = (term->esc_args[0] <= 0);
+                       term->erase_char = ERASE_CHAR;
+                       if (term->use_bce)
+                           term->erase_char = (' ' | ATTR_ASCII |
+                                               (term->curr_attr & 
+                                                (ATTR_FGMASK | ATTR_BGMASK)));
                        break;
                      case ANSI('E', '='):
                        compatibility(OTHER);
-                       blink_is_real = (esc_args[0] >= 1);
+                       term->blink_is_real = (term->esc_args[0] >= 1);
                        break;
                      case ANSI('p', '"'):
-                       /* Allow the host to make this emulator a 'perfect' VT102.
-                        * This first appeared in the VT220, but we do need to get 
-                        * back to PuTTY mode so I won't check it.
+                       /*
+                        * Allow the host to make this emulator a
+                        * 'perfect' VT102. This first appeared in
+                        * the VT220, but we do need to get back to
+                        * PuTTY mode so I won't check it.
                         *
                         * The arg in 40..42,50 are a PuTTY extension.
                         * The 2nd arg, 8bit vs 7bit is not checked.
                         *
-                        * Setting VT102 mode should also change the Fkeys to
-                        * generate PF* codes as a real VT102 has no Fkeys.
-                        * The VT220 does this, F11..F13 become ESC,BS,LF other Fkeys
-                        * send nothing.
+                        * Setting VT102 mode should also change
+                        * the Fkeys to generate PF* codes as a
+                        * real VT102 has no Fkeys. The VT220 does
+                        * this, F11..F13 become ESC,BS,LF other
+                        * Fkeys send nothing.
                         *
                         * Note ESC c will NOT change this!
                         */
 
-                       switch (esc_args[0]) {
+                       switch (term->esc_args[0]) {
                          case 61:
-                           compatibility_level &= ~TM_VTXXX;
-                           compatibility_level |= TM_VT102;
+                           term->compatibility_level &= ~TM_VTXXX;
+                           term->compatibility_level |= TM_VT102;
                            break;
                          case 62:
-                           compatibility_level &= ~TM_VTXXX;
-                           compatibility_level |= TM_VT220;
+                           term->compatibility_level &= ~TM_VTXXX;
+                           term->compatibility_level |= TM_VT220;
                            break;
 
                          default:
-                           if (esc_args[0] > 60 && esc_args[0] < 70)
-                               compatibility_level |= TM_VTXXX;
+                           if (term->esc_args[0] > 60 &&
+                               term->esc_args[0] < 70)
+                               term->compatibility_level |= TM_VTXXX;
                            break;
 
                          case 40:
-                           compatibility_level &= TM_VTXXX;
+                           term->compatibility_level &= TM_VTXXX;
                            break;
                          case 41:
-                           compatibility_level = TM_PUTTY;
+                           term->compatibility_level = TM_PUTTY;
                            break;
                          case 42:
-                           compatibility_level = TM_SCOANSI;
+                           term->compatibility_level = TM_SCOANSI;
                            break;
 
                          case ARG_DEFAULT:
-                           compatibility_level = TM_PUTTY;
+                           term->compatibility_level = TM_PUTTY;
                            break;
                          case 50:
                            break;
                        }
 
                        /* Change the response to CSI c */
-                       if (esc_args[0] == 50) {
+                       if (term->esc_args[0] == 50) {
                            int i;
                            char lbuf[64];
-                           strcpy(id_string, "\033[?");
-                           for (i = 1; i < esc_nargs; i++) {
+                           strcpy(term->id_string, "\033[?");
+                           for (i = 1; i < term->esc_nargs; i++) {
                                if (i != 1)
-                                   strcat(id_string, ";");
-                               sprintf(lbuf, "%d", esc_args[i]);
-                               strcat(id_string, lbuf);
+                                   strcat(term->id_string, ";");
+                               sprintf(lbuf, "%d", term->esc_args[i]);
+                               strcat(term->id_string, lbuf);
                            }
-                           strcat(id_string, "c");
+                           strcat(term->id_string, "c");
                        }
 #if 0
                        /* Is this a good idea ? 
@@ -2440,7 +2369,7 @@ void term_out(void)
                         */
                        if (!has_compat(VT420) && has_compat(VT100)) {
                            if (!cfg.no_remote_resize) {
-                               if (reset_132)
+                               if (term->reset_132)
                                    request_resize(132, 24);
                                else
                                    request_resize(80, 24);
@@ -2451,20 +2380,20 @@ void term_out(void)
                    }
                break;
              case SEEN_OSC:
-               osc_w = FALSE;
+               term->osc_w = FALSE;
                switch (c) {
                  case 'P':            /* Linux palette sequence */
-                   termstate = SEEN_OSC_P;
-                   osc_strlen = 0;
+                   term->termstate = SEEN_OSC_P;
+                   term->osc_strlen = 0;
                    break;
                  case 'R':            /* Linux palette reset */
                    palette_reset();
-                   term_invalidate();
-                   termstate = TOPLEVEL;
+                   term_invalidate(term);
+                   term->termstate = TOPLEVEL;
                    break;
                  case 'W':            /* word-set */
-                   termstate = SEEN_OSC_W;
-                   osc_w = TRUE;
+                   term->termstate = SEEN_OSC_W;
+                   term->osc_w = TRUE;
                    break;
                  case '0':
                  case '1':
@@ -2476,21 +2405,21 @@ void term_out(void)
                  case '7':
                  case '8':
                  case '9':
-                   esc_args[0] = 10 * esc_args[0] + c - '0';
+                   term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
                    break;
                  case 'L':
                    /*
                     * Grotty hack to support xterm and DECterm title
                     * sequences concurrently.
                     */
-                   if (esc_args[0] == 2) {
-                       esc_args[0] = 1;
+                   if (term->esc_args[0] == 2) {
+                       term->esc_args[0] = 1;
                        break;
                    }
                    /* else fall through */
                  default:
-                   termstate = OSC_STRING;
-                   osc_strlen = 0;
+                   term->termstate = OSC_STRING;
+                   term->osc_strlen = 0;
                }
                break;
              case OSC_STRING:
@@ -2505,7 +2434,7 @@ void term_out(void)
                 * -- RDB
                 */
                if (c == '\n' || c == '\r') {
-                   termstate = TOPLEVEL;
+                   term->termstate = TOPLEVEL;
                } else if (c == 0234 || c == '\007') {
                    /*
                     * These characters terminate the string; ST and BEL
@@ -2514,16 +2443,16 @@ void term_out(void)
                     * mode unless it is followed by \, in which case it is
                     * synonymous with ST in the first place.
                     */
-                   do_osc();
-                   termstate = TOPLEVEL;
+                   do_osc(term);
+                   term->termstate = TOPLEVEL;
                } else if (c == '\033')
-                   termstate = OSC_MAYBE_ST;
-               else if (osc_strlen < OSC_STR_MAX)
-                   osc_string[osc_strlen++] = c;
+                   term->termstate = OSC_MAYBE_ST;
+               else if (term->osc_strlen < OSC_STR_MAX)
+                   term->osc_string[term->osc_strlen++] = c;
                break;
              case SEEN_OSC_P:
                {
-                   int max = (osc_strlen == 0 ? 21 : 16);
+                   int max = (term->osc_strlen == 0 ? 21 : 16);
                    int val;
                    if (c >= '0' && c <= '9')
                        val = c - '0';
@@ -2532,17 +2461,17 @@ void term_out(void)
                    else if (c >= 'a' && c <= 'a' + max - 10)
                        val = c - 'a' + 10;
                    else {
-                       termstate = TOPLEVEL;
+                       term->termstate = TOPLEVEL;
                        break;
                    }
-                   osc_string[osc_strlen++] = val;
-                   if (osc_strlen >= 7) {
-                       palette_set(osc_string[0],
-                                   osc_string[1] * 16 + osc_string[2],
-                                   osc_string[3] * 16 + osc_string[4],
-                                   osc_string[5] * 16 + osc_string[6]);
-                       term_invalidate();
-                       termstate = TOPLEVEL;
+                   term->osc_string[term->osc_strlen++] = val;
+                   if (term->osc_strlen >= 7) {
+                       palette_set(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]);
+                       term_invalidate(term);
+                       term->termstate = TOPLEVEL;
                    }
                }
                break;
@@ -2558,28 +2487,28 @@ void term_out(void)
                  case '7':
                  case '8':
                  case '9':
-                   esc_args[0] = 10 * esc_args[0] + c - '0';
+                   term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
                    break;
                  default:
-                   termstate = OSC_STRING;
-                   osc_strlen = 0;
+                   term->termstate = OSC_STRING;
+                   term->osc_strlen = 0;
                }
                break;
              case VT52_ESC:
-               termstate = TOPLEVEL;
-               seen_disp_event = TRUE;
+               term->termstate = TOPLEVEL;
+               term->seen_disp_event = TRUE;
                switch (c) {
                  case 'A':
-                   move(curs.x, curs.y - 1, 1);
+                   move(term, term->curs.x, term->curs.y - 1, 1);
                    break;
                  case 'B':
-                   move(curs.x, curs.y + 1, 1);
+                   move(term, term->curs.x, term->curs.y + 1, 1);
                    break;
                  case 'C':
-                   move(curs.x + 1, curs.y, 1);
+                   move(term, term->curs.x + 1, term->curs.y, 1);
                    break;
                  case 'D':
-                   move(curs.x - 1, curs.y, 1);
+                   move(term, term->curs.x - 1, term->curs.y, 1);
                    break;
                    /*
                     * From the VT100 Manual
@@ -2622,28 +2551,28 @@ void term_out(void)
                     *
                     */
                  case 'F':
-                   cset_attr[cset = 0] = ATTR_LINEDRW;
+                   term->cset_attr[term->cset = 0] = ATTR_LINEDRW;
                    break;
                  case 'G':
-                   cset_attr[cset = 0] = ATTR_ASCII;
+                   term->cset_attr[term->cset = 0] = ATTR_ASCII;
                    break;
                  case 'H':
-                   move(0, 0, 0);
+                   move(term, 0, 0, 0);
                    break;
                  case 'I':
-                   if (curs.y == 0)
-                       scroll(0, rows - 1, -1, TRUE);
-                   else if (curs.y > 0)
-                       curs.y--;
+                   if (term->curs.y == 0)
+                       scroll(term, 0, term->rows - 1, -1, TRUE);
+                   else if (term->curs.y > 0)
+                       term->curs.y--;
                    fix_cpos;
-                   wrapnext = FALSE;
+                   term->wrapnext = FALSE;
                    break;
                  case 'J':
-                   erase_lots(FALSE, FALSE, TRUE);
-                   disptop = 0;
+                   erase_lots(term, FALSE, FALSE, TRUE);
+                   term->disptop = 0;
                    break;
                  case 'K':
-                   erase_lots(TRUE, FALSE, TRUE);
+                   erase_lots(term, TRUE, FALSE, TRUE);
                    break;
 #if 0
                  case 'V':
@@ -2657,24 +2586,24 @@ void term_out(void)
                    break;
 #endif
                  case 'Y':
-                   termstate = VT52_Y1;
+                   term->termstate = VT52_Y1;
                    break;
                  case 'Z':
                    ldisc_send("\033/Z", 3, 0);
                    break;
                  case '=':
-                   app_keypad_keys = TRUE;
+                   term->app_keypad_keys = TRUE;
                    break;
                  case '>':
-                   app_keypad_keys = FALSE;
+                   term->app_keypad_keys = FALSE;
                    break;
                  case '<':
                    /* XXX This should switch to VT100 mode not current or default
                     *     VT mode. But this will only have effect in a VT220+
                     *     emulation.
                     */
-                   vt52_mode = FALSE;
-                   blink_is_real = cfg.blinktext;
+                   term->vt52_mode = FALSE;
+                   term->blink_is_real = cfg.blinktext;
                    break;
 #if 0
                  case '^':
@@ -2691,148 +2620,150 @@ void term_out(void)
 #ifdef VT52_PLUS
                  case 'E':
                    /* compatibility(ATARI) */
-                   move(0, 0, 0);
-                   erase_lots(FALSE, FALSE, TRUE);
-                   disptop = 0;
+                   move(term, 0, 0, 0);
+                   erase_lots(term, FALSE, FALSE, TRUE);
+                   term->disptop = 0;
                    break;
                  case 'L':
                    /* compatibility(ATARI) */
-                   if (curs.y <= marg_b)
-                       scroll(curs.y, marg_b, -1, FALSE);
+                   if (term->curs.y <= term->marg_b)
+                       scroll(term, term->curs.y, term->marg_b, -1, FALSE);
                    break;
                  case 'M':
                    /* compatibility(ATARI) */
-                   if (curs.y <= marg_b)
-                       scroll(curs.y, marg_b, 1, TRUE);
+                   if (term->curs.y <= term->marg_b)
+                       scroll(term, term->curs.y, term->marg_b, 1, TRUE);
                    break;
                  case 'b':
                    /* compatibility(ATARI) */
-                   termstate = VT52_FG;
+                   term->termstate = VT52_FG;
                    break;
                  case 'c':
                    /* compatibility(ATARI) */
-                   termstate = VT52_BG;
+                   term->termstate = VT52_BG;
                    break;
                  case 'd':
                    /* compatibility(ATARI) */
-                   erase_lots(FALSE, TRUE, FALSE);
-                   disptop = 0;
+                   erase_lots(term, FALSE, TRUE, FALSE);
+                   term->disptop = 0;
                    break;
                  case 'e':
                    /* compatibility(ATARI) */
-                   cursor_on = TRUE;
+                   term->cursor_on = TRUE;
                    break;
                  case 'f':
                    /* compatibility(ATARI) */
-                   cursor_on = FALSE;
+                   term->cursor_on = FALSE;
                    break;
                    /* case 'j': Save cursor position - broken on ST */
                    /* case 'k': Restore cursor position */
                  case 'l':
                    /* compatibility(ATARI) */
-                   erase_lots(TRUE, TRUE, TRUE);
-                   curs.x = 0;
-                   wrapnext = FALSE;
+                   erase_lots(term, TRUE, TRUE, TRUE);
+                   term->curs.x = 0;
+                   term->wrapnext = FALSE;
                    fix_cpos;
                    break;
                  case 'o':
                    /* compatibility(ATARI) */
-                   erase_lots(TRUE, TRUE, FALSE);
+                   erase_lots(term, TRUE, TRUE, FALSE);
                    break;
                  case 'p':
                    /* compatibility(ATARI) */
-                   curr_attr |= ATTR_REVERSE;
+                   term->curr_attr |= ATTR_REVERSE;
                    break;
                  case 'q':
                    /* compatibility(ATARI) */
-                   curr_attr &= ~ATTR_REVERSE;
+                   term->curr_attr &= ~ATTR_REVERSE;
                    break;
                  case 'v':            /* wrap Autowrap on - Wyse style */
                    /* compatibility(ATARI) */
-                   wrap = 1;
+                   term->wrap = 1;
                    break;
                  case 'w':            /* Autowrap off */
                    /* compatibility(ATARI) */
-                   wrap = 0;
+                   term->wrap = 0;
                    break;
 
                  case 'R':
                    /* compatibility(OTHER) */
-                   vt52_bold = FALSE;
-                   curr_attr = ATTR_DEFAULT;
-                   if (use_bce)
-                       erase_char = (' ' | ATTR_ASCII |
-                                    (curr_attr & 
-                                     (ATTR_FGMASK | ATTR_BGMASK)));
+                   term->vt52_bold = FALSE;
+                   term->curr_attr = ATTR_DEFAULT;
+                   if (term->use_bce)
+                       term->erase_char = (' ' | ATTR_ASCII |
+                                           (term->curr_attr & 
+                                            (ATTR_FGMASK | ATTR_BGMASK)));
                    break;
                  case 'S':
                    /* compatibility(VI50) */
-                   curr_attr |= ATTR_UNDER;
+                   term->curr_attr |= ATTR_UNDER;
                    break;
                  case 'W':
                    /* compatibility(VI50) */
-                   curr_attr &= ~ATTR_UNDER;
+                   term->curr_attr &= ~ATTR_UNDER;
                    break;
                  case 'U':
                    /* compatibility(VI50) */
-                   vt52_bold = TRUE;
-                   curr_attr |= ATTR_BOLD;
+                   term->vt52_bold = TRUE;
+                   term->curr_attr |= ATTR_BOLD;
                    break;
                  case 'T':
                    /* compatibility(VI50) */
-                   vt52_bold = FALSE;
-                   curr_attr &= ~ATTR_BOLD;
+                   term->vt52_bold = FALSE;
+                   term->curr_attr &= ~ATTR_BOLD;
                    break;
 #endif
                }
                break;
              case VT52_Y1:
-               termstate = VT52_Y2;
-               move(curs.x, c - ' ', 0);
+               term->termstate = VT52_Y2;
+               move(term, term->curs.x, c - ' ', 0);
                break;
              case VT52_Y2:
-               termstate = TOPLEVEL;
-               move(c - ' ', curs.y, 0);
+               term->termstate = TOPLEVEL;
+               move(term, c - ' ', term->curs.y, 0);
                break;
 
 #ifdef VT52_PLUS
              case VT52_FG:
-               termstate = TOPLEVEL;
-               curr_attr &= ~ATTR_FGMASK;
-               curr_attr &= ~ATTR_BOLD;
-               curr_attr |= (c & 0x7) << ATTR_FGSHIFT;
-               if ((c & 0x8) || vt52_bold)
-                   curr_attr |= ATTR_BOLD;
-
-               if (use_bce)
-                   erase_char = (' ' | ATTR_ASCII |
-                                (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
+               term->termstate = TOPLEVEL;
+               term->curr_attr &= ~ATTR_FGMASK;
+               term->curr_attr &= ~ATTR_BOLD;
+               term->curr_attr |= (c & 0x7) << ATTR_FGSHIFT;
+               if ((c & 0x8) || term->vt52_bold)
+                   term->curr_attr |= ATTR_BOLD;
+
+               if (term->use_bce)
+                   term->erase_char = (' ' | ATTR_ASCII |
+                                       (term->curr_attr &
+                                        (ATTR_FGMASK | ATTR_BGMASK)));
                break;
              case VT52_BG:
-               termstate = TOPLEVEL;
-               curr_attr &= ~ATTR_BGMASK;
-               curr_attr &= ~ATTR_BLINK;
-               curr_attr |= (c & 0x7) << ATTR_BGSHIFT;
+               term->termstate = TOPLEVEL;
+               term->curr_attr &= ~ATTR_BGMASK;
+               term->curr_attr &= ~ATTR_BLINK;
+               term->curr_attr |= (c & 0x7) << ATTR_BGSHIFT;
 
                /* Note: bold background */
                if (c & 0x8)
-                   curr_attr |= ATTR_BLINK;
+                   term->curr_attr |= ATTR_BLINK;
 
-               if (use_bce)
-                   erase_char = (' ' | ATTR_ASCII |
-                                (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
+               if (term->use_bce)
+                   term->erase_char = (' ' | ATTR_ASCII |
+                                       (term->curr_attr &
+                                        (ATTR_FGMASK | ATTR_BGMASK)));
                break;
 #endif
              default: break;          /* placate gcc warning about enum use */
            }
-       if (selstate != NO_SELECTION) {
-           pos cursplus = curs;
+       if (term->selstate != NO_SELECTION) {
+           pos cursplus = term->curs;
            incpos(cursplus);
-           check_selection(curs, cursplus);
+           check_selection(term, term->curs, cursplus);
        }
     }
 
-    term_print_flush();
+    term_print_flush(term);
 }
 
 #if 0
@@ -2841,11 +2772,11 @@ void term_out(void)
  * alike to scroll-optimise one to the other. Return the degree of
  * similarity.
  */
-static int linecmp(unsigned long *a, unsigned long *b)
+static int linecmp(Terminal *term, unsigned long *a, unsigned long *b)
 {
     int i, n;
 
-    for (i = n = 0; i < cols; i++)
+    for (i = n = 0; i < term->cols; i++)
        n += (*a++ == *b++);
     return n;
 }
@@ -2855,7 +2786,7 @@ static int linecmp(unsigned long *a, unsigned long *b)
  * Given a context, update the window. Out of paranoia, we don't
  * allow WM_PAINT responses to do scrolling optimisations.
  */
-static void do_paint(Context ctx, int may_optimise)
+static void do_paint(Terminal *term, Context ctx, int may_optimise)
 {
     int i, j, our_curs_y;
     unsigned long rv, cursor;
@@ -2867,13 +2798,13 @@ static void do_paint(Context ctx, int may_optimise)
     /*
      * Check the visual bell state.
      */
-    if (in_vbell) {
+    if (term->in_vbell) {
        ticks = GETTICKCOUNT();
-       if (ticks - vbell_startpoint >= VBELL_TIMEOUT)
-           in_vbell = FALSE; 
+       if (ticks - term->vbell_startpoint >= VBELL_TIMEOUT)
+           term->in_vbell = FALSE; 
    }
 
-    rv = (!rvideo ^ !in_vbell ? ATTR_REVERSE : 0);
+    rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0);
 
     /* Depends on:
      * screen array, disptop, scrtop,
@@ -2883,35 +2814,36 @@ static void do_paint(Context ctx, int may_optimise)
      */
 
     /* Has the cursor position or type changed ? */
-    if (cursor_on) {
-       if (has_focus) {
-           if (blinker || !cfg.blink_cur)
+    if (term->cursor_on) {
+       if (term->has_focus) {
+           if (term->blinker || !cfg.blink_cur)
                cursor = TATTR_ACTCURS;
            else
                cursor = 0;
        } else
            cursor = TATTR_PASCURS;
-       if (wrapnext)
+       if (term->wrapnext)
            cursor |= TATTR_RIGHTCURS;
     } else
        cursor = 0;
-    our_curs_y = curs.y - disptop;
-
-    if (dispcurs && (curstype != cursor ||
-                    dispcurs !=
-                    disptext + our_curs_y * (cols + 1) + curs.x)) {
-       if (dispcurs > disptext && 
-               (*dispcurs & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
-           dispcurs[-1] |= ATTR_INVALID;
-       if ( (dispcurs[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
-           dispcurs[1] |= ATTR_INVALID;
-       *dispcurs |= ATTR_INVALID;
-       curstype = 0;
+    our_curs_y = term->curs.y - term->disptop;
+
+    if (term->dispcurs && (term->curstype != cursor ||
+                          term->dispcurs !=
+                          term->disptext + our_curs_y * (term->cols + 1) +
+                          term->curs.x)) {
+       if (term->dispcurs > term->disptext && 
+               (*term->dispcurs & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+           term->dispcurs[-1] |= ATTR_INVALID;
+       if ( (term->dispcurs[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+           term->dispcurs[1] |= ATTR_INVALID;
+       *term->dispcurs |= ATTR_INVALID;
+       term->curstype = 0;
     }
-    dispcurs = NULL;
+    term->dispcurs = NULL;
 
     /* The normal screen data */
-    for (i = 0; i < rows; i++) {
+    for (i = 0; i < term->rows; i++) {
        unsigned long *ldata;
        int lattr;
        int idx, dirty_line, dirty_run, selected;
@@ -2921,15 +2853,16 @@ static void do_paint(Context ctx, int may_optimise)
        int ccount = 0;
        int last_run_dirty = 0;
 
-       scrpos.y = i + disptop;
+       scrpos.y = i + term->disptop;
        ldata = lineptr(scrpos.y);
-       lattr = (ldata[cols] & LATTR_MODE);
+       lattr = (ldata[term->cols] & LATTR_MODE);
 
-       idx = i * (cols + 1);
-       dirty_run = dirty_line = (ldata[cols] != disptext[idx + cols]);
-       disptext[idx + cols] = ldata[cols];
+       idx = i * (term->cols + 1);
+       dirty_run = dirty_line = (ldata[term->cols] !=
+                                 term->disptext[idx + term->cols]);
+       term->disptext[idx + term->cols] = ldata[term->cols];
 
-       for (j = 0; j < cols; j++, idx++) {
+       for (j = 0; j < term->cols; j++, idx++) {
            unsigned long tattr, tchar;
            unsigned long *d = ldata + j;
            int break_run;
@@ -2954,16 +2887,18 @@ static void do_paint(Context ctx, int may_optimise)
                    tattr |= ATTR_WIDE;
 
            /* Video reversing things */
-           if (seltype == LEXICOGRAPHIC)
-               selected = posle(selstart, scrpos) && poslt(scrpos, selend);
+           if (term->seltype == LEXICOGRAPHIC)
+               selected = (posle(term->selstart, scrpos) &&
+                           poslt(scrpos, term->selend));
            else
-               selected = posPle(selstart, scrpos) && posPlt(scrpos, selend);
+               selected = (posPle(term->selstart, scrpos) &&
+                           posPlt(scrpos, term->selend));
            tattr = (tattr ^ rv
                     ^ (selected ? ATTR_REVERSE : 0));
 
            /* 'Real' blinking ? */
-           if (blink_is_real && (tattr & ATTR_BLINK)) {
-               if (has_focus && tblinker) {
+           if (term->blink_is_real && (tattr & ATTR_BLINK)) {
+               if (term->has_focus && term->tblinker) {
                    tchar = ' ';
                    tattr &= ~CSET_MASK;
                    tattr |= ATTR_ACP;
@@ -2975,20 +2910,20 @@ static void do_paint(Context ctx, int may_optimise)
             * Check the font we'll _probably_ be using to see if 
             * the character is wide when we don't want it to be.
             */
-           if ((tchar | tattr) != (disptext[idx]& ~ATTR_NARROW)) {
+           if ((tchar | tattr) != (term->disptext[idx]& ~ATTR_NARROW)) {
                if ((tattr & ATTR_WIDE) == 0 && 
                    CharWidth(ctx, (tchar | tattr) & 0xFFFF) == 2)
                    tattr |= ATTR_NARROW;
-           } else if (disptext[idx]&ATTR_NARROW)
+           } else if (term->disptext[idx]&ATTR_NARROW)
                tattr |= ATTR_NARROW;
 
            /* Cursor here ? Save the 'background' */
-           if (i == our_curs_y && j == curs.x) {
+           if (i == our_curs_y && j == term->curs.x) {
                cursor_background = tattr | tchar;
-               dispcurs = disptext + idx;
+               term->dispcurs = term->disptext + idx;
            }
 
-           if ((disptext[idx] ^ tattr) & ATTR_WIDE)
+           if ((term->disptext[idx] ^ tattr) & ATTR_WIDE)
                dirty_line = TRUE;
 
            break_run = (tattr != attr || j - start >= sizeof(ch));
@@ -2998,7 +2933,7 @@ static void do_paint(Context ctx, int may_optimise)
                && tchar <= 0xBD) break_run = TRUE;
 
            if (!dbcs_screenfont && !dirty_line) {
-               if ((tchar | tattr) == disptext[idx])
+               if ((tchar | tattr) == term->disptext[idx])
                    break_run = TRUE;
                else if (!dirty_run && ccount == 1)
                    break_run = TRUE;
@@ -3017,24 +2952,24 @@ static void do_paint(Context ctx, int may_optimise)
                dirty_run = dirty_line;
            }
 
-           if ((tchar | tattr) != disptext[idx])
+           if ((tchar | tattr) != term->disptext[idx])
                dirty_run = TRUE;
            ch[ccount++] = (char) tchar;
-           disptext[idx] = tchar | tattr;
+           term->disptext[idx] = tchar | tattr;
 
            /* If it's a wide char step along to the next one. */
            if (tattr & ATTR_WIDE) {
-               if (++j < cols) {
+               if (++j < term->cols) {
                    idx++;
                    d++;
                    /* Cursor is here ? Ouch! */
-                   if (i == our_curs_y && j == curs.x) {
+                   if (i == our_curs_y && j == term->curs.x) {
                        cursor_background = *d;
-                       dispcurs = disptext + idx;
+                       term->dispcurs = term->disptext + idx;
                    }
-                   if (disptext[idx] != *d)
+                   if (term->disptext[idx] != *d)
                        dirty_run = TRUE;
-                   disptext[idx] = *d;
+                   term->disptext[idx] = *d;
                }
            }
        }
@@ -3044,11 +2979,11 @@ static void do_paint(Context ctx, int may_optimise)
        }
 
        /* Cursor on this line ? (and changed) */
-       if (i == our_curs_y && (curstype != cursor || updated_line)) {
+       if (i == our_curs_y && (term->curstype != cursor || updated_line)) {
            ch[0] = (char) (cursor_background & CHAR_MASK);
            attr = (cursor_background & ATTR_MASK) | cursor;
-           do_cursor(ctx, curs.x, i, ch, 1, attr, lattr);
-           curstype = cursor;
+           do_cursor(ctx, term->curs.x, i, ch, 1, attr, lattr);
+           term->curstype = cursor;
        }
     }
 }
@@ -3057,66 +2992,66 @@ static void do_paint(Context ctx, int may_optimise)
  * Flick the switch that says if blinking things should be shown or hidden.
  */
 
-void term_blink(int flg)
+void term_blink(Terminal *term, int flg)
 {
-    static long last_blink = 0;
-    static long last_tblink = 0;
     long now, blink_diff;
 
     now = GETTICKCOUNT();
-    blink_diff = now - last_tblink;
+    blink_diff = now - term->last_tblink;
 
     /* Make sure the text blinks no more than 2Hz; we'll use 0.45 s period. */
     if (blink_diff < 0 || blink_diff > (TICKSPERSEC * 9 / 20)) {
-       last_tblink = now;
-       tblinker = !tblinker;
+       term->last_tblink = now;
+       term->tblinker = !term->tblinker;
     }
 
     if (flg) {
-       blinker = 1;
-       last_blink = now;
+       term->blinker = 1;
+       term->last_blink = now;
        return;
     }
 
-    blink_diff = now - last_blink;
+    blink_diff = now - term->last_blink;
 
     /* Make sure the cursor blinks no faster than system blink rate */
     if (blink_diff >= 0 && blink_diff < (long) CURSORBLINK)
        return;
 
-    last_blink = now;
-    blinker = !blinker;
+    term->last_blink = now;
+    term->blinker = !term->blinker;
 }
 
 /*
  * Invalidate the whole screen so it will be repainted in full.
  */
-void term_invalidate(void)
+void term_invalidate(Terminal *term)
 {
     int i;
 
-    for (i = 0; i < rows * (cols + 1); i++)
-       disptext[i] = ATTR_INVALID;
+    for (i = 0; i < term->rows * (term->cols + 1); i++)
+       term->disptext[i] = ATTR_INVALID;
 }
 
 /*
  * Paint the window in response to a WM_PAINT message.
  */
-void term_paint(Context ctx, int left, int top, int right, int bottom)
+void term_paint(Terminal *term, Context ctx,
+               int left, int top, int right, int bottom)
 {
     int i, j;
     if (left < 0) left = 0;
     if (top < 0) top = 0;
-    if (right >= cols) right = cols-1;
-    if (bottom >= rows) bottom = rows-1;
-
-    for (i = top; i <= bottom && i < rows; i++) {
-       if ((disptext[i * (cols + 1) + cols] & LATTR_MODE) == LATTR_NORM)
-           for (j = left; j <= right && j < cols; j++)
-               disptext[i * (cols + 1) + j] = ATTR_INVALID;
+    if (right >= term->cols) right = term->cols-1;
+    if (bottom >= term->rows) bottom = term->rows-1;
+
+    for (i = top; i <= bottom && i < term->rows; i++) {
+       if ((term->disptext[i * (term->cols + 1) + term->cols] &
+            LATTR_MODE) == LATTR_NORM)
+           for (j = left; j <= right && j < term->cols; j++)
+               term->disptext[i * (term->cols + 1) + j] = ATTR_INVALID;
        else
-           for (j = left / 2; j <= right / 2 + 1 && j < cols; j++)
-               disptext[i * (cols + 1) + j] = ATTR_INVALID;
+           for (j = left / 2; j <= right / 2 + 1 && j < term->cols; j++)
+               term->disptext[i * (term->cols + 1) + j] = ATTR_INVALID;
     }
 
     /* This should happen soon enough, also for some reason it sometimes 
@@ -3124,7 +3059,7 @@ void term_paint(Context ctx, int left, int top, int right, int bottom)
      * window perhaps ?
      */
     if (alt_pressed)
-        do_paint (ctx, FALSE);
+        do_paint (term, ctx, FALSE);
 }
 
 /*
@@ -3134,20 +3069,20 @@ void term_paint(Context ctx, int left, int top, int right, int bottom)
  * to denote it is relative to the end, and 0 to denote that it is
  * relative to the current position.
  */
-void term_scroll(int rel, int where)
+void term_scroll(Terminal *term, int rel, int where)
 {
-    int sbtop = -count234(scrollback);
-
-    disptop = (rel < 0 ? 0 : rel > 0 ? sbtop : disptop) + where;
-    if (disptop < sbtop)
-       disptop = sbtop;
-    if (disptop > 0)
-       disptop = 0;
-    update_sbar();
-    term_update();
+    int sbtop = -count234(term->scrollback);
+
+    term->disptop = (rel < 0 ? 0 : rel > 0 ? sbtop : term->disptop) + where;
+    if (term->disptop < sbtop)
+       term->disptop = sbtop;
+    if (term->disptop > 0)
+       term->disptop = 0;
+    update_sbar(term);
+    term_update(term);
 }
 
-static void clipme(pos top, pos bottom, int rect)
+static void clipme(Terminal *term, pos top, pos bottom, int rect)
 {
     wchar_t *workbuf;
     wchar_t *wbptr;                   /* where next char goes within workbuf */
@@ -3171,7 +3106,7 @@ static void clipme(pos top, pos bottom, int rect)
         * line...
         */
        nlpos.y = top.y;
-       nlpos.x = cols;
+       nlpos.x = term->cols;
 
        /*
         * ... move it backwards if there's unused space at the end
@@ -3179,7 +3114,7 @@ static void clipme(pos top, pos bottom, int rect)
         * because in normal selection mode this means we need a
         * newline at the end)...
         */
-       if (!(ldata[cols] & LATTR_WRAPPED)) {
+       if (!(ldata[term->cols] & LATTR_WRAPPED)) {
            while (((ldata[nlpos.x - 1] & 0xFF) == 0x20 ||
                    (DIRECT_CHAR(ldata[nlpos.x - 1]) &&
                     (ldata[nlpos.x - 1] & CHAR_MASK) == 0x20))
@@ -3298,19 +3233,19 @@ static void clipme(pos top, pos bottom, int rect)
        sfree(workbuf);
 }
 
-void term_copyall(void)
+void term_copyall(Terminal *term)
 {
     pos top;
-    top.y = -count234(scrollback);
+    top.y = -count234(term->scrollback);
     top.x = 0;
-    clipme(top, curs, 0);
+    clipme(term, top, term->curs, 0);
 }
 
 /*
- * The wordness array is mainly for deciding the disposition of the US-ASCII 
- * characters.
+ * The wordness array is mainly for deciding the disposition of the
+ * US-ASCII characters.
  */
-static int wordtype(int uc)
+static int wordtype(Terminal *term, int uc)
 {
     static struct {
        int start, end, ctype;
@@ -3408,7 +3343,7 @@ static int wordtype(int uc)
        return (uc != ' ');
 
     if (uc < 0x80)
-       return wordness[uc];
+       return term->wordness[uc];
 
     for (wptr = ucs_words; wptr->start; wptr++) {
        if (uc >= wptr->start && uc <= wptr->end)
@@ -3421,28 +3356,28 @@ static int wordtype(int uc)
 /*
  * Spread the selection outwards according to the selection mode.
  */
-static pos sel_spread_half(pos p, int dir)
+static pos sel_spread_half(Terminal *term, pos p, int dir)
 {
     unsigned long *ldata;
     short wvalue;
-    int topy = -count234(scrollback);
+    int topy = -count234(term->scrollback);
 
     ldata = lineptr(p.y);
 
-    switch (selmode) {
+    switch (term->selmode) {
       case SM_CHAR:
        /*
         * In this mode, every character is a separate unit, except
         * for runs of spaces at the end of a non-wrapping line.
         */
-       if (!(ldata[cols] & LATTR_WRAPPED)) {
-           unsigned long *q = ldata + cols;
+       if (!(ldata[term->cols] & LATTR_WRAPPED)) {
+           unsigned long *q = ldata + term->cols;
            while (q > ldata && (q[-1] & CHAR_MASK) == 0x20)
                q--;
-           if (q == ldata + cols)
+           if (q == ldata + term->cols)
                q--;
            if (p.x >= q - ldata)
-               p.x = (dir == -1 ? q - ldata : cols - 1);
+               p.x = (dir == -1 ? q - ldata : term->cols - 1);
        }
        break;
       case SM_WORD:
@@ -3450,19 +3385,19 @@ static pos sel_spread_half(pos p, int dir)
         * In this mode, the units are maximal runs of characters
         * whose `wordness' has the same value.
         */
-       wvalue = wordtype(ldata[p.x]);
+       wvalue = wordtype(term, ldata[p.x]);
        if (dir == +1) {
            while (1) {
-               if (p.x < cols-1) {
-                   if (wordtype(ldata[p.x + 1]) == wvalue)
+               if (p.x < term->cols-1) {
+                   if (wordtype(term, ldata[p.x + 1]) == wvalue)
                        p.x++;
                    else
                        break;
                } else {
-                   if (ldata[cols] & LATTR_WRAPPED) {
+                   if (ldata[term->cols] & LATTR_WRAPPED) {
                        unsigned long *ldata2;
                        ldata2 = lineptr(p.y+1);
-                       if (wordtype(ldata2[0]) == wvalue) {
+                       if (wordtype(term, ldata2[0]) == wvalue) {
                            p.x = 0;
                            p.y++;
                            ldata = ldata2;
@@ -3475,7 +3410,7 @@ static pos sel_spread_half(pos p, int dir)
        } else {
            while (1) {
                if (p.x > 0) {
-                   if (wordtype(ldata[p.x - 1]) == wvalue)
+                   if (wordtype(term, ldata[p.x - 1]) == wvalue)
                        p.x--;
                    else
                        break;
@@ -3484,9 +3419,9 @@ static pos sel_spread_half(pos p, int dir)
                    if (p.y <= topy)
                        break;
                    ldata2 = lineptr(p.y-1);
-                   if ((ldata2[cols] & LATTR_WRAPPED) &&
-                       wordtype(ldata2[cols-1]) == wvalue) {
-                       p.x = cols-1;
+                   if ((ldata2[term->cols] & LATTR_WRAPPED) &&
+                       wordtype(term, ldata2[term->cols-1]) == wvalue) {
+                       p.x = term->cols-1;
                        p.y--;
                        ldata = ldata2;
                    } else
@@ -3499,23 +3434,23 @@ static pos sel_spread_half(pos p, int dir)
        /*
         * In this mode, every line is a unit.
         */
-       p.x = (dir == -1 ? 0 : cols - 1);
+       p.x = (dir == -1 ? 0 : term->cols - 1);
        break;
     }
     return p;
 }
 
-static void sel_spread(void)
+static void sel_spread(Terminal *term)
 {
-    if (seltype == LEXICOGRAPHIC) {
-       selstart = sel_spread_half(selstart, -1);
-       decpos(selend);
-       selend = sel_spread_half(selend, +1);
-       incpos(selend);
+    if (term->seltype == LEXICOGRAPHIC) {
+       term->selstart = sel_spread_half(term, term->selstart, -1);
+       decpos(term->selend);
+       term->selend = sel_spread_half(term, term->selend, +1);
+       incpos(term->selend);
     }
 }
 
-void term_do_paste(void)
+void term_do_paste(Terminal *term)
 {
     wchar_t *data;
     int len;
@@ -3524,12 +3459,12 @@ void term_do_paste(void)
     if (data && len > 0) {
         wchar_t *p, *q;
 
-       term_seen_key_event();         /* pasted data counts */
+       term_seen_key_event(term);     /* pasted data counts */
 
-        if (paste_buffer)
-            sfree(paste_buffer);
-        paste_pos = paste_hold = paste_len = 0;
-        paste_buffer = smalloc(len * sizeof(wchar_t));
+        if (term->paste_buffer)
+            sfree(term->paste_buffer);
+        term->paste_pos = term->paste_hold = term->paste_len = 0;
+        term->paste_buffer = smalloc(len * sizeof(wchar_t));
 
         p = q = data;
         while (p < data + len) {
@@ -3541,36 +3476,36 @@ void term_do_paste(void)
             {
                 int i;
                 for (i = 0; i < p - q; i++) {
-                    paste_buffer[paste_len++] = q[i];
+                    term->paste_buffer[term->paste_len++] = q[i];
                 }
             }
 
             if (p <= data + len - sel_nl_sz &&
                 !memcmp(p, sel_nl, sizeof(sel_nl))) {
-                paste_buffer[paste_len++] = '\r';
+                term->paste_buffer[term->paste_len++] = '\r';
                 p += sel_nl_sz;
             }
             q = p;
         }
 
         /* Assume a small paste will be OK in one go. */
-        if (paste_len < 256) {
-            luni_send(paste_buffer, paste_len, 0);
-            if (paste_buffer)
-                sfree(paste_buffer);
-            paste_buffer = 0;
-            paste_pos = paste_hold = paste_len = 0;
+        if (term->paste_len < 256) {
+            luni_send(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);
 }
 
-void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
+void term_mouse(Terminal *term, Mouse_Button b, Mouse_Action a, int x, int y,
                int shift, int ctrl, int alt)
 {
     pos selpoint;
     unsigned long *ldata;
-    int raw_mouse = (xterm_mouse &&
+    int raw_mouse = (term->xterm_mouse &&
                     !cfg.no_mouse_rep &&
                     !(cfg.mouse_override && shift));
     int default_seltype;
@@ -3578,27 +3513,27 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
     if (y < 0) {
        y = 0;
        if (a == MA_DRAG && !raw_mouse)
-           term_scroll(0, -1);
+           term_scroll(term, 0, -1);
     }
-    if (y >= rows) {
-       y = rows - 1;
+    if (y >= term->rows) {
+       y = term->rows - 1;
        if (a == MA_DRAG && !raw_mouse)
-           term_scroll(0, +1);
+           term_scroll(term, 0, +1);
     }
     if (x < 0) {
        if (y > 0) {
-           x = cols - 1;
+           x = term->cols - 1;
            y--;
        } else
            x = 0;
     }
-    if (x >= cols)
-       x = cols - 1;
+    if (x >= term->cols)
+       x = term->cols - 1;
 
-    selpoint.y = y + disptop;
+    selpoint.y = y + term->disptop;
     selpoint.x = x;
     ldata = lineptr(selpoint.y);
-    if ((ldata[cols] & LATTR_MODE) != LATTR_NORM)
+    if ((ldata[term->cols] & LATTR_MODE) != LATTR_NORM)
        selpoint.x /= 2;
 
     if (raw_mouse) {
@@ -3626,7 +3561,7 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
        }
        switch (a) {
          case MA_DRAG:
-           if (xterm_mouse == 1)
+           if (term->xterm_mouse == 1)
                return;
            encstate += 0x20;
            break;
@@ -3664,41 +3599,41 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
     else
        default_seltype = LEXICOGRAPHIC;
        
-    if (selstate == NO_SELECTION) {
-       seltype = default_seltype;
+    if (term->selstate == NO_SELECTION) {
+       term->seltype = default_seltype;
     }
 
     if (b == MBT_SELECT && a == MA_CLICK) {
-       deselect();
-       selstate = ABOUT_TO;
-       seltype = default_seltype;
-       selanchor = selpoint;
-       selmode = SM_CHAR;
+       deselect(term);
+       term->selstate = ABOUT_TO;
+       term->seltype = default_seltype;
+       term->selanchor = selpoint;
+       term->selmode = SM_CHAR;
     } else if (b == MBT_SELECT && (a == MA_2CLK || a == MA_3CLK)) {
-       deselect();
-       selmode = (a == MA_2CLK ? SM_WORD : SM_LINE);
-       selstate = DRAGGING;
-       selstart = selanchor = selpoint;
-       selend = selstart;
-       incpos(selend);
-       sel_spread();
+       deselect(term);
+       term->selmode = (a == MA_2CLK ? SM_WORD : SM_LINE);
+       term->selstate = DRAGGING;
+       term->selstart = term->selanchor = selpoint;
+       term->selend = term->selstart;
+       incpos(term->selend);
+       sel_spread(term);
     } else if ((b == MBT_SELECT && a == MA_DRAG) ||
               (b == MBT_EXTEND && a != MA_RELEASE)) {
-       if (selstate == ABOUT_TO && poseq(selanchor, selpoint))
+       if (term->selstate == ABOUT_TO && poseq(term->selanchor, selpoint))
            return;
-       if (b == MBT_EXTEND && a != MA_DRAG && selstate == SELECTED) {
-           if (seltype == LEXICOGRAPHIC) {
+       if (b == MBT_EXTEND && a != MA_DRAG && term->selstate == SELECTED) {
+           if (term->seltype == LEXICOGRAPHIC) {
                /*
                 * For normal selection, we extend by moving
                 * whichever end of the current selection is closer
                 * to the mouse.
                 */
-               if (posdiff(selpoint, selstart) <
-                   posdiff(selend, selstart) / 2) {
-                   selanchor = selend;
-                   decpos(selanchor);
+               if (posdiff(selpoint, term->selstart) <
+                   posdiff(term->selend, term->selstart) / 2) {
+                   term->selanchor = term->selend;
+                   decpos(term->selanchor);
                } else {
-                   selanchor = selstart;
+                   term->selanchor = term->selstart;
                }
            } else {
                /*
@@ -3706,34 +3641,34 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
                 * _four_ places to put selanchor and selpoint: the
                 * four corners of the selection.
                 */
-               if (2*selpoint.x < selstart.x + selend.x)
-                   selanchor.x = selend.x-1;
+               if (2*selpoint.x < term->selstart.x + term->selend.x)
+                   term->selanchor.x = term->selend.x-1;
                else
-                   selanchor.x = selstart.x;
+                   term->selanchor.x = term->selstart.x;
 
-               if (2*selpoint.y < selstart.y + selend.y)
-                   selanchor.y = selend.y;
+               if (2*selpoint.y < term->selstart.y + term->selend.y)
+                   term->selanchor.y = term->selend.y;
                else
-                   selanchor.y = selstart.y;
+                   term->selanchor.y = term->selstart.y;
            }
-           selstate = DRAGGING;
+           term->selstate = DRAGGING;
        }
-       if (selstate != ABOUT_TO && selstate != DRAGGING)
-           selanchor = selpoint;
-       selstate = DRAGGING;
-       if (seltype == LEXICOGRAPHIC) {
+       if (term->selstate != ABOUT_TO && term->selstate != DRAGGING)
+           term->selanchor = selpoint;
+       term->selstate = DRAGGING;
+       if (term->seltype == LEXICOGRAPHIC) {
            /*
             * For normal selection, we set (selstart,selend) to
             * (selpoint,selanchor) in some order.
             */
-           if (poslt(selpoint, selanchor)) {
-               selstart = selpoint;
-               selend = selanchor;
-               incpos(selend);
+           if (poslt(selpoint, term->selanchor)) {
+               term->selstart = selpoint;
+               term->selend = term->selanchor;
+               incpos(term->selend);
            } else {
-               selstart = selanchor;
-               selend = selpoint;
-               incpos(selend);
+               term->selstart = term->selanchor;
+               term->selend = selpoint;
+               incpos(term->selend);
            }
        } else {
            /*
@@ -3741,22 +3676,23 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
             * interchange x and y coordinates (if the user has
             * dragged in the -x and +y directions, or vice versa).
             */
-           selstart.x = min(selanchor.x, selpoint.x);
-           selend.x = 1+max(selanchor.x, selpoint.x);
-           selstart.y = min(selanchor.y, selpoint.y);
-           selend.y =   max(selanchor.y, selpoint.y);
+           term->selstart.x = min(term->selanchor.x, selpoint.x);
+           term->selend.x = 1+max(term->selanchor.x, selpoint.x);
+           term->selstart.y = min(term->selanchor.y, selpoint.y);
+           term->selend.y =   max(term->selanchor.y, selpoint.y);
        }
-       sel_spread();
+       sel_spread(term);
     } else if ((b == MBT_SELECT || b == MBT_EXTEND) && a == MA_RELEASE) {
-       if (selstate == DRAGGING) {
+       if (term->selstate == DRAGGING) {
            /*
             * We've completed a selection. We now transfer the
             * data to the clipboard.
             */
-           clipme(selstart, selend, (seltype == RECTANGULAR));
-           selstate = SELECTED;
+           clipme(term, term->selstart, term->selend,
+                  (term->seltype == RECTANGULAR));
+           term->selstate = SELECTED;
        } else
-           selstate = NO_SELECTION;
+           term->selstate = NO_SELECTION;
     } else if (b == MBT_PASTE
               && (a == MA_CLICK
 #if MULTICLICK_ONLY_EVENT
@@ -3766,88 +3702,89 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
        request_paste();
     }
 
-    term_update();
+    term_update(term);
 }
 
-void term_nopaste()
+void term_nopaste(Terminal *term)
 {
-    if (paste_len == 0)
+    if (term->paste_len == 0)
        return;
-    sfree(paste_buffer);
-    paste_buffer = 0;
-    paste_len = 0;
+    sfree(term->paste_buffer);
+    term->paste_buffer = 0;
+    term->paste_len = 0;
 }
 
-int term_paste_pending(void)
+int term_paste_pending(Terminal *term)
 {
-    return paste_len != 0;
+    return term->paste_len != 0;
 }
 
-void term_paste()
+void term_paste(Terminal *term)
 {
-    static long last_paste = 0;
     long now, paste_diff;
 
-    if (paste_len == 0)
+    if (term->paste_len == 0)
        return;
 
     /* Don't wait forever to paste */
-    if (paste_hold) {
+    if (term->paste_hold) {
        now = GETTICKCOUNT();
-       paste_diff = now - last_paste;
+       paste_diff = now - term->last_paste;
        if (paste_diff >= 0 && paste_diff < 450)
            return;
     }
-    paste_hold = 0;
+    term->paste_hold = 0;
 
-    while (paste_pos < paste_len) {
+    while (term->paste_pos < term->paste_len) {
        int n = 0;
-       while (n + paste_pos < paste_len) {
-           if (paste_buffer[paste_pos + n++] == '\r')
+       while (n + term->paste_pos < term->paste_len) {
+           if (term->paste_buffer[term->paste_pos + n++] == '\r')
                break;
        }
-       luni_send(paste_buffer + paste_pos, n, 0);
-       paste_pos += n;
+       luni_send(term->paste_buffer + term->paste_pos, n, 0);
+       term->paste_pos += n;
 
-       if (paste_pos < paste_len) {
-           paste_hold = 1;
+       if (term->paste_pos < term->paste_len) {
+           term->paste_hold = 1;
            return;
        }
     }
-    sfree(paste_buffer);
-    paste_buffer = 0;
-    paste_len = 0;
+    sfree(term->paste_buffer);
+    term->paste_buffer = NULL;
+    term->paste_len = 0;
 }
 
-static void deselect(void)
+static void deselect(Terminal *term)
 {
-    selstate = NO_SELECTION;
-    selstart.x = selstart.y = selend.x = selend.y = 0;
+    term->selstate = NO_SELECTION;
+    term->selstart.x = term->selstart.y = term->selend.x = term->selend.y = 0;
 }
 
-void term_deselect(void)
+void term_deselect(Terminal *term)
 {
-    deselect();
-    term_update();
+    deselect(term);
+    term_update(term);
 }
 
-int term_ldisc(int option)
+int term_ldisc(Terminal *term, int option)
 {
     if (option == LD_ECHO)
-       return term_echoing;
+       return term->term_echoing;
     if (option == LD_EDIT)
-       return term_editing;
+       return term->term_editing;
     return FALSE;
 }
 
 /*
  * from_backend(), to get data from the backend for the terminal.
  */
-int from_backend(int is_stderr, char *data, int len)
+int from_backend(void *vterm, int is_stderr, char *data, int len)
 {
+    Terminal *term = (Terminal *)vterm;
+
     assert(len > 0);
 
-    bufchain_add(&inbuf, data, len);
+    bufchain_add(&term->inbuf, data, len);
 
     /*
      * term_out() always completely empties inbuf. Therefore,
index f8cd3b5..182e244 100644 (file)
--- a/unicode.c
+++ b/unicode.c
@@ -8,6 +8,7 @@
 
 #include <time.h>
 #include "putty.h"
+#include "terminal.h"
 #include "misc.h"
 
 /* Character conversion arrays; they are usually taken from windows,
@@ -622,7 +623,7 @@ void luni_send(wchar_t * widebuf, int len, int interactive)
 {
     static char *linebuffer = 0;
     static int linesize = 0;
-    int ratio = (in_utf)?3:1;
+    int ratio = (in_utf(term))?3:1;
     int i;
     char *p;
 
@@ -632,7 +633,7 @@ void luni_send(wchar_t * widebuf, int len, int interactive)
        linesize = len * ratio * 2;
     }
 
-    if (in_utf) {
+    if (in_utf(term)) {
        /* UTF is a simple algorithm */
        for (p = linebuffer, i = 0; i < len; i++) {
            wchar_t ch = widebuf[i];
index 706ae03..c072e7a 100644 (file)
@@ -18,6 +18,7 @@
 
 #define PUTTY_DO_GLOBALS              /* actually _define_ globals */
 #include "putty.h"
+#include "terminal.h"
 
 #define CAT2(x,y) x ## y
 #define CAT(x,y) CAT2(x,y)
@@ -161,7 +162,7 @@ void set_zorder(int top)
  */
 void refresh_window(void)
 {
-    term_invalidate();
+    term_invalidate(term);
 }
 
 /*
@@ -286,7 +287,7 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
     }
 
     if (need_size) {
-       term_size(h, w, cfg.savelines);
+       term_size(term, h, w, cfg.savelines);
     }
 
     return TRUE;
@@ -410,11 +411,11 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
         * at all.
         */
        if (event->keyval == GDK_Page_Up && (event->state & GDK_SHIFT_MASK)) {
-           term_scroll(0, -cfg.height/2);
+           term_scroll(term, 0, -cfg.height/2);
            return TRUE;
        }
        if (event->keyval == GDK_Page_Down && (event->state & GDK_SHIFT_MASK)) {
-           term_scroll(0, +cfg.height/2);
+           term_scroll(term, 0, +cfg.height/2);
            return TRUE;
        }
 
@@ -517,7 +518,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
        /*
         * Application keypad mode.
         */
-       if (app_keypad_keys && !cfg.no_applic_k) {
+       if (term->app_keypad_keys && !cfg.no_applic_k) {
            int xkey = 0;
            switch (event->keyval) {
              case GDK_Num_Lock: xkey = 'P'; break;
@@ -555,7 +556,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
              case GDK_KP_Decimal: case GDK_KP_Delete: xkey = 'n'; break;
            }
            if (xkey) {
-               if (vt52_mode) {
+               if (term->vt52_mode) {
                    if (xkey >= 'P' && xkey <= 'S')
                        end = 1 + sprintf(output+1, "\033%c", xkey);
                    else
@@ -663,7 +664,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
            if (cfg.funky_type == 3 && code <= 6)
                code = "\0\2\1\4\5\3\6"[code];
 
-           if (vt52_mode && code > 0 && code <= 6) {
+           if (term->vt52_mode && code > 0 && code <= 6) {
                end = 1 + sprintf(output+1, "\x1B%c", " HLMEIG"[code]);
                goto done;
            }
@@ -702,13 +703,14 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
                }
                goto done;
            }
-           if ((vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) {
+           if ((term->vt52_mode || cfg.funky_type == 4) &&
+               code >= 11 && code <= 24) {
                int offt = 0;
                if (code > 15)
                    offt++;
                if (code > 21)
                    offt++;
-               if (vt52_mode)
+               if (term->vt52_mode)
                    end = 1 + sprintf(output+1,
                                      "\x1B%c", code + 'P' - 11 - offt);
                else
@@ -721,7 +723,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
                goto done;
            }
            if (cfg.funky_type == 2 && code >= 11 && code <= 14) {
-               if (vt52_mode)
+               if (term->vt52_mode)
                    end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11);
                else
                    end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11);
@@ -759,9 +761,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
                 * app cursor keys mode they do ESC O A instead.
                 * Ctrl toggles the two modes.
                 */
-               if (vt52_mode) {
+               if (term->vt52_mode) {
                    end = 1 + sprintf(output+1, "\033%c", xkey);
-               } else if (!app_cursor_keys ^
+               } else if (!term->app_cursor_keys ^
                           !(event->state & GDK_CONTROL_MASK)) {
                    end = 1 + sprintf(output+1, "\033O%c", xkey);
                } else {                    
@@ -786,8 +788,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
 
        ldisc_send(output+start, end-start, 1);
        show_mouseptr(0);
-       term_seen_key_event();
-       term_out();
+       term_seen_key_event(term);
+       term_out(term);
     }
 
     return TRUE;
@@ -801,11 +803,11 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
     show_mouseptr(1);
 
     if (event->button == 4 && event->type == GDK_BUTTON_PRESS) {
-       term_scroll(0, -5);
+       term_scroll(term, 0, -5);
        return TRUE;
     }
     if (event->button == 5 && event->type == GDK_BUTTON_PRESS) {
-       term_scroll(0, +5);
+       term_scroll(term, 0, +5);
        return TRUE;
     }
 
@@ -836,7 +838,7 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
     x = (event->x - cfg.window_border) / inst->font_width;
     y = (event->y - cfg.window_border) / inst->font_height;
 
-    term_mouse(button, act, x, y, shift, ctrl, alt);
+    term_mouse(term, button, act, x, y, shift, ctrl, alt);
 
     return TRUE;
 }
@@ -863,7 +865,7 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
     x = (event->x - cfg.window_border) / inst->font_width;
     y = (event->y - cfg.window_border) / inst->font_height;
 
-    term_mouse(button, MA_DRAG, x, y, shift, ctrl, alt);
+    term_mouse(term, button, MA_DRAG, x, y, shift, ctrl, alt);
 
     return TRUE;
 }
@@ -885,8 +887,8 @@ gint timer_func(gpointer data)
        exit(0);
     }
 
-    term_update();
-    term_blink(0);
+    term_update(term);
+    term_blink(term, 0);
     return TRUE;
 }
 
@@ -912,9 +914,9 @@ void pty_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
        exit(1);
     }
     if (ret > 0)
-       from_backend(0, buf, ret);
-    term_blink(1);
-    term_out();
+       from_backend(term, 0, buf, ret);
+    term_blink(term, 1);
+    term_out(term);
 }
 
 void destroy(GtkWidget *widget, gpointer data)
@@ -924,9 +926,9 @@ void destroy(GtkWidget *widget, gpointer data)
 
 gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
 {
-    has_focus = event->in;
-    term_out();
-    term_update();
+    term->has_focus = event->in;
+    term_out(term);
+    term_update(term);
     show_mouseptr(1);
     return FALSE;
 }
@@ -1100,7 +1102,7 @@ void selection_get(GtkWidget *widget, GtkSelectionData *seldata,
 gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
                     gpointer data)
 {
-    term_deselect();
+    term_deselect(term);
     if (inst->pasteout_data)
        sfree(inst->pasteout_data);
     inst->pasteout_data = NULL;
@@ -1136,9 +1138,9 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
     mb_to_wc(0, 0, seldata->data, seldata->length,
             inst->pastein_data, inst->pastein_data_len);
 
-    term_do_paste();
+    term_do_paste(term);
 
-    if (term_paste_pending())
+    if (term_paste_pending(term))
        inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);
 }
 
@@ -1146,8 +1148,8 @@ gint idle_paste_func(gpointer data)
 {
     struct gui_data *inst = (struct gui_data *)data;
 
-    if (term_paste_pending())
-       term_paste();
+    if (term_paste_pending(term))
+       term_paste(term);
     else
        gtk_idle_remove(inst->term_paste_idle_id);
 
@@ -1197,7 +1199,7 @@ void scrollbar_moved(GtkAdjustment *adj, gpointer data)
     if (!cfg.scrollbar)
        return;
     if (!inst->ignore_sbar)
-       term_scroll(1, (int)adj->value);
+       term_scroll(term, 1, (int)adj->value);
 }
 
 void sys_cursor(int x, int y)
@@ -1280,10 +1282,10 @@ void do_text_internal(Context ctx, int x, int y, char *text, int len,
 
     if (lattr != LATTR_NORM) {
        x *= 2;
-       if (x >= cols)
+       if (x >= term->cols)
            return;
-       if (x + len*2 > cols)
-           len = (cols-x)/2;          /* trim to LH half */
+       if (x + len*2 > term->cols)
+           len = (term->cols-x)/2;    /* trim to LH half */
     }
 
     gdk_gc_set_foreground(gc, &inst->cols[nbg]);
@@ -1362,10 +1364,10 @@ void do_text(Context ctx, int x, int y, char *text, int len,
 
     if (lattr != LATTR_NORM) {
        x *= 2;
-       if (x >= cols)
+       if (x >= term->cols)
            return;
-       if (x + len*2 > cols)
-           len = (cols-x)/2;          /* trim to LH half */
+       if (x + len*2 > term->cols)
+           len = (term->cols-x)/2;    /* trim to LH half */
        len *= 2;
     }
 
@@ -1395,10 +1397,10 @@ void do_cursor(Context ctx, int x, int y, char *text, int len,
 
     if (lattr != LATTR_NORM) {
        x *= 2;
-       if (x >= cols)
+       if (x >= term->cols)
            return;
-       if (x + len*2 > cols)
-           len = (cols-x)/2;          /* trim to LH half */
+       if (x + len*2 > term->cols)
+           len = (term->cols-x)/2;    /* trim to LH half */
        len *= 2;
     }
 
@@ -1875,13 +1877,15 @@ int main(int argc, char **argv)
     inst->currcursor = inst->textcursor;
     show_mouseptr(1);
 
+    term = term_init();
+
     back = &pty_backend;
-    back->init(NULL, 0, NULL, 0);
+    back->init((void *)term, NULL, 0, NULL, 0);
 
-    gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst);
+    term_size(term, cfg.height, cfg.width, cfg.savelines);
+    ldisc_send(NULL, 0, 0);           /* cause ldisc to notice changes */
 
-    term_init();
-    term_size(cfg.height, cfg.width, cfg.savelines);
+    gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst);
 
     gtk_main();
 
index 7fe0dc7..98ea4f2 100644 (file)
@@ -18,6 +18,7 @@
 #include <sys/ioctl.h>
 
 #include "putty.h"
+#include "terminal.h"
 
 #ifndef FALSE
 #define FALSE 0
@@ -372,7 +373,8 @@ void pty_pre_init(void)
  * Also places the canonical host name into `realhost'. It must be
  * freed by the caller.
  */
-static char *pty_init(char *host, int port, char **realhost, int nodelay)
+static char *pty_init(void *frontend,
+                     char *host, int port, char **realhost, int nodelay)
 {
     int slavefd;
     pid_t pid, pgrp;
@@ -521,10 +523,10 @@ static void pty_size(void)
 {
     struct winsize size;
 
-    size.ws_row = (unsigned short)rows;
-    size.ws_col = (unsigned short)cols;
-    size.ws_xpixel = (unsigned short) cols * font_dimension(0);
-    size.ws_ypixel = (unsigned short) rows * font_dimension(1);
+    size.ws_row = (unsigned short)term->rows;
+    size.ws_col = (unsigned short)term->cols;
+    size.ws_xpixel = (unsigned short) term->cols * font_dimension(0);
+    size.ws_ypixel = (unsigned short) term->rows * font_dimension(1);
     ioctl(pty_master_fd, TIOCSWINSZ, (void *)&size);
     return;
 }
index b0b825c..78d196f 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <time.h>
 #include "putty.h"
+#include "terminal.h"
 #include "misc.h"
 
 /*
@@ -22,7 +23,7 @@ void luni_send(wchar_t * widebuf, int len, int interactive)
 {
     static char *linebuffer = 0;
     static int linesize = 0;
-    int ratio = (in_utf)?6:1;
+    int ratio = (in_utf(term))?6:1;
     int i;
     char *p;
 
@@ -32,7 +33,7 @@ void luni_send(wchar_t * widebuf, int len, int interactive)
        linesize = len * ratio * 2;
     }
 
-    if (in_utf) {
+    if (in_utf(term)) {
        /* UTF is a simple algorithm */
        for (p = linebuffer, i = 0; i < len; i++) {
            wchar_t ch = widebuf[i];
index 3b60154..abbfdd8 100644 (file)
--- a/window.c
+++ b/window.c
@@ -26,6 +26,7 @@
 
 #define PUTTY_DO_GLOBALS              /* actually _define_ globals */
 #include "putty.h"
+#include "terminal.h"
 #include "winstuff.h"
 #include "storage.h"
 #include "win_res.h"
@@ -492,8 +493,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 
     hwnd = NULL;
 
-    savelines = cfg.savelines;
-    term_init();
+    term = term_init();
 
     cfgtopalette();
 
@@ -508,9 +508,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     font_height = 20;
     extra_width = 25;
     extra_height = 28;
-    term_size(cfg.height, cfg.width, cfg.savelines);
-    guess_width = extra_width + font_width * cols;
-    guess_height = extra_height + font_height * rows;
+    term_size(term, cfg.height, cfg.width, cfg.savelines);
+    guess_width = extra_width + font_width * term->cols;
+    guess_height = extra_height + font_height * term->rows;
     {
        RECT r;
                get_fullscreen_rect(&r);
@@ -559,8 +559,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      * Resize the window, now we know what size we _really_ want it
      * to be.
      */
-    guess_width = extra_width + font_width * cols;
-    guess_height = extra_height + font_height * rows;
+    guess_width = extra_width + font_width * term->cols;
+    guess_height = extra_height + font_height * term->rows;
     SetWindowPos(hwnd, NULL, 0, 0, guess_width, guess_height,
                 SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
 
@@ -586,8 +586,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        si.cbSize = sizeof(si);
        si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
        si.nMin = 0;
-       si.nMax = rows - 1;
-       si.nPage = rows;
+       si.nMax = term->rows - 1;
+       si.nPage = term->rows;
        si.nPos = 0;
        SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
     }
@@ -600,7 +600,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        char msg[1024], *title;
        char *realhost;
 
-       error = back->init(cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
+       error = back->init((void *)term,
+                          cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
        if (error) {
            sprintf(msg, "Unable to open connection to\n"
                    "%.800s\n" "%s", cfg.host, error);
@@ -706,7 +707,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     logpal = NULL;
     init_palette();
 
-    has_focus = (GetForegroundWindow() == hwnd);
+    term->has_focus = (GetForegroundWindow() == hwnd);
     UpdateWindow(hwnd);
 
     if (GetMessage(&msg, NULL, 0, 0) == 1) {
@@ -729,10 +730,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                DispatchMessage(&msg);
 
            /* Make sure we blink everything that needs it. */
-           term_blink(0);
+           term_blink(term, 0);
 
            /* Send the paste buffer if there's anything to send */
-           term_paste();
+           term_paste(term);
 
            /* If there's nothing new in the queue then we can do everything
             * we've delayed, reading the socket, writing, and repainting
@@ -745,7 +746,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                enact_pending_netevent();
 
                /* Force the cursor blink on */
-               term_blink(1);
+               term_blink(term, 1);
 
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                    continue;
@@ -761,20 +762,21 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
            }
            HideCaret(hwnd);
            if (GetCapture() != hwnd || 
-               (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed())))
-               term_out();
-           term_update();
+               (send_raw_mouse &&
+                !(cfg.mouse_override && is_shift_pressed())))
+               term_out(term);
+           term_update(term);
            ShowCaret(hwnd);
 
            flash_window(1);           /* maintain */
 
            /* The messages seem unreliable; especially if we're being tricky */
-           has_focus = (GetForegroundWindow() == hwnd);
+           term->has_focus = (GetForegroundWindow() == hwnd);
 
-           if (in_vbell)
+           if (term->in_vbell)
                /* Hmm, term_update didn't want to do an update too soon ... */
                timer_id = SetTimer(hwnd, 1, 50, NULL);
-           else if (!has_focus)
+           else if (!term->has_focus)
                timer_id = SetTimer(hwnd, 1, 500, NULL);
            else
                timer_id = SetTimer(hwnd, 1, 100, NULL);
@@ -1250,7 +1252,7 @@ void request_resize(int w, int h)
     }
 
     if (cfg.resize_action == RESIZE_DISABLED) return;
-    if (h == rows && w == cols) return;
+    if (h == term->rows && w == term->cols) return;
 
     /* Sanity checks ... */
     {
@@ -1280,7 +1282,7 @@ void request_resize(int w, int h)
        }
     }
 
-    term_size(h, w, cfg.savelines);
+    term_size(term, h, w, cfg.savelines);
 
     if (cfg.resize_action != RESIZE_FONT && !IsZoomed(hwnd)) {
        width = extra_width + font_width * w;
@@ -1334,10 +1336,10 @@ static void reset_window(int reinit) {
 
     /* Is the window out of position ? */
     if ( !reinit && 
-           (offset_width != (win_width-font_width*cols)/2 ||
-            offset_height != (win_height-font_height*rows)/2) ){
-       offset_width = (win_width-font_width*cols)/2;
-       offset_height = (win_height-font_height*rows)/2;
+           (offset_width != (win_width-font_width*term->cols)/2 ||
+            offset_height != (win_height-font_height*term->rows)/2) ){
+       offset_width = (win_width-font_width*term->cols)/2;
+       offset_height = (win_height-font_height*term->rows)/2;
        InvalidateRect(hwnd, NULL, TRUE);
 #ifdef RDB_DEBUG_PATCH
        debug((27, "reset_window() -> Reposition terminal"));
@@ -1353,12 +1355,12 @@ static void reset_window(int reinit) {
        extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
 
        if (cfg.resize_action != RESIZE_TERM) {
-           if (  font_width != win_width/cols || 
-                 font_height != win_height/rows) {
+           if (  font_width != win_width/term->cols || 
+                 font_height != win_height/term->rows) {
                deinit_fonts();
-               init_fonts(win_width/cols, win_height/rows);
-               offset_width = (win_width-font_width*cols)/2;
-               offset_height = (win_height-font_height*rows)/2;
+               init_fonts(win_width/term->cols, win_height/term->rows);
+               offset_width = (win_width-font_width*term->cols)/2;
+               offset_height = (win_height-font_height*term->rows)/2;
                InvalidateRect(hwnd, NULL, TRUE);
 #ifdef RDB_DEBUG_PATCH
                debug((25, "reset_window() -> Z font resize to (%d, %d)",
@@ -1366,15 +1368,15 @@ static void reset_window(int reinit) {
 #endif
            }
        } else {
-           if (  font_width != win_width/cols || 
-                 font_height != win_height/rows) {
+           if (  font_width != win_width/term->cols || 
+                 font_height != win_height/term->rows) {
                /* Our only choice at this point is to change the 
                 * size of the terminal; Oh well.
                 */
-               term_size( win_height/font_height, win_width/font_width,
-                          cfg.savelines);
-               offset_width = (win_width-font_width*cols)/2;
-               offset_height = (win_height-font_height*rows)/2;
+               term_size(term, win_height/font_height, win_width/font_width,
+                         cfg.savelines);
+               offset_width = (win_width-font_width*term->cols)/2;
+               offset_height = (win_height-font_height*term->rows)/2;
                InvalidateRect(hwnd, NULL, TRUE);
 #ifdef RDB_DEBUG_PATCH
                debug((27, "reset_window() -> Zoomed term_size"));
@@ -1396,16 +1398,16 @@ static void reset_window(int reinit) {
        extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2;
        extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2;
 
-       if (win_width != font_width*cols + offset_width*2 ||
-           win_height != font_height*rows + offset_height*2) {
+       if (win_width != font_width*term->cols + offset_width*2 ||
+           win_height != font_height*term->rows + offset_height*2) {
 
            /* If this is too large windows will resize it to the maximum
             * allowed window size, we will then be back in here and resize
             * the font or terminal to fit.
             */
            SetWindowPos(hwnd, NULL, 0, 0, 
-                        font_width*cols + extra_width, 
-                        font_height*rows + extra_height,
+                        font_width*term->cols + extra_width, 
+                        font_height*term->rows + extra_height,
                         SWP_NOMOVE | SWP_NOZORDER);
        }
 
@@ -1424,8 +1426,8 @@ static void reset_window(int reinit) {
        extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2;
        extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2;
 
-       if (win_width != font_width*cols + offset_width*2 ||
-           win_height != font_height*rows + offset_height*2) {
+       if (win_width != font_width*term->cols + offset_width*2 ||
+           win_height != font_height*term->rows + offset_height*2) {
 
            static RECT ss;
            int width, height;
@@ -1436,13 +1438,15 @@ static void reset_window(int reinit) {
            height = (ss.bottom - ss.top - extra_height) / font_height;
 
            /* Grrr too big */
-           if ( rows > height || cols > width ) {
+           if ( term->rows > height || term->cols > width ) {
                if (cfg.resize_action == RESIZE_EITHER) {
                    /* Make the font the biggest we can */
-                   if (cols > width)
-                       font_width = (ss.right - ss.left - extra_width)/cols;
-                   if (rows > height)
-                       font_height = (ss.bottom - ss.top - extra_height)/rows;
+                   if (term->cols > width)
+                       font_width = (ss.right - ss.left - extra_width)
+                           / term->cols;
+                   if (term->rows > height)
+                       font_height = (ss.bottom - ss.top - extra_height)
+                           / term->rows;
 
                    deinit_fonts();
                    init_fonts(font_width, font_height);
@@ -1450,9 +1454,9 @@ static void reset_window(int reinit) {
                    width = (ss.right - ss.left - extra_width) / font_width;
                    height = (ss.bottom - ss.top - extra_height) / font_height;
                } else {
-                   if ( height > rows ) height = rows;
-                   if ( width > cols )  width = cols;
-                   term_size(height, width, cfg.savelines);
+                   if ( height > term->rows ) height = term->rows;
+                   if ( width > term->cols )  width = term->cols;
+                   term_size(term, height, width, cfg.savelines);
 #ifdef RDB_DEBUG_PATCH
                    debug((27, "reset_window() -> term resize to (%d,%d)",
                               height, width));
@@ -1461,15 +1465,15 @@ static void reset_window(int reinit) {
            }
            
            SetWindowPos(hwnd, NULL, 0, 0, 
-                        font_width*cols + extra_width, 
-                        font_height*rows + extra_height,
+                        font_width*term->cols + extra_width, 
+                        font_height*term->rows + extra_height,
                         SWP_NOMOVE | SWP_NOZORDER);
 
            InvalidateRect(hwnd, NULL, TRUE);
 #ifdef RDB_DEBUG_PATCH
            debug((27, "reset_window() -> window resize to (%d,%d)",
-                       font_width*cols + extra_width,
-                       font_height*rows + extra_height));
+                       font_width*term->cols + extra_width,
+                       font_height*term->rows + extra_height));
 #endif
        }
        return;
@@ -1477,14 +1481,14 @@ static void reset_window(int reinit) {
 
     /* We're allowed to or must change the font but do we want to ?  */
 
-    if (font_width != (win_width-cfg.window_border*2)/cols || 
-       font_height != (win_height-cfg.window_border*2)/rows) {
+    if (font_width != (win_width-cfg.window_border*2)/term->cols || 
+       font_height != (win_height-cfg.window_border*2)/term->rows) {
 
        deinit_fonts();
-       init_fonts((win_width-cfg.window_border*2)/cols, 
-                  (win_height-cfg.window_border*2)/rows);
-       offset_width = (win_width-font_width*cols)/2;
-       offset_height = (win_height-font_height*rows)/2;
+       init_fonts((win_width-cfg.window_border*2)/term->cols, 
+                  (win_height-cfg.window_border*2)/term->rows);
+       offset_width = (win_width-font_width*term->cols)/2;
+       offset_height = (win_height-font_height*term->rows)/2;
 
        extra_width = wr.right - wr.left - cr.right + cr.left +offset_width*2;
        extra_height = wr.bottom - wr.top - cr.bottom + cr.top+offset_height*2;
@@ -1513,7 +1517,7 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt)
 
     if (send_raw_mouse && !(cfg.mouse_override && shift)) {
        lastbtn = MBT_NOTHING;
-       term_mouse(b, MA_CLICK, x, y, shift, ctrl, alt);
+       term_mouse(term, b, MA_CLICK, x, y, shift, ctrl, alt);
        return;
     }
 
@@ -1526,7 +1530,7 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt)
        lastact = MA_CLICK;
     }
     if (lastact != MA_NOTHING)
-       term_mouse(b, lastact, x, y, shift, ctrl, alt);
+       term_mouse(term, b, lastact, x, y, shift, ctrl, alt);
     lasttime = thistime;
 }
 
@@ -1597,10 +1601,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            enact_pending_netevent();
        if (GetCapture() != hwnd || 
            (send_raw_mouse && !(cfg.mouse_override && is_shift_pressed())))
-           term_out();
+           term_out(term);
        noise_regular();
        HideCaret(hwnd);
-       term_update();
+       term_update(term);
        ShowCaret(hwnd);
        if (cfg.ping_interval > 0) {
            time_t now;
@@ -1748,7 +1752,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                init_palette();
 
                /* Give terminal a heads-up on miscellaneous stuff */
-               term_reconfig();
+               term_reconfig(term);
 
                /* Screen size changed ? */
                if (cfg.height != prev_cfg.height ||
@@ -1757,7 +1761,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    cfg.resize_action == RESIZE_FONT ||
                    (cfg.resize_action == RESIZE_EITHER && IsZoomed(hwnd)) ||
                    cfg.resize_action == RESIZE_DISABLED)
-                   term_size(cfg.height, cfg.width, cfg.savelines);
+                   term_size(term, cfg.height, cfg.width, cfg.savelines);
 
                /* Enable or disable the scroll bar, etc */
                {
@@ -1846,13 +1850,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            }
            break;
          case IDM_COPYALL:
-           term_copyall();
+           term_copyall(term);
            break;
          case IDM_CLRSB:
-           term_clrsb();
+           term_clrsb(term);
            break;
          case IDM_RESET:
-           term_pwron();
+           term_pwron(term);
+           ldisc_send(NULL, 0, 0);
            break;
          case IDM_TEL_AYT:
            back->special(TS_AYT);
@@ -2004,7 +2009,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                      is_alt_pressed());
                SetCapture(hwnd);
            } else {
-               term_mouse(button, MA_RELEASE,
+               term_mouse(term, button, MA_RELEASE,
                           TO_CHR_X(X_POS(lParam)),
                           TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
                           wParam & MK_CONTROL, is_alt_pressed());
@@ -2029,7 +2034,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                b = MBT_MIDDLE;
            else
                b = MBT_RIGHT;
-           term_mouse(b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
+           term_mouse(term, b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
                       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
                       wParam & MK_CONTROL, is_alt_pressed());
        }
@@ -2043,7 +2048,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        break;
       case WM_DESTROYCLIPBOARD:
        if (!ignore_clip)
-           term_deselect();
+           term_deselect(term);
        ignore_clip = FALSE;
        return 0;
       case WM_PAINT:
@@ -2055,7 +2060,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                SelectPalette(hdc, pal, TRUE);
                RealizePalette(hdc);
            }
-           term_paint(hdc, 
+           term_paint(term, hdc, 
                       (p.rcPaint.left-offset_width)/font_width,
                       (p.rcPaint.top-offset_height)/font_height,
                       (p.rcPaint.right-offset_width-1)/font_width,
@@ -2064,8 +2069,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (p.fErase ||
                p.rcPaint.left  < offset_width  ||
                p.rcPaint.top   < offset_height ||
-               p.rcPaint.right >= offset_width + font_width*cols ||
-               p.rcPaint.bottom>= offset_height + font_height*rows)
+               p.rcPaint.right >= offset_width + font_width*term->cols ||
+               p.rcPaint.bottom>= offset_height + font_height*term->rows)
            {
                HBRUSH fillcolour, oldbrush;
                HPEN   edge, oldpen;
@@ -2089,8 +2094,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
                ExcludeClipRect(hdc, 
                        offset_width, offset_height,
-                       offset_width+font_width*cols,
-                       offset_height+font_height*rows);
+                       offset_width+font_width*term->cols,
+                       offset_height+font_height*term->rows);
 
                Rectangle(hdc, p.rcPaint.left, p.rcPaint.top, 
                          p.rcPaint.right, p.rcPaint.bottom);
@@ -2125,21 +2130,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        time(&last_movement);
        return 0;
       case WM_SETFOCUS:
-       has_focus = TRUE;
+       term->has_focus = TRUE;
        CreateCaret(hwnd, caretbm, font_width, font_height);
        ShowCaret(hwnd);
        flash_window(0);               /* stop */
        compose_state = 0;
-       term_out();
-       term_update();
+       term_out(term);
+       term_update(term);
        break;
       case WM_KILLFOCUS:
        show_mouseptr(1);
-       has_focus = FALSE;
+       term->has_focus = FALSE;
        DestroyCaret();
        caret_x = caret_y = -1;        /* ensure caret is replaced next time */
-       term_out();
-       term_update();
+       term_out(term);
+       term_update(term);
        break;
       case WM_ENTERSIZEMOVE:
 #ifdef RDB_DEBUG_PATCH
@@ -2156,7 +2161,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
        debug((27, "WM_EXITSIZEMOVE"));
 #endif
        if (need_backend_resize) {
-           term_size(cfg.height, cfg.width, cfg.savelines);
+           term_size(term, cfg.height, cfg.width, cfg.savelines);
            InvalidateRect(hwnd, NULL, TRUE);
        }
        break;
@@ -2171,7 +2176,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            LPRECT r = (LPRECT) lParam;
 
            if ( !need_backend_resize && cfg.resize_action == RESIZE_EITHER &&
-                   (cfg.height != rows || cfg.width != cols )) {
+                   (cfg.height != term->rows || cfg.width != term->cols )) {
                /* 
                 * Great! It seems that both the terminal size and the
                 * font size have been changed and the user is now dragging.
@@ -2181,10 +2186,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                 *
                 * This would be easier but it seems to be too confusing.
 
-               term_size(cfg.height, cfg.width, cfg.savelines);
+               term_size(term, cfg.height, cfg.width, cfg.savelines);
                reset_window(2);
                 */
-               cfg.height=rows; cfg.width=cols;
+               cfg.height=term->rows; cfg.width=term->cols;
 
                InvalidateRect(hwnd, NULL, TRUE);
                need_backend_resize = TRUE;
@@ -2228,25 +2233,25 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            width = r->right - r->left - ex_width;
            height = r->bottom - r->top - ex_height;
 
-           w = (width + cols/2)/cols;
-           h = (height + rows/2)/rows;
-           if ( r->right != r->left + w*cols + ex_width) 
+           w = (width + term->cols/2)/term->cols;
+           h = (height + term->rows/2)/term->rows;
+           if ( r->right != r->left + w*term->cols + ex_width)
                rv = 1;
 
            if (wParam == WMSZ_LEFT ||
                wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_TOPLEFT)
-               r->left = r->right - w*cols - ex_width;
+               r->left = r->right - w*term->cols - ex_width;
            else
-               r->right = r->left + w*cols + ex_width;
+               r->right = r->left + w*term->cols + ex_width;
 
-           if (r->bottom != r->top + h*rows + ex_height)
+           if (r->bottom != r->top + h*term->rows + ex_height)
                rv = 1;
 
            if (wParam == WMSZ_TOP ||
                wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)
-               r->top = r->bottom - h*rows - ex_height;
+               r->top = r->bottom - h*term->rows - ex_height;
            else
-               r->bottom = r->top + h*rows + ex_height;
+               r->bottom = r->top + h*term->rows + ex_height;
 
            return rv;
        }
@@ -2292,21 +2297,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (!resizing) {
                if (wParam == SIZE_MAXIMIZED && !was_zoomed) {
                    was_zoomed = 1;
-                   prev_rows = rows;
-                   prev_cols = cols;
+                   prev_rows = term->rows;
+                   prev_cols = term->cols;
                    if (cfg.resize_action == RESIZE_TERM) {
                        w = width / font_width;
                        if (w < 1) w = 1;
                        h = height / font_height;
                        if (h < 1) h = 1;
 
-                       term_size(h, w, cfg.savelines);
+                       term_size(term, h, w, cfg.savelines);
                    }
                    reset_window(0);
                } else if (wParam == SIZE_RESTORED && was_zoomed) {
                    was_zoomed = 0;
                    if (cfg.resize_action == RESIZE_TERM)
-                       term_size(prev_rows, prev_cols, cfg.savelines);
+                       term_size(term, prev_rows, prev_cols, cfg.savelines);
                    if (cfg.resize_action != RESIZE_FONT)
                        reset_window(2);
                    else
@@ -2345,26 +2350,26 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_VSCROLL:
        switch (LOWORD(wParam)) {
          case SB_BOTTOM:
-           term_scroll(-1, 0);
+           term_scroll(term, -1, 0);
            break;
          case SB_TOP:
-           term_scroll(+1, 0);
+           term_scroll(term, +1, 0);
            break;
          case SB_LINEDOWN:
-           term_scroll(0, +1);
+           term_scroll(term, 0, +1);
            break;
          case SB_LINEUP:
-           term_scroll(0, -1);
+           term_scroll(term, 0, -1);
            break;
          case SB_PAGEDOWN:
-           term_scroll(0, +rows / 2);
+           term_scroll(term, 0, +term->rows / 2);
            break;
          case SB_PAGEUP:
-           term_scroll(0, -rows / 2);
+           term_scroll(term, 0, -term->rows / 2);
            break;
          case SB_THUMBPOSITION:
          case SB_THUMBTRACK:
-           term_scroll(1, HIWORD(wParam));
+           term_scroll(term, 1, HIWORD(wParam));
            break;
        }
        break;
@@ -2429,7 +2434,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                     * preferable to having to faff about buffering
                     * things.
                     */
-                   term_nopaste();
+                   term_nopaste(term);
 
                    /*
                     * We need not bother about stdin backlogs
@@ -2439,7 +2444,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                     * messages. We _have_ to buffer everything
                     * we're sent.
                     */
-                   term_seen_key_event();
+                   term_seen_key_event(term);
                    ldisc_send(buf, len, 1);
                    show_mouseptr(0);
                }
@@ -2486,7 +2491,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                 * luni_send() covering the whole of buff. So
                 * instead we luni_send the characters one by one.
                 */
-               term_seen_key_event();
+               term_seen_key_event(term);
                for (i = 0; i < n; i += 2) {
                    luni_send((unsigned short *)(buff+i), 1, 1);
                }
@@ -2502,11 +2507,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
            buf[1] = wParam;
            buf[0] = wParam >> 8;
-           term_seen_key_event();
+           term_seen_key_event(term);
            lpage_send(kbd_codepage, buf, 2, 1);
        } else {
            char c = (unsigned char) wParam;
-           term_seen_key_event();
+           term_seen_key_event(term);
            lpage_send(kbd_codepage, &c, 1, 1);
        }
        return (0);
@@ -2520,7 +2525,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
         */
        {
            char c = (unsigned char)wParam;
-           term_seen_key_event();
+           term_seen_key_event(term);
            lpage_send(CP_ACP, &c, 1, 1);
        }
        return 0;
@@ -2563,18 +2568,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                if (send_raw_mouse &&
                    !(cfg.mouse_override && shift_pressed)) {
                    /* send a mouse-down followed by a mouse up */
-                   term_mouse(b,
+                   term_mouse(term, b,
                               MA_CLICK,
                               TO_CHR_X(X_POS(lParam)),
                               TO_CHR_Y(Y_POS(lParam)), shift_pressed,
                               control_pressed, is_alt_pressed());
-                   term_mouse(b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
+                   term_mouse(term, b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
                               TO_CHR_Y(Y_POS(lParam)), shift_pressed,
                               control_pressed, is_alt_pressed());
                } else {
                    /* trigger a scroll */
-                   term_scroll(0,
-                               b == MBT_WHEEL_UP ? -rows / 2 : rows / 2);
+                   term_scroll(term, 0,
+                               b == MBT_WHEEL_UP ?
+                               -term->rows / 2 : term->rows / 2);
                }
            }
            return 0;
@@ -2594,7 +2600,7 @@ void sys_cursor(int x, int y)
 {
     int cx, cy;
 
-    if (!has_focus) return;
+    if (!term->has_focus) return;
 
     /*
      * Avoid gratuitously re-updating the cursor position and IMM
@@ -2615,7 +2621,7 @@ static void sys_cursor_update(void)
     COMPOSITIONFORM cf;
     HIMC hIMC;
 
-    if (!has_focus) return;
+    if (!term->has_focus) return;
 
     if (caret_x < 0 || caret_y < 0)
        return;
@@ -2672,7 +2678,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     }
 
     /* Only want the left half of double width lines */
-    if (lattr != LATTR_NORM && x*2 >= cols)
+    if (lattr != LATTR_NORM && x*2 >= term->cols)
        return;
 
     x *= fnt_width;
@@ -2680,7 +2686,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     x += offset_width;
     y += offset_height;
 
-    if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || big_cursor)) {
+    if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) {
        attr &= ATTR_CUR_AND | (bold_mode != BOLD_COLOURS ? ATTR_BOLD : 0);
        attr ^= ATTR_CUR_XOR;
     }
@@ -2781,8 +2787,8 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     line_box.bottom = y + font_height;
 
     /* Only want the left half of double width lines */
-    if (line_box.right > font_width*cols+offset_width)
-       line_box.right = font_width*cols+offset_width;
+    if (line_box.right > font_width*term->cols+offset_width)
+       line_box.right = font_width*term->cols+offset_width;
 
     /* We're using a private area for direct to font. (512 chars.) */
     if (dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) {
@@ -2896,7 +2902,7 @@ void do_cursor(Context ctx, int x, int y, char *text, int len,
     HDC hdc = ctx;
     int ctype = cfg.cursor_type;
 
-    if ((attr & TATTR_ACTCURS) && (ctype == 0 || big_cursor)) {
+    if ((attr & TATTR_ACTCURS) && (ctype == 0 || term->big_cursor)) {
        if (((attr & CSET_MASK) | (unsigned char) *text) != UCSWIDE) {
            do_text(ctx, x, y, text, len, attr, lattr);
            return;
@@ -2913,7 +2919,7 @@ void do_cursor(Context ctx, int x, int y, char *text, int len,
     x += offset_width;
     y += offset_height;
 
-    if ((attr & TATTR_PASCURS) && (ctype == 0 || big_cursor)) {
+    if ((attr & TATTR_PASCURS) && (ctype == 0 || term->big_cursor)) {
        POINT pts[5];
        HPEN oldpen;
        pts[0].x = pts[1].x = pts[4].x = x;
@@ -3129,7 +3135,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
        /* Nastyness with NUMLock - Shift-NUMLock is left alone though */
        if ((cfg.funky_type == 3 ||
-            (cfg.funky_type <= 1 && app_keypad_keys && !cfg.no_applic_k))
+            (cfg.funky_type <= 1 && term->app_keypad_keys &&
+             !cfg.no_applic_k))
            && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) {
 
            wParam = VK_EXECUTE;
@@ -3144,7 +3151,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
     }
 
     /* Disable Auto repeat if required */
-    if (repeat_off && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT)
+    if (term->repeat_off &&
+       (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == KF_REPEAT)
        return 0;
 
     if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0)
@@ -3194,7 +3202,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        compose_state = 0;
 
     /* Sanitize the number pad if not using a PC NumPad */
-    if (left_alt || (app_keypad_keys && !cfg.no_applic_k
+    if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k
                     && cfg.funky_type != 2)
        || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state) {
        if ((HIWORD(lParam) & KF_EXTENDED) == 0) {
@@ -3258,7 +3266,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            return 0;
        }
        if (wParam == VK_INSERT && shift_state == 1) {
-           term_do_paste();
+           term_do_paste(term);
            return 0;
        }
        if (left_alt && wParam == VK_F4 && cfg.alt_f4) {
@@ -3276,7 +3284,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        }
        /* Control-Numlock for app-keypad mode switch */
        if (wParam == VK_PAUSE && shift_state == 2) {
-           app_keypad_keys ^= 1;
+           term->app_keypad_keys ^= 1;
            return 0;
        }
 
@@ -3319,7 +3327,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
            if (cfg.funky_type == 3 ||
                (cfg.funky_type <= 1 &&
-                app_keypad_keys && !cfg.no_applic_k)) switch (wParam) {
+                term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) {
                  case VK_EXECUTE:
                    xkey = 'P';
                    break;
@@ -3333,7 +3341,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    xkey = 'S';
                    break;
                }
-           if (app_keypad_keys && !cfg.no_applic_k)
+           if (term->app_keypad_keys && !cfg.no_applic_k)
                switch (wParam) {
                  case VK_NUMPAD0:
                    xkey = 'p';
@@ -3400,7 +3408,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                    break;
                }
            if (xkey) {
-               if (vt52_mode) {
+               if (term->vt52_mode) {
                    if (xkey >= 'P' && xkey <= 'S')
                        p += sprintf((char *) p, "\x1B%c", xkey);
                    else
@@ -3459,7 +3467,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            *p++ = 0x1C;
            return p - output;
        }
-       if (shift_state == 0 && wParam == VK_RETURN && cr_lf_return) {
+       if (shift_state == 0 && wParam == VK_RETURN && term->cr_lf_return) {
            *p++ = '\r';
            *p++ = '\n';
            return p - output;
@@ -3561,7 +3569,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        if (cfg.funky_type == 3 && code <= 6)
            code = "\0\2\1\4\5\3\6"[code];
 
-       if (vt52_mode && code > 0 && code <= 6) {
+       if (term->vt52_mode && code > 0 && code <= 6) {
            p += sprintf((char *) p, "\x1B%c", " HLMEIG"[code]);
            return p - output;
        }
@@ -3599,13 +3607,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            }
            return p - output;
        }
-       if ((vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) {
+       if ((term->vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) {
            int offt = 0;
            if (code > 15)
                offt++;
            if (code > 21)
                offt++;
-           if (vt52_mode)
+           if (term->vt52_mode)
                p += sprintf((char *) p, "\x1B%c", code + 'P' - 11 - offt);
            else
                p +=
@@ -3617,7 +3625,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            return p - output;
        }
        if (cfg.funky_type == 2 && code >= 11 && code <= 14) {
-           if (vt52_mode)
+           if (term->vt52_mode)
                p += sprintf((char *) p, "\x1B%c", code + 'P' - 11);
            else
                p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11);
@@ -3656,10 +3664,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                break;
            }
            if (xkey) {
-               if (vt52_mode)
+               if (term->vt52_mode)
                    p += sprintf((char *) p, "\x1B%c", xkey);
                else {
-                   int app_flg = (app_cursor_keys && !cfg.no_applic_c);
+                   int app_flg = (term->app_cursor_keys && !cfg.no_applic_c);
 #if 0
                    /*
                     * RDB: VT100 & VT102 manuals both state the
@@ -3675,7 +3683,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                     * _this_ I'll have to put in a configurable
                     * option.
                     */
-                   if (!app_keypad_keys)
+                   if (!term->app_keypad_keys)
                        app_flg = 0;
 #endif
                    /* Useful mapping of Ctrl-arrows */
@@ -3722,7 +3730,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 #ifdef SHOW_TOASCII_RESULT
        if (r == 1 && !key_down) {
            if (alt_sum) {
-               if (in_utf || dbcs_screenfont)
+               if (in_utf(term) || dbcs_screenfont)
                    debug((", (U+%04x)", alt_sum));
                else
                    debug((", LCH(%d)", alt_sum));
@@ -3746,7 +3754,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
             * sensible, but for the moment it's preferable to
             * having to faff about buffering things.
             */
-           term_nopaste();
+           term_nopaste(term);
 
            p = output;
            for (i = 0; i < r; i++) {
@@ -3766,7 +3774,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                        return 0;
                    }
                    keybuf = nc;
-                   term_seen_key_event();
+                   term_seen_key_event(term);
                    luni_send(&keybuf, 1, 1);
                    continue;
                }
@@ -3775,9 +3783,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
                if (!key_down) {
                    if (alt_sum) {
-                       if (in_utf || dbcs_screenfont) {
+                       if (in_utf(term) || dbcs_screenfont) {
                            keybuf = alt_sum;
-                           term_seen_key_event();
+                           term_seen_key_event(term);
                            luni_send(&keybuf, 1, 1);
                        } else {
                            ch = (char) alt_sum;
@@ -3790,25 +3798,25 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                             * messages. We _have_ to buffer
                             * everything we're sent.
                             */
-                           term_seen_key_event();
+                           term_seen_key_event(term);
                            ldisc_send(&ch, 1, 1);
                        }
                        alt_sum = 0;
                    } else
-                       term_seen_key_event();
+                       term_seen_key_event(term);
                        lpage_send(kbd_codepage, &ch, 1, 1);
                } else {
                    if(capsOn && ch < 0x80) {
                        WCHAR cbuf[2];
                        cbuf[0] = 27;
                        cbuf[1] = xlat_uskbd2cyrllic(ch);
-                       term_seen_key_event();
+                       term_seen_key_event(term);
                        luni_send(cbuf+!left_alt, 1+!!left_alt, 1);
                    } else {
                        char cbuf[2];
                        cbuf[0] = '\033';
                        cbuf[1] = ch;
-                       term_seen_key_event();
+                       term_seen_key_event(term);
                        lpage_send(kbd_codepage, cbuf+!left_alt, 1+!!left_alt, 1);
                    }
                }
@@ -3824,7 +3832,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        if (!left_alt)
            keys[0] = 0;
        /* If we will be using alt_sum fix the 256s */
-       else if (keys[0] && (in_utf || dbcs_screenfont))
+       else if (keys[0] && (in_utf(term) || dbcs_screenfont))
            keys[0] = 10;
     }
 
@@ -3848,7 +3856,7 @@ void request_paste(void)
      * clipboard with no difficulty, so request_paste() can just go
      * ahead and paste.
      */
-    term_do_paste();
+    term_do_paste(term);
 }
 
 void set_title(char *title)
@@ -4213,7 +4221,7 @@ void optimised_move(int to, int from, int lines)
     max = to + from - min;
 
     r.left = offset_width;
-    r.right = offset_width + cols * font_width;
+    r.right = offset_width + term->cols * font_width;
     r.top = offset_height + min * font_height;
     r.bottom = offset_height + (max + lines) * font_height;
     ScrollWindow(hwnd, 0, (to - from) * font_height, &r, &r);
@@ -4322,7 +4330,7 @@ void beep(int mode)
        }
     }
     /* Otherwise, either visual bell or disabled; do nothing here */
-    if (!has_focus) {
+    if (!term->has_focus) {
        flash_window(2);               /* start */
     }
 }