]> code.delx.au - gnu-emacs/blobdiff - src/term.c
Merged in changes from CVS trunk.
[gnu-emacs] / src / term.c
index e3b176c51ea181c0b4a6e12fd1817c8df2cd270c..899829ebadb29b6b7890f915eb5e9854fb8ff5e3 100644 (file)
@@ -29,7 +29,12 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/file.h>
 
 #include <unistd.h>             /* For isatty. */
-#include <sys/ioctl.h>          /* For TIOCNOTTY. */
+
+#if HAVE_TERMIOS_H
+#include <termios.h>           /* For TIOCNOTTY. */
+#endif
+
+#include <signal.h>
 
 #include "lisp.h"
 #include "termchar.h"
@@ -43,6 +48,8 @@ Boston, MA 02111-1307, USA.  */
 #include "dispextern.h"
 #include "window.h"
 #include "keymap.h"
+#include "syssignal.h"
+#include "systty.h"
 
 /* For now, don't try to include termcap.h.  On some systems,
    configure finds a non-standard termcap.h that the main build
@@ -78,6 +85,8 @@ 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 *));
 
+static struct display *get_tty_display (Lisp_Object display);
+
 void delete_initial_display P_ ((struct display *));
 void create_tty_output P_ ((struct frame *));
 void delete_tty_output P_ ((struct frame *));
@@ -102,12 +111,19 @@ void delete_tty_output P_ ((struct frame *));
 
 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
 
+/* Display space properties */
+
+extern Lisp_Object Qspace, QCalign_to, QCwidth;
+
 /* Function to use to ring the bell.  */
 
 Lisp_Object Vring_bell_function;
 
-/* Functions to call after a tty was deleted. */
-Lisp_Object Vdelete_tty_after_functions;
+/* Functions to call after suspending a tty. */
+Lisp_Object Vsuspend_tty_functions;
+
+/* Functions to call after resuming a tty. */
+Lisp_Object Vresume_tty_functions;
 
 /* Chain of all displays currently in use. */
 struct display *display_list;
@@ -124,9 +140,6 @@ struct tty_display_info *tty_list;
    else. */
 int no_redraw_on_reenter;
 
-Lisp_Object Qframe_tty_name, Qframe_tty_type;
-
-
 
 /* Meaning of bits in no_color_video.  Each bit set means that the
    corresponding attribute cannot be combined with colors.  */
@@ -154,15 +167,13 @@ int max_frame_cols;
 
 int max_frame_lines;
 
-/* Frame currently being redisplayed; 0 if not currently redisplaying.
-   (Direct output does not count).  */
-
-FRAME_PTR updating_frame;
-
 /* Non-zero if we have dropped our controlling tty and therefore
    should not open a frame on stdout. */
 static int no_controlling_tty;
 
+/* The first unallocated display id. */
+static int next_display_id;
+
 /* Provided for lisp packages.  */
 
 static int system_uses_terminfo;
@@ -184,10 +195,8 @@ extern char *tgetstr ();
 #endif /* WINDOWSNT */
 
 void
-ring_bell ()
+ring_bell (struct frame *f)
 {
-  struct frame *f = XFRAME (selected_frame);
-
   if (!NILP (Vring_bell_function))
     {
       Lisp_Object function;
@@ -208,20 +217,23 @@ ring_bell ()
       Vring_bell_function = function;
     }
   else if (FRAME_DISPLAY (f)->ring_bell_hook)
-    (*FRAME_DISPLAY (f)->ring_bell_hook) ();
+    (*FRAME_DISPLAY (f)->ring_bell_hook) (f);
 }
 
 /* Ring the bell on a tty. */
 
 void
-tty_ring_bell ()
+tty_ring_bell (struct frame *f)
 {
-  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));
+  if (tty->output)
+    {
+      OUTPUT (tty, (tty->TS_visible_bell && visible_bell
+                    ? tty->TS_visible_bell
+                    : tty->TS_bell));
+      fflush (tty->output);
+    }
 }
 
 /* Set up termcap modes for Emacs. */
@@ -231,10 +243,13 @@ 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);
+  if (tty->output)
+    {
+      OUTPUT_IF (tty, tty->TS_termcap_modes);
+      OUTPUT_IF (tty, tty->TS_cursor_visible);
+      OUTPUT_IF (tty, tty->TS_keypad_mode);
+      losecursor (tty);
+    }
 }
 
 /* Reset termcap modes before exiting Emacs. */
@@ -243,34 +258,33 @@ 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);
-  OUTPUT_IF (tty, tty->TS_cursor_normal);
-  OUTPUT_IF (tty, tty->TS_end_termcap_modes);
-  OUTPUT_IF (tty, tty->TS_orig_pair);
-  /* Output raw CR so kernel can track the cursor hpos.  */
-  current_tty = tty;
-  cmputc ('\r');
+
+  if (tty->output)
+    {
+      turn_off_highlight (tty);
+      turn_off_insert (tty);
+      OUTPUT_IF (tty, tty->TS_end_keypad_mode);
+      OUTPUT_IF (tty, tty->TS_cursor_normal);
+      OUTPUT_IF (tty, tty->TS_end_termcap_modes);
+      OUTPUT_IF (tty, tty->TS_orig_pair);
+      /* Output raw CR so kernel can track the cursor hpos.  */
+      current_tty = tty;
+      cmputc ('\r');
+    }
 }
 
 void
-update_begin (f)
-     struct frame *f;
+update_begin (struct frame *f)
 {
-  updating_frame = f;
   if (FRAME_DISPLAY (f)->update_begin_hook)
     (*FRAME_DISPLAY (f)->update_begin_hook) (f);
 }
 
 void
-update_end (f)
-     struct frame *f;
+update_end (struct frame *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. */
@@ -292,36 +306,28 @@ tty_update_end (struct frame *f)
    that is bounded by calls to update_begin and update_end.  */
 
 void
-set_terminal_window (size)
-     int size;
+set_terminal_window (struct frame *f, int 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);
+    (*FRAME_DISPLAY (f)->set_terminal_window_hook) (f, size);
 }
 
 /* The implementation of set_terminal_window for termcap frames. */
 
 void
-tty_set_terminal_window (int size)
+tty_set_terminal_window (struct frame *f, 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);
+    set_scroll_region (f, 0, tty->specified_window);
 }
 
 void
-set_scroll_region (start, stop)
-     int start, stop;
+set_scroll_region (struct frame *f, int start, int stop)
 {
   char *buf;
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   struct tty_display_info *tty = FRAME_TTY (f);
 
   if (tty->TS_set_scroll_region)
@@ -440,20 +446,15 @@ highlight_if_desired (struct tty_display_info *tty)
    frame-relative coordinates.  */
 
 void
-cursor_to (vpos, hpos)
-     int vpos, hpos;
+cursor_to (struct frame *f, int vpos, int hpos)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   if (FRAME_DISPLAY (f)->cursor_to_hook)
-    (*FRAME_DISPLAY (f)->cursor_to_hook) (vpos, hpos);
+    (*FRAME_DISPLAY (f)->cursor_to_hook) (f, vpos, hpos);
 }
 
 void
-tty_cursor_to (int vpos, int hpos)
+tty_cursor_to (struct frame *f, 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
@@ -474,20 +475,15 @@ tty_cursor_to (int vpos, int hpos)
 /* Similar but don't take any account of the wasted characters.  */
 
 void
-raw_cursor_to (row, col)
-     int row, col;
+raw_cursor_to (struct frame *f, int row, int col)
 {
-  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);  
+    (*FRAME_DISPLAY (f)->raw_cursor_to_hook) (f, row, col);  
 }
 
 void
-tty_raw_cursor_to (int row, int col)
+tty_raw_cursor_to (struct frame *f, 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
@@ -504,21 +500,18 @@ tty_raw_cursor_to (int row, int col)
 
 /* Clear from cursor to end of frame. */
 void
-clear_to_end ()
+clear_to_end (struct frame *f)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   if (FRAME_DISPLAY (f)->clear_to_end_hook)
-    (*FRAME_DISPLAY (f)->clear_to_end_hook) ();
+    (*FRAME_DISPLAY (f)->clear_to_end_hook) (f);
 }
 
 /* Clear from cursor to end of frame on a termcap device. */
 
 void
-tty_clear_to_end (void)
+tty_clear_to_end (struct frame *f)
 {
   register int i;
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
   struct tty_display_info *tty = FRAME_TTY (f);
 
   if (tty->TS_clr_to_bottom)
@@ -530,8 +523,8 @@ tty_clear_to_end (void)
     {
       for (i = curY (tty); i < FRAME_LINES (f); i++)
        {
-         cursor_to (i, 0);
-         clear_end_of_line (FRAME_COLS (f));
+         cursor_to (f, i, 0);
+         clear_end_of_line (f, FRAME_COLS (f));
        }
     }
 }
@@ -539,21 +532,17 @@ tty_clear_to_end (void)
 /* Clear entire frame */
 
 void
-clear_frame ()
+clear_frame (struct frame *f)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   if (FRAME_DISPLAY (f)->clear_frame_hook)
-    (*FRAME_DISPLAY (f)->clear_frame_hook) ();
+    (*FRAME_DISPLAY (f)->clear_frame_hook) (f);
 }
 
 /* Clear an entire termcap frame. */
 
 void
-tty_clear_frame ()
+tty_clear_frame (struct frame *f)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   struct tty_display_info *tty = FRAME_TTY (f);
 
   if (tty->TS_clr_frame)
@@ -564,8 +553,8 @@ tty_clear_frame ()
     }
   else
     {
-      cursor_to (0, 0);
-      clear_to_end ();
+      cursor_to (f, 0, 0);
+      clear_to_end (f);
     }
 }
 
@@ -575,13 +564,10 @@ tty_clear_frame ()
    Note that the cursor may be moved, on terminals lacking a `ce' string.  */
 
 void
-clear_end_of_line (first_unused_hpos)
-     int first_unused_hpos;
+clear_end_of_line (struct frame *f, int first_unused_hpos)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   if (FRAME_DISPLAY (f)->clear_end_of_line_hook)
-    (*FRAME_DISPLAY (f)->clear_end_of_line_hook) (first_unused_hpos);
+    (*FRAME_DISPLAY (f)->clear_end_of_line_hook) (f, first_unused_hpos);
 }
 
 /* An implementation of clear_end_of_line for termcap frames.
@@ -589,10 +575,9 @@ clear_end_of_line (first_unused_hpos)
    Note that the cursor may be moved, on terminals lacking a `ce' string.  */
 
 void
-tty_clear_end_of_line (int first_unused_hpos)
+tty_clear_end_of_line (struct frame *f, 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
@@ -619,9 +604,9 @@ tty_clear_end_of_line (int first_unused_hpos)
 
       for (i = curX (tty); i < first_unused_hpos; i++)
        {
-         if (TTY_TERMSCRIPT (tty))
-           fputc (' ', TTY_TERMSCRIPT (tty));
-         fputc (' ', TTY_OUTPUT (tty));
+         if (tty->termscript)
+           fputc (' ', tty->termscript);
+         fputc (' ', tty->output);
        }
       cmplus (tty, first_unused_hpos - curX (tty));
     }
@@ -636,11 +621,12 @@ tty_clear_end_of_line (int first_unused_hpos)
    return value is the number of bytes store in DST.  */
 
 int
-encode_terminal_code (src, dst, src_len, dst_len, consumed)
-     struct glyph *src;
-     int src_len;
-     unsigned char *dst;
-     int dst_len, *consumed;
+encode_terminal_code (struct coding_system *coding,
+                      struct glyph *src,
+                      unsigned char *dst,
+                      int src_len,
+                      int dst_len,
+                      int *consumed)
 {
   struct glyph *src_start = src, *src_end = src + src_len;
   unsigned char *dst_start = dst, *dst_end = dst + dst_len;
@@ -651,13 +637,12 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
   int result;
-  struct coding_system *coding;
 
-  /* If terminal_coding does any conversion, use it, otherwise use
+  /* If the specified coding does any conversion, use it, otherwise use
      safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
-     because it always return 1 if the member src_multibyte is 1.  */
-  coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
-           ? &terminal_coding
+     because it always returns 1 if the member src_multibyte is 1.  */
+  coding = (coding->common_flags & CODING_REQUIRE_ENCODING_MASK
+           ? coding
            : &safe_terminal_coding);
 
   while (src < src_end)
@@ -740,27 +725,21 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
    Advance the nominal cursor over the text.  */
 
 void
-write_glyphs (string, len)
-     register struct glyph *string;
-     register int len;
+write_glyphs (struct frame *f, struct glyph *string, 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);
+    (*FRAME_DISPLAY (f)->write_glyphs_hook) (f, string, len);
 }
 
 /* An implementation of write_glyphs for termcap frames. */
 
 void
-tty_write_glyphs (struct glyph *string, int len)
+tty_write_glyphs (struct frame *f, struct glyph *string, int len)
 {
   int produced, consumed;
   unsigned char conversion_buffer[1024];
   int conversion_buffer_size = sizeof conversion_buffer;
 
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   struct tty_display_info *tty = FRAME_TTY (f);
 
   turn_off_insert (tty);
@@ -780,7 +759,7 @@ tty_write_glyphs (struct glyph *string, int len)
 
   /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
      the tail.  */
-  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
+  FRAME_TERMINAL_CODING (f)->mode &= ~CODING_MODE_LAST_BLOCK;
 
   while (len > 0)
     {
@@ -801,18 +780,19 @@ tty_write_glyphs (struct glyph *string, int len)
          /* We use a fixed size (1024 bytes) of conversion buffer.
             Usually it is sufficient, but if not, we just repeat the
             loop.  */
-         produced = encode_terminal_code (string, conversion_buffer,
+         produced = encode_terminal_code (FRAME_TERMINAL_CODING (f),
+                                           string, conversion_buffer,
                                           n, conversion_buffer_size,
                                           &consumed);
          if (produced > 0)
            {
              fwrite (conversion_buffer, 1, produced,
-                      TTY_OUTPUT (tty));
-             if (ferror (TTY_OUTPUT (tty)))
-               clearerr (TTY_OUTPUT (tty));
-             if (TTY_TERMSCRIPT (tty))
+                      tty->output);
+             if (ferror (tty->output))
+               clearerr (tty->output);
+             if (tty->termscript)
                fwrite (conversion_buffer, 1, produced,
-                        TTY_TERMSCRIPT (tty));
+                        tty->termscript);
            }
          len -= consumed;
          n -= consumed;
@@ -825,20 +805,22 @@ tty_write_glyphs (struct glyph *string, int len)
     }
 
   /* We may have to output some codes to terminate the writing.  */
-  if (CODING_REQUIRE_FLUSHING (&terminal_coding))
+  if (CODING_REQUIRE_FLUSHING (FRAME_TERMINAL_CODING (f)))
     {
-      terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
-      encode_coding (&terminal_coding, "", conversion_buffer,
-                    0, conversion_buffer_size);
-      if (terminal_coding.produced > 0)
+      FRAME_TERMINAL_CODING (f)->mode |= CODING_MODE_LAST_BLOCK;
+      encode_coding (FRAME_TERMINAL_CODING (f), "",
+                     conversion_buffer, 0, conversion_buffer_size);
+      if (FRAME_TERMINAL_CODING (f)->produced > 0)
        {
-         fwrite (conversion_buffer, 1, terminal_coding.produced,
-                  TTY_OUTPUT (tty));
-         if (ferror (TTY_OUTPUT (tty)))
-           clearerr (TTY_OUTPUT (tty));
-         if (TTY_TERMSCRIPT (tty))
-           fwrite (conversion_buffer, 1, terminal_coding.produced,
-                   TTY_TERMSCRIPT (tty));
+         fwrite (conversion_buffer, 1,
+                  FRAME_TERMINAL_CODING (f)->produced,
+                  tty->output);
+         if (ferror (tty->output))
+           clearerr (tty->output);
+         if (tty->termscript)
+           fwrite (conversion_buffer, 1,
+                    FRAME_TERMINAL_CODING (f)->produced,
+                   tty->termscript);
        }
     }
 
@@ -850,27 +832,22 @@ tty_write_glyphs (struct glyph *string, int len)
    If start is zero, insert blanks instead of a string at start */
 
 void
-insert_glyphs (start, len)
-     register struct glyph *start;
-     register int len;
+insert_glyphs (struct frame *f, struct glyph *start, int len)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-
   if (len <= 0)
     return;
 
   if (FRAME_DISPLAY (f)->insert_glyphs_hook)
-    (*FRAME_DISPLAY (f)->insert_glyphs_hook) (start, len);
+    (*FRAME_DISPLAY (f)->insert_glyphs_hook) (f, start, len);
 }
 
 /* An implementation of insert_glyphs for termcap frames. */
 
 void
-tty_insert_glyphs (struct glyph *start, int len)
+tty_insert_glyphs (struct frame *f, struct glyph *start, int len)
 {
   char *buf;
   struct glyph *glyph = NULL;
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
 
   struct tty_display_info *tty = FRAME_TTY (f);
 
@@ -880,14 +857,14 @@ tty_insert_glyphs (struct glyph *start, int len)
       OUTPUT1 (tty, buf);
       xfree (buf);
       if (start)
-       write_glyphs (start, len);
+       write_glyphs (f, start, len);
       return;
     }
 
   turn_on_insert (tty);
   cmplus (tty, len);
   /* The bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail.  */
-  terminal_coding.mode &= ~CODING_MODE_LAST_BLOCK;
+  FRAME_TERMINAL_CODING (f)->mode &= ~CODING_MODE_LAST_BLOCK;
   while (len-- > 0)
     {
       int produced, consumed;
@@ -916,23 +893,24 @@ tty_insert_glyphs (struct glyph *start, int len)
 
          if (len <= 0)
            /* This is the last glyph.  */
-           terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
+           FRAME_TERMINAL_CODING (f)->mode |= CODING_MODE_LAST_BLOCK;
 
          /* The size of conversion buffer (1024 bytes) is surely
             sufficient for just one glyph.  */
-         produced = encode_terminal_code (glyph, conversion_buffer, 1,
+         produced = encode_terminal_code (FRAME_TERMINAL_CODING (f),
+                                           glyph, conversion_buffer, 1,
                                           conversion_buffer_size, &consumed);
        }
 
       if (produced > 0)
        {
          fwrite (conversion_buffer, 1, produced,
-                  TTY_OUTPUT (tty));
-         if (ferror (TTY_OUTPUT (tty)))
-           clearerr (TTY_OUTPUT (tty));
-         if (TTY_TERMSCRIPT (tty))
+                  tty->output);
+         if (ferror (tty->output))
+           clearerr (tty->output);
+         if (tty->termscript)
            fwrite (conversion_buffer, 1, produced,
-                    TTY_TERMSCRIPT (tty));
+                    tty->termscript);
        }
 
       OUTPUT1_IF (tty, tty->TS_pad_inserted_char);
@@ -949,23 +927,19 @@ tty_insert_glyphs (struct glyph *start, int len)
 /* Delete N glyphs at the nominal cursor position. */
 
 void
-delete_glyphs (n)
-     register int n;
+delete_glyphs (struct frame *f, 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);
+    (*FRAME_DISPLAY (f)->delete_glyphs_hook) (f, n);
 }
 
 /* An implementation of delete_glyphs for termcap frames. */
 
 void
-tty_delete_glyphs (int n)
+tty_delete_glyphs (struct frame *f, 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);
 
@@ -995,22 +969,17 @@ tty_delete_glyphs (int n)
 /* Insert N lines at vpos VPOS.  If N is negative, delete -N lines.  */
 
 void
-ins_del_lines (vpos, n)
-     int vpos, n;
+ins_del_lines (struct frame *f, int vpos, int n)
 {
-  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);
+    (*FRAME_DISPLAY (f)->ins_del_lines_hook) (f, vpos, n);
 }
 
 /* An implementation of ins_del_lines for termcap frames. */
 
 void
-tty_ins_del_lines (int vpos, int n)
+tty_ins_del_lines (struct frame *f, 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;
@@ -1035,7 +1004,7 @@ tty_ins_del_lines (int vpos, int n)
   
   if (multi)
     {
-      raw_cursor_to (vpos, 0);
+      raw_cursor_to (f, vpos, 0);
       background_highlight (tty);
       buf = tparam (multi, 0, 0, i);
       OUTPUT (tty, buf);
@@ -1043,7 +1012,7 @@ tty_ins_del_lines (int vpos, int n)
     }
   else if (single)
     {
-      raw_cursor_to (vpos, 0);
+      raw_cursor_to (f, vpos, 0);
       background_highlight (tty);
       while (--i >= 0)
         OUTPUT (tty, single);
@@ -1052,23 +1021,23 @@ tty_ins_del_lines (int vpos, int n)
     }
   else
     {
-      set_scroll_region (vpos, tty->specified_window);
+      set_scroll_region (f, vpos, tty->specified_window);
       if (n < 0)
-        raw_cursor_to (tty->specified_window - 1, 0);
+        raw_cursor_to (f, tty->specified_window - 1, 0);
       else
-        raw_cursor_to (vpos, 0);
+        raw_cursor_to (f, vpos, 0);
       background_highlight (tty);
       while (--i >= 0)
         OUTPUTL (tty, scroll, tty->specified_window - vpos);
-      set_scroll_region (0, tty->specified_window);
+      set_scroll_region (f, 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 ();
+      cursor_to (f, FRAME_LINES (f) + n, 0);
+      clear_to_end (f);
     }
 }
 \f
@@ -1076,8 +1045,7 @@ tty_ins_del_lines (int vpos, int n)
    not counting any line-dependent padding.  */
 
 int
-string_cost (str)
-     char *str;
+string_cost (char *str)
 {
   cost = 0;
   if (str)
@@ -1089,8 +1057,7 @@ string_cost (str)
    counting any line-dependent padding at one line.  */
 
 static int
-string_cost_one_line (str)
-     char *str;
+string_cost_one_line (char *str)
 {
   cost = 0;
   if (str)
@@ -1102,8 +1069,7 @@ string_cost_one_line (str)
    in tenths of characters.  */
 
 int
-per_line_cost (str)
-     register char *str;
+per_line_cost (char *str)
 {
   cost = 0;
   if (str)
@@ -1126,8 +1092,7 @@ int *char_ins_del_vector;
 
 /* ARGSUSED */
 static void
-calculate_ins_del_char_costs (f)
-     FRAME_PTR f;
+calculate_ins_del_char_costs (struct frame *f)
 {
   struct tty_display_info *tty = FRAME_TTY (f);
   int ins_startup_cost, del_startup_cost;
@@ -1188,8 +1153,7 @@ calculate_ins_del_char_costs (f)
 }
 
 void
-calculate_costs (frame)
-     FRAME_PTR frame;
+calculate_costs (struct frame *frame)
 {
   FRAME_COST_BAUD_RATE (frame) = baud_rate;
 
@@ -1481,6 +1445,7 @@ term_get_fkeys_1 ()
  ***********************************************************************/
 
 static void append_glyph P_ ((struct it *));
+static void produce_stretch_glyph P_ ((struct it *));
 
 
 /* Append glyphs to IT's glyph_row.  Called from produce_glyphs for
@@ -1544,9 +1509,14 @@ produce_glyphs (it)
   /* If a hook is installed, let it do the work.  */
   xassert (it->what == IT_CHARACTER
           || it->what == IT_COMPOSITION
-          || it->what == IT_IMAGE
           || it->what == IT_STRETCH);
 
+  if (it->what == IT_STRETCH)
+    {
+      produce_stretch_glyph (it);
+      goto done;
+    }
+
   /* Nothing but characters are supported on terminal frames.  For a
      composition sequence, it->c is the first character of the
      sequence.  */
@@ -1620,6 +1590,7 @@ produce_glyphs (it)
        append_glyph (it);
     }
 
+ done:
   /* Advance current_x by the pixel width as a convenience for
      the caller.  */
   if (it->area == TEXT_AREA)
@@ -1629,6 +1600,81 @@ produce_glyphs (it)
 }
 
 
+/* Produce a stretch glyph for iterator IT.  IT->object is the value
+   of the glyph property displayed.  The value must be a list
+   `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+   being recognized:
+
+   1. `:width WIDTH' specifies that the space should be WIDTH *
+   canonical char width wide.  WIDTH may be an integer or floating
+   point number.
+
+   2. `:align-to HPOS' specifies that the space should be wide enough
+   to reach HPOS, a value in canonical character units.  */
+
+static void
+produce_stretch_glyph (it)
+     struct it *it;
+{
+  /* (space :width WIDTH ...)  */
+  Lisp_Object prop, plist;
+  int width = 0, align_to = -1;
+  int zero_width_ok_p = 0;
+  double tem;
+
+  /* List should start with `space'.  */
+  xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+  plist = XCDR (it->object);
+
+  /* Compute the width of the stretch.  */
+  if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
+      && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
+    {
+      /* Absolute width `:width WIDTH' specified and valid.  */
+      zero_width_ok_p = 1;
+      width = (int)(tem + 0.5);
+    }
+  else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
+          && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
+    {
+      if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
+       align_to = (align_to < 0 
+                   ? 0
+                   : align_to - window_box_left_offset (it->w, TEXT_AREA));
+      else if (align_to < 0)
+       align_to = window_box_left_offset (it->w, TEXT_AREA);
+      width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
+      zero_width_ok_p = 1;
+    }
+  else
+    /* Nothing specified -> width defaults to canonical char width.  */
+    width = FRAME_COLUMN_WIDTH (it->f);
+
+  if (width <= 0 && (width < 0 || !zero_width_ok_p))
+    width = 1;
+
+  if (width > 0 && it->glyph_row)
+    {
+      Lisp_Object o_object = it->object;
+      Lisp_Object object = it->stack[it->sp - 1].string;
+      int n = width;
+      int c = it->c;
+
+      if (!STRINGP (object))
+       object = it->w->buffer;
+      it->object = object;
+      it->c = ' ';
+      it->pixel_width = it->len = 1;
+      while (n--)
+       append_glyph (it);
+      it->object = o_object;
+      it->c = c;
+    }
+  it->pixel_width = width;
+  it->nglyphs = width;
+}
+
+
 /* Get information about special display element WHAT in an
    environment described by IT.  WHAT is one of IT_TRUNCATION or
    IT_CONTINUATION.  Maybe produce glyphs for WHAT if IT has a
@@ -1881,58 +1927,11 @@ tty_capable_p (tty, caps, fg, bg)
   return 1;
 }
 
-/* Return the tty display object specified by DISPLAY.  DISPLAY may be
-   a frame, a string, or nil for the display device of the current
-   frame. */
-
-static struct display *
-get_tty_display (Lisp_Object display)
-{
-  struct display *d;
-
-  if (NILP (display))
-    display = selected_frame;
-
-  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.  */
 
 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
        0, 1, 0,
-       doc: /* Return non-nil if TTY can display colors on DISPLAY.  */)
+       doc: /* Return non-nil if the tty device that DISPLAY uses can display colors. */)
      (display)
      Lisp_Object display;
 {
@@ -1946,13 +1945,13 @@ DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
 /* Return the number of supported colors.  */
 DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
        Stty_display_color_cells, 0, 1, 0,
-       doc: /* Return the number of colors supported by TTY on DISPLAY.  */)
+       doc: /* Return the number of colors supported by the tty device that DISPLAY uses.  */)
      (display)
      Lisp_Object display;
 {
   struct display *d = get_tty_display (display);
   if (!d)
-    return Qnil;
+    return make_number (0);
   else
     return make_number (d->display_info.tty->TN_max_colors);
 }
@@ -2096,8 +2095,65 @@ set_tty_color_mode (f, val)
 
 \f
 
-/* Return the termcap display with the given name.  If NAME is null,
-   return the display corresponding to our controlling terminal.
+/* Return the display object specified by DISPLAY.  DISPLAY may be a
+   display id, a frame, or nil for the display device of the current
+   frame. */
+
+struct display *
+get_display (Lisp_Object display)
+{
+  if (NILP (display))
+    display = selected_frame;
+
+  if (! INTEGERP (display) && ! FRAMEP (display))
+    return NULL;
+
+  if (INTEGERP (display))
+    {
+      struct display *d;
+
+      for (d = display_list; d; d = d->next_display)
+        {
+          if (d->id == XINT (display))
+            return d;
+        }
+      return NULL;
+    }
+  else if (FRAMEP (display))
+    {
+      return FRAME_DISPLAY (XFRAME (display));
+    }
+  return NULL;
+}
+
+/* Return the tty display object specified by DISPLAY. */
+
+static struct display *
+get_tty_display (Lisp_Object display)
+{
+  struct display *d = get_display (display);
+  
+  if (d && d->type == output_initial)
+    d = NULL;
+
+  if (d && d->type != output_termcap)
+    {
+#if 0   /* XXX We need a predicate as the first argument; find one. */
+      wrong_type_argument ("Not a termcap display", display);
+#else /* Until we fix the wrong_type_argument call above, simply throw
+         a dumb error. */
+      error ("DISPLAY is not a termcap display");
+#endif
+    }
+
+  return d;
+}
+
+/* Return the active termcap display that uses the tty device with the
+   given name.  If NAME is NULL, return the display corresponding to
+   our controlling terminal.
+
+   This function ignores suspended displays.
 
    Returns NULL if the named terminal device is not opened.  */
  
@@ -2111,7 +2167,8 @@ get_named_tty_display (name)
     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))))
+                && !strcmp (d->display_info.tty->name, name)))
+        && DISPLAY_ACTIVE_P (d))
       return d;
   };
 
@@ -2120,56 +2177,58 @@ get_named_tty_display (name)
 
 \f
 
-DEFUN ("frame-tty-name", Fframe_tty_name, Sframe_tty_name, 0, 1, 0,
-       doc: /* Return the name of the TTY device that FRAME is displayed on. */)
-  (frame)
-     Lisp_Object frame;
-{
-  struct frame *f;
+DEFUN ("display-name", Fdisplay_name, Sdisplay_name, 0, 1, 0,
+       doc: /* Return the name of the device that DISPLAY uses.
+It is not guaranteed that the returned value is unique among opened displays.
 
-  if (NILP (frame))
-    {
-      f = XFRAME (selected_frame);
-    }
-  else
-    {
-      CHECK_LIVE_FRAME (frame);
-      f = XFRAME (frame);
-    }
+DISPLAY can be a display, a frame, or nil (meaning the selected
+frame's display). */)
+  (display)
+     Lisp_Object display;
+{
+  struct display *d = get_display (display);
 
-  if (f->output_method != output_termcap)
-    wrong_type_argument (Qframe_tty_name, frame);
+  if (!d)
+    wrong_type_argument (Qdisplay_live_p, display);
 
-  if (FRAME_TTY (f)->name)
-    return build_string (FRAME_TTY (f)->name);
+  if (d->name)
+    return build_string (d->name);
   else
     return Qnil;
 }
 
-DEFUN ("frame-tty-type", Fframe_tty_type, Sframe_tty_type, 0, 1, 0,
-       doc: /* Return the type of the TTY device that FRAME is displayed on. */)
-  (frame)
-     Lisp_Object frame;
+DEFUN ("display-tty-type", Fdisplay_tty_type, Sdisplay_tty_type, 0, 1, 0,
+       doc: /* Return the type of the TTY device that DISPLAY uses. */)
+  (display)
+     Lisp_Object display;
 {
-  struct frame *f;
+  struct display *d = get_display (display);
 
-  if (NILP (frame))
-    {
-      f = XFRAME (selected_frame);
-    }
+  if (!d)
+    wrong_type_argument (Qdisplay_live_p, display);
+  if (d->type != output_termcap)
+    error ("Display %d is not a termcap display", d->id);
+           
+  if (d->display_info.tty->type)
+    return build_string (d->display_info.tty->type);
   else
-    {
-      CHECK_LIVE_FRAME (frame);
-      f = XFRAME (frame);
-    }
+    return Qnil;
+}
 
-  if (f->output_method != output_termcap)
-    wrong_type_argument (Qframe_tty_type, frame);
+DEFUN ("display-controlling-tty-p", Fdisplay_controlling_tty_p, Sdisplay_controlling_tty_p, 0, 1, 0,
+       doc: /* Return non-nil if DISPLAY is on the controlling tty of the Emacs process. */)
+  (display)
+     Lisp_Object display;
+{
+  struct display *d = get_display (display);
 
-  if (FRAME_TTY (f)->type)
-    return build_string (FRAME_TTY (f)->type);
-  else
+  if (!d)
+    wrong_type_argument (Qdisplay_live_p, display);
+
+  if (d->type != output_termcap || d->display_info.tty->name)
     return Qnil;
+  else
+    return Qt;
 }
 
 \f
@@ -2188,7 +2247,8 @@ init_initial_display (void)
 
   initial_display = create_display ();
   initial_display->type = output_initial;
-  
+  initial_display->name = xstrdup ("initial_display");
+
   initial_display->delete_display_hook = &delete_initial_display;
   /* All other hooks are NULL. */
   
@@ -2208,6 +2268,36 @@ delete_initial_display (struct display *display)
   initial_display = NULL;
 }
 
+/* Drop the controlling terminal if fd is the same device. */
+void
+dissociate_if_controlling_tty (int fd)
+{
+  int pgid;
+  EMACS_GET_TTY_PGRP (fd, &pgid); /* If tcgetpgrp succeeds, fd is the ctty. */
+  if (pgid != -1)
+    {
+#if defined (USG) && !defined (BSD_PGRPS)
+      setpgrp ();
+      no_controlling_tty = 1;
+#else
+#ifdef TIOCNOTTY                /* Try BSD ioctls. */
+      sigblock (sigmask (SIGTTOU));
+      fd = emacs_open ("/dev/tty", O_RDWR, 0);
+      if (fd != -1 && ioctl (fd, TIOCNOTTY, 0) != -1)
+        {
+          no_controlling_tty = 1;
+        }
+      if (fd != -1)
+        emacs_close (fd);
+      sigunblock (sigmask (SIGTTOU));
+#else
+      /* Unknown system. */
+      croak ();
+#endif  /* ! TIOCNOTTY */
+#endif  /* ! USG */
+    }
+}
+
 /* Create a termcap display on the tty device with the given name and
    type.
 
@@ -2237,10 +2327,15 @@ term_init (char *name, char *terminal_type, int must_succeed)
     maybe_fatal (must_succeed, 0, 0,
                  "Unknown terminal type",
                  "Unknown terminal type");
-  
+
+  /* If we already have an active display on the given device, use that.
+     If all displays are suspended, create a new one instead.  */
+  /* XXX Perhaps this should be made explicit by having term_init
+     always create a new display and separating display and frame
+     creation on Lisp level.  */
   display = get_named_tty_display (name);
   if (display)
-    return display;             /* We have already opened a display there. */
+    return display;
 
   display = create_display ();
   tty = (struct tty_display_info *) xmalloc (sizeof (struct tty_display_info));
@@ -2304,21 +2399,13 @@ term_init (char *name, char *terminal_type, int must_succeed)
          if we don't have one at the moment.  */
       fd = emacs_open (name, O_RDWR | O_IGNORE_CTTY | O_NOCTTY, 0);
 #else
-      /* Alas, O_IGNORE_CTTY is a GNU extension that is only defined
-         on Hurd.  On other systems, we need to dissociate ourselves
-         from the controlling tty when we want to open a frame on the
-         same terminal.  The function setsid should be used for this,
-         but it didn't work for me. */
+      /* Alas, O_IGNORE_CTTY is a GNU extension that seems to be only
+         defined on Hurd.  On other systems, we need to dissociate
+         ourselves from the controlling tty when we want to open a
+         frame on the same terminal.  */
 
       fd = emacs_open (name, O_RDWR | O_NOCTTY, 0);
-      
-#ifdef TIOCNOTTY
-      /* Drop our controlling tty if it is the same device. */
-      if (ioctl (fd, TIOCNOTTY, 0) != -1)
-        {
-          no_controlling_tty = 1;
-        }
-#endif
+
 #endif /* O_IGNORE_CTTY */
 
       if (fd < 0)
@@ -2332,8 +2419,11 @@ term_init (char *name, char *terminal_type, int must_succeed)
           error ("Not a tty device: %s", name);
         }
 
+      dissociate_if_controlling_tty (fd);
+      
       file = fdopen (fd, "w+");
       tty->name = xstrdup (name);
+      display->name = xstrdup (name);
       tty->input = file;
       tty->output = file;
     }
@@ -2346,6 +2436,7 @@ term_init (char *name, char *terminal_type, int must_succeed)
           error ("There is no controlling terminal any more");
         }
       tty->name = 0;
+      display->name = xstrdup (ttyname (0));
       tty->input = stdin;
       tty->output = stdout;
     }
@@ -2389,7 +2480,13 @@ term_init (char *name, char *terminal_type, int must_succeed)
   Wcm_clear (tty);
 
   buffer = (char *) xmalloc (buffer_size);
+  
+  /* On some systems, tgetent tries to access the controlling
+     terminal. */
+  sigblock (sigmask (SIGTTOU));
   status = tgetent (buffer, terminal_type);
+  sigunblock (sigmask (SIGTTOU));
+  
   if (status < 0)
     {
 #ifdef TERMINFO
@@ -2550,7 +2647,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   /* Get frame size from system, or else from termcap.  */
   {
     int height, width;
-    get_tty_size (fileno (TTY_INPUT (tty)), &width, &height);
+    get_tty_size (fileno (tty->input), &width, &height);
     FrameCols (tty) = width;
     FrameRows (tty) = height;
   }
@@ -2735,7 +2832,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
               && tty->TS_end_standout_mode
               && !strcmp (tty->TS_standout_mode, tty->TS_end_standout_mode));
 
-  UseTabs (tty) = tabs_safe_p (fileno (TTY_INPUT (tty))) && TabWidth (tty) == 8;
+  UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
 
   display->scroll_region_ok
     = (tty->Wcm->cm_abs
@@ -2754,7 +2851,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
 
   display->fast_clear_end_of_line = tty->TS_clr_line != 0;
 
-  init_baud_rate (fileno (TTY_INPUT (tty)));
+  init_baud_rate (fileno (tty->input));
 
 #ifdef AIXHFT
   /* The HFT system on AIX doesn't optimize for scrolling, so it's
@@ -2825,37 +2922,6 @@ 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.
-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 display *d;
-  char *name = 0;
-
-  CHECK_STRING (tty);
-
-  if (SBYTES (tty) > 0)
-    {
-      name = (char *) alloca (SBYTES (tty) + 1);
-      strncpy (name, SDATA (tty), SBYTES (tty));
-      name[SBYTES (tty)] = 0;
-    }
-
-  d = get_named_tty_display (name);
-
-  if (! d)
-    error ("No such terminal device: %s", name);
-
-  delete_tty (d);
-
-  return Qnil;
-}
-
 static int deleting_tty = 0;
 
 
@@ -2956,21 +3022,6 @@ delete_tty (struct display *display)
   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
@@ -3030,19 +3081,29 @@ mark_ttys ()
 struct display *
 create_display (void)
 {
-  struct display *dev = (struct display *) xmalloc (sizeof (struct display));
+  struct display *display = (struct display *) xmalloc (sizeof (struct display));
   
-  bzero (dev, sizeof (struct display));
-  dev->next_display = display_list;
-  display_list = dev;
+  bzero (display, sizeof (struct display));
+  display->next_display = display_list;
+  display_list = display;
+
+  display->id = next_display_id++;
 
-  return dev;
+  display->keyboard_coding =
+    (struct coding_system *) xmalloc (sizeof (struct coding_system));
+  display->terminal_coding =
+    (struct coding_system *) xmalloc (sizeof (struct coding_system));
+  
+  setup_coding_system (Qnil, display->keyboard_coding);
+  setup_coding_system (Qnil, display->terminal_coding);
+  
+  return display;
 }
 
 /* Remove a display from the display list and free its memory. */
 
 void
-delete_display (struct display *dev)
+delete_display (struct display *display)
 {
   struct display **dp;
   Lisp_Object tail, frame;
@@ -3052,21 +3113,235 @@ delete_display (struct display *dev)
   FOR_EACH_FRAME (tail, frame)
     {
       struct frame *f = XFRAME (frame);
-      if (FRAME_LIVE_P (f) && f->display == dev)
+      if (FRAME_LIVE_P (f) && f->display == display)
         {
           Fdelete_frame (frame, Qt);
         }
     }
 
-  for (dp = &display_list; *dp != dev; dp = &(*dp)->next_display)
+  for (dp = &display_list; *dp != display; dp = &(*dp)->next_display)
     if (! *dp)
       abort ();
-  *dp = dev->next_display;
+  *dp = display->next_display;
+
+  if (display->keyboard_coding)
+    xfree (display->keyboard_coding);
+  if (display->terminal_coding)
+    xfree (display->terminal_coding);
+  if (display->name)
+    xfree (display->name);
+  
+  bzero (display, sizeof (struct display));
+  xfree (display);
+}
+
+DEFUN ("delete-display", Fdelete_display, Sdelete_display, 0, 2, 0,
+       doc: /* Delete DISPLAY by deleting all frames on it and closing the device.
+DISPLAY may be a display id, a frame, or nil for the display
+device of the current frame.
+
+Normally, you may not delete a display if all other displays are suspended,
+but if the second argument FORCE is non-nil, you may do so. */)
+  (display, force)
+     Lisp_Object display, force;
+{
+  struct display *d, *p;
+
+  d = get_display (display);
+
+  if (!d)
+    return Qnil;
+
+  p = display_list;
+  while (p && (p == d || !DISPLAY_ACTIVE_P (p)))
+    p = p->next_display;
+  
+  if (NILP (force) && !p)
+    error ("Attempt to delete the sole active display");
+
+  if (d->delete_display_hook)
+    (*d->delete_display_hook) (d);
+  else
+    delete_display (d);
+
+  return Qnil;
+}
+
+DEFUN ("display-live-p", Fdisplay_live_p, Sdisplay_live_p, 1, 1, 0,
+       doc: /* Return non-nil if OBJECT is a display which has not been deleted.
+Value is nil if OBJECT is not a live display.
+If object is a live display, the return value indicates what sort of
+output device it uses.  See the documentation of `framep' for possible
+return values.
+
+Displays are represented by their integer identifiers. */)
+  (object)
+     Lisp_Object object;
+{
+  struct display *d;
+  
+  if (!INTEGERP (object))
+    return Qnil;
+
+  d = get_display (object);
+
+  if (!d)
+    return Qnil;
+
+  switch (d->type)
+    {
+    case output_initial: /* The initial frame is like a termcap frame. */
+    case output_termcap:
+      return Qt;
+    case output_x_window:
+      return Qx;
+    case output_w32:
+      return Qw32;
+    case output_msdos_raw:
+      return Qpc;
+    case output_mac:
+      return Qmac;
+    default:
+      abort ();
+    }
+}
 
-  bzero (dev, sizeof (struct display));
-  xfree (dev);
+DEFUN ("display-list", Fdisplay_list, Sdisplay_list, 0, 0, 0,
+       doc: /* Return a list of all displays.
+Displays are represented by their integer identifiers. */)
+  ()
+{
+  Lisp_Object displays = Qnil;
+  struct display *d;
+
+  for (d = display_list; d; d = d->next_display)
+    displays = Fcons (make_number (d->id), displays);
+
+  return displays;
 }
 
+            
+\f
+
+DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
+       doc: /* Suspend the terminal device TTY.
+The terminal is restored to its default state, and Emacs ceases all
+access to the terminal device.  Frames that use the device are not
+deleted, but input is not read from them and if they change, their
+display is not updated.
+
+TTY may be a display id, a frame, or nil for the display device of the
+currently selected frame.
+
+This function runs `suspend-tty-functions' after suspending the
+device.  The functions are run with one arg, the id of the suspended
+display device.
+
+`suspend-tty' does nothing if it is called on an already suspended
+device.
+
+A suspended terminal device may be resumed by calling `resume-tty' on
+it. */)
+  (tty)
+     Lisp_Object tty;
+{
+  struct display *d = get_tty_display (tty);
+  FILE *f;
+  
+  if (!d)
+    error ("Unknown tty device");
+
+  f = d->display_info.tty->input;
+  
+  if (f)
+    {
+      reset_sys_modes (d->display_info.tty);
+
+      delete_keyboard_wait_descriptor (fileno (f));
+      
+      fclose (f);
+      if (f != d->display_info.tty->output)
+        fclose (d->display_info.tty->output);
+      
+      d->display_info.tty->input = 0;
+      d->display_info.tty->output = 0;
+
+      if (FRAMEP (d->display_info.tty->top_frame))
+        FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 0);
+      
+      /* Run `suspend-tty-functions'.  */
+      if (!NILP (Vrun_hooks))
+        {
+          Lisp_Object args[2];
+          args[0] = intern ("suspend-tty-functions");
+          args[1] = make_number (d->id);
+          Frun_hook_with_args (2, args);
+        }
+    }
+
+  return Qnil;
+}
+
+
+DEFUN ("resume-tty", Fresume_tty, Sresume_tty, 0, 1, 0,
+       doc: /* Resume the previously suspended terminal device TTY.
+The terminal is opened and reinitialized.  Frames that are on the
+suspended display are revived.
+
+It is an error to resume a display while another display is active on
+the same device.
+
+This function runs `resume-tty-functions' after resuming the device.
+The functions are run with one arg, the id of the resumed display
+device.
+
+`resume-tty' does nothing if it is called on a device that is not
+suspended.
+
+TTY may be a display id, a frame, or nil for the display device of the
+currently selected frame. */)
+  (tty)
+     Lisp_Object tty;
+{
+  struct display *d = get_tty_display (tty);
+  int fd;
+
+  if (!d)
+    error ("Unknown tty device");
+
+  if (!d->display_info.tty->input)
+    {
+      if (get_named_tty_display (d->display_info.tty->name))
+        error ("Cannot resume display while another display is active on the same device");
+
+      fd = emacs_open (d->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
+
+      /* XXX What if open fails? */
+
+      dissociate_if_controlling_tty (fd);
+      
+      d->display_info.tty->output = fdopen (fd, "w+");
+      d->display_info.tty->input = d->display_info.tty->output;
+    
+      add_keyboard_wait_descriptor (fd);
+
+      if (FRAMEP (d->display_info.tty->top_frame))
+        FRAME_SET_VISIBLE (XFRAME (d->display_info.tty->top_frame), 1);
+
+      init_sys_modes (d->display_info.tty);
+
+      /* Run `suspend-tty-functions'.  */
+      if (!NILP (Vrun_hooks))
+        {
+          Lisp_Object args[2];
+          args[0] = intern ("resume-tty-functions");
+          args[1] = make_number (d->id);
+          Frun_hook_with_args (2, args);
+        }
+    }
+
+  return Qnil;
+}
 
 \f
 void
@@ -3086,23 +3361,29 @@ 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;
+  DEFVAR_LISP ("suspend-tty-functions", &Vsuspend_tty_functions,
+    doc: /* Functions to be run after suspending a tty.
+The functions are run with one argument, the name of the tty to be suspended.
+See `suspend-tty'.  */);
+  Vsuspend_tty_functions = Qnil;
 
-  Qframe_tty_name = intern ("frame-tty-name");
-  staticpro (&Qframe_tty_name);
 
-  Qframe_tty_type = intern ("frame-tty-type");
-  staticpro (&Qframe_tty_type);
+  DEFVAR_LISP ("resume-tty-functions", &Vresume_tty_functions,
+    doc: /* Functions to be run after resuming a tty.
+The functions are run with one argument, the name of the tty that was revived.
+See `resume-tty'.  */);
+  Vresume_tty_functions = Qnil;
 
   defsubr (&Stty_display_color_p);
   defsubr (&Stty_display_color_cells);
-  defsubr (&Sframe_tty_name);
-  defsubr (&Sframe_tty_type);
-  defsubr (&Sdelete_tty);
+  defsubr (&Sdisplay_name);
+  defsubr (&Sdisplay_tty_type);
+  defsubr (&Sdisplay_controlling_tty_p);
+  defsubr (&Sdelete_display);
+  defsubr (&Sdisplay_live_p);
+  defsubr (&Sdisplay_list);
+  defsubr (&Ssuspend_tty);
+  defsubr (&Sresume_tty);
 
   Fprovide (intern ("multi-tty"), Qnil);