Removed %T in mode-line-format. Trivial documentation changes.
[bpt/emacs.git] / src / term.c
index 24dbc61..65b6c15 100644 (file)
@@ -29,7 +29,6 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/file.h>
 
 #include "lisp.h"
-#include "systty.h" /* For emacs_tty in termchar.h */
 #include "termchar.h"
 #include "termopts.h"
 #include "charset.h"
@@ -72,9 +71,10 @@ static void turn_off_face P_ ((struct frame *, int face_id));
 static void tty_show_cursor P_ ((struct tty_display_info *));
 static void tty_hide_cursor P_ ((struct tty_display_info *));
 
-void delete_tty P_ ((struct tty_display_info *));
-static void delete_tty_1 P_ ((struct tty_display_info *));
-
+void delete_initial_display P_ ((struct display *));
+void delete_tty P_ ((struct display *));
+void create_tty_output P_ ((struct frame *));
+void delete_tty_output P_ ((struct frame *));
 
 #define OUTPUT(tty, a)                                          \
   emacs_tputs ((tty), a,                                        \
@@ -100,8 +100,16 @@ static void delete_tty_1 P_ ((struct tty_display_info *));
 
 Lisp_Object Vring_bell_function;
 
-/* Terminal characteristics that higher levels want to look at. */
+/* Functions to call after a tty was deleted. */
+Lisp_Object Vdelete_tty_after_functions;
+
+/* Chain of all displays currently in use. */
+struct display *display_list;
 
+/* The initial display device, created by initial_term_init. */
+struct display *initial_display;
+
+/* Chain of all tty device parameters. */
 struct tty_display_info *tty_list;
 
 /* Nonzero means no need to redraw the entire frame on resuming a
@@ -112,133 +120,6 @@ int no_redraw_on_reenter;
 
 Lisp_Object Qframe_tty_name, Qframe_tty_type;
 
-/* Hook functions that you can set to snap out the functions in this file.
-   These are all extern'd in termhooks.h  */
-
-void (*cursor_to_hook) P_ ((int, int));
-void (*raw_cursor_to_hook) P_ ((int, int));
-void (*clear_to_end_hook) P_ ((void));
-void (*clear_frame_hook) P_ ((void));
-void (*clear_end_of_line_hook) P_ ((int));
-
-void (*ins_del_lines_hook) P_ ((int, int));
-
-void (*delete_glyphs_hook) P_ ((int));
-
-void (*ring_bell_hook) P_ ((void));
-
-void (*reset_terminal_modes_hook) P_ ((void));
-void (*set_terminal_modes_hook) P_ ((void));
-void (*update_begin_hook) P_ ((struct frame *));
-void (*update_end_hook) P_ ((struct frame *));
-void (*set_terminal_window_hook) P_ ((int));
-void (*insert_glyphs_hook) P_ ((struct glyph *, int));
-void (*write_glyphs_hook) P_ ((struct glyph *, int));
-void (*delete_glyphs_hook) P_ ((int));
-
-int (*read_socket_hook) P_ ((struct input_event *, int, int));
-
-void (*frame_up_to_date_hook) P_ ((struct frame *));
-
-/* Return the current position of the mouse.
-
-   Set *f to the frame the mouse is in, or zero if the mouse is in no
-   Emacs frame.  If it is set to zero, all the other arguments are
-   garbage.
-
-   If the motion started in a scroll bar, set *bar_window to the
-   scroll bar's window, *part to the part the mouse is currently over,
-   *x to the position of the mouse along the scroll bar, and *y to the
-   overall length of the scroll bar.
-
-   Otherwise, set *bar_window to Qnil, and *x and *y to the column and
-   row of the character cell the mouse is over.
-
-   Set *time to the time the mouse was at the returned position.
-
-   This should clear mouse_moved until the next motion
-   event arrives.  */
-
-void (*mouse_position_hook) P_ ((FRAME_PTR *f, int insist,
-                                Lisp_Object *bar_window,
-                                enum scroll_bar_part *part,
-                                Lisp_Object *x,
-                                Lisp_Object *y,
-                                unsigned long *time));
-
-/* When reading from a minibuffer in a different frame, Emacs wants
-   to shift the highlight from the selected frame to the mini-buffer's
-   frame; under X, this means it lies about where the focus is.
-   This hook tells the window system code to re-decide where to put
-   the highlight.  */
-
-void (*frame_rehighlight_hook) P_ ((FRAME_PTR f));
-
-/* If we're displaying frames using a window system that can stack
-   frames on top of each other, this hook allows you to bring a frame
-   to the front, or bury it behind all the other windows.  If this
-   hook is zero, that means the device we're displaying on doesn't
-   support overlapping frames, so there's no need to raise or lower
-   anything.
-
-   If RAISE is non-zero, F is brought to the front, before all other
-   windows.  If RAISE is zero, F is sent to the back, behind all other
-   windows.  */
-
-void (*frame_raise_lower_hook) P_ ((FRAME_PTR f, int raise));
-
-/* Set the vertical scroll bar for WINDOW to have its upper left corner
-   at (TOP, LEFT), and be LENGTH rows high.  Set its handle to
-   indicate that we are displaying PORTION characters out of a total
-   of WHOLE characters, starting at POSITION.  If WINDOW doesn't yet
-   have a scroll bar, create one for it.  */
-
-void (*set_vertical_scroll_bar_hook)
-     P_ ((struct window *window,
-         int portion, int whole, int position));
-
-
-/* The following three hooks are used when we're doing a thorough
-   redisplay of the frame.  We don't explicitly know which scroll bars
-   are going to be deleted, because keeping track of when windows go
-   away is a real pain - can you say set-window-configuration?
-   Instead, we just assert at the beginning of redisplay that *all*
-   scroll bars are to be removed, and then save scroll bars from the
-   fiery pit when we actually redisplay their window.  */
-
-/* Arrange for all scroll bars on FRAME to be removed at the next call
-   to `*judge_scroll_bars_hook'.  A scroll bar may be spared if
-   `*redeem_scroll_bar_hook' is applied to its window before the judgment.
-
-   This should be applied to each frame each time its window tree is
-   redisplayed, even if it is not displaying scroll bars at the moment;
-   if the HAS_SCROLL_BARS flag has just been turned off, only calling
-   this and the judge_scroll_bars_hook will get rid of them.
-
-   If non-zero, this hook should be safe to apply to any frame,
-   whether or not it can support scroll bars, and whether or not it is
-   currently displaying them.  */
-
-void (*condemn_scroll_bars_hook) P_ ((FRAME_PTR frame));
-
-/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
-   Note that it's okay to redeem a scroll bar that is not condemned.  */
-
-void (*redeem_scroll_bar_hook) P_ ((struct window *window));
-
-/* Remove all scroll bars on FRAME that haven't been saved since the
-   last call to `*condemn_scroll_bars_hook'.
-
-   This should be applied to each frame after each time its window
-   tree is redisplayed, even if it is not displaying scroll bars at the
-   moment; if the HAS_SCROLL_BARS flag has just been turned off, only
-   calling this and condemn_scroll_bars_hook will get rid of them.
-
-   If non-zero, this hook should be safe to apply to any frame,
-   whether or not it can support scroll bars, and whether or not it is
-   currently displaying them.  */
-
-void (*judge_scroll_bars_hook) P_ ((FRAME_PTR FRAME));
 
 
 /* Meaning of bits in no_color_video.  Each bit set means that the
@@ -267,10 +148,6 @@ int max_frame_cols;
 
 int max_frame_lines;
 
-/* A template for tty display methods, with common values
-   preinitialized. */
-static struct display_method tty_display_method_template;
-
 /* Frame currently being redisplayed; 0 if not currently redisplaying.
    (Direct output does not count).  */
 
@@ -299,7 +176,7 @@ extern char *tgetstr ();
 void
 ring_bell ()
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct frame *f = XFRAME (selected_frame);
 
   if (!NILP (Vring_bell_function))
     {
@@ -320,34 +197,43 @@ ring_bell ()
 
       Vring_bell_function = function;
     }
-  else if (!FRAME_TERMCAP_P (f))
-    (*ring_bell_hook) ();
-  else {
-    struct tty_display_info *tty = FRAME_TTY (f);
-    OUTPUT (tty, tty->TS_visible_bell && visible_bell ? tty->TS_visible_bell : tty->TS_bell);
-  }
+  else if (FRAME_DISPLAY (f)->ring_bell_hook)
+    (*FRAME_DISPLAY (f)->ring_bell_hook) ();
+}
+
+/* Ring the bell on a tty. */
+
+void
+tty_ring_bell ()
+{
+  struct frame *f = XFRAME (selected_frame);
+  struct tty_display_info *tty = FRAME_TTY (f);
+
+  OUTPUT (tty, (tty->TS_visible_bell && visible_bell
+                ? tty->TS_visible_bell
+                : tty->TS_bell));
 }
 
-void tty_set_terminal_modes (struct tty_display_info *tty)
+/* Set up termcap modes for Emacs. */
+
+void
+tty_set_terminal_modes (struct display *display)
 {
+  struct tty_display_info *tty = display->display_info.tty;
+  
   OUTPUT_IF (tty, tty->TS_termcap_modes);
   OUTPUT_IF (tty, tty->TS_cursor_visible);
   OUTPUT_IF (tty, tty->TS_keypad_mode);
   losecursor (tty);
 }
 
-void
-set_terminal_modes ()
-{
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  if (FRAME_TERMCAP_P (f))
-    tty_set_terminal_modes (FRAME_TTY (f));
-  else
-    (*set_terminal_modes_hook) ();
-}
+/* Reset termcap modes before exiting Emacs. */
 
-void tty_reset_terminal_modes (struct tty_display_info *tty)
+void
+tty_reset_terminal_modes (struct display *display)
 {
+  struct tty_display_info *tty = display->display_info.tty;
+  
   turn_off_highlight (tty);
   turn_off_insert (tty);
   OUTPUT_IF (tty, tty->TS_end_keypad_mode);
@@ -359,57 +245,68 @@ void tty_reset_terminal_modes (struct tty_display_info *tty)
   cmputc ('\r');
 }
 
-void
-reset_terminal_modes ()
-{
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  if (FRAME_TERMCAP_P (f))
-    tty_reset_terminal_modes (FRAME_TTY (f));
-  else if (reset_terminal_modes_hook)
-    (*reset_terminal_modes_hook) ();
-}
-
 void
 update_begin (f)
      struct frame *f;
 {
   updating_frame = f;
-  if (!FRAME_TERMCAP_P (f))
-    update_begin_hook (f);
+  if (FRAME_DISPLAY (f)->update_begin_hook)
+    (*FRAME_DISPLAY (f)->update_begin_hook) (f);
 }
 
 void
 update_end (f)
      struct frame *f;
 {
-  if (FRAME_TERMCAP_P (f))
-    {
-      struct tty_display_info *tty = FRAME_TTY (f);
-      if (!XWINDOW (selected_window)->cursor_off_p)
-       tty_show_cursor (tty);
-      turn_off_insert (tty);
-      background_highlight (tty);
-    }
-  else
-    update_end_hook (f);
-
+  if (FRAME_DISPLAY (f)->update_end_hook)
+    (*FRAME_DISPLAY (f)->update_end_hook) (f);
   updating_frame = NULL;
 }
 
+/* Flag the end of a display update on a termcap display. */
+
+void
+tty_update_end (struct frame *f)
+{
+  struct tty_display_info *tty = FRAME_TTY (f);
+
+  if (!XWINDOW (selected_window)->cursor_off_p)
+    tty_show_cursor (tty);
+  turn_off_insert (tty);
+  background_highlight (tty);
+}
+
+/* Specify how many text lines, from the top of the window,
+   should be affected by insert-lines and delete-lines operations.
+   This, and those operations, are used only within an update
+   that is bounded by calls to update_begin and update_end.  */
+
 void
 set_terminal_window (size)
      int size;
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  if (FRAME_TERMCAP_P (f))
-    {
-      struct tty_display_info *tty = FRAME_TTY (f);
-      tty->specified_window = size ? size : FRAME_LINES (f);
-      if (FRAME_SCROLL_REGION_OK (f))
-       set_scroll_region (0, tty->specified_window);
-    }
-  else
-    set_terminal_window_hook (size);
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  if (FRAME_DISPLAY (f)->set_terminal_window_hook)
+    (*FRAME_DISPLAY (f)->set_terminal_window_hook) (size);
+}
+
+/* The implementation of set_terminal_window for termcap frames. */
+
+void
+tty_set_terminal_window (int size)
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  struct tty_display_info *tty = FRAME_TTY (f);
+
+  tty->specified_window = size ? size : FRAME_LINES (f);
+  if (FRAME_SCROLL_REGION_OK (f))
+    set_scroll_region (0, tty->specified_window);
 }
 
 void
@@ -417,7 +314,10 @@ set_scroll_region (start, stop)
      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_display_info *tty = FRAME_TTY (f);
 
   if (tty->TS_set_scroll_region)
@@ -539,16 +439,22 @@ void
 cursor_to (vpos, hpos)
      int vpos, hpos;
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  struct tty_display_info *tty;
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
-  if (! FRAME_TERMCAP_P (f) && cursor_to_hook)
-    {
-      (*cursor_to_hook) (vpos, hpos);
-      return;
-    }
+  if (FRAME_DISPLAY (f)->cursor_to_hook)
+    (*FRAME_DISPLAY (f)->cursor_to_hook) (vpos, hpos);
+}
 
-  tty = FRAME_TTY (f);
+void
+tty_cursor_to (int vpos, int hpos)
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+  
+  struct tty_display_info *tty = FRAME_TTY (f);
 
   /* Detect the case where we are called from reset_sys_modes
      and the costs have never been calculated.  Do nothing.  */
@@ -571,14 +477,23 @@ void
 raw_cursor_to (row, col)
      int row, col;
 {
-  struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
-  struct tty_display_info *tty;
-  if (! FRAME_TERMCAP_P (f))
-    {
-      (*raw_cursor_to_hook) (row, col);
-      return;
-    }
-  tty = FRAME_TTY (f);
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  if (FRAME_DISPLAY (f)->raw_cursor_to_hook)
+    (*FRAME_DISPLAY (f)->raw_cursor_to_hook) (row, col);  
+}
+
+void
+tty_raw_cursor_to (int row, int col)
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  struct tty_display_info *tty = FRAME_TTY (f);
+
   if (curY (tty) == row
       && curX (tty) == col)
     return;
@@ -591,21 +506,29 @@ raw_cursor_to (row, col)
 \f
 /* Erase operations */
 
-/* clear from cursor to end of frame */
+/* Clear from cursor to end of frame. */
 void
 clear_to_end ()
 {
-  register int i;
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  struct tty_display_info *tty;
+  if (FRAME_DISPLAY (f)->clear_to_end_hook)
+    (*FRAME_DISPLAY (f)->clear_to_end_hook) ();
+}
+
+/* Clear from cursor to end of frame on a termcap device. */
+
+void
+tty_clear_to_end (void)
+{
+  register int i;
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+  struct tty_display_info *tty = FRAME_TTY (f);
 
-  if (clear_to_end_hook && ! FRAME_TERMCAP_P (f))
-    {
-      (*clear_to_end_hook) ();
-      return;
-    }
-  tty = FRAME_TTY (f);
   if (tty->TS_clr_to_bottom)
     {
       background_highlight (tty);
@@ -627,14 +550,22 @@ void
 clear_frame ()
 {
   struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  struct tty_display_info *tty;
 
-  if (clear_frame_hook && ! FRAME_TERMCAP_P (f))
-    {
-      (*clear_frame_hook) ();
-      return;
-    }
-  tty = FRAME_TTY (f);
+  if (FRAME_DISPLAY (f)->clear_frame_hook)
+    (*FRAME_DISPLAY (f)->clear_frame_hook) ();
+}
+
+/* Clear an entire termcap frame. */
+
+void
+tty_clear_frame ()
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  struct tty_display_info *tty = FRAME_TTY (f);
+
   if (tty->TS_clr_frame)
     {
       background_highlight (tty);
@@ -657,22 +588,27 @@ void
 clear_end_of_line (first_unused_hpos)
      int first_unused_hpos;
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  struct tty_display_info *tty;
-
-  if (clear_end_of_line_hook && ! FRAME_TERMCAP_P (f))
-    {
-      (*clear_end_of_line_hook) (first_unused_hpos);
-      return;
-    }
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
-  tty_clear_end_of_line (FRAME_TTY (f), first_unused_hpos);
+  if (FRAME_DISPLAY (f)->clear_end_of_line_hook)
+    (*FRAME_DISPLAY (f)->clear_end_of_line_hook) (first_unused_hpos);
 }
 
+/* An implementation of clear_end_of_line for termcap frames.
+
+   Note that the cursor may be moved, on terminals lacking a `ce' string.  */
+
 void
-tty_clear_end_of_line (struct tty_display_info *tty, int first_unused_hpos)
+tty_clear_end_of_line (int first_unused_hpos)
 {
   register int i;
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+  struct tty_display_info *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 (! tty->costs_set)
@@ -814,24 +750,36 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
 }
 
 
+/* Output LEN glyphs starting at STRING at the nominal cursor position.
+   Advance the nominal cursor over the text.  */
+
 void
 write_glyphs (string, len)
      register struct glyph *string;
      register int len;
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  if (FRAME_DISPLAY (f)->write_glyphs_hook)
+    (*FRAME_DISPLAY (f)->write_glyphs_hook) (string, len);
+}
+
+/* An implementation of write_glyphs for termcap frames. */
+
+void
+tty_write_glyphs (struct glyph *string, int len)
 {
   int produced, consumed;
-  struct frame *f = updating_frame ? updating_frame : XFRAME (selected_frame);
-  struct tty_display_info *tty;
   unsigned char conversion_buffer[1024];
   int conversion_buffer_size = sizeof conversion_buffer;
 
-  if (write_glyphs_hook && ! FRAME_TERMCAP_P (f))
-    {
-      (*write_glyphs_hook) (string, len);
-      return;
-    }
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
-  tty = FRAME_TTY (f);
+  struct tty_display_info *tty = FRAME_TTY (f);
 
   turn_off_insert (tty);
   tty_hide_cursor (tty);
@@ -915,30 +863,38 @@ write_glyphs (string, len)
   cmcheckmagic (tty);
 }
 
-/* If start is zero, insert blanks instead of a string at start */
+/* Insert LEN glyphs from START at the nominal cursor position.
+
+   If start is zero, insert blanks instead of a string at start */
 
 void
 insert_glyphs (start, len)
      register struct glyph *start;
      register int len;
 {
-  char *buf;
-  struct glyph *glyph = NULL;
-  struct frame *f;
-  struct tty_display_info *tty;
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
   if (len <= 0)
     return;
 
-  f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  if (FRAME_DISPLAY (f)->insert_glyphs_hook)
+    (*FRAME_DISPLAY (f)->insert_glyphs_hook) (start, len);
+}
+
+/* An implementation of insert_glyphs for termcap frames. */
 
-  if (insert_glyphs_hook && ! FRAME_TERMCAP_P (f))
-    {
-      (*insert_glyphs_hook) (start, len);
-      return;
-    }
+void
+tty_insert_glyphs (struct glyph *start, int len)
+{
+  char *buf;
+  struct glyph *glyph = NULL;
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
-  tty = FRAME_TTY (f);
+  struct tty_display_info *tty = FRAME_TTY (f);
 
   if (tty->TS_ins_multi_chars)
     {
@@ -1012,21 +968,32 @@ insert_glyphs (start, len)
   cmcheckmagic (tty);
 }
 
+/* Delete N glyphs at the nominal cursor position. */
+
 void
 delete_glyphs (n)
      register int n;
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  if (FRAME_DISPLAY (f)->delete_glyphs_hook)
+    (*FRAME_DISPLAY (f)->delete_glyphs_hook) (n);
+}
+
+/* An implementation of delete_glyphs for termcap frames. */
+
+void
+tty_delete_glyphs (int n)
 {
   char *buf;
   register int i;
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  struct tty_display_info *tty = FRAME_TTY (f);
-
-  if (delete_glyphs_hook && ! FRAME_TERMCAP_P (f))
-    {
-      (*delete_glyphs_hook) (n);
-      return;
-    }
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
+  struct tty_display_info *tty = FRAME_TTY (f);
 
   if (tty->delete_in_insert_mode)
     {
@@ -1057,73 +1024,81 @@ void
 ins_del_lines (vpos, n)
      int vpos, n;
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  if (ins_del_lines_hook && ! FRAME_TERMCAP_P (f))
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+  
+  if (FRAME_DISPLAY (f)->ins_del_lines_hook)
+    (*FRAME_DISPLAY (f)->ins_del_lines_hook) (vpos, n);
+}
+
+/* An implementation of ins_del_lines for termcap frames. */
+
+void
+tty_ins_del_lines (int vpos, int n)
+{
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
+
+  struct tty_display_info *tty = FRAME_TTY (f);
+  char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
+  char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
+  char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
+
+  register int i = n > 0 ? n : -n;
+  register char *buf;
+
+  /* If the lines below the insertion are being pushed
+     into the end of the window, this is the same as clearing;
+     and we know the lines are already clear, since the matching
+     deletion has already been done.  So can ignore this.  */
+  /* 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 (FRAME_SCROLL_REGION_OK (f)
+      && vpos + i >= tty->specified_window)
+    return;
+  if (!FRAME_MEMORY_BELOW_FRAME (f)
+      && vpos + i >= FRAME_LINES (f))
+    return;
+  
+  if (multi)
     {
-      (*ins_del_lines_hook) (vpos, n);
-      return;
+      raw_cursor_to (vpos, 0);
+      background_highlight (tty);
+      buf = tparam (multi, 0, 0, i);
+      OUTPUT (tty, buf);
+      xfree (buf);
+    }
+  else if (single)
+    {
+      raw_cursor_to (vpos, 0);
+      background_highlight (tty);
+      while (--i >= 0)
+        OUTPUT (tty, single);
+      if (tty->TF_teleray)
+        curX (tty) = 0;
     }
   else
     {
-      struct tty_display_info *tty = FRAME_TTY (f);
-      char *multi = n > 0 ? tty->TS_ins_multi_lines : tty->TS_del_multi_lines;
-      char *single = n > 0 ? tty->TS_ins_line : tty->TS_del_line;
-      char *scroll = n > 0 ? tty->TS_rev_scroll : tty->TS_fwd_scroll;
-
-      register int i = n > 0 ? n : -n;
-      register char *buf;
-
-      /* If the lines below the insertion are being pushed
-         into the end of the window, this is the same as clearing;
-         and we know the lines are already clear, since the matching
-         deletion has already been done.  So can ignore this.  */
-      /* 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 (FRAME_SCROLL_REGION_OK (f)
-          && vpos + i >= tty->specified_window)
-        return;
-      if (!FRAME_MEMORY_BELOW_FRAME (f)
-          && vpos + i >= FRAME_LINES (f))
-        return;
-
-      if (multi)
-        {
-          raw_cursor_to (vpos, 0);
-          background_highlight (tty);
-          buf = tparam (multi, 0, 0, i);
-          OUTPUT (tty, buf);
-          xfree (buf);
-        }
-      else if (single)
-        {
-          raw_cursor_to (vpos, 0);
-          background_highlight (tty);
-          while (--i >= 0)
-            OUTPUT (tty, single);
-          if (tty->TF_teleray)
-            curX (tty) = 0;
-        }
+      set_scroll_region (vpos, tty->specified_window);
+      if (n < 0)
+        raw_cursor_to (tty->specified_window - 1, 0);
       else
-        {
-          set_scroll_region (vpos, tty->specified_window);
-          if (n < 0)
-            raw_cursor_to (tty->specified_window - 1, 0);
-          else
-            raw_cursor_to (vpos, 0);
-          background_highlight (tty);
-          while (--i >= 0)
-            OUTPUTL (tty, scroll, tty->specified_window - vpos);
-          set_scroll_region (0, tty->specified_window);
-        }
-
-      if (!FRAME_SCROLL_REGION_OK (f)
-          && FRAME_MEMORY_BELOW_FRAME (f)
-          && n < 0)
-        {
-          cursor_to (FRAME_LINES (f) + n, 0);
-          clear_to_end ();
-        }
+        raw_cursor_to (vpos, 0);
+      background_highlight (tty);
+      while (--i >= 0)
+        OUTPUTL (tty, scroll, tty->specified_window - vpos);
+      set_scroll_region (0, tty->specified_window);
+    }
+  
+  if (!FRAME_SCROLL_REGION_OK (f)
+      && FRAME_MEMORY_BELOW_FRAME (f)
+      && n < 0)
+    {
+      cursor_to (FRAME_LINES (f) + n, 0);
+      clear_to_end ();
     }
 }
 \f
@@ -1936,6 +1911,48 @@ tty_capable_p (tty, caps, fg, bg)
   return 1;
 }
 
+/* Return the tty display object specified by DISPLAY.
+   DISPLAY may be a frame or a string. */
+
+static struct display *
+get_tty_display (Lisp_Object display)
+{
+  struct display *d;
+
+  if (! FRAMEP (display) && ! STRINGP (display))
+    return 0;
+
+  /* The initial frame does not support colors. */
+  if (FRAMEP (display) && FRAME_INITIAL_P (XFRAME (display)))
+    return 0;
+
+  if (FRAMEP (display))
+    {
+      if (! FRAME_TERMCAP_P (XFRAME (display)))
+#if 0   /* XXX We need a predicate as the first argument; find one. */
+        wrong_type_argument ("Not a termcap frame", display);
+#else /* Until we fix the wrong_type_argument call above, simply throw
+         a dumb error. */
+      error ("DISPLAY is not a termcap frame");
+#endif  
+  
+      d = FRAME_DISPLAY (XFRAME (display));
+    }
+  else if (STRINGP (display))
+    {
+      char *name = (char *) alloca (SBYTES (display) + 1);
+      strncpy (name, SDATA (display), SBYTES (display));
+      name[SBYTES (display)] = 0;
+
+      d = get_named_tty_display (name);
+
+      if (!d)
+        error ("There is no tty display on %s", name);
+    }
+
+  return d;
+}
+
 
 /* Return non-zero if the terminal is capable to display colors.  */
 
@@ -1945,8 +1962,11 @@ DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
      (display)
      Lisp_Object display;
 {
-  struct tty_display_info *tty = FRAME_TTY (SELECTED_FRAME ());
-  return tty->TN_max_colors > 0 ? Qt : Qnil;
+  struct display *d = get_tty_display (display);
+  if (!d)
+    return Qnil;
+  else
+    return d->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
 }
 
 /* Return the number of supported colors.  */
@@ -1956,8 +1976,11 @@ DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
      (display)
      Lisp_Object display;
 {
-  struct tty_display_info *tty = FRAME_TTY (SELECTED_FRAME ());
-  return make_number (tty->TN_max_colors);
+  struct display *d = get_tty_display (display);
+  if (!d)
+    return Qnil;
+  else
+    return make_number (d->display_info.tty->TN_max_colors);
 }
 
 #ifndef WINDOWSNT
@@ -2099,17 +2122,23 @@ set_tty_color_mode (f, val)
 
 \f
 
-struct tty_display_info *
-get_named_tty (name)
+/* Return the termcap display with the given name.  If NAME is null,
+   return the display corresponding to our controlling terminal.
+
+   Returns NULL if the named terminal device is not opened.  */
+struct display *
+get_named_tty_display (name)
      char *name;
 {
-  struct tty_display_info *tty = tty_list;
-
-  while (tty) {
-    if ((tty->name == 0 && name == 0)
-        || (name && tty->name && !strcmp (tty->name, name)))
-      return tty;
-    tty = tty->next;
+  struct display *d;
+
+  for (d = display_list; d; d = d->next_display) {
+    if (d->type == output_termcap
+        && ((d->display_info.tty->name == 0 && name == 0)
+            || (name && d->display_info.tty->name
+                && !strcmp (d->display_info.tty->name, name))))
+      return d;
   };
 
   return 0;
@@ -2174,26 +2203,52 @@ DEFUN ("frame-tty-type", Fframe_tty_type, Sframe_tty_type, 0, 1, 0,
                            Initialization
  ***********************************************************************/
 
-struct tty_display_info *
-term_dummy_init (void)
+/* Create the bootstrap display device for the initial frame.
+   Returns a display of type output_initial. */
+
+struct display *
+init_initial_display (void)
+{
+  struct tty_display_info *tty;
+  
+  if (initialized || display_list || tty_list)
+    abort ();
+
+  initial_display = create_display ();
+  initial_display->type = output_initial;
+  
+  initial_display->delete_display_hook = &delete_initial_display;
+  /* All other hooks are NULL. */
+  
+  return initial_display;
+}
+
+/* Deletes the bootstrap display device.
+   Called through delete_display_hook. */
+
+void
+delete_initial_display (struct display *display)
 {
-  if (initialized || tty_list)
-    error ("tty already initialized");
+  if (display != initial_display)
+    abort ();
 
-  tty_list = xmalloc (sizeof (struct tty_display_info));
-  bzero (tty_list, sizeof (struct tty_display_info));
-  tty_list->name = 0;
-  tty_list->input = stdin;
-  tty_list->output = stdout;
-  tty_list->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
-  tty_list->display_method = (struct display_method *) xmalloc (sizeof (struct display_method));
-  tty_list->kboard = initial_kboard;
-  return tty_list;
+  delete_display (display);
+  initial_display = NULL;
 }
 
+/* Create a termcap display on the tty device with the given name and
+   type.
 
-struct tty_display_info *
-term_init (Lisp_Object frame, char *name, char *terminal_type)
+   If NAME is NULL, then use the controlling tty, i.e., stdin/stdout.
+   Otherwise NAME should be a path to the tty device file,
+   e.g. "/dev/pts/7".
+
+   TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
+
+   If MUST_SUCCEED is true, then all errors are fatal. */
+
+struct display *
+term_init (char *name, char *terminal_type, int must_succeed)
 {
   char *area;
   char **address = &area;
@@ -2201,52 +2256,71 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
   int buffer_size = 4096;
   register char *p;
   int status;
-  struct frame *f = XFRAME (frame);
   struct tty_display_info *tty;
+  struct display *display;
 
-  tty = get_named_tty (name);
-  if (tty)
-    {
-      /* Return the previously initialized terminal, except if it is
-         the dummy terminal created for the initial frame. */
-      if (tty->type)
-        return tty;
+  static void maybe_fatal();
 
-      /* Free up temporary structures. */
-      if (tty->Wcm)
-        xfree (tty->Wcm);
-      if (tty->display_method)
-        xfree (tty->display_method);
-      if (tty->kboard != initial_kboard)
-        abort ();
-      tty->kboard = 0;
-    }
-  else
-    {
-      tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
-      bzero (tty, sizeof (struct tty_display_info));
-      tty->next = tty_list;
-      tty_list = tty;
-    }
+  if (!terminal_type)
+    maybe_fatal (must_succeed, 0, 0,
+                 "Unknown terminal type",
+                 "Unknown terminal type");
+  
+  display = get_named_tty_display (name);
+  if (display)
+    return display;             /* We have already opened a display there. */
+
+  display = create_display ();
+  tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
+  bzero (tty, sizeof (struct tty_display_info));
+  tty->next = tty_list;
+  tty_list = tty;
+
+  display->type = output_termcap;
+  display->display_info.tty = tty;
+  tty->display = display;
 
   tty->Wcm = (struct cm *) xmalloc (sizeof (struct cm));
   Wcm_clear (tty);
 
-  /* Each termcap frame has its own display method. */
-  tty->display_method = (struct display_method *) xmalloc (sizeof (struct display_method));
-  bzero (tty->display_method, sizeof (struct display_method));
+  display->rif = 0; /* ttys don't support window-based redisplay. */
 
-  /* Initialize the common members in the new display method with our
-     predefined template. */
-  *tty->display_method = tty_display_method_template;
-  f->display_method = tty->display_method;
+  display->cursor_to_hook = &tty_cursor_to;
+  display->raw_cursor_to_hook = &tty_raw_cursor_to;
 
-  /* Make sure the frame is live; if an error happens, it must be
-     deleted. */
-  f->output_method = output_termcap;
-  if (! f->output_data.tty)
-    abort ();
-  f->output_data.tty->display_info = tty;
+  display->clear_to_end_hook = &tty_clear_to_end;
+  display->clear_frame_hook = &tty_clear_frame;
+  display->clear_end_of_line_hook = &tty_clear_end_of_line;
+
+  display->ins_del_lines_hook = &tty_ins_del_lines;
+
+  display->insert_glyphs_hook = &tty_insert_glyphs;
+  display->write_glyphs_hook = &tty_write_glyphs;
+  display->delete_glyphs_hook = &tty_delete_glyphs;
+
+  display->ring_bell_hook = &tty_ring_bell;
+  
+  display->reset_terminal_modes_hook = &tty_reset_terminal_modes;
+  display->set_terminal_modes_hook = &tty_set_terminal_modes;
+  display->update_begin_hook = 0; /* Not needed. */
+  display->update_end_hook = &tty_update_end;
+  display->set_terminal_window_hook = &tty_set_terminal_window;
+
+  display->mouse_position_hook = 0; /* Not needed. */
+  display->frame_rehighlight_hook = 0; /* Not needed. */
+  display->frame_raise_lower_hook = 0; /* Not needed. */
+
+  display->set_vertical_scroll_bar_hook = 0; /* Not needed. */
+  display->condemn_scroll_bars_hook = 0; /* Not needed. */
+  display->redeem_scroll_bar_hook = 0; /* Not needed. */
+  display->judge_scroll_bars_hook = 0; /* Not needed. */
+
+  display->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
+  display->frame_up_to_date_hook = 0; /* Not needed. */
+  
+  display->delete_frame_hook = &delete_tty_output;
+  display->delete_display_hook = &delete_tty;
+  
   if (name)
     {
       int fd;
@@ -2254,7 +2328,7 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
       fd = emacs_open (name, O_RDWR, 0);
       if (fd < 0)
         {
-          delete_tty (tty);
+          delete_tty (display);
           error ("Could not open file: %s", name);
         }
       file = fdopen (fd, "w+");
@@ -2280,29 +2354,29 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
 
   area = (char *) xmalloc (2044);
 
-  FrameRows (tty) = FRAME_LINES (f);
-  FrameCols (tty) = FRAME_COLS (f);
-  tty->specified_window = FRAME_LINES (f);
+  FrameRows (tty) = FRAME_LINES (f); /* XXX */
+  FrameCols (tty) = FRAME_COLS (f);  /* XXX */
+  tty->specified_window = FRAME_LINES (f); /* XXX */
 
-  tty->display_method->delete_in_insert_mode = 1;
+  tty->display->delete_in_insert_mode = 1;
 
   UseTabs (tty) = 0;
-  FRAME_SCROLL_REGION_OK (f) = 0;
+  display->scroll_region_ok = 0;
 
   /* Seems to insert lines when it's not supposed to, messing
      up the display.  In doing a trace, it didn't seem to be
      called much, so I don't think we're losing anything by
      turning it off.  */
-  FRAME_LINE_INS_DEL_OK (f) = 0;
-  FRAME_CHAR_INS_DEL_OK (f) = 1;
+  display->line_ins_del_ok = 0;
+  display->char_ins_del_ok = 1;
 
   baud_rate = 19200;
 
-  FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
-  FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
+  FRAME_CAN_HAVE_SCROLL_BARS (f) = 0; /* XXX */
+  FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none; /* XXX */
   TN_max_colors = 16;  /* Required to be non-zero for tty-display-color-p */
 
-  return tty;
+  return display;
 #else  /* not WINDOWSNT */
 
   Wcm_clear (tty);
@@ -2312,55 +2386,35 @@ term_init (Lisp_Object frame, char *name, char *terminal_type)
   if (status < 0)
     {
 #ifdef TERMINFO
-      if (name)
-        {
-          xfree (buffer);
-          delete_tty (tty);
-          error ("Cannot open terminfo database file");
-        }
-      else
-        fatal ("Cannot open terminfo database file");
+      maybe_fatal (must_succeed, buffer, display,
+                   "Cannot open terminfo database file",
+                   "Cannot open terminfo database file");
 #else
-      if (name)
-        {
-          xfree (buffer);
-          delete_tty (tty);
-          error ("Cannot open termcap database file");
-        }
-      else
-        fatal ("Cannot open termcap database file");
+      maybe_fatal (must_succeed, buffer, display,
+                   "Cannot open termcap database file",
+                   "Cannot open termcap database file");
 #endif
     }
   if (status == 0)
     {
 #ifdef TERMINFO
-      if (name)
-        {
-          xfree (buffer);
-          delete_tty (tty);
-          error ("Terminal type %s is not defined", terminal_type);
-        }
-      else
-        fatal ("Terminal type %s is not defined.\n\
+      maybe_fatal (must_succeed, buffer, display,
+                   "Terminal type %s is not defined",
+                   "Terminal type %s is not defined.\n\
 If that is not the actual type of terminal you have,\n\
 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
 `setenv TERM ...') to specify the correct type.  It may be necessary\n\
 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
-               terminal_type);
+                   terminal_type);
 #else
-      if (name)
-        {
-          xfree (buffer);
-          delete_tty (tty);
-          error ("Terminal type %s is not defined", terminal_type);
-        }
-      else
-        fatal ("Terminal type %s is not defined.\n\
+      maybe_fatal (must_succeed, buffer, display,
+                   "Terminal type %s is not defined",
+                   "Terminal type %s is not defined.\n\
 If that is not the actual type of terminal you have,\n\
 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
 `setenv TERM ...') to specify the correct type.  It may be necessary\n\
 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
-               terminal_type);
+                   terminal_type);
 #endif
     }
 
@@ -2475,9 +2529,9 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   /* Since we make MagicWrap terminals look like AutoWrap, we need to have
      the former flag imply the latter.  */
   AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
-  FRAME_MEMORY_BELOW_FRAME (f) = tgetflag ("db");
+  display->memory_below_frame = tgetflag ("db");
   tty->TF_hazeltine = tgetflag ("hz");
-  FRAME_MUST_WRITE_SPACES (f) = tgetflag ("in");
+  display->must_write_spaces = tgetflag ("in");
   tty->meta_key = tgetflag ("km") || tgetflag ("MT");
   tty->TF_insmode_motion = tgetflag ("mi");
   tty->TF_standout_motion = tgetflag ("ms");
@@ -2500,22 +2554,13 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
     FrameRows (tty) = tgetnum ("li");
 
   if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
-    {
-      if (initialized)
-        {
-          delete_tty (tty);
-          error ("Screen size %dx%d is too small",
-                 FrameCols (tty), FrameRows (tty));
-        }
-      else
-        {
-          fatal ("Screen size %dx%d is too small",
+    maybe_fatal (must_succeed, NULL, display,
+                 "Screen size %dx%d is too small"
+                 "Screen size %dx%d is too small",
                  FrameCols (tty), FrameRows (tty));
-        }
-    }
 
 #if 0  /* This is not used anywhere. */
-  tty->display_method->min_padding_speed = tgetnum ("pb");
+  tty->display->min_padding_speed = tgetnum ("pb");
 #endif
 
   TabWidth (tty) = tgetnum ("tw");
@@ -2593,7 +2638,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
 
   if (!strcmp (terminal_type, "supdup"))
     {
-      FRAME_MEMORY_BELOW_FRAME (f) = 1;
+      display->memory_below_frame = 1;
       tty->Wcm->cm_losewrap = 1;
     }
   if (!strncmp (terminal_type, "c10", 3)
@@ -2620,7 +2665,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
            tty->TS_set_window = "\033v%C %C %C %C ";
        }
       /* Termcap entry often fails to have :in: flag */
-      FRAME_MUST_WRITE_SPACES (f) = 1;
+      display->must_write_spaces = 1;
       /* :ti string typically fails to have \E^G! in it */
       /* This limits scope of insert-char to one line.  */
       strcpy (area, tty->TS_termcap_modes);
@@ -2641,51 +2686,39 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   tty->specified_window = FrameRows (tty);
 
   if (Wcm_init (tty) == -1)    /* can't do cursor motion */
-    if (name)
-      {
-        delete_tty (tty);
-        error ("Terminal type \"%s\" is not powerful enough to run Emacs",
-               terminal_type);
-      }
-    else {
+    {
+      maybe_fatal (must_succeed, NULL, display,
+                   "Terminal type \"%s\" is not powerful enough to run Emacs",
 #ifdef VMS
-      fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
+                   "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
 It lacks the ability to position the cursor.\n\
 If that is not the actual type of terminal you have, use either the\n\
 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
 or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.",
-             terminal_type);
 #else /* not VMS */
 # ifdef TERMINFO
-      fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
+                   "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
 It lacks the ability to position the cursor.\n\
 If that is not the actual type of terminal you have,\n\
 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
 `setenv TERM ...') to specify the correct type.  It may be necessary\n\
 to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
-             terminal_type);
 # else /* TERMCAP */
-      fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
+                   "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
 It lacks the ability to position the cursor.\n\
 If that is not the actual type of terminal you have,\n\
 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
 `setenv TERM ...') to specify the correct type.  It may be necessary\n\
 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
-             terminal_type);
 # endif /* TERMINFO */
 #endif /*VMS */
+                   terminal_type);
     }
 
   if (FrameRows (tty) <= 0 || FrameCols (tty) <= 0)
-    {
-      if (name)
-        {
-          delete_tty (tty);
-          error ("The frame size has not been specified");
-        }
-      else
-        fatal ("The frame size has not been specified");
-    }
+    maybe_fatal (must_succeed, NULL, display,
+                 "Could not determine the frame size",
+                 "Could not determine the frame size");
 
   tty->delete_in_insert_mode
     = tty->TS_delete_mode && tty->TS_insert_mode
@@ -2697,36 +2730,30 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
 
   UseTabs (tty) = tabs_safe_p (fileno (TTY_INPUT (tty))) && TabWidth (tty) == 8;
 
-  FRAME_SCROLL_REGION_OK (f)
+  display->scroll_region_ok
     = (tty->Wcm->cm_abs
        && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
 
-  FRAME_LINE_INS_DEL_OK (f)
+  display->line_ins_del_ok
     = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
         && (tty->TS_del_line || tty->TS_del_multi_lines))
-       || (FRAME_SCROLL_REGION_OK (f)
+       || (display->scroll_region_ok
            && tty->TS_fwd_scroll && tty->TS_rev_scroll));
 
-  FRAME_CHAR_INS_DEL_OK (f)
+  display->char_ins_del_ok
     = ((tty->TS_ins_char || tty->TS_insert_mode
         || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
        && (tty->TS_del_char || tty->TS_del_multi_chars));
 
-  FRAME_FAST_CLEAR_END_OF_LINE (f) = tty->TS_clr_line != 0;
+  display->fast_clear_end_of_line = tty->TS_clr_line != 0;
 
   init_baud_rate (fileno (TTY_INPUT (tty)));
-  if (read_socket_hook)                /* Baudrate is somewhat
-                                   meaningless in this case */
-    baud_rate = 9600;
-
-  FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
-  FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
 
 #ifdef AIXHFT
   /* The HFT system on AIX doesn't optimize for scrolling, so it's
      really ugly at times.  */
-  FRAME_LINE_INS_DEL_OK (f) = 0;
-  FRAME_CHAR_INS_DEL_OK (f) = 0;
+  display->line_ins_del_ok = 0;
+  display->char_ins_del_ok = 0;
 #endif
 
 #ifdef MULTI_KBOARD
@@ -2745,18 +2772,38 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   /* Don't do this.  I think termcap may still need the buffer. */
   /* xfree (buffer); */
 
-  /* Set the top frame to the first frame on this display. */
-  tty->top_frame = frame;
-
   /* Init system terminal modes (RAW or CBREAK, etc.).  */
   init_sys_modes (tty);
 
-  tty_set_terminal_modes (tty);
-
-  return tty;
+  return display;
 #endif /* not WINDOWSNT */
 }
 
+/* Auxiliary error-handling function for term_init.
+   Free BUFFER and delete DISPLAY, then call error or fatal
+   with str1 or str2, respectively, according to MUST_SUCCEED.  */
+
+static void
+maybe_fatal (must_succeed, buffer, display, str1, str2, arg1, arg2)
+     int must_succeed;
+     char *buffer;
+     struct display *display;
+     char *str1, *str2, *arg1, *arg2;
+{
+  if (buffer)
+    xfree (buffer);
+
+  if (display)
+    delete_tty (display);
+  
+  if (must_succeed)
+    fatal (str2, arg1, arg2);
+  else
+    error (str1, arg1, arg2);
+
+  abort ();
+}
+
 /* VARARGS 1 */
 void
 fatal (str, arg1, arg2)
@@ -2772,11 +2819,15 @@ fatal (str, arg1, arg2)
 \f
 
 DEFUN ("delete-tty", Fdelete_tty, Sdelete_tty, 0, 1, 0,
-       doc: /* Delete all frames on the terminal named TTY, and close the device. */)
+       doc: /* Delete all frames on the terminal named TTY, and close the device.
+If omitted, TTY defaults to the controlling terminal.
+
+This function runs `delete-tty-after-functions' after closing the
+tty.  The functions are run with one arg, the frame to be deleted.  */)
   (tty)
      Lisp_Object tty;
 {
-  struct tty_display_info *t;
+  struct display *d;
   char *name = 0;
 
   CHECK_STRING (tty);
@@ -2788,28 +2839,38 @@ DEFUN ("delete-tty", Fdelete_tty, Sdelete_tty, 0, 1, 0,
       name[SBYTES (tty)] = 0;
     }
 
-  t = get_named_tty (name);
+  d = get_named_tty_display (name);
 
-  if (! t)
-    error ("No such tty device: %s", name);
+  if (! d)
+    error ("No such terminal device: %s", name);
 
-  delete_tty (t);
+  delete_tty (d);
 }
 
 static int deleting_tty = 0;
 
+
+/* Delete the given terminal device, closing all frames on it. */
+
 void
-delete_tty (struct tty_display_info *tty)
+delete_tty (struct display *display)
 {
+  struct tty_display_info *tty;
   Lisp_Object tail, frame;
-
+  char *tty_name;
+  
   if (deleting_tty)
     /* We get a recursive call when we delete the last frame on this
-       tty. */
+       display. */
     return;
 
   deleting_tty = 1;
 
+  if (display->type != output_termcap)
+    abort ();
+
+  tty = display->display_info.tty;
+  
   if (tty == tty_list)
     tty_list = tty->next;
   else
@@ -2832,14 +2893,16 @@ delete_tty (struct tty_display_info *tty)
       if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f) && FRAME_TTY (f) == tty)
         {
           Fdelete_frame (frame, Qt);
-          f->output_data.tty = 0;
         }
     }
 
+  /* reset_sys_modes needs a valid display, so this call needs to be
+     before delete_display. */
   reset_sys_modes (tty);
 
-  if (tty->name)
-    xfree (tty->name);
+  delete_display (display);
+
+  tty_name = tty->name;
   if (tty->type)
     xfree (tty->type);
 
@@ -2860,9 +2923,6 @@ delete_tty (struct tty_display_info *tty)
   if (tty->Wcm)
     xfree (tty->Wcm);
 
-  if (tty->display_method)
-    xfree (tty->display_method);
-
 #ifdef MULTI_KBOARD
   if (tty->kboard && --tty->kboard->reference_count > 0)
     abort ();
@@ -2873,6 +2933,53 @@ delete_tty (struct tty_display_info *tty)
   bzero (tty, sizeof (struct tty_display_info));
   xfree (tty);
   deleting_tty = 0;
+
+  /* Run `delete-tty-after-functions'.  */
+  if (!NILP (Vrun_hooks))
+    {
+      Lisp_Object args[2];
+      args[0] = intern ("delete-tty-after-functions");
+      if (tty_name)
+        {
+          args[1] = build_string (tty_name);
+          xfree (tty_name);
+        }
+      else
+        args[1] = Qnil;
+      Frun_hook_with_args (2, args);
+    }
+}
+
+\f
+
+/* Initialize the tty-dependent part of frame F.  The frame must
+   already have its display initialized. */
+
+void
+create_tty_output (struct frame *f)
+{
+  struct tty_output *t;
+
+  if (! FRAME_TERMCAP_P (f))
+    abort ();
+
+  t = xmalloc (sizeof (struct tty_output));
+  bzero (t, sizeof (struct tty_output));
+
+  t->display_info = FRAME_DISPLAY (f)->display_info.tty;
+
+  f->output_data.tty = t;
+}
+
+/* Delete the tty-dependent part of frame F. */
+
+void
+delete_tty_output (struct frame *f)
+{
+  if (! FRAME_TERMCAP_P (f))
+    abort ();
+
+  xfree (f->output_data.tty);
 }
 
 
@@ -2880,6 +2987,7 @@ delete_tty (struct tty_display_info *tty)
 
 /* Mark the pointers in the tty_display_info objects.
    Called by the Fgarbage_collector.  */
+
 void
 mark_ttys ()
 {
@@ -2892,6 +3000,50 @@ mark_ttys ()
     }
 }
 
+\f
+
+/* Create a new display object and add it to the display list. */
+
+struct display *
+create_display (void)
+{
+  struct display *dev = (struct display *) xmalloc (sizeof (struct display));
+  
+  bzero (dev, sizeof (struct display));
+  dev->next_display = display_list;
+  display_list = dev;
+
+  return dev;
+}
+
+/* Remove a display from the display list and free its memory. */
+
+void
+delete_display (struct display *dev)
+{
+  struct display **dp;
+  Lisp_Object tail, frame;
+  
+  /* Check for and close live frames that are still on this
+     display. */
+  FOR_EACH_FRAME (tail, frame)
+    {
+      struct frame *f = XFRAME (frame);
+      if (FRAME_LIVE_P (f) && f->display == dev)
+        {
+          Fdelete_frame (frame, Qt);
+        }
+    }
+
+  for (dp = &display_list; *dp != dev; dp = &(*dp)->next_display)
+    if (! *dp)
+      abort ();
+  *dp = dev->next_display;
+
+  bzero (dev, sizeof (struct display));
+  xfree (dev);
+}
+
 
 \f
 void
@@ -2911,6 +3063,12 @@ This variable can be used by terminal emulator packages.  */);
 The function should accept no arguments.  */);
   Vring_bell_function = Qnil;
 
+  DEFVAR_LISP ("delete-tty-after-functions", &Vdelete_tty_after_functions,
+    doc: /* Functions to be run after deleting a tty.
+The functions are run with one argument, the name of the tty to be deleted.
+See `delete-tty'.  */);
+  Vdelete_tty_after_functions = Qnil;
+
   Qframe_tty_name = intern ("frame-tty-name");
   staticpro (&Qframe_tty_name);
 
@@ -2925,11 +3083,6 @@ The function should accept no arguments.  */);
 
   Fprovide (intern ("multi-tty"), Qnil);
 
-  /* Initialize the display method template. */
-  
-  /* Termcap-based displays don't support window-based redisplay. */
-  tty_display_method_template.rif = 0;
-
 }