diff src/term.c @ 83008:040dd41ed7d0

Hookified termcap devices, added bootstrap display device, plus many bugfixes. lisp/frame.el (display-color-cells): Pass display parameter to tty-display-color-cells. lisp/term/xterm.el (xterm-register-default-colors): Pass the selected-frame to display-color-cells. src/dispextern.h (set_terminal_modes, reset_terminal_modes): Removed declarations. (get_named_tty_display): New prototype. (tty_clear_end_of_line, term_init): Updated to new prototype. (initial_term_init): Renamed to init_initial_display. src/dispnew.c (Fredraw_frame): ifdef-out DOS-specific code. Add display parameter to set_terminal_modes call. (update_frame): Don't flush the tty of there is no tty. (init_display): Set up a termcap display on the controlling tty and change the initial frame to use that. Delete the initial display. src/frame.c (Fframep): Return t for the initial frame. (make_initial_frame): New function for creating the initial frame during bootstrap. Use init_initial_display, not initial_term_init. (make_terminal_frame): Removed special cases for creating the initial frame. src/frame.h (enum output_method): New entry: output_initial for the bootstrap display. (FRAME_INITIAL_P): New macro. (make_initial_frame): New prototype. src/keyboard.c (interrupt_signal): Exit Emacs on SIGINT from the (frameless) controlling tty, if possible. Explain this in a comment. (init_keyboard): Added comment about exiting on SIGINT. (Fset_input_mode): A termcap frame is never the initial frame anymore. src/sysdep.c (init_sys_modes): Update tty_set_terminal_modes call to the new prototype. (reset_sys_modes): Comment out tty_clear_end_of_line call; it doesn't work anymore. Update tty_reset_terminal_modes call. src/termchar.h (struct tty_display_info): Added pointer to the display structure, for reset_sys_modes. src/termhooks.h (struct display): Added display parameter to set_terminal_modes_hook and reset_terminal_modes_hook. src/term.c (initial_display): New variable. (tty_ring_bell, tty_update_end, tty_set_terminal_window, tty_cursor_to) (tty_raw_cursor_to, tty_clear_to_end, tty_clear_frame, tty_clear_end_of_line) (tty_write_glyphs, tty_insert_glyphs, tty_delete_glyphs, tty_ins_del_lines): New functions. (ring_bell, update_end, set_terminal_window, cursor_to, raw_cursor_to) (clear_to_end, clear_frame, clear_end_of_line, write_glyphs, insert_glyphs) (delete_glyphs, ins_del_lines): Removed special casing of termcap displays. (get_tty_display): New function. (Ftty_display_color_p, Ftty_display_color_cells): Use it. (get_named_tty_display): Removed static. (tty_set_terminal_modes, tty_reset_terminal_modes): Changed to use a display parameter instead of tty_display_info for hook compatibility. (set_terminal_modes, reset_terminal_modes): Removed. (initial_term_init): Renamed to init_initial_display. Set up an output_initial device, not a termcap display. (delete_initial_display): New function. (maybe_fatal): New function, for private use of term_init. (term_init): New parameter for choosing between fatal and simple errors. Removed incomprehensible special casing for the second initialization of the controlling tty. Use maybe_fatal for error handling. Initialize termcap display hooks in the new device. Initialize the display pointer in the tty_display_info structure. (delete_tty): Replace order of reset_sys_modes and delete_display. src/window.c (init_window_once): Call make_initial_frame instead of make_terminal_frame. src/xfaces.c (realize_default_face, realize_face): Don't abort on the bootstrap display device. src/xterm.c (XTset_terminal_modes, XTreset_terminal_modes): Added display parameter. git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-48
author Karoly Lorentey <lorentey@elte.hu>
date Fri, 09 Jan 2004 18:57:53 +0000
parents 7900111db01c
children c4d4cbf86260
line wrap: on
line diff
--- a/src/term.c	Fri Jan 09 13:12:28 2004 +0000
+++ b/src/term.c	Fri Jan 09 18:57:53 2004 +0000
@@ -71,6 +71,7 @@
 static void tty_show_cursor P_ ((struct tty_display_info *));
 static void tty_hide_cursor 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 *));
@@ -105,6 +106,9 @@
 /* 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;
 
@@ -172,7 +176,9 @@
 void
 ring_bell ()
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
   if (!NILP (Vring_bell_function))
     {
@@ -195,32 +201,36 @@
     }
   else if (FRAME_DISPLAY (f)->ring_bell_hook)
     (*FRAME_DISPLAY (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);
-  }
 }
 
-void tty_set_terminal_modes (struct tty_display_info *tty)
+void
+tty_ring_bell ()
 {
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : 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 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 ()
+void tty_reset_terminal_modes (struct display *display)
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  if (FRAME_DISPLAY (f)->set_terminal_modes_hook)
-    (*FRAME_DISPLAY (f)->set_terminal_modes_hook) ();
-  else 
-    tty_set_terminal_modes (FRAME_TTY (f));
-}
-
-void tty_reset_terminal_modes (struct tty_display_info *tty)
-{
+  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);
@@ -233,16 +243,6 @@
 }
 
 void
-reset_terminal_modes ()
-{
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  if (FRAME_DISPLAY (f)->reset_terminal_modes_hook)
-    (*FRAME_DISPLAY (f)->reset_terminal_modes_hook) ();
-  else
-    tty_reset_terminal_modes (FRAME_TTY (f));
-}
-
-void
 update_begin (f)
      struct frame *f;
 {
@@ -257,32 +257,44 @@
 {
   if (FRAME_DISPLAY (f)->update_end_hook)
     (*FRAME_DISPLAY (f)->update_end_hook) (f);
-  else 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);
-    }
-
   updating_frame = NULL;
 }
 
 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);
+}
+
+void
 set_terminal_window (size)
      int size;
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  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);
-  else 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);
-    }
+}
+
+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
@@ -290,7 +302,10 @@
      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)
@@ -412,16 +427,22 @@
 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_DISPLAY (f)->cursor_to_hook)
-    {
-      (*FRAME_DISPLAY (f)->cursor_to_hook) (vpos, hpos);
-      return;
-    }
-
-  tty = FRAME_TTY (f);
+    (*FRAME_DISPLAY (f)->cursor_to_hook) (vpos, hpos);
+}
+
+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.  */
@@ -444,14 +465,23 @@
 raw_cursor_to (row, col)
      int row, col;
 {
-  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_DISPLAY (f)->raw_cursor_to_hook)
-    {
-      (*FRAME_DISPLAY (f)->raw_cursor_to_hook) (row, col);
-      return;
-    }
-  tty = FRAME_TTY (f);
+    (*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;
@@ -468,17 +498,23 @@
 void
 clear_to_end ()
 {
-  register int i;
-
-  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_DISPLAY (f)->clear_to_end_hook)
-    {
-      (*FRAME_DISPLAY (f)->clear_to_end_hook) ();
-      return;
-    }
-  tty = FRAME_TTY (f);
+    (*FRAME_DISPLAY (f)->clear_to_end_hook) ();
+}
+
+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 (tty->TS_clr_to_bottom)
     {
       background_highlight (tty);
@@ -500,14 +536,20 @@
 clear_frame ()
 {
   struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
-  struct tty_display_info *tty;
 
   if (FRAME_DISPLAY (f)->clear_frame_hook)
-    {
-      (*FRAME_DISPLAY (f)->clear_frame_hook) ();
-      return;
-    }
-  tty = FRAME_TTY (f);
+    (*FRAME_DISPLAY (f)->clear_frame_hook) ();
+}
+
+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);
@@ -530,22 +572,23 @@
 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;
+  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);
-      return;
-    }
-
-  tty_clear_end_of_line (FRAME_TTY (f), first_unused_hpos);
+    (*FRAME_DISPLAY (f)->clear_end_of_line_hook) (first_unused_hpos);
 }
 
 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)
@@ -692,19 +735,26 @@
      register struct glyph *string;
      register 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;
+  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);
-      return;
-    }
-
-  tty = FRAME_TTY (f);
+    (*FRAME_DISPLAY (f)->write_glyphs_hook) (string, len);
+}
+
+void
+tty_write_glyphs (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);
   tty_hide_cursor (tty);
@@ -795,23 +845,27 @@
      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);
-      return;
-    }
-
-  tty = FRAME_TTY (f);
+    (*FRAME_DISPLAY (f)->insert_glyphs_hook) (start, len);
+}
+
+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));
+
+  struct tty_display_info *tty = FRAME_TTY (f);
 
   if (tty->TS_ins_multi_chars)
     {
@@ -889,17 +943,24 @@
 delete_glyphs (n)
      register 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);
+  struct frame *f = (updating_frame
+                     ? updating_frame
+                     : XFRAME (selected_frame));
 
   if (FRAME_DISPLAY (f)->delete_glyphs_hook)
-    {
-      (*FRAME_DISPLAY (f)->delete_glyphs_hook) (n);
-      return;
-    }
-
+    (*FRAME_DISPLAY (f)->delete_glyphs_hook) (n);
+}
+
+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 (tty->delete_in_insert_mode)
     {
@@ -930,73 +991,79 @@
 ins_del_lines (vpos, n)
      int vpos, n;
 {
-  struct frame *f = (updating_frame ? updating_frame : XFRAME (selected_frame));
+  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);
+}
+
+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)
     {
-      (*FRAME_DISPLAY (f)->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 ();
     }
 }
 
@@ -1809,6 +1876,48 @@
   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.  */
 
@@ -1818,13 +1927,11 @@
      (display)
      Lisp_Object display;
 {
-  struct tty_display_info *tty;
-
-  if (! FRAMEP (display))
+  struct display *d = get_tty_display (display);
+  if (!d)
     return Qnil;
-  
-  tty = FRAME_TTY (XFRAME (display));
-  return tty->TN_max_colors > 0 ? Qt : Qnil;
+  else
+    return d->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
 }
 
 /* Return the number of supported colors.  */
@@ -1834,13 +1941,11 @@
      (display)
      Lisp_Object display;
 {
-  struct tty_display_info *tty;
-
-  if (! FRAMEP (display))
+  struct display *d = get_tty_display (display);
+  if (!d)
     return Qnil;
-  
-  tty = FRAME_TTY (XFRAME (display));
-  return make_number (tty->TN_max_colors);
+  else
+    return make_number (d->display_info.tty->TN_max_colors);
 }
 
 #ifndef WINDOWSNT
@@ -1982,7 +2087,7 @@
 
 
 
-static struct display *
+struct display *
 get_named_tty_display (name)
      char *name;
 {
@@ -2058,33 +2163,50 @@
 			    Initialization
  ***********************************************************************/
 
+/* Create the bootstrap display device for the initial frame.
+
+Returns a display of type output_initial. */
 struct display *
-initial_term_init (void)
+init_initial_display (void)
 {
+  struct tty_display_info *tty;
+  
   if (initialized || display_list || tty_list)
     abort ();
 
-  display_list = create_display ();
-
-  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));
-#ifdef MULTI_KBOARD
-  tty_list->kboard = initial_kboard;
-#endif
+  initial_display = create_display ();
+  initial_display->type = output_initial;
+  
+  initial_display->delete_display_hook = &delete_initial_display;
+  /* All other hooks are NULL. */
   
-  display_list->type = output_termcap;
-  display_list->display_info.tty = tty_list;
-  
-  return display_list;
+  return initial_display;
+}
+
+/* Deletes the bootstrap display device.
+   Called through delete_display_hook. */
+void
+delete_initial_display (struct display *display)
+{
+  if (display != initial_display)
+    abort ();
+
+  delete_display (display);
+  initial_display = NULL;
 }
 
-
+/* Create a termcap display on the tty device with the given name and
+   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)
+term_init (char *name, char *terminal_type, int must_succeed)
 {
   char *area;
   char **address = &area;
@@ -2095,39 +2217,65 @@
   struct tty_display_info *tty;
   struct display *display;
 
+  static void maybe_fatal();
+
+  if (!terminal_type)
+    maybe_fatal (must_succeed, 0, 0,
+                 "Unknown terminal type",
+                 "Unknown terminal type");
+  
   display = get_named_tty_display (name);
   if (display)
-    {
-      tty = display->display_info.tty;
-
-      /* Return the previously initialized terminal, except if it is
-         the dummy terminal created for the initial frame. */
-      if (tty->type)
-        return display;
-
-      /* Free up temporary structures. */
-      if (tty->Wcm)
-        xfree (tty->Wcm);
-      if (tty->kboard != initial_kboard)
-        abort ();
-      tty->kboard = 0;
-    }
-  else
-    {
-      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;
-    }
+    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);
 
   display->rif = 0; /* ttys don't support window-based redisplay. */
+
+  display->cursor_to_hook = &tty_cursor_to;
+  display->raw_cursor_to_hook = &tty_raw_cursor_to;
+
+  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 = 0; /* Not needed. */
+  display->frame_up_to_date_hook = 0; /* Not needed. */
+  
   display->delete_frame_hook = &delete_tty_output;
   display->delete_display_hook = &delete_tty;
   
@@ -2196,55 +2344,35 @@
   if (status < 0)
     {
 #ifdef TERMINFO
-      if (name)
-        {
-          xfree (buffer);
-          delete_tty (display);
-          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 (display);
-          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 (display);
-          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 (display);
-          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
     }
 
@@ -2384,19 +2512,10 @@
     FrameRows (tty) = tgetnum ("li");
 
   if (FrameRows (tty) < 3 || FrameCols (tty) < 3)
-    {
-      if (initialized)
-        {
-          delete_tty (display);
-          error ("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));
-        }
-      else
-        {
-          fatal ("Screen size %dx%d is too small",
-                 FrameCols (tty), FrameRows (tty));
-        }
-    }
 
 #if 0  /* This is not used anywhere. */
   tty->display->min_padding_speed = tgetnum ("pb");
@@ -2525,51 +2644,39 @@
   tty->specified_window = FrameRows (tty);
 
   if (Wcm_init (tty) == -1)	/* can't do cursor motion */
-    if (name)
-      {
-        delete_tty (display);
-        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 (display);
-          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
@@ -2635,6 +2742,31 @@
 #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)
@@ -2725,10 +2857,12 @@
         }
     }
 
+  /* reset_sys_modes needs a valid display, so this call needs to be
+     before delete_display. */
+  reset_sys_modes (tty);
+
   delete_display (display);
 
-  reset_sys_modes (tty);
-
   tty_name = tty->name;
   if (tty->type)
     xfree (tty->type);