changeset 53229:33c3c7c16e13

lib-src/emacsclient.c: Implemented --here option (open a new Emacs tty). Needs more work. (here): New variable. (decode_options): Use it. (ec_get_tty, ec_set_tty, init_tty, window_change, hang_up_signal): New functions. (window_change_signal, init_signals, reset_tty, init_pty, copy_from_to): Ditto. (pty_conversation): Ditto. (main): Use them. (master, pty_name, old_tty, tty, old_tty_valid, tty_erase_char): New variables. (flow_control, meta_key, _sobuf, in_conversation, quit_conversation): Ditto. lisp/server.el (server-process-filter): Added support for opening a new terminal frame. dispextern.h (get_frame_size): Renamed to get_tty_size, added tty_output parameter. dispnew.c (Fredraw_frame): fflush the current terminal instead of stdout. (direct_output_for_insert, direct_output_forward_char, update_frame_1): Ditto. (Fding, bitch_at_user): Ditto. (update_frame_1): Count pending output for current terminal instead of stdout. (window_change_signal): Resize all terminals. (change_frame_size): Don't resize all terminals to the same size. frame.c (Vterminal_frame): Removed. (syms_of_frame): Removed declaration of Vterminal_frame. (make_terminal_frame): Set the top frame of the terminal to the new frame. (Fmake_terminal_frame): Get a new frame size from get_tty_size, don't copy it. (do_switch_frame): Handle terminal frame visibility. (next_frame, prev_frame): Skip over frames on different terminals. frame.h (Vterminal_frame): Removed. keyboard.c (input_fd): Removed. (read_avail_input): Removed first argument from read_socket_hook. Try to read from each available tty, until one succeeds. (Fsuspend_emacs): Don't suspend if there are multiple terminals. lisp.h (get_frame_size): Removed superflous declaration. xterm.c (Xtread_socket): Removed first parameter. macterm.h (XTread_socket): Ditto. w32inevt.c (w32_console_read_socket): Ditto. w32term.c (w32_read_socket): Ditto. sysdep.c (input_fd): Removed. (change_input_fd): Removed. (discard_tty_input): Discard pending input on _all_ input descriptors. (stuff_char, tabs_safe_p): Use current terminal instead of input_fd. (init_baud_rate, request_sigio, unrequest_sigio): Ditto. (init_sys_modes, reset_sys_modes): Ditto. (narrow_foreground_group, widen_foreground_group): Use stdin. (init_sys_modes, reset_sys_modes): otty parameter renamed to tty_out. (get_frame_size): Renamed to get_tty_size, added tty_out parameter. term.c (read_socket_hook): Removed first parameter. (clear_end_of_line): Use updating_frame, if possible. (write_glyphs, insert_glyphs, ins_del_lines): Ditto. (term_init): Renamed get_frame_size to get_tty_size. termchar.h (struct tty_output): New entries: top_frame, previous_terminal_frame. termhooks.h (read_socket_hook): Removed first parameter. window.c (init_window_once): Removed reference to Vterminal_frame. xdisp.c (previous_terminal_frame): Moved to struct tty_output. (redisplay_internal): Updated to use previous_terminal_frame in tty_output. Allow for simultaneous refresh of multiple ttys. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-5
author Karoly Lorentey <lorentey@elte.hu>
date Fri, 26 Dec 2003 04:24:54 +0000
parents c5b253fd2504
children dfd82236be81
files README.multi-tty lib-src/emacsclient.c lib-src/pty.c lib-src/pty.h lisp/server.el src/dispextern.h src/dispnew.c src/emacs.c src/frame.c src/frame.h src/keyboard.c src/lisp.h src/macterm.c src/scroll.c src/sysdep.c src/term.c src/termchar.h src/termhooks.h src/w32inevt.c src/w32term.c src/window.c src/xdisp.c src/xterm.c
diffstat 23 files changed, 1208 insertions(+), 312 deletions(-) [+]
line wrap: on
line diff
--- a/README.multi-tty	Thu Dec 25 07:36:05 2003 +0000
+++ b/README.multi-tty	Fri Dec 26 04:24:54 2003 +0000
@@ -25,19 +25,18 @@
 ------
 
 We can create frames on new tty devices, but there are problems with
-refresh (only the (single) selected frame is refreshed), and input is
-read only from the initial terminal.  At the moment, the type of the
-new terminals must be the same as the initial terminal.
-
-To try it out, start up emacs, and evaluate the following:
+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.
 
-	(make-terminal-frame '((tty . "/dev/pts/5") (tty-type . "xterm")))
+To try it out, start up the emacs server (M-x server-start), and then
+start emacsclient with
 
-(With your own values, of course.)  If you switch to the new frame
-with M-x other-frame, the new tty is refreshed with the frame
-contents.  The result of input from the original terminal appears on
-the new.  If you exit emacs, both terminals are restored to their
-previous states.
+	emacsclient -h
+
+If you exit emacs, both terminals are restored to their previous
+states.
 
 X, Mac, Windows and DOS support is broken.
 
@@ -50,6 +49,8 @@
    specify a terminal device (`tty' parameter) and a terminal type
    (`tty-type' parameter) to `make-terminal-frame'.
 
+** Emacsclient has been extended to support opening a new terminal
+   frame.
 
 CHANGELOG
 ---------
@@ -76,15 +77,50 @@
    (Done, new frame parameters: `tty' and `tty-type'.)
 
 
+-- Implement support for reading from multiple terminals.
+
+   (Done, read_avail_input tries to read from each terminal, until one
+   succeeds.)
+
+-- other-frame should cycle through the frames on the `current'
+   terminal.  
+
+   (Done.  A little fragile, but seems to work.)
+
+-- Support different terminal sizes.
+   
+   (Done, no problem.)
+
+-- Make sure terminal resizes are handled gracefully.  (Could be
+   problematic.)
+
+   (Done.  We don't get SIGWINCH for additional ttys, though.)
+
+-- Extend emacsclient to automatically open a new tty when it connects
+   to Emacs.
+   
+   (Done.  It's an ugly hack, needs more work.)
+
+-- Redisplay must refresh the topmost frame on all terminals, not just
+   the initial terminal.
+   
+   (Done, but introduced ugly redisplay problems.  Ugh.)
+
+
 THINGS TO DO
 ------------
 
+** Fix redisplay problems.
+
 ** 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.
+
 ** 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.
@@ -96,27 +132,14 @@
    Currently, they are still stored in global variables, so we don't
    really support multiple terminal types.
 
-** Support different terminal sizes.  (Should be solved by the
-   previous entry.)
 
-** Make sure terminal resizes are handled gracefully.  (Could be
-   problematic.)
-
-** Implement support for reading from multiple terminals.
-
-** other-frame should cycle through the frames on the `current'
-   terminal.  This means that Emacs must know from which terminal the
-   last keyboard event came from.  (Multikeyboard support may help
-   with this.)
-
-** Redisplay must refresh the topmost on all terminals, not just
-   the initial terminal.
+** 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.
 
-** Extend emacsclient to automatically open a new tty when it connects
-   to Emacs.
-
 ** 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.
--- a/lib-src/emacsclient.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/lib-src/emacsclient.c	Fri Dec 26 04:24:54 2003 +0000
@@ -41,6 +41,54 @@
 # include <pwd.h>
 #endif /* not VMS */
 
+
+/****************************************/
+
+#include <errno.h>
+#include <signal.h>
+
+#ifndef INCLUDED_FCNTL
+#define INCLUDED_FCNTL
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_TERMIOS
+#ifndef NO_TERMIO
+#include <termio.h>
+#endif
+#include <termios.h>
+#endif /* not HAVE_TERMIOS */
+
+#ifdef __GNU_LIBRARY__
+#include <sys/ioctl.h>
+#include <termios.h>
+#endif
+
+#if (defined (POSIX) || defined (NEED_UNISTD_H)) && defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+
+
+/* Try to establish the correct character to disable terminal functions
+   in a system-independent manner.  Note that USG (at least) define
+   _POSIX_VDISABLE as 0!  */
+
+#ifdef _POSIX_VDISABLE
+#define CDISABLE _POSIX_VDISABLE
+#else /* not _POSIX_VDISABLE */
+#ifdef CDEL
+#undef CDISABLE
+#define CDISABLE CDEL
+#else /* not CDEL */
+#define CDISABLE 255
+#endif /* not CDEL */
+#endif /* not _POSIX_VDISABLE */
+
+
+
+/****************************************/
+
 char *getenv (), *getwd ();
 char *getcwd ();
 
@@ -63,6 +111,9 @@
 /* The display on which Emacs should work.  --display.  */
 char *display = NULL;
 
+/* Nonzero means open a new Emacs frame on the current terminal. */
+int here = 0;
+
 /* If non-NULL, the name of an editor to fallback to if the server
    is not running.  --alternate-editor.   */
 const char * alternate_editor = NULL;
@@ -78,6 +129,7 @@
   { "eval",	no_argument,	   NULL, 'e' },
   { "help",	no_argument,	   NULL, 'H' },
   { "version",	no_argument,	   NULL, 'V' },
+  { "here",	no_argument,       NULL, 'h' },
   { "alternate-editor", required_argument, NULL, 'a' },
   { "socket-name",	required_argument, NULL, 's' },
   { "display",	required_argument, NULL, 'd' },
@@ -95,7 +147,7 @@
   while (1)
     {
       int opt = getopt_long (argc, argv,
-			     "VHnea:s:d:", longopts, 0);
+			     "VHnea:s:d:h", longopts, 0);
 
       if (opt == EOF)
 	break;
@@ -134,6 +186,10 @@
 	  exit (0);
 	  break;
 
+        case 'h':
+          here = 1;
+          break;
+          
 	case 'H':
 	  print_help_and_exit ();
 	  break;
@@ -144,6 +200,12 @@
 	  break;
 	}
     }
+
+  if (here) {
+    nowait = 0;
+    display = 0;
+  }
+  
 }
 
 void
@@ -157,6 +219,7 @@
 The following OPTIONS are accepted:\n\
 -V, --version           Just print a version info and return\n\
 -H, --help              Print this usage information message\n\
+-h, --here              Open a new Emacs frame on the current terminal\n\
 -n, --no-wait           Don't wait for the server to return\n\
 -e, --eval              Evaluate the FILE arguments as ELisp expressions\n\
 -d, --display=DISPLAY   Visit the file in the given display\n\
@@ -247,6 +310,455 @@
     }
 }
 
+
+#ifdef HAVE_TERMIOS
+
+/* Adapted from emacs_get_tty() in sysdep.c. */
+int
+ec_get_tty (int fd, struct termios *settings)
+{
+  bzero (settings, sizeof (struct termios));
+  if (tcgetattr (fd, settings) < 0)
+    return -1;
+  return 0;
+}
+
+/* Adapted from emacs_set_tty() in sysdep.c. */
+int
+ec_set_tty (int fd, struct termios *settings, int flushp)
+{
+  /* Set the primary parameters - baud rate, character size, etcetera.  */
+
+  int i;
+  /* We have those nifty POSIX tcmumbleattr functions.
+     William J. Smith <wjs@wiis.wang.com> writes:
+     "POSIX 1003.1 defines tcsetattr to return success if it was
+     able to perform any of the requested actions, even if some
+     of the requested actions could not be performed.
+     We must read settings back to ensure tty setup properly.
+     AIX requires this to keep tty from hanging occasionally."  */
+  /* This make sure that we don't loop indefinitely in here.  */
+  for (i = 0 ; i < 10 ; i++)
+    if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, settings) < 0)
+      {
+	if (errno == EINTR)
+	  continue;
+	else
+	  return -1;
+      }
+    else
+      {
+	struct termios new;
+        
+	bzero (&new, sizeof (new));
+	/* Get the current settings, and see if they're what we asked for.  */
+	tcgetattr (fd, &new);
+	/* We cannot use memcmp on the whole structure here because under
+	 * aix386 the termios structure has some reserved field that may
+	 * not be filled in.
+	 */
+	if (   new.c_iflag == settings->c_iflag
+	    && new.c_oflag == settings->c_oflag
+	    && new.c_cflag == settings->c_cflag
+	    && new.c_lflag == settings->c_lflag
+	    && memcmp (new.c_cc, settings->c_cc, NCCS) == 0)
+	  break;
+	else
+	  continue;
+      }
+  return 0;
+}
+
+int master;
+char *pty_name;
+
+struct termios old_tty;
+struct termios tty;
+int old_tty_valid;
+
+int tty_erase_char;
+int flow_control = 0;
+int meta_key = 0;
+char _sobuf[BUFSIZ];
+
+/* Adapted from init_sys_modes() in sysdep.c. */
+int
+init_tty ()
+{
+  if (! isatty (0))
+    {
+      fprintf (stderr, "%s: Input is not a terminal", "init_tty");
+      return 0;
+    }
+  
+  ec_get_tty (0, &old_tty);
+  old_tty_valid = 1;
+  tty = old_tty;
+  
+  tty_erase_char = old_tty.c_cc[VERASE];
+  
+  tty.c_iflag |= (IGNBRK);	/* Ignore break condition */
+  tty.c_iflag &= ~ICRNL;	/* Disable map of CR to NL on input */
+#ifdef INLCR
+  tty.c_iflag &= ~INLCR;	/* Disable map of NL to CR on input */
+#endif
+#ifdef ISTRIP
+  tty.c_iflag &= ~ISTRIP;	/* don't strip 8th bit on input */
+#endif
+  tty.c_lflag &= ~ECHO;         /* Disable echo */
+  tty.c_lflag &= ~ICANON;	/* Disable erase/kill processing */
+#ifdef IEXTEN
+  tty.c_lflag &= ~IEXTEN;	/* Disable other editing characters.  */
+#endif
+  tty.c_lflag |= ISIG;          /* Enable signals */
+  if (flow_control)
+    {
+      tty.c_iflag |= IXON;	/* Enable start/stop output control */
+#ifdef IXANY
+      tty.c_iflag &= ~IXANY;
+#endif /* IXANY */
+    }
+  else
+    tty.c_iflag &= ~IXON;	/* Disable start/stop output control */
+  tty.c_oflag &= ~ONLCR;	/* Disable map of NL to CR-NL
+                                   on output */
+  tty.c_oflag &= ~TAB3;         /* Disable tab expansion */
+#ifdef CS8
+  if (meta_key)
+    {
+      tty.c_cflag |= CS8;	/* allow 8th bit on input */
+      tty.c_cflag &= ~PARENB;   /* Don't check parity */
+    }
+#endif
+  tty.c_cc[VINTR] = CDISABLE;
+  tty.c_cc[VQUIT] = CDISABLE;
+  tty.c_cc[VMIN] = 1;      /* Input should wait for at least 1 char */
+  tty.c_cc[VTIME] = 0;          /* no matter how long that takes.  */
+#ifdef VSWTCH
+  tty.c_cc[VSWTCH] = CDISABLE;	/* Turn off shell layering use of C-z */
+#endif
+
+#ifdef VSUSP
+  tty.c_cc[VSUSP] = CDISABLE;	/* Turn off mips handling of C-z.  */
+#endif /* VSUSP */
+#ifdef V_DSUSP
+  tty.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y.  */
+#endif /* V_DSUSP */
+#ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP.  */
+  tty.c_cc[VDSUSP] = CDISABLE;
+#endif /* VDSUSP */
+#ifdef VLNEXT
+  tty.c_cc[VLNEXT] = CDISABLE;
+#endif /* VLNEXT */
+#ifdef VREPRINT
+  tty.c_cc[VREPRINT] = CDISABLE;
+#endif /* VREPRINT */
+#ifdef VWERASE
+  tty.c_cc[VWERASE] = CDISABLE;
+#endif /* VWERASE */
+#ifdef VDISCARD
+  tty.c_cc[VDISCARD] = CDISABLE;
+#endif /* VDISCARD */
+
+  if (flow_control)
+    {
+#ifdef VSTART
+      tty.c_cc[VSTART] = '\021';
+#endif /* VSTART */
+#ifdef VSTOP
+      tty.c_cc[VSTOP] = '\023';
+#endif /* VSTOP */
+    }
+  else
+    {
+#ifdef VSTART
+      tty.c_cc[VSTART] = CDISABLE;
+#endif /* VSTART */
+#ifdef VSTOP
+      tty.c_cc[VSTOP] = CDISABLE;
+#endif /* VSTOP */
+    }
+  
+#ifdef SET_LINE_DISCIPLINE
+  /* Need to explicitly request TERMIODISC line discipline or
+     Ultrix's termios does not work correctly.  */
+  tty.c_line = SET_LINE_DISCIPLINE;
+#endif
+  
+#ifdef AIX
+#ifndef IBMR2AIX
+  /* AIX enhanced edit loses NULs, so disable it.  */
+  tty.c_line = 0;
+  tty.c_iflag &= ~ASCEDIT;
+#else
+  tty.c_cc[VSTRT] = 255;
+  tty.c_cc[VSTOP] = 255;
+  tty.c_cc[VSUSP] = 255;
+  tty.c_cc[VDSUSP] = 255;
+#endif /* IBMR2AIX */
+  if (flow_control)
+    {
+#ifdef VSTART
+      tty.c_cc[VSTART] = '\021';
+#endif /* VSTART */
+#ifdef VSTOP
+      tty.c_cc[VSTOP] = '\023';
+#endif /* VSTOP */
+    }
+  /* Also, PTY overloads NUL and BREAK.
+     don't ignore break, but don't signal either, so it looks like NUL.
+     This really serves a purpose only if running in an XTERM window
+     or via TELNET or the like, but does no harm elsewhere.  */
+  tty.c_iflag &= ~IGNBRK;
+  tty.c_iflag &= ~BRKINT;
+#endif /* AIX */
+  
+  ec_set_tty (0, &tty, 0);
+
+      /* This code added to insure that, if flow-control is not to be used,
+	 we have an unlocked terminal at the start. */
+
+#ifdef TCXONC
+  if (!flow_control) ioctl (0, TCXONC, 1);
+#endif
+#ifndef APOLLO
+#ifdef TIOCSTART
+  if (!flow_control) ioctl (0, TIOCSTART, 0);
+#endif
+#endif
+
+#if defined (HAVE_TERMIOS) || defined (HPUX9)
+#ifdef TCOON
+  if (!flow_control) tcflow (0, TCOON);
+#endif
+#endif
+  
+#ifdef _IOFBF
+  /* This symbol is defined on recent USG systems.
+     Someone says without this call USG won't really buffer the file
+     even with a call to setbuf. */
+  setvbuf (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf);
+#else
+  setbuf (stdout, (char *) _sobuf);
+#endif
+
+  return 1;
+}
+
+void
+window_change ()
+{
+  int width, height;
+
+#ifdef TIOCGWINSZ
+  {
+    /* BSD-style.  */
+    struct winsize size;
+    
+    if (ioctl (0, TIOCGWINSZ, &size) == -1)
+      width = height = 0;
+    else
+      {
+        width = size.ws_col;
+        height = size.ws_row;
+      }
+  }
+#else
+#ifdef TIOCGSIZE
+  {
+    /* SunOS - style.  */
+    struct ttysize size;
+    
+    if (ioctl (0, TIOCGSIZE, &size) == -1)
+      width = height = 0;
+    else
+      {
+        width = size.ts_cols;
+        height = size.ts_lines;
+      }
+  }
+#endif /* not SunOS-style */
+#endif /* not BSD-style */
+
+#ifdef TIOCSWINSZ
+  {
+    /* BSD-style.  */
+    struct winsize size;
+    size.ws_row = height;
+    size.ws_col = width;
+    
+    ioctl (master, TIOCSWINSZ, &size);
+  }
+#else
+#ifdef TIOCSSIZE
+  {
+    /* SunOS - style.  */
+    struct ttysize size;
+    size.ts_lines = height;
+    size.ts_cols = width;
+    
+    ioctl (master, TIOCGSIZE, &size);
+  }
+#endif /* not SunOS-style */
+#endif /* not BSD-style */
+}
+
+int in_conversation = 0;
+int quit_conversation = 0;
+
+SIGTYPE
+hang_up_signal (int signalnum)
+{
+  int old_errno = errno;
+  
+  if (! in_conversation)
+    return;
+
+  quit_conversation = 1;
+  
+  errno = old_errno;
+}
+
+SIGTYPE
+window_change_signal (int signalnum)
+{
+  int old_errno = errno;
+
+  if (! in_conversation)
+    goto end;
+
+  window_change();
+
+ end:
+  signal (SIGWINCH, window_change_signal);
+  errno = old_errno;
+}
+
+int
+init_signals ()
+{
+  /* Set up signal handlers. */
+  signal (SIGWINCH, window_change_signal);
+  signal (SIGHUP, hang_up_signal);
+
+  return 1;
+}
+
+
+
+/* Adapted from reset_sys_modes in sysdep.c. */
+int
+reset_tty ()
+{
+  fflush (stdout);
+#ifdef BSD_SYSTEM
+#ifndef BSD4_1
+  /* Avoid possible loss of output when changing terminal modes.  */
+  fsync (fileno (stdout));
+#endif
+#endif
+
+#ifdef F_SETFL
+#ifdef O_NDELAY
+  fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NDELAY);
+#endif
+#endif /* F_SETFL */
+
+  if (old_tty_valid)
+    while (ec_set_tty (0, &old_tty, 0) < 0 && errno == EINTR)
+      ;
+
+  return 1;
+}
+
+
+int
+init_pty ()
+{
+  master = getpt ();
+  if (master < 0)
+    return 0;
+
+  if (grantpt (master) < 0 || unlockpt (master) < 0)
+    goto close_master;
+  pty_name = strdup (ptsname (master));
+  if (! pty_name)
+    goto close_master;
+
+  /* Propagate window size. */
+  window_change ();
+  
+  return 1;
+  
+ close_master:
+  close (master);
+  return 0;
+}
+
+int
+copy_from_to (int in, int out)
+{
+  static char buf[BUFSIZ];
+  int nread = read (in, &buf, BUFSIZ);
+  if (nread == 0)
+    return 1;                   /* EOF */
+  else if (nread < 0 && errno != EAGAIN)
+    return 0;                   /* Error */
+  else if (nread > 0)
+    {
+      int r = 0;
+      int written = 0;
+
+      do {
+        r = write (out, &buf, nread);
+      } while ((r < 0 && errno == EAGAIN)
+               || (r > 0 && (written += r) && written != nread));
+      
+      if (r < 0)
+        return 0;               /* Error */
+    }
+  return 1;
+}
+
+int
+pty_conversation ()
+{
+  fd_set set;
+
+  in_conversation = 1;
+  
+  while (! quit_conversation) {
+    int res;
+    
+    FD_ZERO (&set);
+    FD_SET (master, &set);
+    FD_SET (1, &set);
+    res = select (FD_SETSIZE, &set, NULL, NULL, NULL);
+    if (res < 0)
+      {
+        if (errno != EINTR)
+          return 0;
+      }
+    else if (res > 0)
+      {
+        if (FD_ISSET (master, &set))
+          {
+            /* Copy Emacs output to stdout. */
+            if (! copy_from_to (master, 0))
+              return 1;
+          }
+        if (FD_ISSET (1, &set))
+          {
+            /* Forward user input to Emacs. */
+            if (! copy_from_to (1, master))
+              return 1;
+          }
+      }
+  }
+  return 1;
+}
+
+#endif /* HAVE_TERMIOS */
 
 
 #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
@@ -312,7 +824,7 @@
   /* Process options.  */
   decode_options (argc, argv);
 
-  if ((argc - optind < 1) && !eval)
+  if ((argc - optind < 1) && !eval && !here)
     {
       fprintf (stderr, "%s: file name or argument required\n", progname);
       fprintf (stderr, "Try `%s --help' for more information\n", progname);
@@ -484,6 +996,38 @@
       fprintf (out, " ");
     }
 
+  if (here)
+    {
+      if (! init_signals ())
+        {
+          fprintf (stderr, "%s: ", argv[0]);
+          perror ("fdopen");
+          fail (argc, argv);
+        }
+        
+      if (! init_tty ())
+        {
+          reset_tty ();
+          fprintf (stderr, "%s: ", argv[0]);
+          perror ("fdopen");
+          fail (argc, argv);
+        }
+      
+      if (! init_pty ())
+        {
+          reset_tty ();
+          fprintf (stderr, "%s: ", argv[0]);
+          perror ("fdopen");
+          fail (argc, argv);
+        }
+      
+      fprintf (out, "-pty ");
+      quote_file_name (pty_name, out);
+      fprintf (out, " ");
+      quote_file_name (getenv("TERM"), out);
+      fprintf (out, " ");
+    }
+  
   if ((argc - optind > 0))
     {
       for (i = optind; i < argc; i++)
@@ -512,11 +1056,14 @@
     }
   else
     {
-      while ((str = fgets (string, BUFSIZ, stdin)))
-	{
-	  quote_file_name (str, out);
-	}
-      fprintf (out, " ");
+      if (!here)
+        {
+          while ((str = fgets (string, BUFSIZ, stdin)))
+            {
+              quote_file_name (str, out);
+            }
+          fprintf (out, " ");
+        }
     }
   
   fprintf (out, "\n");
@@ -524,8 +1071,25 @@
 
   /* Maybe wait for an answer.   */
   if (nowait)
-    return 0;
+    {
+      reset_tty ();
+      return 0;
+    }
 
+  if (here)
+    {
+      if (! pty_conversation ())
+        {
+          reset_tty ();
+          fprintf (stderr, "%s: ", argv[0]);
+          perror ("fdopen");
+          fail (argc, argv);
+        }
+      close (master);
+      reset_tty ();
+      return 0;
+    }
+  
   if (!eval)
     {
       printf ("Waiting for Emacs...");
@@ -546,6 +1110,7 @@
     printf ("\n");
   fflush (stdout);
 
+  reset_tty ();
   return 0;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib-src/pty.c	Fri Dec 26 04:24:54 2003 +0000
@@ -0,0 +1,20 @@
+/* Terminal initialization for emacsclient.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib-src/pty.h	Fri Dec 26 04:24:54 2003 +0000
@@ -0,0 +1,224 @@
+/* Terminal initialization for emacsclient.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Adapted from systty.h */
+
+
+#ifdef HAVE_TERMIOS
+#define HAVE_TCATTR
+#endif
+
+
+/* Include the proper files.  */
+#ifdef HAVE_TERMIO
+#ifdef __DGUX
+#include <sys/ioctl.h>
+#endif
+#ifndef NO_TERMIO
+#include <termio.h>
+#endif /* not NO_TERMIO */
+#ifndef INCLUDED_FCNTL
+#define INCLUDED_FCNTL
+#include <fcntl.h>
+#endif
+#else /* not HAVE_TERMIO */
+#ifdef HAVE_TERMIOS
+#if defined(_AIX) && defined(_I386)
+#include <termios.h>		/* termios.h needs to be before termio.h */
+#include <termio.h>
+#else /* not (_AIX && _I386) */
+#ifndef NO_TERMIO
+#include <termio.h>
+#endif
+#include <termios.h>
+#endif /* not (_AIX && _I386) */
+#define INCLUDED_FCNTL
+#include <fcntl.h>
+#else /* neither HAVE_TERMIO nor HAVE_TERMIOS */
+#ifndef VMS
+#ifndef DOS_NT
+#include <sgtty.h>
+#endif /* not DOS_NT */
+#else /* VMS */
+#include <descrip.h>
+static struct iosb
+{
+  short status;
+  short offset;
+  short termlen;
+  short term;
+} input_iosb;
+
+extern int waiting_for_ast;
+extern int stop_input;
+extern int input_ef;
+extern int timer_ef;
+extern int process_ef;
+extern int input_eflist;
+extern int timer_eflist;
+
+static $DESCRIPTOR (input_dsc, "TT");
+static int terminator_mask[2] = { 0, 0 };
+
+static struct sensemode {
+  short status;
+  unsigned char xmit_baud;
+  unsigned char rcv_baud;
+  unsigned char crfill;
+  unsigned char lffill;
+  unsigned char parity;
+  unsigned char unused;
+  char class;
+  char type;
+  short scr_wid;
+  unsigned long tt_char : 24, scr_len : 8;
+  unsigned long tt2_char;
+} sensemode_iosb;
+#endif /* VMS */
+#endif /* not HAVE_TERMIOS */
+#endif /* not HAVE_TERMIO */
+
+#ifdef __GNU_LIBRARY__
+#include <sys/ioctl.h>
+#include <termios.h>
+#endif
+
+#ifdef AIXHFT
+/* Get files for keyboard remapping */
+#define HFNKEYS 2
+#include <sys/hft.h>
+#include <sys/devinfo.h>
+#endif
+
+/* Get rid of LLITOUT in 4.1, since it is said to stimulate kernel bugs.  */
+#ifdef BSD4_1
+#undef LLITOUT
+#define LLITOUT 0
+#endif /* 4.1 */
+
+#ifdef NEED_BSDTTY
+#include <sys/bsdtty.h>
+#endif
+
+#if defined (HPUX) && defined (HAVE_PTYS)
+#include <sys/ptyio.h>
+#endif
+
+#ifdef AIX
+#include <sys/pty.h>
+#endif /* AIX */
+
+#if (defined (POSIX) || defined (NEED_UNISTD_H)) && defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#ifdef SYSV_PTYS
+#include <sys/types.h>
+#include <sys/tty.h>
+#ifdef titan
+#include <sys/ttyhw.h>
+#include <sys/stream.h>
+#endif
+#ifndef NO_PTY_H
+#include <sys/pty.h>
+#endif
+#endif
+
+/* saka@pfu.fujitsu.co.JP writes:
+   FASYNC defined in this file. But, FASYNC don't working.
+   so no problem, because unrequest_sigio only need. */
+#if defined (pfa)
+#include <sys/file.h>
+#endif
+
+
+/* Special cases - inhibiting the use of certain features.  */
+
+#ifdef APOLLO
+#undef TIOCSTART
+#endif
+
+#ifdef XENIX
+#undef TIOCGETC  /* Avoid confusing some conditionals that test this.  */
+#endif
+
+#ifdef BROKEN_TIOCGETC
+#undef TIOCGETC  /* Avoid confusing some conditionals that test this.  */
+#endif
+
+/* UNIPLUS systems may have FIONREAD.  */
+#ifdef UNIPLUS
+#include <sys.ioctl.h>
+#endif
+
+/* Allow m- file to inhibit use of FIONREAD.  */
+#ifdef BROKEN_FIONREAD
+#undef FIONREAD
+#undef ASYNC
+#endif
+
+/* Interrupt input is not used if there is no FIONREAD.  */
+#ifndef FIONREAD
+#undef SIGIO
+#endif
+
+/* On TERMIOS systems, the tcmumbleattr calls take care of these
+   parameters, and it's a bad idea to use them (on AIX, it makes the
+   tty hang for a long time).  */
+#if defined (TIOCGLTC) && !defined (HAVE_TERMIOS)
+#define HAVE_LTCHARS
+#endif
+
+#if defined (TIOCGETC) && !defined (HAVE_TERMIOS)
+#define HAVE_TCHARS
+#endif
+
+
+/* Try to establish the correct character to disable terminal functions
+   in a system-independent manner.  Note that USG (at least) define
+   _POSIX_VDISABLE as 0!  */
+
+#ifdef _POSIX_VDISABLE
+#define CDISABLE _POSIX_VDISABLE
+#else /* not _POSIX_VDISABLE */
+#ifdef CDEL
+#undef CDISABLE
+#define CDISABLE CDEL
+#else /* not CDEL */
+#define CDISABLE 255
+#endif /* not CDEL */
+#endif /* not _POSIX_VDISABLE */
+
+/* Get the number of characters queued for output.  */
+
+/* EMACS_OUTQSIZE(FD, int *SIZE) stores the number of characters
+   queued for output to the terminal FD in *SIZE, if FD is a tty.
+   Returns -1 if there was an error (i.e. FD is not a tty), 0
+   otherwise.  */
+#ifdef TIOCOUTQ
+#define EMACS_OUTQSIZE(fd, size) (ioctl ((fd), TIOCOUTQ, (size)))
+#endif
+
+#ifdef HAVE_TERMIO
+#ifdef TCOUTQ
+#undef EMACS_OUTQSIZE
+#define EMACS_OUTQSIZE(fd, size) (ioctl ((fd), TCOUTQ, (size)))
+#endif
+#endif
--- a/lisp/server.el	Thu Dec 25 07:36:05 2003 +0000
+++ b/lisp/server.el	Fri Dec 26 04:24:54 2003 +0000
@@ -319,6 +319,15 @@
 		  (server-select-display display)
 		(error (process-send-string proc (nth 1 err))
 		       (setq request "")))))
+	   ;; Open a new tty at the client.
+	   ((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)))
+		(error (process-send-string proc (nth 1 err))
+		       (setq request "")))))
 	   ;; ARG is a line number option.
 	   ((string-match "\\`\\+[0-9]+\\'" arg)
 	    (setq lineno (string-to-int (substring arg 1))))
--- a/src/dispextern.h	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/dispextern.h	Fri Dec 26 04:24:54 2003 +0000
@@ -2555,7 +2555,7 @@
 
 /* Defined in sysdep.c */
 
-void get_frame_size P_ ((int *, int *));
+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));
--- a/src/dispnew.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/dispnew.c	Fri Dec 26 04:24:54 2003 +0000
@@ -3321,7 +3321,7 @@
   clear_frame ();
   clear_current_matrices (f);
   update_end (f);
-  fflush (stdout);
+  fflush (TTY_OUTPUT (FRAME_TTY (f)));
   windows_or_buffers_changed++;
   /* Mark all windows as inaccurate, so that every window will have
      its redisplay done.  */
@@ -3461,7 +3461,7 @@
 
   /* If we can't insert glyphs, we can use this method only
      at the end of a line.  */
-  if (!TTY_CHAR_INS_DEL_OK (CURTTY ()))
+  if (!TTY_CHAR_INS_DEL_OK (FRAME_TTY (f)))
     if (PT != ZV && FETCH_BYTE (PT_BYTE) != '\n')
       return 0;
 
@@ -3658,7 +3658,7 @@
     rif->update_window_end_hook (w, 1, 0);
   update_end (f);
   updated_row = NULL;
-  fflush (stdout);
+  fflush (TTY_OUTPUT (CURTTY ());
 
   TRACE ((stderr, "direct output for insert\n"));
   mark_window_display_accurate (it.window, 1);
@@ -3749,7 +3749,7 @@
       cursor_to (y, x);
     }
 
-  fflush (stdout);
+  fflush (TTY_OUTPUT (CURTTY ()));
   redisplay_performed_directly_p = 1;
   return 1;
 }
@@ -5102,18 +5102,18 @@
 		 Also flush out if likely to have more than 1k buffered
 		 otherwise.   I'm told that some telnet connections get
 		 really screwed by more than 1k output at once.  */
-	      int outq = PENDING_OUTPUT_COUNT (stdout);
+	      int outq = PENDING_OUTPUT_COUNT (TTY_OUTPUT (FRAME_TTY (f)));
 	      if (outq > 900
 		  || (outq > 20 && ((i - 1) % preempt_count == 0)))
 		{
-		  fflush (stdout);
+		  fflush (TTY_OUTPUT (FRAME_TTY (f)));
 		  if (preempt_count == 1)
 		    {
 #ifdef EMACS_OUTQSIZE
 		      if (EMACS_OUTQSIZE (0, &outq) < 0)
 			/* Probably not a tty.  Ignore the error and reset
 			   the outq count.  */
-			outq = PENDING_OUTPUT_COUNT (stdout);
+			outq = PENDING_OUTPUT_COUNT (TTY_OUTPUT (FRAME_TTY (f)));
 #endif
 		      outq *= 10;
 		      if (baud_rate <= outq && baud_rate > 0)
@@ -5893,28 +5893,34 @@
 #endif
   int old_errno = errno;
 
-  get_frame_size (&width, &height);
-
-  /* The frame size change obviously applies to a termcap-controlled
-     frame.  Find such a frame in the list, and assume it's the only
-     one (since the redisplay code always writes to stdout, not a
-     FILE * specified in the frame structure).  Record the new size,
-     but don't reallocate the data structures now.  Let that be done
-     later outside of the signal handler.  */
-
-  {
-    Lisp_Object tail, frame;
-
-    FOR_EACH_FRAME (tail, frame)
-      {
-	if (FRAME_TERMCAP_P (XFRAME (frame)))
-	  {
-	    change_frame_size (XFRAME (frame), height, width, 0, 1, 0);
-	    break;
-	  }
-      }
+  struct tty_output *tty;
+  
+  /* The frame size change obviously applies to a single
+     termcap-controlled terminal, but we can't decide which.
+     Therefore, we resize the frames corresponding to each tty.
+     
+     XXX In fact we only get the signal for the initial terminal.
+  */
+  for (tty = tty_list; tty; tty = tty->next) {
+
+    get_tty_size (tty, &width, &height);
+    
+    {
+      Lisp_Object tail, frame;
+      
+      FOR_EACH_FRAME (tail, frame)
+        {
+          if (FRAME_TERMCAP_P (XFRAME (frame)) && FRAME_TTY (XFRAME (frame)) == tty)
+            {
+              /* Record the new sizes, but don't reallocate the data structures
+                 now.  Let that be done later outside of the signal handler.  */
+              change_frame_size (XFRAME (frame), height, width, 0, 1, 0);
+              break;
+            }
+        }
+    }
   }
-
+  
   signal (SIGWINCH, window_change_signal);
   errno = old_errno;
 }
@@ -5969,10 +5975,11 @@
 {
   Lisp_Object tail, frame;
 
-  if (! FRAME_WINDOW_P (f))
+  if (FRAME_MSDOS_P (f))
     {
-      /* When using termcap, or on MS-DOS, all frames use
-	 the same screen, so a change in size affects all frames.  */
+      /* On MS-DOS, all frames use the same screen, so a change in
+         size affects all frames.  Termcap now supports multiple
+         ttys. */
       FOR_EACH_FRAME (tail, frame)
 	if (! FRAME_WINDOW_P (XFRAME (frame)))
 	  change_frame_size_1 (XFRAME (frame), newheight, newwidth,
@@ -6162,7 +6169,7 @@
 	putchar (07);
       else
 	ring_bell ();
-      fflush (stdout);
+      fflush (TTY_OUTPUT (CURTTY ()));
     }
   else
     bitch_at_user ();
@@ -6179,7 +6186,7 @@
     error ("Keyboard macro terminated by a command ringing the bell");
   else
     ring_bell ();
-  fflush (stdout);
+  fflush (TTY_OUTPUT (CURTTY ()));
 }
 
 
--- a/src/emacs.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/emacs.c	Fri Dec 26 04:24:54 2003 +0000
@@ -1564,7 +1564,7 @@
   if (!noninteractive)
     {
 #ifdef VMS
-      init_vms_input ();/* init_display calls get_frame_size, that needs this.  */
+      init_vms_input ();/* init_display calls get_tty_size, that needs this.  */
 #endif /* VMS */
       init_display ();	/* Determine terminal type.  Calls init_sys_modes.  */
     }
--- a/src/frame.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/frame.c	Fri Dec 26 04:24:54 2003 +0000
@@ -114,8 +114,6 @@
 
 Lisp_Object Qface_set_after_frame_default;
 
-
-Lisp_Object Vterminal_frame;
 Lisp_Object Vdefault_frame_alist;
 Lisp_Object Vdefault_frame_scroll_bars;
 Lisp_Object Vmouse_position_function;
@@ -550,6 +548,7 @@
     f->output_data.tty = term_init (tty, tty_type);
   else
     f->output_data.tty = term_dummy_init ();
+  f->output_data.tty->top_frame = frame;
 #ifdef CANNOT_DUMP
   FRAME_FOREGROUND_PIXEL(f) = FACE_TTY_DEFAULT_FG_COLOR;
   FRAME_BACKGROUND_PIXEL(f) = FACE_TTY_DEFAULT_BG_COLOR;
@@ -637,12 +636,15 @@
         type[SBYTES (tty_type)] = 0;
       }
 
-    
     f = make_terminal_frame (name, type);
   }
 
-  change_frame_size (f, FRAME_LINES (sf),
-		     FRAME_COLS (sf), 0, 0, 0);
+  {
+    int width, height;
+    get_tty_size (FRAME_TTY (f), &width, &height);
+    change_frame_size (f, height, width, 0, 0, 0);
+  }
+  
   adjust_glyphs (f);
   calculate_costs (f);
   XSETFRAME (frame, f);
@@ -746,6 +748,15 @@
   if (!for_deletion && FRAME_HAS_MINIBUF_P (sf))
     resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1);
 
+  if (FRAME_TERMCAP_P (XFRAME (selected_frame))
+      && FRAME_TERMCAP_P (XFRAME (frame))
+      && FRAME_TTY (XFRAME (selected_frame)) == FRAME_TTY (XFRAME (frame)))
+    {
+      XFRAME (selected_frame)->async_visible = 0;
+      XFRAME (frame)->async_visible = 1;
+      FRAME_TTY (XFRAME (frame))->top_frame = frame;
+    }
+
   selected_frame = frame;
   if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame)))
     last_nonminibuf_frame = XFRAME (selected_frame);
@@ -979,7 +990,10 @@
 	f = XCAR (tail);
 
 	if (passed
-	    && FRAME_KBOARD (XFRAME (f)) == FRAME_KBOARD (XFRAME (frame)))
+	    && ((!FRAME_TERMCAP_P (XFRAME (f)) && !FRAME_TERMCAP_P (XFRAME (frame))
+                 && FRAME_KBOARD (XFRAME (f)) == FRAME_KBOARD (XFRAME (frame)))
+                || (FRAME_TERMCAP_P (XFRAME (f)) && FRAME_TERMCAP_P (XFRAME (frame))
+                    && FRAME_TTY (XFRAME (f)) == FRAME_TTY (XFRAME (frame)))))
 	  {
 	    /* Decide whether this frame is eligible to be returned.  */
 
@@ -1056,7 +1070,10 @@
       if (EQ (frame, f) && !NILP (prev))
 	return prev;
 
-      if (FRAME_KBOARD (XFRAME (f)) == FRAME_KBOARD (XFRAME (frame)))
+      if ((!FRAME_TERMCAP_P (XFRAME (f)) && !FRAME_TERMCAP_P (XFRAME (frame))
+           && FRAME_KBOARD (XFRAME (f)) == FRAME_KBOARD (XFRAME (frame)))
+          || (FRAME_TERMCAP_P (XFRAME (f)) && FRAME_TERMCAP_P (XFRAME (frame))
+              && FRAME_TTY (XFRAME (f)) == FRAME_TTY (XFRAME (frame))))
 	{
 	  /* Decide whether this frame is eligible to be returned,
 	     according to minibuf.  */
@@ -4081,9 +4098,6 @@
     = intern ("inhibit-default-face-x-resources");
   staticpro (&Qinhibit_default_face_x_resources);
 
-  DEFVAR_LISP ("terminal-frame", &Vterminal_frame,
-	       doc: /* The initial frame-object, which represents Emacs's stdout.  */);
-
   DEFVAR_LISP ("emacs-iconified", &Vemacs_iconified,
 	       doc: /* Non-nil if all of emacs is iconified and frame updates are not needed.  */);
   Vemacs_iconified = Qnil;
--- a/src/frame.h	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/frame.h	Fri Dec 26 04:24:54 2003 +0000
@@ -28,9 +28,7 @@
 
 /* Miscellanea.  */
 
-/* Nonzero means don't assume anything about current contents of
-   actual terminal frame */
-
+/* Nonzero means there is at least one garbaged frame. */
 extern int frame_garbaged;
 
 /* Nonzero means FRAME_MESSAGE_BUF (selected_frame) is being used by
@@ -71,7 +69,7 @@
 
 #if !defined(HAVE_X_WINDOWS)
 
-#define PIX_TYPE int
+#define PIX_TYPE unsigned long
 
 /* A (mostly empty) x_output structure definition for building Emacs
    on Unix and GNU/Linux without X support.  */
@@ -743,7 +741,10 @@
 
    Also, if a frame used to be invisible, but has just become visible,
    it must be marked as garbaged, since redisplay hasn't been keeping
-   up its contents.  */
+   up its contents.
+
+   Note that a tty frame is visible if and only if it is the topmost
+   frame. */
 
 #define FRAME_SAMPLE_VISIBILITY(f) \
   (((f)->async_visible && (f)->visible != (f)->async_visible) ? \
@@ -799,8 +800,6 @@
 extern Lisp_Object Vframe_list;
 extern Lisp_Object Vdefault_frame_alist;
 
-extern Lisp_Object Vterminal_frame;
-
 extern Lisp_Object Vmouse_highlight;
 
 /* The currently selected frame.  */
--- a/src/keyboard.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/keyboard.c	Fri Dec 26 04:24:54 2003 +0000
@@ -22,10 +22,10 @@
 #include <config.h>
 #include <signal.h>
 #include <stdio.h>
+#include "lisp.h"
 #include "systty.h" /* This must be included befor termchar.h. */
 #include "termchar.h"
 #include "termopts.h"
-#include "lisp.h"
 #include "termhooks.h"
 #include "macros.h"
 #include "keyboard.h"
@@ -89,9 +89,6 @@
 int interrupt_input_pending;
 
 
-/* File descriptor to use for input.  */
-extern int input_fd;
-
 #ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
 #ifdef MAC_OS8
@@ -6588,7 +6585,7 @@
 
   if (read_socket_hook)
     /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
+    nread = (*read_socket_hook) (buf, KBD_BUFFER_SIZE, expected);
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -6597,7 +6594,6 @@
       unsigned char cbuf[KBD_BUFFER_SIZE - 1];
       int n_to_read;
 
-      /* Determine how many characters we should *try* to read.  */
 #ifdef WINDOWSNT
       return 0;
 #else /* not WINDOWSNT */
@@ -6605,88 +6601,121 @@
       n_to_read = dos_keysns ();
       if (n_to_read == 0)
 	return 0;
+
+      cbuf[0] = dos_keyread ();
+      nread = 1;
+
 #else /* not MSDOS */
+
+      struct tty_output *tty;
+      nread = 0;
+
+      /* Try to read from each available tty, until one succeeds. */
+      for (tty = tty_list; tty && !nread; tty = tty->next) {
+        
+        /* Determine how many characters we should *try* to read.  */
 #ifdef FIONREAD
-      /* Find out how much input is available.  */
-      if (ioctl (input_fd, FIONREAD, &n_to_read) < 0)
-	/* Formerly simply reported no input, but that sometimes led to
-	   a failure of Emacs to terminate.
-	   SIGHUP seems appropriate if we can't reach the terminal.  */
-	/* ??? 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.  */
-	{
-	  if (! noninteractive)
-	    kill (getpid (), SIGHUP);
-	  else
-	    n_to_read = 0;
-	}
-      if (n_to_read == 0)
-	return 0;
-      if (n_to_read > sizeof cbuf)
-	n_to_read = sizeof cbuf;
+        /* Find out how much input is available.  */
+        if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0)
+          {
+            /* Formerly simply reported no input, but that sometimes led to
+               a failure of Emacs to terminate.
+               SIGHUP seems appropriate if we can't reach the terminal.  */
+            /* ??? 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.  */
+            if (! noninteractive)
+              {
+                if (! tty_list->next)
+                  kill (getpid (), SIGHUP); /* This was the last terminal. */
+                else
+                  n_to_read = 0; /* XXX tty should be closed here. */
+              }
+            else
+              {
+                n_to_read = 0;
+              }
+          }
+        if (n_to_read == 0)
+          continue;
+        if (n_to_read > sizeof cbuf)
+          n_to_read = sizeof cbuf;
 #else /* no FIONREAD */
 #if defined (USG) || defined (DGUX) || defined(CYGWIN)
-      /* Read some input if available, but don't wait.  */
-      n_to_read = sizeof cbuf;
-      fcntl (input_fd, F_SETFL, O_NDELAY);
+        /* Read some input if available, but don't wait.  */
+        n_to_read = sizeof cbuf;
+        fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY);
 #else
-      you lose;
-#endif
-#endif
+        you lose;
+#endif
+#endif
+
+        /* Now read; for one reason or another, this will not block.
+           NREAD is set to the number of chars read.  */
+        do
+          {
+            nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read);
+            /* POSIX infers that processes which are not in the session leader's
+               process group won't get SIGHUP's at logout time.  BSDI adheres to
+               this part standard and returns -1 from read (0) with errno==EIO
+               when the control tty is taken away.
+               Jeffrey Honig <jch@bsdi.com> says this is generally safe.  */
+            if (nread == -1 && errno == EIO)
+              {
+                if (! tty_list->next)
+                  kill (0, SIGHUP); /* This was the last terminal. */
+                else
+                  ;             /* XXX tty should be closed here. */
+              }
+#if defined (AIX) && (! defined (aix386) && defined (_BSD))
+            /* The kernel sometimes fails to deliver SIGHUP for ptys.
+               This looks incorrect, but it isn't, because _BSD causes
+               O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
+               and that causes a value other than 0 when there is no input.  */
+            if (nread == 0)
+              {
+                if (! tty_list->next)
+                  kill (0, SIGHUP); /* This was the last terminal. */
+                else
+                  ;             /* XXX tty should be closed here. */
+              }
+#endif
+          }
+        while (
+               /* We used to retry the read if it was interrupted.
+                  But this does the wrong thing when O_NDELAY causes
+                  an EAGAIN error.  Does anybody know of a situation
+                  where a retry is actually needed?  */
+#if 0
+               nread < 0 && (errno == EAGAIN
+#ifdef EFAULT
+                             || errno == EFAULT
+#endif
+#ifdef EBADSLT
+                             || errno == EBADSLT
+#endif
+                             )
+#else
+               0
+#endif
+               );
+        
+#ifndef FIONREAD
+#if defined (USG) || defined (DGUX) || defined (CYGWIN)
+        fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0);
+#endif /* USG or DGUX or CYGWIN */
+#endif /* no FIONREAD */
+
+      } /* for each tty */
+      
+      if (! nread)
+        return 0;
+      
 #endif /* not MSDOS */
 #endif /* not WINDOWSNT */
 
-      /* Now read; for one reason or another, this will not block.
-	 NREAD is set to the number of chars read.  */
-      do
-	{
-#ifdef MSDOS
-	  cbuf[0] = dos_keyread ();
-	  nread = 1;
-#else
-	  nread = emacs_read (input_fd, cbuf, n_to_read);
-#endif
-	  /* POSIX infers that processes which are not in the session leader's
-	     process group won't get SIGHUP's at logout time.  BSDI adheres to
-	     this part standard and returns -1 from read (0) with errno==EIO
-	     when the control tty is taken away.
-	     Jeffrey Honig <jch@bsdi.com> says this is generally safe.  */
-	  if (nread == -1 && errno == EIO)
-	    kill (0, SIGHUP);
-#if defined (AIX) && (! defined (aix386) && defined (_BSD))
-	  /* The kernel sometimes fails to deliver SIGHUP for ptys.
-	     This looks incorrect, but it isn't, because _BSD causes
-	     O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
-	     and that causes a value other than 0 when there is no input.  */
-	  if (nread == 0)
-	    kill (0, SIGHUP);
-#endif
-	}
-      while (
-	     /* We used to retry the read if it was interrupted.
-		But this does the wrong thing when O_NDELAY causes
-		an EAGAIN error.  Does anybody know of a situation
-		where a retry is actually needed?  */
-#if 0
-	     nread < 0 && (errno == EAGAIN
-#ifdef EFAULT
-			   || errno == EFAULT
-#endif
-#ifdef EBADSLT
-			   || errno == EBADSLT
-#endif
-			   )
-#else
-	     0
-#endif
-	     );
-
-#ifndef FIONREAD
-#if defined (USG) || defined (DGUX) || defined (CYGWIN)
-      fcntl (input_fd, F_SETFL, 0);
-#endif /* USG or DGUX or CYGWIN */
-#endif /* no FIONREAD */
+      /* XXX Select frame corresponding to the tty. */
+      
       for (i = 0; i < nread; i++)
 	{
 	  buf[i].kind = ASCII_KEYSTROKE_EVENT;
@@ -10058,6 +10087,9 @@
   int width, height;
   struct gcpro gcpro1;
 
+  if (tty_list && tty_list->next)
+    error ("Suspend is not supported with multiple ttys");
+  
   if (!NILP (stuffstring))
     CHECK_STRING (stuffstring);
 
@@ -10066,7 +10098,7 @@
     call1 (Vrun_hooks, intern ("suspend-hook"));
 
   GCPRO1 (stuffstring);
-  get_frame_size (&old_width, &old_height);
+  get_tty_size (CURTTY (), &old_width, &old_height);
   reset_all_sys_modes ();
   /* sys_suspend can get an error if it tries to fork a subshell
      and the system resources aren't available for that.  */
@@ -10082,7 +10114,7 @@
   /* Check if terminal/window size has changed.
      Note that this is not useful when we are running directly
      with a window system; but suspend should be disabled in that case.  */
-  get_frame_size (&width, &height);
+  get_tty_size (CURTTY (), &width, &height);
   if (width != old_width || height != old_height)
     change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0);
 
--- a/src/lisp.h	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/lisp.h	Fri Dec 26 04:24:54 2003 +0000
@@ -2946,7 +2946,6 @@
 extern void reset_sys_modes P_ ((struct tty_output *));
 extern void init_all_sys_modes P_ ((void));
 extern void reset_all_sys_modes P_ ((void));
-extern void get_frame_size P_ ((int *, int *));
 extern void wait_for_termination P_ ((int));
 extern void flush_pending_output P_ ((int));
 extern void child_setup_tty P_ ((int));
--- a/src/macterm.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/macterm.c	Fri Dec 26 04:24:54 2003 +0000
@@ -7598,7 +7598,7 @@
 /* Emacs calls this whenever it wants to read an input event from the
    user. */
 int
-XTread_socket (int sd, struct input_event *bufp, int numchars, int expected)
+XTread_socket (struct input_event *bufp, int numchars, int expected)
 {
   int count = 0;
 #if USE_CARBON_EVENTS
--- a/src/scroll.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/scroll.c	Fri Dec 26 04:24:54 2003 +0000
@@ -22,9 +22,9 @@
 #include <config.h>
 #include <stdio.h>
 #include <string.h>
+#include "lisp.h"
 #include "systty.h" /* For emacs_tty in termchar.h */
 #include "termchar.h"
-#include "lisp.h"
 #include "dispextern.h"
 #include "keyboard.h"
 #include "frame.h"
--- a/src/sysdep.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/sysdep.c	Fri Dec 26 04:24:54 2003 +0000
@@ -246,11 +246,6 @@
 
 int emacs_ospeed;
 
-/* The file descriptor for Emacs's input terminal.
-   Under Unix, this is normally zero except when using X;
-   under VMS, we place the input channel number here.  */
-int input_fd;
-
 void croak P_ ((char *));
 
 #ifdef AIXHFT
@@ -263,16 +258,7 @@
 SIGMASKTYPE sigprocmask_set;
 
 
-/* Specify a different file descriptor for further input operations.  */
-
-void
-change_input_fd (fd)
-     int fd;
-{
-  input_fd = fd;
-}
-
-/* Discard pending input on descriptor input_fd.  */
+/* Discard pending input on all input descriptors.  */
 
 void
 discard_tty_input ()
@@ -290,22 +276,28 @@
 
 #ifdef VMS
   end_kbd_input ();
-  SYS$QIOW (0, input_fd, IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
+  SYS$QIOW (0, fileno (TTY_INPUT (CURTTY())), IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
 	    &buf.main, 0, 0, terminator_mask, 0, 0);
   queue_kbd_input ();
 #else /* not VMS */
 #ifdef APOLLO
   {
     int zero = 0;
-    ioctl (input_fd, TIOCFLUSH, &zero);
+    ioctl (fileno (TTY_INPUT (CURTTY())), TIOCFLUSH, &zero);
   }
 #else /* not Apollo */
 #ifdef MSDOS    /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
   while (dos_keyread () != -1)
     ;
 #else /* not MSDOS */
-  EMACS_GET_TTY (input_fd, &buf);
-  EMACS_SET_TTY (input_fd, &buf, 0);
+  {
+    struct tty_output tty;
+    for (tty = tty_list; tty; tty = tty->next)
+      {
+        EMACS_GET_TTY (fileno (TTY_INPUT (tty)), &buf);
+        EMACS_SET_TTY (fileno (TTY_INPUT (tty)), &buf, 0);
+      }
+  }
 #endif /* not MSDOS */
 #endif /* not Apollo */
 #endif /* not VMS */
@@ -330,7 +322,7 @@
 
 /* Should perhaps error if in batch mode */
 #ifdef TIOCSTI
-  ioctl (input_fd, TIOCSTI, &c);
+  ioctl (fileno (TTY_INPUT (CURTTY())), TIOCSTI, &c);
 #else /* no TIOCSTI */
   error ("Cannot stuff terminal input characters in this version of Unix");
 #endif /* no TIOCSTI */
@@ -354,7 +346,7 @@
 #ifdef VMS
       struct sensemode sg;
 
-      SYS$QIOW (0, input_fd, IO$_SENSEMODE, &sg, 0, 0,
+      SYS$QIOW (0, fileno (TTY_INPUT (CURTTY())), IO$_SENSEMODE, &sg, 0, 0,
 		&sg.class, 12, 0, 0, 0, 0 );
       emacs_ospeed = sg.xmit_baud;
 #else /* not VMS */
@@ -362,7 +354,7 @@
       struct termios sg;
 
       sg.c_cflag = B9600;
-      tcgetattr (input_fd, &sg);
+      tcgetattr (fileno (TTY_INPUT (CURTTY())), &sg);
       emacs_ospeed = cfgetospeed (&sg);
 #if defined (USE_GETOBAUD) && defined (getobaud)
       /* m88k-motorola-sysv3 needs this (ghazi@noc.rutgers.edu) 9/1/94. */
@@ -375,16 +367,16 @@
 
       sg.c_cflag = B9600;
 #ifdef HAVE_TCATTR
-      tcgetattr (input_fd, &sg);
+      tcgetattr (fileno (TTY_INPUT (CURTTY())), &sg);
 #else
-      ioctl (input_fd, TCGETA, &sg);
+      ioctl (fileno (TTY_INPUT (CURTTY())), TCGETA, &sg);
 #endif
       emacs_ospeed = sg.c_cflag & CBAUD;
 #else /* neither VMS nor TERMIOS nor TERMIO */
       struct sgttyb sg;
 
       sg.sg_ospeed = B9600;
-      if (ioctl (input_fd, TIOCGETP, &sg) < 0)
+      if (ioctl (fileno (TTY_INPUT (CURTTY())), TIOCGETP, &sg) < 0)
 	abort ();
       emacs_ospeed = sg.sg_ospeed;
 #endif /* not HAVE_TERMIO */
@@ -947,7 +939,7 @@
 #ifdef SIGWINCH
   sigunblock (sigmask (SIGWINCH));
 #endif
-  fcntl (input_fd, F_SETFL, old_fcntl_flags | FASYNC);
+  fcntl (fileno (TTY_INPUT (CURTTY())), F_SETFL, old_fcntl_flags | FASYNC);
 
   interrupts_deferred = 0;
 }
@@ -961,7 +953,7 @@
 #ifdef SIGWINCH
   sigblock (sigmask (SIGWINCH));
 #endif
-  fcntl (input_fd, F_SETFL, old_fcntl_flags);
+  fcntl (fileno (TTY_INPUT (CURTTY())), F_SETFL, old_fcntl_flags);
   interrupts_deferred = 1;
 }
 
@@ -976,7 +968,7 @@
   if (read_socket_hook)
     return;
 
-  ioctl (input_fd, FIOASYNC, &on);
+  ioctl (fileno (TTY_INPUT (CURTTY())), FIOASYNC, &on);
   interrupts_deferred = 0;
 }
 
@@ -988,7 +980,7 @@
   if (read_socket_hook)
     return;
 
-  ioctl (input_fd, FIOASYNC, &off);
+  ioctl (fileno (TTY_INPUT (CURTTY())), FIOASYNC, &off);
   interrupts_deferred = 1;
 }
 
@@ -1009,7 +1001,7 @@
 
   sigemptyset (&st);
   sigaddset (&st, SIGIO);
-  ioctl (input_fd, FIOASYNC, &on);
+  ioctl (fileno (TTY_INPUT (CURTTY())), FIOASYNC, &on);
   interrupts_deferred = 0;
   sigprocmask (SIG_UNBLOCK, &st, (sigset_t *)0);
 }
@@ -1022,7 +1014,7 @@
   if (read_socket_hook)
     return;
 
-  ioctl (input_fd, FIOASYNC, &off);
+  ioctl (fileno (TTY_INPUT (CURTTY())), FIOASYNC, &off);
   interrupts_deferred = 1;
 }
 
@@ -1088,7 +1080,7 @@
 
   setpgrp (0, inherited_pgroup);
   if (inherited_pgroup != me)
-    EMACS_SET_TTY_PGRP (input_fd, &me);
+    EMACS_SET_TTY_PGRP (fileno (stdin), &me); /* stdin is intentional here */
   setpgrp (0, me);
 }
 
@@ -1097,7 +1089,7 @@
 widen_foreground_group ()
 {
   if (inherited_pgroup != getpid ())
-    EMACS_SET_TTY_PGRP (input_fd, &inherited_pgroup);
+    EMACS_SET_TTY_PGRP (fileno (stdin), &inherited_pgroup); /* stdin is intentional here */
   setpgrp (0, inherited_pgroup);
 }
 
@@ -1300,8 +1292,8 @@
 }
 
 void
-init_sys_modes (otty)
-     struct tty_output *otty;
+init_sys_modes (tty_out)
+     struct tty_output *tty_out;
 {
   struct emacs_tty tty;
 
@@ -1357,7 +1349,7 @@
 #ifndef VMS4_4
   sys_access_reinit ();
 #endif
-#endif /* not VMS */
+#endif /* VMS */
 
 #ifdef BSD_PGRPS
   if (! read_socket_hook && EQ (Vwindow_system, Qnil))
@@ -1370,14 +1362,14 @@
   if (!read_socket_hook && EQ (Vwindow_system, Qnil))
 #endif
     {
-      EMACS_GET_TTY (input_fd, &otty->old_tty);
-
-      otty->old_tty_valid = 1;
-
-      tty = otty->old_tty;
+      EMACS_GET_TTY (fileno (TTY_INPUT (tty_out)), &tty_out->old_tty);
+
+      tty_out->old_tty_valid = 1;
+
+      tty = tty_out->old_tty;
 
 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
-      XSETINT (Vtty_erase_char, otty->old_tty.main.c_cc[VERASE]);
+      XSETINT (Vtty_erase_char, tty_out->old_tty.main.c_cc[VERASE]);
 
 #ifdef DGUX
       /* This allows meta to be sent on 8th bit.  */
@@ -1542,7 +1534,7 @@
 	  tty.tchars.t_stopc = '\023';
 	}
 
-      tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | otty->old_tty.lmode;
+      tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | tty_out->old_tty.lmode;
 #ifdef ultrix
       /* Under Ultrix 4.2a, leaving this out doesn't seem to hurt
 	 anything, and leaving it in breaks the meta key.  Go figure.  */
@@ -1560,28 +1552,28 @@
       tty.ltchars = new_ltchars;
 #endif /* HAVE_LTCHARS */
 #ifdef MSDOS	/* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
-      if (!otty->term_initted)
+      if (!tty_out->term_initted)
 	internal_terminal_init ();
       dos_ttraw ();
 #endif
 
-      EMACS_SET_TTY (input_fd, &tty, 0);
+      EMACS_SET_TTY (fileno (TTY_INPUT (tty_out)), &tty, 0);
 
       /* This code added to insure that, if flow-control is not to be used,
 	 we have an unlocked terminal at the start. */
 
 #ifdef TCXONC
-      if (!flow_control) ioctl (input_fd, TCXONC, 1);
+      if (!flow_control) ioctl (fileno (TTY_INPUT (tty_out)), TCXONC, 1);
 #endif
 #ifndef APOLLO
 #ifdef TIOCSTART
-      if (!flow_control) ioctl (input_fd, TIOCSTART, 0);
+      if (!flow_control) ioctl (fileno (TTY_INPUT (tty_out)), TIOCSTART, 0);
 #endif
 #endif
 
 #if defined (HAVE_TERMIOS) || defined (HPUX9)
 #ifdef TCOON
-      if (!flow_control) tcflow (input_fd, TCOON);
+      if (!flow_control) tcflow (fileno (TTY_INPUT (tty_out)), TCOON);
 #endif
 #endif
 
@@ -1601,7 +1593,7 @@
 
 #ifdef VMS
 /*  Appears to do nothing when in PASTHRU mode.
-      SYS$QIOW (0, input_fd, IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
+      SYS$QIOW (0, fileno (TTY_INPUT (tty_out)), IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
 		interrupt_signal, oob_chars, 0, 0, 0, 0);
 */
       queue_kbd_input (0);
@@ -1614,9 +1606,9 @@
   if (interrupt_input
       && ! read_socket_hook && EQ (Vwindow_system, Qnil))
     {
-      old_fcntl_owner = fcntl (input_fd, F_GETOWN, 0);
-      fcntl (input_fd, F_SETOWN, getpid ());
-      init_sigio (input_fd);
+      old_fcntl_owner = fcntl (fileno (TTY_INPUT (tty_out)), F_GETOWN, 0);
+      fcntl (fileno (TTY_INPUT (tty_out)), F_SETOWN, getpid ());
+      init_sigio (fileno (TTY_INPUT (tty_out)));
     }
 #endif /* F_GETOWN */
 #endif /* F_SETOWN_BUG */
@@ -1624,7 +1616,7 @@
 
 #ifdef BSD4_1
   if (interrupt_input)
-    init_sigio (input_fd);
+    init_sigio (fileno (TTY_INPUT (tty_out)));
 #endif
 
 #ifdef VMS  /* VMS sometimes has this symbol but lacks setvbuf.  */
@@ -1634,9 +1626,9 @@
   /* This symbol is defined on recent USG systems.
      Someone says without this call USG won't really buffer the file
      even with a call to setbuf. */
-  setvbuf (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf);
+  setvbuf (TTY_OUTPUT (tty_out), (char *) _sobuf, _IOFBF, sizeof _sobuf);
 #else
-  setbuf (stdout, (char *) _sobuf);
+  setbuf (TTY_OUTPUT (tty_out), (char *) _sobuf);
 #endif
 #ifdef HAVE_WINDOW_SYSTEM
   /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
@@ -1649,26 +1641,37 @@
 #endif
       )
 #endif
-    set_terminal_modes (otty);
-
-  if (!otty->term_initted
-      && FRAMEP (Vterminal_frame)
-      && FRAME_TERMCAP_P (XFRAME (Vterminal_frame)))
-    init_frame_faces (XFRAME (Vterminal_frame));
-
-  if (otty->term_initted && no_redraw_on_reenter)
+    set_terminal_modes (tty_out);
+
+  if (!tty_out->term_initted)
+    {
+      Lisp_Object tail, frame;
+      FOR_EACH_FRAME (tail, frame)
+        {
+          if (FRAME_TERMCAP_P (XFRAME (frame))
+              && FRAME_TTY (XFRAME (frame)) == tty_out)
+            init_frame_faces (XFRAME (frame));
+        }
+    }
+
+  if (tty_out->term_initted && no_redraw_on_reenter)
     {
       if (display_completed)
 	direct_output_forward_char (0);
     }
   else
     {
+      Lisp_Object tail, frame;
       frame_garbaged = 1;
-      if (FRAMEP (Vterminal_frame))
-	FRAME_GARBAGED_P (XFRAME (Vterminal_frame)) = 1;
+      FOR_EACH_FRAME (tail, frame)
+        {
+          if (FRAME_TERMCAP_P (XFRAME (frame))
+              && FRAME_TTY (XFRAME (frame)) == tty_out)
+            FRAME_GARBAGED_P (XFRAME (frame)) = 1;
+        }
     }
 
-  otty->term_initted = 1;
+  tty_out->term_initted = 1;
 }
 
 /* Return nonzero if safe to use tabs in output.
@@ -1679,7 +1682,7 @@
 {
   struct emacs_tty tty;
 
-  EMACS_GET_TTY (input_fd, &tty);
+  EMACS_GET_TTY (fileno (TTY_INPUT (CURTTY())), &tty);
   return EMACS_TTY_TABS_OK (&tty);
 }
 
@@ -1688,7 +1691,8 @@
    We store 0 if there's no valid information.  */
 
 void
-get_frame_size (widthp, heightp)
+get_tty_size (tty_out, widthp, heightp)
+     struct tty_output *tty_out;
      int *widthp, *heightp;
 {
 
@@ -1697,7 +1701,7 @@
   /* BSD-style.  */
   struct winsize size;
 
-  if (ioctl (input_fd, TIOCGWINSZ, &size) == -1)
+  if (ioctl (fileno (TTY_INPUT (tty_out)), TIOCGWINSZ, &size) == -1)
     *widthp = *heightp = 0;
   else
     {
@@ -1711,7 +1715,7 @@
   /* SunOS - style.  */
   struct ttysize size;
 
-  if (ioctl (input_fd, TIOCGSIZE, &size) == -1)
+  if (ioctl (fileno (TTY_INPUT (tty_out)), TIOCGSIZE, &size) == -1)
     *widthp = *heightp = 0;
   else
     {
@@ -1724,7 +1728,7 @@
 
   struct sensemode tty;
 
-  SYS$QIOW (0, input_fd, IO$_SENSEMODE, &tty, 0, 0,
+  SYS$QIOW (0, fileno (TTY_INPUT (CURTTY())), IO$_SENSEMODE, &tty, 0, 0,
 	    &tty.class, 12, 0, 0, 0, 0);
   *widthp = tty.scr_wid;
   *heightp = tty.scr_len;
@@ -1794,8 +1798,8 @@
 /* Prepare the terminal for exiting Emacs; move the cursor to the
    bottom of the frame, turn off interrupt-driven I/O, etc.  */
 void
-reset_sys_modes (otty)
-     struct tty_output *otty;
+reset_sys_modes (tty_out)
+     struct tty_output *tty_out;
 {
   struct frame *sf;
 
@@ -1804,7 +1808,7 @@
       fflush (stdout);
       return;
     }
-  if (!otty->term_initted)
+  if (!tty_out->term_initted)
     return;
 #ifdef HAVE_WINDOW_SYSTEM
   /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
@@ -1834,12 +1838,12 @@
   }
 #endif
 
-  reset_terminal_modes (otty);
-  fflush (stdout);
+  reset_terminal_modes (tty_out);
+  fflush (TTY_OUTPUT (tty_out));
 #ifdef BSD_SYSTEM
 #ifndef BSD4_1
   /* Avoid possible loss of output when changing terminal modes.  */
-  fsync (fileno (stdout));
+  fsync (TTY_OUTPUT (tty_out));
 #endif
 #endif
 
@@ -1849,12 +1853,13 @@
   if (interrupt_input)
     {
       reset_sigio ();
-      fcntl (input_fd, F_SETOWN, old_fcntl_owner);
+      fcntl (fileno (TTY_INPUT (tty_out)), F_SETOWN, old_fcntl_owner);
     }
 #endif /* F_SETOWN */
 #endif /* F_SETOWN_BUG */
 #ifdef O_NDELAY
-  fcntl (input_fd, F_SETFL, fcntl (input_fd, F_GETFL, 0) & ~O_NDELAY);
+  fcntl (fileno (TTY_INPUT (tty_out)), F_SETFL,
+         fcntl (fileno (TTY_INPUT (tty_out)), F_GETFL, 0) & ~O_NDELAY);
 #endif
 #endif /* F_SETFL */
 #ifdef BSD4_1
@@ -1862,8 +1867,9 @@
     reset_sigio ();
 #endif /* BSD4_1 */
 
-  if (otty->old_tty_valid)
-    while (EMACS_SET_TTY (input_fd, &otty->old_tty, 0) < 0 && errno == EINTR)
+  if (tty_out->old_tty_valid)
+    while (EMACS_SET_TTY (fileno (TTY_INPUT (tty_out)),
+                          &tty_out->old_tty, 0) < 0 && errno == EINTR)
       ;
 
 #ifdef MSDOS	/* Demacs 1.1.2 91/10/20 Manabu Higashida */
@@ -1874,7 +1880,7 @@
   /* Ultrix's termios *ignores* any line discipline except TERMIODISC.
      A different old line discipline is therefore not restored, yet.
      Restore the old line discipline by hand.  */
-  ioctl (0, TIOCSETD, &otty->old_tty.main.c_line);
+  ioctl (0, TIOCSETD, &tty_out->old_tty.main.c_line);
 #endif
 
 #ifdef AIXHFT
@@ -1947,9 +1953,9 @@
 {
   int status;
 
-  if (input_fd == 0)
+  if (fileno (TTY_INPUT (CURTTY())) == 0)
     {
-      status = SYS$ASSIGN (&input_dsc, &input_fd, 0, 0);
+      status = SYS$ASSIGN (&input_dsc, &fileno (TTY_INPUT (CURTTY())), 0, 0);
       if (! (status & 1))
 	LIB$STOP (status);
     }
@@ -1960,7 +1966,7 @@
 void
 stop_vms_input ()
 {
-  return SYS$DASSGN (input_fd);
+  return SYS$DASSGN (fileno (TTY_INPUT (CURTTY())));
 }
 
 short input_buffer;
@@ -1976,7 +1982,7 @@
 
   waiting_for_ast = 0;
   stop_input = 0;
-  status = SYS$QIO (0, input_fd, IO$_READVBLK,
+  status = SYS$QIO (0, fileno (TTY_INPUT (CURTTY())), IO$_READVBLK,
 		    &input_iosb, kbd_input_ast, 1,
 		    &input_buffer, 1, 0, terminator_mask, 0, 0);
 }
@@ -2093,7 +2099,7 @@
 #endif
   if (LIB$AST_IN_PROG ())  /* Don't wait if suspending from kbd_buffer_store_event! */
     {
-      SYS$CANCEL (input_fd);
+      SYS$CANCEL (fileno (TTY_INPUT (CURTTY())));
       return;
     }
 
@@ -2102,7 +2108,7 @@
   SYS$CLREF (input_ef);
   waiting_for_ast = 1;
   stop_input = 1;
-  SYS$CANCEL (input_fd);
+  SYS$CANCEL (fileno (TTY_INPUT (CURTTY())));
   SYS$SETAST (1);
   SYS$WAITFR (input_ef);
   waiting_for_ast = 0;
--- a/src/term.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/term.c	Fri Dec 26 04:24:54 2003 +0000
@@ -28,10 +28,10 @@
 
 #include <sys/file.h>
 
+#include "lisp.h"
 #include "systty.h" /* For emacs_tty in termchar.h */
 #include "termchar.h"
 #include "termopts.h"
-#include "lisp.h"
 #include "charset.h"
 #include "coding.h"
 #include "keyboard.h"
@@ -123,7 +123,7 @@
 void (*write_glyphs_hook) P_ ((struct glyph *, int));
 void (*delete_glyphs_hook) P_ ((int));
 
-int (*read_socket_hook) P_ ((int, struct input_event *, int, int));
+int (*read_socket_hook) P_ ((struct input_event *, int, int));
 
 void (*frame_up_to_date_hook) P_ ((struct frame *));
 
@@ -792,12 +792,11 @@
     }
   else
     {			/* have to do it the hard way */
-      struct frame *sf = XFRAME (selected_frame);
       turn_off_insert ();
 
       /* Do not write in last row last col with Auto-wrap on. */
-      if (AutoWrap && curY == FRAME_LINES (sf) - 1
-	  && first_unused_hpos == FRAME_COLS (sf))
+      if (AutoWrap && curY == FRAME_LINES (f) - 1
+	  && first_unused_hpos == FRAME_COLS (f))
 	first_unused_hpos--;
 
       for (i = curX; i < first_unused_hpos; i++)
@@ -925,8 +924,7 @@
      register int len;
 {
   int produced, consumed;
-  struct frame *sf = XFRAME (selected_frame);
-  struct frame *f = updating_frame ? updating_frame : sf;
+  struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
   unsigned char conversion_buffer[1024];
   int conversion_buffer_size = sizeof conversion_buffer;
 
@@ -944,8 +942,8 @@
      since that would scroll the whole frame on some terminals.  */
 
   if (AutoWrap
-      && curY + 1 == FRAME_LINES (sf)
-      && (curX + len) == FRAME_COLS (sf))
+      && curY + 1 == FRAME_LINES (f)
+      && (curX + len) == FRAME_COLS (f))
     len --;
   if (len <= 0)
     return;
@@ -1028,7 +1026,7 @@
 {
   char *buf;
   struct glyph *glyph = NULL;
-  struct frame *f, *sf;
+  struct frame *f;
 
   if (len <= 0)
     return;
@@ -1039,8 +1037,7 @@
       return;
     }
 
-  sf = XFRAME (selected_frame);
-  f = updating_frame ? updating_frame : sf;
+  f = updating_frame ? updating_frame : XFRAME (selected_frame);
 
   if (TS_ins_multi_chars)
     {
@@ -1159,7 +1156,7 @@
   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 *sf;
+  struct frame *f;
 
   register int i = n > 0 ? n : -n;
   register char *buf;
@@ -1170,7 +1167,7 @@
       return;
     }
 
-  sf = XFRAME (selected_frame);
+  f = (updating_frame ? updating_frame : XFRAME (selected_frame));
 
   /* If the lines below the insertion are being pushed
      into the end of the window, this is the same as clearing;
@@ -1179,11 +1176,11 @@
   /* 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 (sf))
+  if (TTY_SCROLL_REGION_OK (FRAME_TTY (f))
       && vpos + i >= specified_window)
     return;
-  if (!TTY_MEMORY_BELOW_FRAME (FRAME_TTY (sf))
-      && vpos + i >= FRAME_LINES (sf))
+  if (!TTY_MEMORY_BELOW_FRAME (FRAME_TTY (f))
+      && vpos + i >= FRAME_LINES (f))
     return;
 
   if (multi)
@@ -1191,7 +1188,7 @@
       raw_cursor_to (vpos, 0);
       background_highlight ();
       buf = tparam (multi, 0, 0, i);
-      OUTPUT (FRAME_TTY (sf), buf);
+      OUTPUT (FRAME_TTY (f), buf);
       xfree (buf);
     }
   else if (single)
@@ -1199,7 +1196,7 @@
       raw_cursor_to (vpos, 0);
       background_highlight ();
       while (--i >= 0)
-	OUTPUT (FRAME_TTY (sf), single);
+	OUTPUT (FRAME_TTY (f), single);
       if (TF_teleray)
 	curX = 0;
     }
@@ -1212,15 +1209,15 @@
 	raw_cursor_to (vpos, 0);
       background_highlight ();
       while (--i >= 0)
-	OUTPUTL (FRAME_TTY (sf), scroll, specified_window - vpos);
+	OUTPUTL (FRAME_TTY (f), scroll, specified_window - vpos);
       set_scroll_region (0, specified_window);
     }
 
-  if (!TTY_SCROLL_REGION_OK (FRAME_TTY (sf))
-      && TTY_MEMORY_BELOW_FRAME (FRAME_TTY (sf))
+  if (!TTY_SCROLL_REGION_OK (FRAME_TTY (f))
+      && TTY_MEMORY_BELOW_FRAME (FRAME_TTY (f))
       && n < 0)
     {
-      cursor_to (FRAME_LINES (sf) + n, 0);
+      cursor_to (FRAME_LINES (f) + n, 0);
       clear_to_end ();
     }
 }
@@ -2475,7 +2472,7 @@
   /* Get frame size from system, or else from termcap.  */
   {
     int height, width;
-    get_frame_size (&width, &height);
+    get_tty_size (tty, &width, &height);
     FRAME_COLS (sf) = width;
     FRAME_LINES (sf) = height;
   }
--- a/src/termchar.h	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/termchar.h	Fri Dec 26 04:24:54 2003 +0000
@@ -39,8 +39,16 @@
 
   int term_initted;             /* 1 if we have been through init_sys_modes. */
   int old_tty_valid;            /* 1 if outer tty status has been recorded.  */
+
+
+  /* Redisplay. */
+
+  /* XXX This may cause problems with GC. */
+  Lisp_Object top_frame;        /* The topmost frame on this tty. */
   
-  
+  /* The previous terminal frame we displayed on this tty.  */
+  struct frame *previous_terminal_frame;
+
   /* Pixel values.
      XXX What are these used for? */
   
--- a/src/termhooks.h	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/termhooks.h	Fri Dec 26 04:24:54 2003 +0000
@@ -371,7 +371,7 @@
 #define EVENT_INIT(event) bzero (&(event), sizeof (struct input_event))
 
 /* Called to read input events.  */
-extern int (*read_socket_hook) P_ ((int, struct input_event *, int, int));
+extern int (*read_socket_hook) P_ ((struct input_event *, int, int));
 
 /* Called when a frame's display becomes entirely up to date.  */
 extern void (*frame_up_to_date_hook) P_ ((struct frame *));
--- a/src/w32inevt.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/w32inevt.c	Fri Dec 26 04:24:54 2003 +0000
@@ -642,7 +642,7 @@
 }
 
 int
-w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
+w32_console_read_socket (struct input_event *bufp, int numchars,
 			 int expected)
 {
   BOOL no_events = TRUE;
--- a/src/w32term.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/w32term.c	Fri Dec 26 04:24:54 2003 +0000
@@ -4078,8 +4078,7 @@
 */
 
 int
-w32_read_socket (sd, bufp, numchars, expected)
-     register int sd;
+w32_read_socket (bufp, numchars, expected)
      /* register */ struct input_event *bufp;
      /* register */ int numchars;
      int expected;
--- a/src/window.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/window.c	Fri Dec 26 04:24:54 2003 +0000
@@ -6384,7 +6384,6 @@
 {
   struct frame *f = make_terminal_frame (0, 0);
   XSETFRAME (selected_frame, f);
-  Vterminal_frame = selected_frame;
   minibuf_window = f->minibuffer_window;
   selected_window = f->selected_window;
   last_nonminibuf_frame = f;
--- a/src/xdisp.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/xdisp.c	Fri Dec 26 04:24:54 2003 +0000
@@ -736,10 +736,6 @@
 #define CLEAR_FACE_CACHE_COUNT	500
 static int clear_face_cache_count;
 
-/* Record the previous terminal frame we displayed.  */
-
-static struct frame *previous_terminal_frame;
-
 /* Non-zero while redisplay_internal is in progress.  */
 
 int redisplaying_p;
@@ -2012,7 +2008,7 @@
 
   /* If realized faces have been removed, e.g. because of face
      attribute changes of named faces, recompute them.  When running
-     in batch mode, the face cache of Vterminal_frame is null.  If
+     in batch mode, the face cache of the initial frame is null.  If
      we happen to get called, make a dummy face cache.  */
   if (noninteractive && FRAME_FACE_CACHE (it->f) == NULL)
     init_frame_faces (it->f);
@@ -7559,11 +7555,11 @@
     {
       Lisp_Object tail, frame;
       int changed_count = 0;
-
+      
       FOR_EACH_FRAME (tail, frame)
 	{
 	  struct frame *f = XFRAME (frame);
-
+	  
 	  if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
 	    {
 	      if (f->resized_p)
@@ -7574,7 +7570,7 @@
 	      f->resized_p = 0;
 	    }
 	}
-
+      
       frame_garbaged = 0;
       if (changed_count)
 	++windows_or_buffers_changed;
@@ -7610,7 +7606,7 @@
   /* When Emacs starts, selected_frame may be a visible terminal
      frame, even if we run under a window system.  If we let this
      through, a message would be displayed on the terminal.  */
-  if (EQ (selected_frame, Vterminal_frame)
+  if (!FRAME_WINDOW_P (XFRAME (selected_frame))
       && !NILP (Vwindow_system))
     return 0;
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -9687,17 +9683,16 @@
   if (face_change_count)
     ++windows_or_buffers_changed;
 
-  if (! FRAME_WINDOW_P (sf)
-      && previous_terminal_frame != sf)
-    {
-      /* Since frames on an ASCII terminal share the same display
-	 area, displaying a different frame means redisplay the whole
-	 thing.  */
+  if (FRAME_TERMCAP_P (sf)
+      && FRAME_TTY (sf)->previous_terminal_frame != sf)
+    {
+      /* Since frames on a single ASCII terminal share the same
+	 display area, displaying a different frame means redisplay
+	 the whole thing.  */
       windows_or_buffers_changed++;
       SET_FRAME_GARBAGED (sf);
-      XSETFRAME (Vterminal_frame, sf);
-    }
-  previous_terminal_frame = sf;
+      FRAME_TTY (sf)->previous_terminal_frame = sf;
+    }
 
   /* Set the visible flags for all frames.  Do this before checking
      for resized or garbaged frames; they want to know if their frames
@@ -9719,6 +9714,7 @@
       }
   }
 
+  
   /* Notice any pending interrupt request to change frame size.  */
   do_pending_window_change (1);
 
@@ -10076,7 +10072,7 @@
 	{
 	  struct frame *f = XFRAME (frame);
 
-	  if (FRAME_WINDOW_P (f) || f == sf)
+	  if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
 	    {
 	      if (! EQ (frame, selected_frame))
 		/* Select the frame, for the sake of frame-local
--- a/src/xterm.c	Thu Dec 25 07:36:05 2003 +0000
+++ b/src/xterm.c	Fri Dec 26 04:24:54 2003 +0000
@@ -7057,8 +7057,7 @@
    EXPECTED is nonzero if the caller knows input is available.  */
 
 static int
-XTread_socket (sd, bufp, numchars, expected)
-     register int sd;
+XTread_socket (bufp, numchars, expected)
      /* register */ struct input_event *bufp;
      /* register */ int numchars;
      int expected;