changeset 53232:22aaf1e5fbe6

Full support for multiple terminal I/O (with some rough edges). lib-src/emacsclient.c (emacs_pid): New variable. (window_change): Forward the SIGWINCH signal to the Emacs process after copying the size parameters to the proxy terminal. (copy_from_to): New parameter (sigio), kill Emacs with SIGIO if it is nonzero. (main): Set emacs_pid. lisp/server.el (server-process-filter): Send the pid of Emacs to emacsclient. src/cm.c: Added tty parameters to all functions and all Wcm macro calls. src/cm.h: Added tty parameters to all macros. Updated function prototypes. (Wcm): Moved to struct tty_output. src/dispextern.h: Updated function prototypes. src/dispnew.c: Added tty parameters to all Wcm macro calls. (do_switch_frame): Make old frame obscured, not invisible, to solve problems with other-frame. (Wcm): Moved to struct tty_output. src/keyboard.c (read_avail_input): Select the frame corresponding to the tty that was read. Slight rearrangement of tty loop. src/lisp.h (tabs_safe_p): Removed duplicate prototype. src/sysdep.c (hft_init, hft_reset): Added tty_output parameter. (discard_tty_input): Discard input from all ttys on APOLLO, too. Whatever it is. (narrow_foreground_group, widen_foreground_group): Added tty parameter (not really useful, the functions only work on the controlling tty.) (tabs_safe_p): Added tty parameter. src/term.c Added tty parameters to all Wcm macro calls. Standardised updating_frame vs. selected frame and tty_output access. (term_init): Allocate Wcm. (syms_of_term): Provide the `multi-tty' feature. src/termchar.h (struct tty_output): Added Wcm. src/xdisp.c (try_window_id): Make sure we use the tty device corresponding to the current frame. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-8
author Karoly Lorentey <lorentey@elte.hu>
date Sat, 27 Dec 2003 01:12:57 +0000
parents e0c359b85b58
children fe9b37bee5f7
files README.multi-tty lib-src/emacsclient.c lisp/server.el src/cm.c src/cm.h src/dispextern.h src/dispnew.c src/frame.c src/frame.h src/keyboard.c src/lisp.h src/sysdep.c src/term.c src/termchar.h src/xdisp.c
diffstat 15 files changed, 490 insertions(+), 394 deletions(-) [+]
line wrap: on
line diff
--- a/README.multi-tty	Fri Dec 26 04:31:27 2003 +0000
+++ b/README.multi-tty	Sat Dec 27 01:12:57 2003 +0000
@@ -13,7 +13,7 @@
 
 Patches or suggestions are welcome!
 
-Retrieving the branch:
+Retrieving the latest version of the branch:
 
 	tla register-archive lorentey@elte.hu--2004 http://lorentey.web.elte.hu/arch/2004/
 	tla get lorentey@elte.hu--2004/emacs--multi-tty--0 <directory>
@@ -24,21 +24,24 @@
 STATUS
 ------
 
-We can create frames on new tty devices, but there are problems with
-redisplay.  Input is read from all terminals (NOT via MULTIKBOARD!).
-At the moment, the type of the new terminals must be the same as the
-initial terminal.  Emacsclient is extended to support opening a new
-terminal frame.
+Basic support is there; there are some rough edges, but it already
+seems to be usable.  Input is read from all terminals (NOT via
+MULTIKBOARD!).  At the moment, the type of the new terminals must be
+the same as the initial terminal.  Emacsclient was extended to support
+opening a new terminal frame.
 
 To try it out, start up the emacs server (M-x server-start), and then
-start emacsclient with
+(from a shell prompt on another terminal) start emacsclient with
 
 	emacsclient -h
 
-If you exit emacs, both terminals are restored to their previous
+You'll have two fully working frames on separate terminals.  If you
+exit emacs, both terminals should be restored to their previous
 states.
 
-X, Mac, Windows and DOS support is broken.
+X, Mac, Windows and DOS support is broken at the moment.
+
+Tested under GNU/Linux only.
 
 NEWS
 ----
@@ -47,7 +50,19 @@
 
 ** Support for multiple terminal devices has been added.  You can
    specify a terminal device (`tty' parameter) and a terminal type
-   (`tty-type' parameter) to `make-terminal-frame'.
+   (`tty-type' parameter) to `make-terminal-frame'. `tty' must be a
+   terminal device created by the new emacsclient, or there will be
+   problems with terminal input and window resizes.  (The kernel
+   notifies processes about pending input or terminal resizes only on
+   the controlling terminal, so we need emacsclient to sit on the real
+   terminal device, create SIGIO signals upon terminal input, and
+   forward SIGWINCH signals to us.)
+
+   You can test for the presence of multiple terminal support by
+   testing for the `multi-tty' feature.
+
+** A make-frame-on-tty function has been added to make it easier to
+   create frames on new terminals.
 
 ** Emacsclient has been extended to support opening a new terminal
    frame.
@@ -58,8 +73,10 @@
 See arch logs.
 
 
-THINGS THAT ARE DONE
---------------------
+DIARY OF CHANGES
+----------------
+
+(ex-TODO items with explanations.)
 
 -- Introduce a new abstraction for terminal devices.  
 
@@ -80,12 +97,13 @@
 -- Implement support for reading from multiple terminals.
 
    (Done, read_avail_input tries to read from each terminal, until one
-   succeeds.)
+   succeeds.  MULTIKBOARD is not used.  Secondary terminals don't send
+   SIGIO!)
 
 -- other-frame should cycle through the frames on the `current'
-   terminal.  
+   terminal only.  
 
-   (Done.  A little fragile, but seems to work.)
+   (Done, by trivially modifiying next_frame and prev_frame.)
 
 -- Support different terminal sizes.
    
@@ -94,7 +112,8 @@
 -- Make sure terminal resizes are handled gracefully.  (Could be
    problematic.)
 
-   (Done.  We don't get SIGWINCH for additional ttys, though.)
+   (Done.  We don't get automatic SIGWINCH for additional ttys,
+   though.)
 
 -- Extend emacsclient to automatically open a new tty when it connects
    to Emacs.
@@ -106,46 +125,71 @@
    
    (Done, but introduced ugly redisplay problems.  Ugh.)
 
+-- Fix redisplay problems.
+
+   (Done, it turned out that the entire Wcm structure must be moved
+   inside tty_output.  Why was it so hard for me to find this out?)
+
+-- Provide a way for emacsclient to tell Emacs that the tty has been
+   resized.
+
+   (Done, simply forward the SIGWINCH signal.)
+
+-- Each keypress should automatically select the frame corresponding
+   to the terminal that it was coming from.  This means that Emacs
+   must know from which terminal the last keyboard event came from.
+   (Multikeyboard support may help with this.)
+
+   (Done, it was quite simple.)
+
+-- Fix SIGIO issue with secondary terminals.
+
+   (Done, emacsclient signals Emacs after writing to the proxy pseudo
+   terminal.  This means that multi-tty does not work with raw ttys!)
 
 THINGS TO DO
 ------------
 
-** Fix redisplay problems.
+** Implement sane error handling after initialization.  (Currently
+   emacs exits if you specify a bad terminal type.)  The helpful error
+   messages must still be provided when Emacs starts.
+
+** C-g should work on secondary terminals.
 
 ** Make make-terminal-frame look up the tty and tty-type parameters
    from the currently selected terminal before the global default.
 
 ** Move optimalization parameters (costs) from union output_data to
-   struct frame.
-
-** Provide a way for emacsclient to tell Emacs that the tty has been
-   resized.
+   a backend-neutral per-device structure.
 
-** Implement terminal deletion, i.e., closing the tty device and
-   restoring its previous state without exiting Emacs.  This should be
-   exported to the Lisp interpreter.
+** Implement terminal deletion, i.e., deleting local frames, closing
+   the tty device and restoring its previous state without exiting
+   Emacs.  This should be exported to the Lisp environment.
 
-** Implement automatic deletion of terminals, when the last frame on
+** Implement automatic deletion of terminals when the last frame on
    that terminal is closed.
 
 ** Put all cached terminal escape sequences into struct tty_output.
    Currently, they are still stored in global variables, so we don't
    really support multiple terminal types.
 
-
-** Each keypress should automatically select the frame corresponding
-   to the terminal that it was coming from.  This means that Emacs
-   must know from which terminal the last keyboard event came from.
-   (Multikeyboard support may help with this.)
-
-** Make struct tty_output available from Lisp.
+** Make parts of struct tty_output accessible from Lisp.  The device
+   name and the type is sufficient.
 
 ** Implement support for starting an interactive Emacs session without
    an initial frame.  (The user would connect to it and open frames
    later, with emacsclient.)  Not necessary a good idea.
 
+** Support raw secondary terminals.  (This one is tricky, SIGIO works
+   only on the controlling terminal.)
+
+** What does interrupt_input do?  I tried to disable it for raw
+   secondary tty support, but it seems not to do anything useful.
+
 ** Fix X support.
 
+** Do tty output through term_hooks, too.
+
 ** Allow simultaneous X and tty frames.
 
 ** Fix Mac support (I can't do this myself).
--- a/lib-src/emacsclient.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/lib-src/emacsclient.c	Sat Dec 27 01:12:57 2003 +0000
@@ -380,6 +380,7 @@
 int flow_control = 0;
 int meta_key = 0;
 char _sobuf[BUFSIZ];
+int emacs_pid;
 
 /* Adapted from init_sys_modes() in sysdep.c. */
 int
@@ -548,7 +549,7 @@
 void
 window_change ()
 {
-  int width, height;
+  int width = 0, height = 0;
 
 #ifdef TIOCGWINSZ
   {
@@ -601,6 +602,9 @@
   }
 #endif /* not SunOS-style */
 #endif /* not BSD-style */
+
+  if (width != 0 && height != 0)
+    kill (emacs_pid, SIGWINCH);
 }
 
 int in_conversation = 0;
@@ -696,7 +700,7 @@
 }
 
 int
-copy_from_to (int in, int out)
+copy_from_to (int in, int out, int sigio)
 {
   static char buf[BUFSIZ];
   int nread = read (in, &buf, BUFSIZ);
@@ -716,6 +720,11 @@
       
       if (r < 0)
         return 0;               /* Error */
+
+      if (sigio)
+        {
+          kill (emacs_pid, SIGIO);
+        }
     }
   return 1;
 }
@@ -744,13 +753,13 @@
         if (FD_ISSET (master, &set))
           {
             /* Copy Emacs output to stdout. */
-            if (! copy_from_to (master, 0))
+            if (! copy_from_to (master, 0, 0))
               return 1;
           }
         if (FD_ISSET (1, &set))
           {
             /* Forward user input to Emacs. */
-            if (! copy_from_to (1, master))
+            if (! copy_from_to (1, master, 1))
               return 1;
           }
       }
@@ -1078,6 +1087,18 @@
 
   if (here)
     {
+      /* First of all, get the pid of the Emacs process.
+         XXX Is there is some nifty libc/kernel feature for doing this?
+       */
+      str = fgets (string, BUFSIZ, in);
+      emacs_pid = atoi (str);
+      if (emacs_pid == 0)
+        {
+          reset_tty ();
+          fprintf (stderr, "%s: Could not get process id of Emacs\n", argv[0]);
+          fail (argc, argv);
+        }
+      
       if (! pty_conversation ())
         {
           reset_tty ();
--- a/lisp/server.el	Fri Dec 26 04:31:27 2003 +0000
+++ b/lisp/server.el	Sat Dec 27 01:12:57 2003 +0000
@@ -319,13 +319,15 @@
 		  (server-select-display display)
 		(error (process-send-string proc (nth 1 err))
 		       (setq request "")))))
-	   ;; Open a new tty at the client.
+	   ;; Open a new frame at the client.  ARG is the name of the pseudo tty.
 	   ((and (equal "-pty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
 	    (let ((pty (server-unquote-arg (match-string 1 request)))
 		  (type (server-unquote-arg (match-string 2 request))))
 	      (setq request (substring request (match-end 0)))
 	      (condition-case err
-		  (make-terminal-frame `((tty . ,pty) (tty-type . ,type)))
+		  (progn
+		    (make-terminal-frame `((tty . ,pty) (tty-type . ,type)))
+		    (process-send-string proc (concat (number-to-string (emacs-pid)) "\n")))
 		(error (process-send-string proc (nth 1 err))
 		       (setq request "")))))
 	   ;; ARG is a line number option.
--- a/src/cm.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/cm.c	Sat Dec 27 01:12:57 2003 +0000
@@ -137,9 +137,9 @@
 cmcheckmagic (tty)
      struct tty_output *tty;
 {
-  if (curX == FrameCols)
+  if (curX (tty) == FrameCols (tty))
     {
-      if (!MagicWrap || curY >= FrameRows - 1)
+      if (!MagicWrap (tty) || curY (tty) >= FrameRows (tty) - 1)
 	abort ();
       if (TTY_TERMSCRIPT (tty))
 	putc ('\r', TTY_TERMSCRIPT (tty));
@@ -147,8 +147,8 @@
       if (TTY_TERMSCRIPT (tty))
 	putc ('\n', TTY_TERMSCRIPT (tty));
       putc ('\n', TTY_OUTPUT (tty));
-      curX = 0;
-      curY++;
+      curX (tty) = 0;
+      curY (tty)++;
     }
 }
 
@@ -160,21 +160,21 @@
  */
 
 void
-cmcostinit ()
+cmcostinit (struct tty_output *tty)
 {
     char *p;
 
 #define	COST(x,e)	(x ? (cost = 0, tputs (x, 1, e), cost) : BIG)
 #define CMCOST(x,e)	((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e)))
 
-    Wcm.cc_up =		COST (Wcm.cm_up, evalcost);
-    Wcm.cc_down =	COST (Wcm.cm_down, evalcost);
-    Wcm.cc_left =	COST (Wcm.cm_left, evalcost);
-    Wcm.cc_right =	COST (Wcm.cm_right, evalcost);
-    Wcm.cc_home =	COST (Wcm.cm_home, evalcost);
-    Wcm.cc_cr =		COST (Wcm.cm_cr, evalcost);
-    Wcm.cc_ll =		COST (Wcm.cm_ll, evalcost);
-    Wcm.cc_tab =	Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG;
+    tty->Wcm->cc_up =	 COST (tty->Wcm->cm_up, evalcost);
+    tty->Wcm->cc_down =	 COST (tty->Wcm->cm_down, evalcost);
+    tty->Wcm->cc_left =	 COST (tty->Wcm->cm_left, evalcost);
+    tty->Wcm->cc_right = COST (tty->Wcm->cm_right, evalcost);
+    tty->Wcm->cc_home =	 COST (tty->Wcm->cm_home, evalcost);
+    tty->Wcm->cc_cr =	 COST (tty->Wcm->cm_cr, evalcost);
+    tty->Wcm->cc_ll =	 COST (tty->Wcm->cm_ll, evalcost);
+    tty->Wcm->cc_tab =	 tty->Wcm->cm_tabwidth ? COST (tty->Wcm->cm_tab, evalcost) : BIG;
 
     /*
      * These last three are actually minimum costs.  When (if) they are
@@ -185,9 +185,9 @@
      * cursor motion seem to take straight numeric values.  --ACT)
      */
 
-    Wcm.cc_abs =  CMCOST (Wcm.cm_abs, evalcost);
-    Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost);
-    Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost);
+    tty->Wcm->cc_abs =  CMCOST (tty->Wcm->cm_abs, evalcost);
+    tty->Wcm->cc_habs = CMCOST (tty->Wcm->cm_habs, evalcost);
+    tty->Wcm->cc_vabs = CMCOST (tty->Wcm->cm_vabs, evalcost);
 
 #undef CMCOST
 #undef COST
@@ -217,16 +217,16 @@
        don't believe the cursor position: give up here
        and force use of absolute positioning.  */
 
-    if (curX == Wcm.cm_cols)
+    if (curX (tty) == tty->Wcm->cm_cols)
       goto fail;
 
     totalcost = 0;
     if ((deltay = dsty - srcy) == 0)
 	goto x;
     if (deltay < 0)
-	p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay;
+	p = tty->Wcm->cm_up, c = tty->Wcm->cc_up, deltay = -deltay;
     else
-	p = Wcm.cm_down, c = Wcm.cc_down;
+	p = tty->Wcm->cm_down, c = tty->Wcm->cc_down;
     if (c == BIG) {		/* caint get thar from here */
 	if (doit)
 	    printf ("OOPS");
@@ -240,11 +240,11 @@
     if ((deltax = dstx - srcx) == 0)
 	goto done;
     if (deltax < 0) {
-	p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
+	p = tty->Wcm->cm_left, c = tty->Wcm->cc_left, deltax = -deltax;
 	goto dodelta;		/* skip all the tab junk */
     }
     /* Tabs (the toughie) */
-    if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs)
+    if (tty->Wcm->cc_tab >= BIG || !tty->Wcm->cm_usetabs)
 	goto olddelta;		/* forget it! */
 
     /*
@@ -255,12 +255,12 @@
      * we will put into tabx (for ntabs) and tab2x (for n2tabs)).
      */
 
-    ntabs = (deltax + srcx % Wcm.cm_tabwidth) / Wcm.cm_tabwidth;
+    ntabs = (deltax + srcx % tty->Wcm->cm_tabwidth) / tty->Wcm->cm_tabwidth;
     n2tabs = ntabs + 1;
-    tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth;
-    tab2x = tabx + Wcm.cm_tabwidth;
+    tabx = (srcx / tty->Wcm->cm_tabwidth + ntabs) * tty->Wcm->cm_tabwidth;
+    tab2x = tabx + tty->Wcm->cm_tabwidth;
 
-    if (tab2x >= Wcm.cm_cols)	/* too far (past edge) */
+    if (tab2x >= tty->Wcm->cm_cols)	/* too far (past edge) */
 	n2tabs = 0;
 
     /*
@@ -269,11 +269,11 @@
      */
 
 		   /* cost for ntabs     +    cost for right motion */
-    tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right
+    tabcost = ntabs ? ntabs * tty->Wcm->cc_tab + (dstx - tabx) * tty->Wcm->cc_right
 		    : BIG;
 
 		   /* cost for n2tabs    +    cost for left motion */
-    c = n2tabs  ?    n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left
+    c = n2tabs  ?    n2tabs * tty->Wcm->cc_tab + (tab2x - dstx) * tty->Wcm->cc_left
 		: BIG;
 
     if (c < tabcost)		/* then cheaper to overshoot & back up */
@@ -286,11 +286,11 @@
      * See if tabcost is less than just moving right
      */
 
-    if (tabcost < (deltax * Wcm.cc_right)) {
+    if (tabcost < (deltax * tty->Wcm->cc_right)) {
 	totalcost += tabcost;	/* use the tabs */
 	if (doit)
 	    while (--ntabs >= 0)
-              emacs_tputs (tty, Wcm.cm_tab, 1, cmputc);
+              emacs_tputs (tty, tty->Wcm->cm_tab, 1, cmputc);
 	srcx = tabx;
     }
 
@@ -303,9 +303,9 @@
 	goto done;
 olddelta:
     if (deltax > 0)
-	p = Wcm.cm_right, c = Wcm.cc_right;
+	p = tty->Wcm->cm_right, c = tty->Wcm->cc_right;
     else
-	p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
+	p = tty->Wcm->cm_left, c = tty->Wcm->cc_left, deltax = -deltax;
 
 dodelta:
     if (c == BIG) {		/* caint get thar from here */
@@ -349,47 +349,47 @@
            *dcm;
 
   /* First the degenerate case */
-  if (row == curY && col == curX) /* already there */
+    if (row == curY (tty) && col == curX (tty)) /* already there */
     return;
 
-  if (curY >= 0 && curX >= 0)
+    if (curY (tty) >= 0 && curX (tty) >= 0)
     {
       /* We may have quick ways to go to the upper-left, bottom-left,
        * start-of-line, or start-of-next-line.  Or it might be best to
        * start where we are.  Examine the options, and pick the cheapest.
        */
 
-      relcost = calccost (tty, curY, curX, row, col, 0);
+      relcost = calccost (tty, curY (tty), curX (tty), row, col, 0);
       use = USEREL;
-      if ((homecost = Wcm.cc_home) < BIG)
+      if ((homecost = tty->Wcm->cc_home) < BIG)
           homecost += calccost (tty, 0, 0, row, col, 0);
       if (homecost < relcost)
           relcost = homecost, use = USEHOME;
-      if ((llcost = Wcm.cc_ll) < BIG)
-          llcost += calccost (tty, Wcm.cm_rows - 1, 0, row, col, 0);
+      if ((llcost = tty->Wcm->cc_ll) < BIG)
+          llcost += calccost (tty, tty->Wcm->cm_rows - 1, 0, row, col, 0);
       if (llcost < relcost)
           relcost = llcost, use = USELL;
-      if ((crcost = Wcm.cc_cr) < BIG) {
-	  if (Wcm.cm_autolf)
-	      if (curY + 1 >= Wcm.cm_rows)
-		  crcost = BIG;
+      if ((crcost = tty->Wcm->cc_cr) < BIG) {
+	  if (tty->Wcm->cm_autolf)
+            if (curY (tty) + 1 >= tty->Wcm->cm_rows)
+                crcost = BIG;
 	      else
-                  crcost += calccost (tty, curY + 1, 0, row, col, 0);
+                crcost += calccost (tty, curY (tty) + 1, 0, row, col, 0);
 	  else
-	      crcost += calccost (tty, curY, 0, row, col, 0);
+            crcost += calccost (tty, curY (tty), 0, row, col, 0);
       }
       if (crcost < relcost)
 	  relcost = crcost, use = USECR;
-      directcost = Wcm.cc_abs, dcm = Wcm.cm_abs;
-      if (row == curY && Wcm.cc_habs < BIG)
-	  directcost = Wcm.cc_habs, dcm = Wcm.cm_habs;
-      else if (col == curX && Wcm.cc_vabs < BIG)
-	  directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs;
+      directcost = tty->Wcm->cc_abs, dcm = tty->Wcm->cm_abs;
+      if (row == curY (tty) && tty->Wcm->cc_habs < BIG)
+	  directcost = tty->Wcm->cc_habs, dcm = tty->Wcm->cm_habs;
+      else if (col == curX (tty) && tty->Wcm->cc_vabs < BIG)
+	  directcost = tty->Wcm->cc_vabs, dcm = tty->Wcm->cm_vabs;
     }
   else
     {
       directcost = 0, relcost = 100000;
-      dcm = Wcm.cm_abs;
+      dcm = tty->Wcm->cm_abs;
     }
 
   /*
@@ -400,13 +400,14 @@
     {
       /* compute REAL direct cost */
       cost = 0;
-      p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) :
-			       tgoto (dcm, col, row);
+      p = dcm == tty->Wcm->cm_habs
+        ? tgoto (dcm, row, col)
+        : tgoto (dcm, col, row);
       emacs_tputs (tty, p, 1, evalcost);
       if (cost <= relcost)
 	{	/* really is cheaper */
 	  emacs_tputs (tty, p, 1, cmputc);
-	  curY = row, curX = col;
+	  curY (tty) = row, curX (tty) = col;
 	  return;
 	}
     }
@@ -414,25 +415,25 @@
   switch (use)
     {
     case USEHOME:
-      emacs_tputs (tty, Wcm.cm_home, 1, cmputc);
-      curY = 0, curX = 0;
+      emacs_tputs (tty, tty->Wcm->cm_home, 1, cmputc);
+      curY (tty) = 0, curX (tty) = 0;
       break;
 
     case USELL:
-      emacs_tputs (tty, Wcm.cm_ll, 1, cmputc);
-      curY = Wcm.cm_rows - 1, curX = 0;
+      emacs_tputs (tty, tty->Wcm->cm_ll, 1, cmputc);
+      curY (tty) = tty->Wcm->cm_rows - 1, curX (tty) = 0;
       break;
 
     case USECR:
-      emacs_tputs (tty, Wcm.cm_cr, 1, cmputc);
-      if (Wcm.cm_autolf)
-	curY++;
-      curX = 0;
+      emacs_tputs (tty, tty->Wcm->cm_cr, 1, cmputc);
+      if (tty->Wcm->cm_autolf)
+	curY (tty)++;
+      curX (tty) = 0;
       break;
     }
 
-  (void) calccost (tty, curY, curX, row, col, 1);
-  curY = row, curX = col;
+  (void) calccost (tty, curY (tty), curX (tty), row, col, 1);
+  curY (tty) = row, curX (tty) = col;
 }
 
 /* Clear out all terminal info.
@@ -440,9 +441,9 @@
  */
 
 void
-Wcm_clear ()
+Wcm_clear (struct tty_output *tty)
 {
-  bzero (&Wcm, sizeof Wcm);
+  bzero (tty->Wcm, sizeof (struct cm));
   UP = 0;
   BC = 0;
 }
@@ -455,21 +456,21 @@
  */
 
 int
-Wcm_init ()
+Wcm_init (struct tty_output *tty)
 {
 #if 0
-  if (Wcm.cm_abs && !Wcm.cm_ds)
+  if (tty->Wcm->cm_abs && !tty->Wcm->cm_ds)
     return 0;
 #endif
-  if (Wcm.cm_abs)
+  if (tty->Wcm->cm_abs)
     return 0;
   /* Require up and left, and, if no absolute, down and right */
-  if (!Wcm.cm_up || !Wcm.cm_left)
+  if (!tty->Wcm->cm_up || !tty->Wcm->cm_left)
     return - 1;
-  if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
+  if (!tty->Wcm->cm_abs && (!tty->Wcm->cm_down || !tty->Wcm->cm_right))
     return - 1;
   /* Check that we know the size of the screen.... */
-  if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
+  if (tty->Wcm->cm_rows <= 0 || tty->Wcm->cm_cols <= 0)
     return - 2;
   return 0;
 }
--- a/src/cm.h	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/cm.h	Sat Dec 27 01:12:57 2003 +0000
@@ -98,66 +98,65 @@
     int cc_vabs;
   };
 
-extern struct cm Wcm;		/* Terminal capabilities */
 extern char PC;			/* Pad character */
 
 /* Shorthand */
 #ifndef NoCMShortHand
-#define curY		Wcm.cm_curY
-#define curX		Wcm.cm_curX
-#define Up		Wcm.cm_up
-#define Down		Wcm.cm_down
-#define Left		Wcm.cm_left
-#define Right		Wcm.cm_right
-#define Tab		Wcm.cm_tab
-#define BackTab		Wcm.cm_backtab
-#define TabWidth	Wcm.cm_tabwidth
-#define CR		Wcm.cm_cr
-#define Home		Wcm.cm_home
-#define LastLine	Wcm.cm_ll
-#define AbsPosition	Wcm.cm_abs
-#define ColPosition	Wcm.cm_habs
-#define RowPosition	Wcm.cm_vabs
-#define MultiUp		Wcm.cm_multiup
-#define MultiDown	Wcm.cm_multidown
-#define MultiLeft	Wcm.cm_multileft
-#define MultiRight	Wcm.cm_multiright
-#define AutoWrap	Wcm.cm_autowrap
-#define MagicWrap	Wcm.cm_magicwrap
-#define UseTabs		Wcm.cm_usetabs
-#define FrameRows	Wcm.cm_rows
-#define FrameCols	Wcm.cm_cols
+#define curY(tty)		(tty)->Wcm->cm_curY
+#define curX(tty)		(tty)->Wcm->cm_curX
+#define Up(tty)			(tty)->Wcm->cm_up
+#define Down(tty)		(tty)->Wcm->cm_down
+#define Left(tty)		(tty)->Wcm->cm_left
+#define Right(tty)		(tty)->Wcm->cm_right
+#define Tab(tty)		(tty)->Wcm->cm_tab
+#define BackTab(tty)		(tty)->Wcm->cm_backtab
+#define TabWidth(tty)		(tty)->Wcm->cm_tabwidth
+#define CR(tty)			(tty)->Wcm->cm_cr
+#define Home(tty)		(tty)->Wcm->cm_home
+#define LastLine(tty)		(tty)->Wcm->cm_ll
+#define AbsPosition(tty)	(tty)->Wcm->cm_abs
+#define ColPosition(tty)	(tty)->Wcm->cm_habs
+#define RowPosition(tty)	(tty)->Wcm->cm_vabs
+#define MultiUp(tty)		(tty)->Wcm->cm_multiup
+#define MultiDown(tty)		(tty)->Wcm->cm_multidown
+#define MultiLeft(tty)		(tty)->Wcm->cm_multileft
+#define MultiRight(tty)		(tty)->Wcm->cm_multiright
+#define AutoWrap(tty)		(tty)->Wcm->cm_autowrap
+#define MagicWrap(tty)		(tty)->Wcm->cm_magicwrap
+#define UseTabs(tty)		(tty)->Wcm->cm_usetabs
+#define FrameRows(tty)		(tty)->Wcm->cm_rows
+#define FrameCols(tty)		(tty)->Wcm->cm_cols
 
-#define UpCost		Wcm.cc_up
-#define DownCost	Wcm.cc_down
-#define LeftCost	Wcm.cc_left
-#define RightCost	Wcm.cc_right
-#define HomeCost	Wcm.cc_home
-#define CRCost		Wcm.cc_cr
-#define LastLineCost	Wcm.cc_ll
-#define TabCost		Wcm.cc_tab
-#define BackTabCost	Wcm.cc_backtab
-#define AbsPositionCost	Wcm.cc_abs
-#define ColPositionCost	Wcm.cc_habs
-#define RowPositionCost	Wcm.cc_vabs
-#define MultiUpCost	Wcm.cc_multiup
-#define MultiDownCost	Wcm.cc_multidown
-#define MultiLeftCost	Wcm.cc_multileft
-#define MultiRightCost	Wcm.cc_multiright
+#define UpCost(tty)		(tty)->Wcm->cc_up
+#define DownCost(tty)		(tty)->Wcm->cc_down
+#define LeftCost(tty)		(tty)->Wcm->cc_left
+#define RightCost(tty)		(tty)->Wcm->cc_right
+#define HomeCost(tty)		(tty)->Wcm->cc_home
+#define CRCost(tty)		(tty)->Wcm->cc_cr
+#define LastLineCost(tty)	(tty)->Wcm->cc_ll
+#define TabCost(tty)		(tty)->Wcm->cc_tab
+#define BackTabCost(tty)	(tty)->Wcm->cc_backtab
+#define AbsPositionCost(tty)	(tty)->Wcm->cc_abs
+#define ColPositionCost(tty)	(tty)->Wcm->cc_habs
+#define RowPositionCost(tty)	(tty)->Wcm->cc_vabs
+#define MultiUpCost(tty)	(tty)->Wcm->cc_multiup
+#define MultiDownCost(tty)	(tty)->Wcm->cc_multidown
+#define MultiLeftCost(tty)	(tty)->Wcm->cc_multileft
+#define MultiRightCost(tty)	(tty)->Wcm->cc_multiright
 #endif
 
-#define cmat(row,col)	(curY = (row), curX = (col))
-#define cmplus(n)					\
-  {							\
-    if ((curX += (n)) >= FrameCols && !MagicWrap)	\
-      {							\
-	if (Wcm.cm_losewrap) losecursor ();		\
-	else if (AutoWrap) curX = 0, curY++;		\
-	else curX--;					\
-      }							\
+#define cmat(tty,row,col)	(curY(tty) = (row), curX(tty) = (col))
+#define cmplus(tty,n)					            \
+  {                                                                 \
+    if ((curX (tty) += (n)) >= FrameCols (tty) && !MagicWrap (tty)) \
+      {                                                             \
+	if ((tty)->Wcm->cm_losewrap) losecursor (tty);              \
+	else if (AutoWrap (tty)) curX (tty) = 0, curY (tty)++;      \
+	else curX (tty)--;                                          \
+      }                                                             \
   }
 
-#define losecursor()	(curX = -1, curY = -1)
+#define losecursor(tty)	 (curX(tty) = -1, curY(tty) = -1)
 
 extern int cost;
 extern int evalcost ();
@@ -167,10 +166,10 @@
 extern struct tty_output *current_tty;
 extern void cmcheckmagic P_ ((struct tty_output *));
 extern int cmputc P_ ((int));
-extern void cmcostinit ();
+extern void cmcostinit P_ ((struct tty_output *tty));
 extern void cmgoto P_ ((struct tty_output *, int, int));
-extern void Wcm_clear ();
-extern int Wcm_init ();
+extern void Wcm_clear P_ ((struct tty_output *tty));
+extern int Wcm_init P_ ((struct tty_output *tty));
 
 /* arch-tag: acc1535a-7136-49d6-b22d-9bc85702251b
    (do not change this comment) */
--- a/src/dispextern.h	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/dispextern.h	Sat Dec 27 01:12:57 2003 +0000
@@ -2558,7 +2558,7 @@
 void get_tty_size P_ ((struct tty_output *, int *, int *));
 void request_sigio P_ ((void));
 void unrequest_sigio P_ ((void));
-int tabs_safe_p P_ ((void));
+int tabs_safe_p P_ ((struct tty_output *));
 void init_baud_rate P_ ((void));
 void init_sigio P_ ((int));
 
@@ -2724,8 +2724,8 @@
 /* Defined in term.c */
 
 extern void ring_bell P_ ((void));
-extern void set_terminal_modes P_ ((struct tty_output *));
-extern void reset_terminal_modes P_ ((struct tty_output *));
+extern void set_terminal_modes P_ (());
+extern void reset_terminal_modes P_ (());
 extern void update_begin P_ ((struct frame *));
 extern void update_end P_ ((struct frame *));
 extern void set_terminal_window P_ ((int));
--- a/src/dispnew.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/dispnew.c	Sat Dec 27 01:12:57 2003 +0000
@@ -259,10 +259,6 @@
 
 struct frame *last_nonminibuf_frame;
 
-/* Structure for info on cursor positioning.  */
-
-struct cm Wcm;
-
 /* 1 means SIGWINCH happened when not safe.  */
 
 int delayed_size_change;
@@ -6059,7 +6055,7 @@
 			   newheight - FRAME_TOP_MARGIN (f), 0);
 
       if (FRAME_TERMCAP_P (f) && !pretend)
-	FrameRows = newheight;
+	FrameRows (FRAME_TTY (f)) = newheight;
     }
 
   if (new_frame_total_cols != FRAME_TOTAL_COLS (f))
@@ -6069,7 +6065,7 @@
 	set_window_width (FRAME_MINIBUF_WINDOW (f), new_frame_total_cols, 0);
 
       if (FRAME_TERMCAP_P (f) && !pretend)
-	FrameCols = newwidth;
+	FrameCols (FRAME_TTY (f)) = newwidth;
 
       if (WINDOWP (f->tool_bar_window))
 	XSETFASTINT (XWINDOW (f->tool_bar_window)->total_cols, newwidth);
--- a/src/frame.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/frame.c	Sat Dec 27 01:12:57 2003 +0000
@@ -752,7 +752,7 @@
       && FRAME_TERMCAP_P (XFRAME (frame))
       && FRAME_TTY (XFRAME (selected_frame)) == FRAME_TTY (XFRAME (frame)))
     {
-      XFRAME (selected_frame)->async_visible = 0;
+      XFRAME (selected_frame)->async_visible = 2; /* obscured */
       XFRAME (frame)->async_visible = 1;
       FRAME_TTY (XFRAME (frame))->top_frame = frame;
     }
--- a/src/frame.h	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/frame.h	Sat Dec 27 01:12:57 2003 +0000
@@ -341,13 +341,13 @@
      frame becomes visible again, it must be marked as garbaged.  The
      FRAME_SAMPLE_VISIBILITY macro takes care of this.
 
-     On Windows NT/9X, to avoid wasting effort updating visible frames
-     that are actually completely obscured by other windows on the
-     display, we bend the meaning of visible slightly: if greater than
-     1, then the frame is obscured - we still consider it to be
-     "visible" as seen from lisp, but we don't bother updating it.  We
-     must take care to garbage the frame when it ceaces to be obscured
-     though.  Note that these semantics are only used on NT/9X.
+     On ttys and on Windows NT/9X, to avoid wasting effort updating
+     visible frames that are actually completely obscured by other
+     windows on the display, we bend the meaning of visible slightly:
+     if greater than 1, then the frame is obscured - we still consider
+     it to be "visible" as seen from lisp, but we don't bother
+     updating it.  We must take care to garbage the frame when it
+     ceaces to be obscured though.
 
      iconified is nonzero if the frame is currently iconified.
 
--- a/src/keyboard.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/keyboard.c	Sat Dec 27 01:12:57 2003 +0000
@@ -6460,7 +6460,7 @@
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
     return;
-
+  
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
   *addr = (!NILP (Vquit_flag)
@@ -6579,7 +6579,7 @@
   struct input_event buf[KBD_BUFFER_SIZE];
   register int i;
   int nread;
-
+  
   for (i = 0; i < KBD_BUFFER_SIZE; i++)
     EVENT_INIT (buf[i]);
 
@@ -6611,8 +6611,8 @@
       nread = 0;
 
       /* Try to read from each available tty, until one succeeds. */
-      for (tty = tty_list; tty && !nread; tty = tty->next) {
-        
+      for (tty = tty_list; tty; tty = tty->next) {
+      
         /* Determine how many characters we should *try* to read.  */
 #ifdef FIONREAD
         /* Find out how much input is available.  */
@@ -6624,6 +6624,7 @@
             /* ??? Is it really right to send the signal just to this process
                rather than to the whole process group?
                Perhaps on systems with FIONREAD Emacs is alone in its group.  */
+            /* It appears to be the case, see narrow_foreground_group. */
             if (! noninteractive)
               {
                 if (! tty_list->next)
@@ -6706,15 +6707,20 @@
 #endif /* USG or DGUX or CYGWIN */
 #endif /* no FIONREAD */
 
+        if (nread > 0)
+          break;
       } /* for each tty */
       
-      if (! nread)
+      if (nread <= 0)
         return 0;
       
 #endif /* not MSDOS */
 #endif /* not WINDOWSNT */
 
-      /* XXX Select frame corresponding to the tty. */
+      /* Select frame corresponding to the active tty.  Note that the
+         value of selected_frame is not reliable here, redisplay tends
+         to temporarily change it.  But tty should always be non-NULL. */
+      Lisp_Object frame = (tty ? tty->top_frame : selected_frame);
       
       for (i = 0; i < nread; i++)
 	{
@@ -6725,8 +6731,8 @@
 	  if (meta_key != 2)
 	    cbuf[i] &= ~0x80;
 
-	  buf[i].code = cbuf[i];
-	  buf[i].frame_or_window = selected_frame;
+          buf[i].code = cbuf[i];
+	  buf[i].frame_or_window = frame;
 	  buf[i].arg = Qnil;
 	}
     }
--- a/src/lisp.h	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/lisp.h	Sat Dec 27 01:12:57 2003 +0000
@@ -2952,7 +2952,6 @@
 extern void setup_pty P_ ((int));
 extern int set_window_size P_ ((int, int, int));
 extern void create_process P_ ((Lisp_Object, char **, Lisp_Object));
-extern int tabs_safe_p P_ ((void));
 extern void init_baud_rate P_ ((void));
 extern int emacs_open P_ ((const char *, int, int));
 extern int emacs_close P_ ((int));
--- a/src/sysdep.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/sysdep.c	Sat Dec 27 01:12:57 2003 +0000
@@ -249,8 +249,8 @@
 void croak P_ ((char *));
 
 #ifdef AIXHFT
-void hft_init ();
-void hft_reset ();
+void hft_init P_ ((struct tty_output *));
+void hft_reset P_ ((struct tty_output *));
 #endif
 
 /* Temporary used by `sigblock' when defined in terms of signprocmask.  */
@@ -282,8 +282,12 @@
 #else /* not VMS */
 #ifdef APOLLO
   {
-    int zero = 0;
-    ioctl (fileno (TTY_INPUT (CURTTY())), TIOCFLUSH, &zero);
+    struct tty_output *tty;
+    for (tty = tty_list; tty; tty = tty->next)
+      {
+        int zero = 0;
+        ioctl (fileno (TTY_INPUT (tty)), TIOCFLUSH, &zero);
+      }
   }
 #else /* not Apollo */
 #ifdef MSDOS    /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
@@ -310,12 +314,7 @@
    the terminal.  */
 
 void
-#ifdef PROTOTYPES
 stuff_char (char c)
-#else
-stuff_char (c)
-     char c;
-#endif
 {
   if (read_socket_hook)
     return;
@@ -1074,22 +1073,23 @@
    group, redirect the TTY to point to our own process group.  We need
    to be in our own process group to receive SIGIO properly.  */
 void
-narrow_foreground_group ()
+narrow_foreground_group (struct tty_output *tty)
 {
   int me = getpid ();
 
   setpgrp (0, inherited_pgroup);
+  /* XXX This only works on the controlling tty. */
   if (inherited_pgroup != me)
-    EMACS_SET_TTY_PGRP (fileno (stdin), &me); /* stdin is intentional here */
+    EMACS_SET_TTY_PGRP (fileno (TTY_INPUT (tty)), &me);
   setpgrp (0, me);
 }
 
 /* Set the tty to our original foreground group.  */
 void
-widen_foreground_group ()
+widen_foreground_group (struct tty_output *tty)
 {
   if (inherited_pgroup != getpid ())
-    EMACS_SET_TTY_PGRP (fileno (stdin), &inherited_pgroup); /* stdin is intentional here */
+    EMACS_SET_TTY_PGRP (fileno (TTY_INPUT (tty)), &inherited_pgroup);
   setpgrp (0, inherited_pgroup);
 }
 
@@ -1353,7 +1353,7 @@
 
 #ifdef BSD_PGRPS
   if (! read_socket_hook && EQ (Vwindow_system, Qnil))
-    narrow_foreground_group ();
+    narrow_foreground_group (tty_out);
 #endif
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -1578,7 +1578,7 @@
 #endif
 
 #ifdef AIXHFT
-      hft_init ();
+      hft_init (tty_out);
 #ifdef IBMR2AIX
       {
 	/* IBM's HFT device usually thinks a ^J should be LF/CR.  We need it
@@ -1678,12 +1678,12 @@
    At the time this is called, init_sys_modes has not been done yet.  */
 
 int
-tabs_safe_p ()
+tabs_safe_p (struct tty_output *tty)
 {
-  struct emacs_tty tty;
-
-  EMACS_GET_TTY (fileno (TTY_INPUT (CURTTY())), &tty);
-  return EMACS_TTY_TABS_OK (&tty);
+  struct emacs_tty etty;
+
+  EMACS_GET_TTY (fileno (TTY_INPUT (tty)), &etty);
+  return EMACS_TTY_TABS_OK (&etty);
 }
 
 /* Get terminal size from system.
@@ -1888,7 +1888,7 @@
 #endif
 
 #ifdef BSD_PGRPS
-  widen_foreground_group ();
+  widen_foreground_group (tty_out);
 #endif
 }
 
@@ -5098,7 +5098,7 @@
 
 /* Called from init_sys_modes.  */
 void
-hft_init ()
+hft_init (struct tty_output *tty_out)
 {
   int junk;
 
@@ -5146,14 +5146,14 @@
   }
   /* The HFT system on AIX doesn't optimize for scrolling, so it's really ugly
      at times.  */
-  TTY_LINE_INS_DEL_OK (CURTTY ()) = 0;
-  TTY_CHAR_INS_DEL_OK (CURTTY ()) = 0;
+  TTY_LINE_INS_DEL_OK (tty_out) = 0;
+  TTY_CHAR_INS_DEL_OK (tty_out) = 0;
 }
 
 /* Reset the rubout key to backspace.  */
 
 void
-hft_reset ()
+hft_reset (struct tty_output *tty_out)
 {
   struct hfbuf buf;
   struct hfkeymap keymap;
--- a/src/term.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/term.c	Sat Dec 27 01:12:57 2003 +0000
@@ -72,17 +72,23 @@
 static void tty_show_cursor P_ ((void));
 static void tty_hide_cursor P_ ((void));
 
-#define OUTPUT(tty, a) \
-    emacs_tputs ((tty), a, (int) (FRAME_LINES (XFRAME (selected_frame)) - curY), cmputc)
+#define OUTPUT(tty, a)                                          \
+  emacs_tputs ((tty), a,                                        \
+               (int) (FRAME_LINES (XFRAME (selected_frame))     \
+                      - curY (tty)),                            \
+               cmputc)
+
 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
 #define OUTPUTL(tty, a, lines) emacs_tputs ((tty), a, lines, cmputc)
 
 #define OUTPUT_IF(tty, a)                                               \
-     do {								\
-       if (a)                                                           \
-         emacs_tputs ((tty), a, (int) (FRAME_LINES (XFRAME (selected_frame)) \
-			  - curY), cmputc);				\
-     } while (0)
+  do {                                                                  \
+    if (a)                                                              \
+      emacs_tputs ((tty), a,                                            \
+                   (int) (FRAME_LINES (XFRAME (selected_frame))         \
+                          - curY (tty) ),                               \
+                   cmputc);                                             \
+  } while (0)
 
 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
 
@@ -407,6 +413,8 @@
 void
 ring_bell ()
 {
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+
   if (!NILP (Vring_bell_function))
     {
       Lisp_Object function;
@@ -426,32 +434,37 @@
 
       Vring_bell_function = function;
     }
-  else if (!FRAME_TERMCAP_P (XFRAME (selected_frame)))
+  else if (!FRAME_TERMCAP_P (f))
     (*ring_bell_hook) ();
   else {
-    OUTPUT (CURTTY (), TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
+    struct tty_output *tty = FRAME_TTY (f);
+    OUTPUT (tty, TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
   }
 }
 
 void
-set_terminal_modes (struct tty_output *tty)
+set_terminal_modes ()
 {
-  if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  if (FRAME_TERMCAP_P (f))
     {
+      struct tty_output *tty = FRAME_TTY (f);
       OUTPUT_IF (tty, TS_termcap_modes);
       OUTPUT_IF (tty, TS_cursor_visible);
       OUTPUT_IF (tty, TS_keypad_mode);
-      losecursor ();
+      losecursor (tty);
     }
   else
     (*set_terminal_modes_hook) ();
 }
 
 void
-reset_terminal_modes (struct tty_output *tty)
+reset_terminal_modes ()
 {
-  if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  if (FRAME_TERMCAP_P (f))
     {
+      struct tty_output *tty = FRAME_TTY (f);
       turn_off_highlight ();
       turn_off_insert ();
       OUTPUT_IF (tty, TS_end_keypad_mode);
@@ -496,10 +509,12 @@
 set_terminal_window (size)
      int size;
 {
-  if (FRAME_TERMCAP_P (updating_frame))
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  if (FRAME_TERMCAP_P (f))
     {
-      specified_window = size ? size : FRAME_LINES (updating_frame);
-      if (TTY_SCROLL_REGION_OK (FRAME_TTY (updating_frame)))
+      struct tty_output *tty = FRAME_TTY (f);
+      specified_window = size ? size : FRAME_LINES (f);
+      if (TTY_SCROLL_REGION_OK (tty))
 	set_scroll_region (0, specified_window);
     }
   else
@@ -511,9 +526,8 @@
      int start, stop;
 {
   char *buf;
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
 
   if (TS_set_scroll_region)
     buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
@@ -525,31 +539,29 @@
   else
     buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
 
-  OUTPUT (FRAME_TTY (f), buf);
+  OUTPUT (tty, buf);
   xfree (buf);
-  losecursor ();
+  losecursor (tty);
 }
 
 
 static void
 turn_on_insert ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
   if (!insert_mode)
-    OUTPUT (FRAME_TTY (f), TS_insert_mode);
+    OUTPUT (tty, TS_insert_mode);
   insert_mode = 1;
 }
 
 void
 turn_off_insert ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
   if (insert_mode)
-    OUTPUT (FRAME_TTY (f), TS_end_insert_mode);
+    OUTPUT (tty, TS_end_insert_mode);
   insert_mode = 0;
 }
 
@@ -558,22 +570,20 @@
 void
 turn_off_highlight ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
   if (standout_mode)
-    OUTPUT_IF (FRAME_TTY (f), TS_end_standout_mode);
+    OUTPUT_IF (tty, TS_end_standout_mode);
   standout_mode = 0;
 }
 
 static void
 turn_on_highlight ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
   if (!standout_mode)
-    OUTPUT_IF (FRAME_TTY (f), TS_standout_mode);
+    OUTPUT_IF (tty, TS_standout_mode);
   standout_mode = 1;
 }
 
@@ -592,14 +602,12 @@
 static void
 tty_hide_cursor ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
-
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
   if (tty_cursor_hidden == 0)
     {
       tty_cursor_hidden = 1;
-      OUTPUT_IF (FRAME_TTY (f), TS_cursor_invisible);
+      OUTPUT_IF (tty, TS_cursor_invisible);
     }
 }
 
@@ -609,15 +617,14 @@
 static void
 tty_show_cursor ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
 
   if (tty_cursor_hidden)
     {
       tty_cursor_hidden = 0;
-      OUTPUT_IF (FRAME_TTY (f), TS_cursor_normal);
-      OUTPUT_IF (FRAME_TTY (f), TS_cursor_visible);
+      OUTPUT_IF (tty, TS_cursor_normal);
+      OUTPUT_IF (tty, TS_cursor_visible);
     }
 }
 
@@ -654,7 +661,7 @@
 cursor_to (vpos, hpos)
      int vpos, hpos;
 {
-  struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
 
   if (! FRAME_TERMCAP_P (f) && cursor_to_hook)
     {
@@ -662,18 +669,21 @@
       return;
     }
 
+  struct tty_output *tty = FRAME_TTY (f);
+
   /* Detect the case where we are called from reset_sys_modes
      and the costs have never been calculated.  Do nothing.  */
   if (! costs_set)
     return;
 
-  if (curY == vpos && curX == hpos)
+  if (curY (tty) == vpos
+      && curX (tty) == hpos)
     return;
   if (!TF_standout_motion)
     background_highlight ();
   if (!TF_insmode_motion)
     turn_off_insert ();
-  cmgoto (FRAME_TTY (f), vpos, hpos);
+  cmgoto (tty, vpos, hpos);
 }
 
 /* Similar but don't take any account of the wasted characters.  */
@@ -688,13 +698,15 @@
       (*raw_cursor_to_hook) (row, col);
       return;
     }
-  if (curY == row && curX == col)
+  struct tty_output *tty = FRAME_TTY (f);
+  if (curY (tty) == row
+      && curX (tty) == col)
     return;
   if (!TF_standout_motion)
     background_highlight ();
   if (!TF_insmode_motion)
     turn_off_insert ();
-  cmgoto (FRAME_TTY (f), row, col);
+  cmgoto (tty, row, col);
 }
 
 /* Erase operations */
@@ -705,23 +717,22 @@
 {
   register int i;
 
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
   
   if (clear_to_end_hook && ! FRAME_TERMCAP_P (f))
     {
       (*clear_to_end_hook) ();
       return;
     }
+  struct tty_output *tty = FRAME_TTY (f);
   if (TS_clr_to_bottom)
     {
       background_highlight ();
-      OUTPUT (FRAME_TTY (f), TS_clr_to_bottom);
+      OUTPUT (tty, TS_clr_to_bottom);
     }
   else
     {
-      for (i = curY; i < FRAME_LINES (f); i++)
+      for (i = curY (tty); i < FRAME_LINES (f); i++)
 	{
 	  cursor_to (i, 0);
 	  clear_end_of_line (FRAME_COLS (f));
@@ -734,20 +745,19 @@
 void
 clear_frame ()
 {
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
 
   if (clear_frame_hook && ! FRAME_TERMCAP_P (f))
     {
       (*clear_frame_hook) ();
       return;
     }
+  struct tty_output *tty = FRAME_TTY (f);
   if (TS_clr_frame)
     {
       background_highlight ();
-      OUTPUT (FRAME_TTY (f), TS_clr_frame);
-      cmat (0, 0);
+      OUTPUT (tty, TS_clr_frame);
+      cmat (tty, 0, 0);
     }
   else
     {
@@ -767,9 +777,7 @@
 {
   register int i;
 
-  struct frame *f = (updating_frame
-                     ? updating_frame
-                     : XFRAME (selected_frame));
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
   
   if (clear_end_of_line_hook
       && ! FRAME_TERMCAP_P (f))
@@ -778,34 +786,37 @@
       return;
     }
 
+  struct tty_output *tty = FRAME_TTY (f);
+
   /* Detect the case where we are called from reset_sys_modes
      and the costs have never been calculated.  Do nothing.  */
   if (! costs_set)
     return;
 
-  if (curX >= first_unused_hpos)
+  if (curX (tty) >= first_unused_hpos)
     return;
   background_highlight ();
   if (TS_clr_line)
     {
-      OUTPUT1 (FRAME_TTY (f), TS_clr_line);
+      OUTPUT1 (tty, TS_clr_line);
     }
   else
     {			/* have to do it the hard way */
       turn_off_insert ();
 
       /* Do not write in last row last col with Auto-wrap on. */
-      if (AutoWrap && curY == FRAME_LINES (f) - 1
+      if (AutoWrap (tty)
+          && curY (tty) == FRAME_LINES (f) - 1
 	  && first_unused_hpos == FRAME_COLS (f))
 	first_unused_hpos--;
 
-      for (i = curX; i < first_unused_hpos; i++)
+      for (i = curX (tty); i < first_unused_hpos; i++)
 	{
-	  if (TTY_TERMSCRIPT (FRAME_TTY (f)))
-	    fputc (' ', TTY_TERMSCRIPT (FRAME_TTY (f)));
-	  fputc (' ', TTY_OUTPUT (FRAME_TTY (f)));
+	  if (TTY_TERMSCRIPT (tty))
+	    fputc (' ', TTY_TERMSCRIPT (tty));
+	  fputc (' ', TTY_OUTPUT (tty));
 	}
-      cmplus (first_unused_hpos - curX);
+      cmplus (tty, first_unused_hpos - curX (tty));
     }
 }
 
@@ -935,20 +946,22 @@
       return;
     }
 
+  struct tty_output *tty = FRAME_TTY (f);
+
   turn_off_insert ();
   tty_hide_cursor ();
 
   /* Don't dare write in last column of bottom line, if Auto-Wrap,
      since that would scroll the whole frame on some terminals.  */
 
-  if (AutoWrap
-      && curY + 1 == FRAME_LINES (f)
-      && (curX + len) == FRAME_COLS (f))
+  if (AutoWrap (tty)
+      && curY (tty) + 1 == FRAME_LINES (f)
+      && (curX (tty) + len) == FRAME_COLS (f))
     len --;
   if (len <= 0)
     return;
 
-  cmplus (len);
+  cmplus (tty, len);
 
   /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
      the tail.  */
@@ -979,12 +992,12 @@
 	  if (produced > 0)
 	    {
 	      fwrite (conversion_buffer, 1, produced,
-                      TTY_OUTPUT (FRAME_TTY (f)));
-	      if (ferror (TTY_OUTPUT (FRAME_TTY (f))))
-		clearerr (TTY_OUTPUT (FRAME_TTY (f)));
-	      if (TTY_TERMSCRIPT (FRAME_TTY (f)))
+                      TTY_OUTPUT (tty));
+	      if (ferror (TTY_OUTPUT (tty)))
+		clearerr (TTY_OUTPUT (tty));
+	      if (TTY_TERMSCRIPT (tty))
 		fwrite (conversion_buffer, 1, produced,
-                        TTY_TERMSCRIPT (FRAME_TTY (f)));
+                        TTY_TERMSCRIPT (tty));
 	    }
 	  len -= consumed;
 	  n -= consumed;
@@ -1005,16 +1018,16 @@
       if (terminal_coding.produced > 0)
 	{
 	  fwrite (conversion_buffer, 1, terminal_coding.produced,
-                  TTY_OUTPUT (FRAME_TTY (f)));
-	  if (ferror (TTY_OUTPUT (FRAME_TTY (f))))
-	    clearerr (TTY_OUTPUT (FRAME_TTY (f)));
-	  if (TTY_TERMSCRIPT (FRAME_TTY (f)))
+                  TTY_OUTPUT (tty));
+	  if (ferror (TTY_OUTPUT (tty)))
+	    clearerr (TTY_OUTPUT (tty));
+	  if (TTY_TERMSCRIPT (tty))
 	    fwrite (conversion_buffer, 1, terminal_coding.produced,
-		    TTY_TERMSCRIPT (FRAME_TTY (f)));
+		    TTY_TERMSCRIPT (tty));
 	}
     }
 
-  cmcheckmagic (FRAME_TTY (f));
+  cmcheckmagic (tty);
 }
 
 /* If start is zero, insert blanks instead of a string at start */
@@ -1026,23 +1039,23 @@
 {
   char *buf;
   struct glyph *glyph = NULL;
-  struct frame *f;
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
 
   if (len <= 0)
     return;
 
-  if (insert_glyphs_hook)
+  if (insert_glyphs_hook  && ! FRAME_TERMCAP_P (f))
     {
       (*insert_glyphs_hook) (start, len);
       return;
     }
 
-  f = updating_frame ? updating_frame : XFRAME (selected_frame);
+  struct tty_output *tty = FRAME_TTY (f);
 
   if (TS_ins_multi_chars)
     {
       buf = tparam (TS_ins_multi_chars, 0, 0, len);
-      OUTPUT1 (FRAME_TTY (f), buf);
+      OUTPUT1 (tty, buf);
       xfree (buf);
       if (start)
 	write_glyphs (start, len);
@@ -1050,7 +1063,7 @@
     }
 
   turn_on_insert ();
-  cmplus (len);
+  cmplus (tty, len);
   /* The bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail.  */
   terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
   while (len-- > 0)
@@ -1059,7 +1072,7 @@
       unsigned char conversion_buffer[1024];
       int conversion_buffer_size = sizeof conversion_buffer;
 
-      OUTPUT1_IF (FRAME_TTY (f), TS_ins_char);
+      OUTPUT1_IF (tty, TS_ins_char);
       if (!start)
 	{
 	  conversion_buffer[0] = SPACEGLYPH;
@@ -1075,7 +1088,7 @@
 	     occupies more than one column.  */
 	  while (len && CHAR_GLYPH_PADDING_P (*start))
 	    {
-	      OUTPUT1_IF (FRAME_TTY (f), TS_ins_char);
+	      OUTPUT1_IF (tty, TS_ins_char);
 	      start++, len--;
 	    }
 
@@ -1092,15 +1105,15 @@
       if (produced > 0)
 	{
 	  fwrite (conversion_buffer, 1, produced,
-                  TTY_OUTPUT (FRAME_TTY (f)));
-	  if (ferror (TTY_OUTPUT (FRAME_TTY (f))))
-	    clearerr (TTY_OUTPUT (FRAME_TTY (f)));
-	  if (TTY_TERMSCRIPT (FRAME_TTY (f)))
+                  TTY_OUTPUT (tty));
+	  if (ferror (TTY_OUTPUT (tty)))
+	    clearerr (TTY_OUTPUT (tty));
+	  if (TTY_TERMSCRIPT (tty))
 	    fwrite (conversion_buffer, 1, produced,
-                    TTY_TERMSCRIPT (FRAME_TTY (f)));
+                    TTY_TERMSCRIPT (tty));
 	}
 
-      OUTPUT1_IF (FRAME_TTY (f), TS_pad_inserted_char);
+      OUTPUT1_IF (tty, TS_pad_inserted_char);
       if (start)
 	{
 	  turn_off_face (f, glyph->face_id);
@@ -1108,7 +1121,7 @@
 	}
     }
 
-  cmcheckmagic (FRAME_TTY (f));
+  cmcheckmagic (tty);
 }
 
 void
@@ -1117,13 +1130,16 @@
 {
   char *buf;
   register int i;
-
-  if (delete_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame))
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
+
+  if (delete_glyphs_hook && ! FRAME_TERMCAP_P (f))
     {
       (*delete_glyphs_hook) (n);
       return;
     }
 
+
   if (delete_in_insert_mode)
     {
       turn_on_insert ();
@@ -1131,20 +1147,20 @@
   else
     {
       turn_off_insert ();
-      OUTPUT_IF (FRAME_TTY (updating_frame), TS_delete_mode);
+      OUTPUT_IF (tty, TS_delete_mode);
     }
-
+  
   if (TS_del_multi_chars)
     {
       buf = tparam (TS_del_multi_chars, 0, 0, n);
-      OUTPUT1 (FRAME_TTY (updating_frame), buf);
+      OUTPUT1 (tty, buf);
       xfree (buf);
     }
   else
     for (i = 0; i < n; i++)
-      OUTPUT1 (FRAME_TTY (updating_frame), TS_del_char);
+      OUTPUT1 (tty, TS_del_char);
   if (!delete_in_insert_mode)
-    OUTPUT_IF (FRAME_TTY (updating_frame), TS_end_delete_mode);
+    OUTPUT_IF (tty, TS_end_delete_mode);
 }
 
 /* Insert N lines at vpos VPOS.  If N is negative, delete -N lines.  */
@@ -1156,18 +1172,18 @@
   char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
   char *single = n > 0 ? TS_ins_line : TS_del_line;
   char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
-  struct frame *f;
+  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
 
   register int i = n > 0 ? n : -n;
   register char *buf;
 
-  if (ins_del_lines_hook && ! FRAME_TERMCAP_P (updating_frame))
+  if (ins_del_lines_hook && ! FRAME_TERMCAP_P (f))
     {
       (*ins_del_lines_hook) (vpos, n);
       return;
     }
 
-  f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct tty_output *tty = FRAME_TTY (f);
 
   /* If the lines below the insertion are being pushed
      into the end of the window, this is the same as clearing;
@@ -1176,10 +1192,10 @@
   /* If the lines below the deletion are blank lines coming
      out of the end of the window, don't bother,
      as there will be a matching inslines later that will flush them. */
-  if (TTY_SCROLL_REGION_OK (FRAME_TTY (f))
+  if (TTY_SCROLL_REGION_OK (tty)
       && vpos + i >= specified_window)
     return;
-  if (!TTY_MEMORY_BELOW_FRAME (FRAME_TTY (f))
+  if (!TTY_MEMORY_BELOW_FRAME (tty)
       && vpos + i >= FRAME_LINES (f))
     return;
 
@@ -1188,7 +1204,7 @@
       raw_cursor_to (vpos, 0);
       background_highlight ();
       buf = tparam (multi, 0, 0, i);
-      OUTPUT (FRAME_TTY (f), buf);
+      OUTPUT (tty, buf);
       xfree (buf);
     }
   else if (single)
@@ -1196,9 +1212,9 @@
       raw_cursor_to (vpos, 0);
       background_highlight ();
       while (--i >= 0)
-	OUTPUT (FRAME_TTY (f), single);
+	OUTPUT (tty, single);
       if (TF_teleray)
-	curX = 0;
+	curX (tty) = 0;
     }
   else
     {
@@ -1209,12 +1225,12 @@
 	raw_cursor_to (vpos, 0);
       background_highlight ();
       while (--i >= 0)
-	OUTPUTL (FRAME_TTY (f), scroll, specified_window - vpos);
+	OUTPUTL (tty, scroll, specified_window - vpos);
       set_scroll_region (0, specified_window);
     }
 
-  if (!TTY_SCROLL_REGION_OK (FRAME_TTY (f))
-      && TTY_MEMORY_BELOW_FRAME (FRAME_TTY (f))
+  if (!TTY_SCROLL_REGION_OK (tty)
+      && TTY_MEMORY_BELOW_FRAME (tty)
       && n < 0)
     {
       cursor_to (FRAME_LINES (f) + n, 0);
@@ -1392,7 +1408,7 @@
   else
     RPov = FRAME_COLS (frame) * 2;
 
-  cmcostinit ();		/* set up cursor motion costs */
+  cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */
 }
 
 struct fkey_table {
@@ -1857,6 +1873,7 @@
   struct face *face = FACE_FROM_ID (f, face_id);
   long fg = face->foreground;
   long bg = face->background;
+  struct tty_output *tty = FRAME_TTY (f);
 
   /* Do this first because TS_end_standout_mode may be the same
      as TS_exit_attribute_mode, which turns all appearances off. */
@@ -1907,23 +1924,23 @@
   if (face->tty_bold_p)
     {
       if (MAY_USE_WITH_COLORS_P (NC_BOLD))
-	OUTPUT1_IF (FRAME_TTY (f), TS_enter_bold_mode);
+	OUTPUT1_IF (tty, TS_enter_bold_mode);
     }
   else if (face->tty_dim_p)
     if (MAY_USE_WITH_COLORS_P (NC_DIM))
-      OUTPUT1_IF (FRAME_TTY (f), TS_enter_dim_mode);
+      OUTPUT1_IF (tty, TS_enter_dim_mode);
 
   /* Alternate charset and blinking not yet used.  */
   if (face->tty_alt_charset_p
       && MAY_USE_WITH_COLORS_P (NC_ALT_CHARSET))
-    OUTPUT1_IF (FRAME_TTY (f), TS_enter_alt_charset_mode);
+    OUTPUT1_IF (tty, TS_enter_alt_charset_mode);
 
   if (face->tty_blinking_p
       && MAY_USE_WITH_COLORS_P (NC_BLINK))
-    OUTPUT1_IF (FRAME_TTY (f), TS_enter_blink_mode);
+    OUTPUT1_IF (tty, TS_enter_blink_mode);
 
   if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (NC_UNDERLINE))
-    OUTPUT1_IF (FRAME_TTY (f), TS_enter_underline_mode);
+    OUTPUT1_IF (tty, TS_enter_underline_mode);
 
   if (TN_max_colors > 0)
     {
@@ -1932,14 +1949,14 @@
       if (fg >= 0 && TS_set_foreground)
 	{
 	  p = tparam (TS_set_foreground, NULL, 0, (int) fg);
-	  OUTPUT (FRAME_TTY (f), p);
+	  OUTPUT (tty, p);
 	  xfree (p);
 	}
 
       if (bg >= 0 && TS_set_background)
 	{
 	  p = tparam (TS_set_background, NULL, 0, (int) bg);
-	  OUTPUT (FRAME_TTY (f), p);
+	  OUTPUT (tty, p);
 	  xfree (p);
 	}
     }
@@ -1954,6 +1971,7 @@
      int face_id;
 {
   struct face *face = FACE_FROM_ID (f, face_id);
+  struct tty_output *tty = FRAME_TTY (f);
 
   xassert (face != NULL);
 
@@ -1969,23 +1987,23 @@
 	  || face->tty_blinking_p
 	  || face->tty_underline_p)
 	{
-	  OUTPUT1_IF (FRAME_TTY (f), TS_exit_attribute_mode);
+	  OUTPUT1_IF (tty, TS_exit_attribute_mode);
 	  if (strcmp (TS_exit_attribute_mode, TS_end_standout_mode) == 0)
 	    standout_mode = 0;
 	}
 
       if (face->tty_alt_charset_p)
-	OUTPUT_IF (FRAME_TTY (f), TS_exit_alt_charset_mode);
+	OUTPUT_IF (tty, TS_exit_alt_charset_mode);
     }
   else
     {
       /* If we don't have "me" we can only have those appearances
 	 that have exit sequences defined.  */
       if (face->tty_alt_charset_p)
-	OUTPUT_IF (FRAME_TTY (f), TS_exit_alt_charset_mode);
+	OUTPUT_IF (tty, TS_exit_alt_charset_mode);
 
       if (face->tty_underline_p)
-	OUTPUT_IF (FRAME_TTY (f), TS_exit_underline_mode);
+	OUTPUT_IF (tty, TS_exit_underline_mode);
     }
 
   /* Switch back to default colors.  */
@@ -1994,7 +2012,7 @@
 	   && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
 	  || (face->background != FACE_TTY_DEFAULT_COLOR
 	      && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
-    OUTPUT1_IF (FRAME_TTY (f), TS_orig_pair);
+    OUTPUT1_IF (tty, TS_orig_pair);
 }
 
 
@@ -2256,6 +2274,10 @@
       tty_list = tty;
     }
 
+  if (tty->Wcm)
+    xfree (tty->Wcm);
+  tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
+  
   if (name)
     {
       int fd;
@@ -2314,7 +2336,7 @@
   return tty;
 #else  /* not WINDOWSNT */
 
-  Wcm_clear ();
+  Wcm_clear (tty);
 
   TTY_TYPE (tty) = xstrdup (terminal_type);
 
@@ -2357,16 +2379,16 @@
   TS_ins_line = tgetstr ("al", address);
   TS_ins_multi_lines = tgetstr ("AL", address);
   TS_bell = tgetstr ("bl", address);
-  BackTab = tgetstr ("bt", address);
+  BackTab (tty) = tgetstr ("bt", address);
   TS_clr_to_bottom = tgetstr ("cd", address);
   TS_clr_line = tgetstr ("ce", address);
   TS_clr_frame = tgetstr ("cl", address);
-  ColPosition = NULL; /* tgetstr ("ch", address); */
-  AbsPosition = tgetstr ("cm", address);
-  CR = tgetstr ("cr", address);
+  ColPosition (tty) = NULL; /* tgetstr ("ch", address); */
+  AbsPosition (tty) = tgetstr ("cm", address);
+  CR (tty) = tgetstr ("cr", address);
   TS_set_scroll_region = tgetstr ("cs", address);
   TS_set_scroll_region_1 = tgetstr ("cS", address);
-  RowPosition = tgetstr ("cv", address);
+  RowPosition (tty) = tgetstr ("cv", address);
   TS_del_char = tgetstr ("dc", address);
   TS_del_multi_chars = tgetstr ("DC", address);
   TS_del_line = tgetstr ("dl", address);
@@ -2374,40 +2396,40 @@
   TS_delete_mode = tgetstr ("dm", address);
   TS_end_delete_mode = tgetstr ("ed", address);
   TS_end_insert_mode = tgetstr ("ei", address);
-  Home = tgetstr ("ho", address);
+  Home (tty) = tgetstr ("ho", address);
   TS_ins_char = tgetstr ("ic", address);
   TS_ins_multi_chars = tgetstr ("IC", address);
   TS_insert_mode = tgetstr ("im", address);
   TS_pad_inserted_char = tgetstr ("ip", address);
   TS_end_keypad_mode = tgetstr ("ke", address);
   TS_keypad_mode = tgetstr ("ks", address);
-  LastLine = tgetstr ("ll", address);
-  Right = tgetstr ("nd", address);
-  Down = tgetstr ("do", address);
-  if (!Down)
-    Down = tgetstr ("nl", address); /* Obsolete name for "do" */
+  LastLine (tty) = tgetstr ("ll", address);
+  Right (tty) = tgetstr ("nd", address);
+  Down (tty) = tgetstr ("do", address);
+  if (!Down (tty))
+    Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
 #ifdef VMS
   /* VMS puts a carriage return before each linefeed,
      so it is not safe to use linefeeds.  */
-  if (Down && Down[0] == '\n' && Down[1] == '\0')
-    Down = 0;
+  if (Down (tty) && Down (tty)[0] == '\n' && Down (tty)[1] == '\0')
+    Down (tty) = 0;
 #endif /* VMS */
   if (tgetflag ("bs"))
-    Left = "\b";		  /* can't possibly be longer! */
+    Left (tty) = "\b";		  /* can't possibly be longer! */
   else				  /* (Actually, "bs" is obsolete...) */
-    Left = tgetstr ("le", address);
-  if (!Left)
-    Left = tgetstr ("bc", address); /* Obsolete name for "le" */
+    Left (tty) = tgetstr ("le", address);
+  if (!Left (tty))
+    Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
   TS_pad_char = tgetstr ("pc", address);
   TS_repeat = tgetstr ("rp", address);
   TS_end_standout_mode = tgetstr ("se", address);
   TS_fwd_scroll = tgetstr ("sf", address);
   TS_standout_mode = tgetstr ("so", address);
   TS_rev_scroll = tgetstr ("sr", address);
-  Wcm.cm_tab = tgetstr ("ta", address);
+  tty->Wcm->cm_tab = tgetstr ("ta", address);
   TS_end_termcap_modes = tgetstr ("te", address);
   TS_termcap_modes = tgetstr ("ti", address);
-  Up = tgetstr ("up", address);
+  Up (tty) = tgetstr ("up", address);
   TS_visible_bell = tgetstr ("vb", address);
   TS_cursor_normal = tgetstr ("ve", address);
   TS_cursor_visible = tgetstr ("vs", address);
@@ -2424,10 +2446,10 @@
   TS_exit_alt_charset_mode = tgetstr ("ae", address);
   TS_exit_attribute_mode = tgetstr ("me", address);
 
-  MultiUp = tgetstr ("UP", address);
-  MultiDown = tgetstr ("DO", address);
-  MultiLeft = tgetstr ("LE", address);
-  MultiRight = tgetstr ("RI", address);
+  MultiUp (tty) = tgetstr ("UP", address);
+  MultiDown (tty) = tgetstr ("DO", address);
+  MultiLeft (tty) = tgetstr ("LE", address);
+  MultiRight (tty) = tgetstr ("RI", address);
 
   /* SVr4/ANSI color suppert.  If "op" isn't available, don't support
      color because we can't switch back to the default foreground and
@@ -2454,10 +2476,10 @@
 
   tty_default_color_capabilities (1);
 
-  MagicWrap = tgetflag ("xn");
+  MagicWrap (tty) = tgetflag ("xn");
   /* Since we make MagicWrap terminals look like AutoWrap, we need to have
      the former flag imply the latter.  */
-  AutoWrap = MagicWrap || tgetflag ("am");
+  AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
   TTY_MEMORY_BELOW_FRAME (tty) = tgetflag ("db");
   TF_hazeltine = tgetflag ("hz");
   TTY_MUST_WRITE_SPACES (tty) = tgetflag ("in");
@@ -2493,32 +2515,32 @@
   TTY_MIN_PADDING_SPEED (tty) = tgetnum ("pb");
 #endif
 
-  TabWidth = tgetnum ("tw");
+  TabWidth (tty) = tgetnum ("tw");
 
 #ifdef VMS
   /* These capabilities commonly use ^J.
      I don't know why, but sending them on VMS does not work;
      it causes following spaces to be lost, sometimes.
      For now, the simplest fix is to avoid using these capabilities ever.  */
-  if (Down && Down[0] == '\n')
-    Down = 0;
+  if (Down (tty) && Down (tty)[0] == '\n')
+    Down (tty) = 0;
 #endif /* VMS */
 
   if (!TS_bell)
     TS_bell = "\07";
 
   if (!TS_fwd_scroll)
-    TS_fwd_scroll = Down;
+    TS_fwd_scroll = Down (tty);
 
   PC = TS_pad_char ? *TS_pad_char : 0;
 
-  if (TabWidth < 0)
-    TabWidth = 8;
+  if (TabWidth (tty) < 0)
+    TabWidth (tty) = 8;
 
 /* Turned off since /etc/termcap seems to have :ta= for most terminals
    and newer termcap doc does not seem to say there is a default.
-  if (!Wcm.cm_tab)
-    Wcm.cm_tab = "\t";
+  if (!tty->Wcm->cm_tab)
+    tty->Wcm->cm_tab = "\t";
 */
 
   /* We don't support standout modes that use `magic cookies', so
@@ -2554,14 +2576,14 @@
 
   if (TF_teleray)
     {
-      Wcm.cm_tab = 0;
+      tty->Wcm->cm_tab = 0;
       /* We can't support standout mode, because it uses magic cookies.  */
       TS_standout_mode = 0;
       /* But that means we cannot rely on ^M to go to column zero! */
-      CR = 0;
+      CR (tty) = 0;
       /* LF can't be trusted either -- can alter hpos */
       /* if move at column 0 thru a line with TS_standout_mode */
-      Down = 0;
+      Down (tty) = 0;
     }
 
   /* Special handling for certain terminal types known to need it */
@@ -2569,7 +2591,7 @@
   if (!strcmp (terminal_type, "supdup"))
     {
       TTY_MEMORY_BELOW_FRAME (tty) = 1;
-      Wcm.cm_losewrap = 1;
+      tty->Wcm->cm_losewrap = 1;
     }
   if (!strncmp (terminal_type, "c10", 3)
       || !strcmp (terminal_type, "perq"))
@@ -2602,7 +2624,7 @@
       strcat (area, "\033\007!");
       TS_termcap_modes = area;
       area += strlen (area) + 1;
-      p = AbsPosition;
+      p = AbsPosition (tty);
       /* Change all %+ parameters to %C, to handle
          values above 96 correctly for the C100.  */
       while (*p)
@@ -2613,11 +2635,11 @@
         }
     }
 
-  FrameRows = FRAME_LINES (sf);
-  FrameCols = FRAME_COLS (sf);
+  FrameRows (tty) = FRAME_LINES (sf);
+  FrameCols (tty) = FRAME_COLS (sf);
   specified_window = FRAME_LINES (sf);
 
-  if (Wcm_init () == -1)	/* can't do cursor motion */
+  if (Wcm_init (tty) == -1)	/* can't do cursor motion */
 #ifdef VMS
     fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
 It lacks the ability to position the cursor.\n\
@@ -2656,10 +2678,10 @@
               && TS_end_standout_mode
               && !strcmp (TS_standout_mode, TS_end_standout_mode));
 
-  UseTabs = tabs_safe_p () && TabWidth == 8;
+  UseTabs (tty) = tabs_safe_p (tty) && TabWidth (tty) == 8;
 
   TTY_SCROLL_REGION_OK (tty)
-    = (Wcm.cm_abs
+    = (tty->Wcm->cm_abs
        && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1));
 
   TTY_LINE_INS_DEL_OK (tty)
@@ -2720,6 +2742,8 @@
 
   defsubr (&Stty_display_color_p);
   defsubr (&Stty_display_color_cells);
+
+  Fprovide (intern ("multi-tty"), Qnil);
 }
 
 struct tty_output *
--- a/src/termchar.h	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/termchar.h	Sat Dec 27 01:12:57 2003 +0000
@@ -41,6 +41,10 @@
   int old_tty_valid;            /* 1 if outer tty status has been recorded.  */
 
 
+  /* Structure for info on cursor positioning.  */
+
+  struct cm *Wcm;
+
   /* Redisplay. */
 
   /* XXX This may cause problems with GC. */
--- a/src/xdisp.c	Fri Dec 26 04:31:27 2003 +0000
+++ b/src/xdisp.c	Sat Dec 27 01:12:57 2003 +0000
@@ -9567,7 +9567,7 @@
 {
   Lisp_Object tail, sym, val;
   Lisp_Object old = selected_frame;
-  
+
   selected_frame = frame;
 
   for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
@@ -13319,7 +13319,7 @@
 
 	      /* On dumb terminals delete dvpos lines at the end
 		 before inserting dvpos empty lines.  */
-	      if (!TTY_SCROLL_REGION_OK (CURTTY ()))
+	      if (!TTY_SCROLL_REGION_OK (FRAME_TTY (f)))
 		ins_del_lines (end - dvpos, -dvpos);
 
 	      /* Insert dvpos empty lines in front of
@@ -13340,7 +13340,7 @@
 
 	      /* On a dumb terminal insert dvpos empty lines at the
                  end.  */
-	      if (!TTY_SCROLL_REGION_OK (CURTTY ()))
+	      if (!TTY_SCROLL_REGION_OK (FRAME_TTY (f)))
 		ins_del_lines (end + dvpos, -dvpos);
 	    }