Change doc-string comments to `new style' [w/`doc:' keyword].
[bpt/emacs.git] / src / term.c
index 89c0892..65d0c8c 100644 (file)
@@ -1,6 +1,6 @@
-/* terminal control module for terminals described by TERMCAP
-   Copyright (C) 1985, 86, 87, 93, 94, 95, 98
-     Free Software Foundation, Inc.
+/* Terminal control module for terminals described by TERMCAP
+   Copyright (C) 1985, 86, 87, 93, 94, 95, 98, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -19,51 +19,65 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* New redisplay, TTY faces by Gerd Moellmann <gerd@acm.org>.  */
-
+/* New redisplay, TTY faces by Gerd Moellmann <gerd@gnu.org>.  */
 
 #include <config.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
+
 #include "termchar.h"
 #include "termopts.h"
 #include "lisp.h"
 #include "charset.h"
 #include "coding.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "disptab.h"
 #include "termhooks.h"
-#include "keyboard.h"
 #include "dispextern.h"
 #include "window.h"
+#include "keymap.h"
+
+/* For now, don't try to include termcap.h.  On some systems,
+   configure finds a non-standard termcap.h that the main build
+   won't find.  */
+
+#if defined HAVE_TERMCAP_H && 0
+#include <termcap.h>
+#else
+extern void tputs P_ ((const char *, int, int (*)(int)));
+extern int tgetent P_ ((char *, const char *));
+extern int tgetflag P_ ((char *id));
+extern int tgetnum P_ ((char *id));
+#endif
 
 #include "cm.h"
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #endif
+#ifdef macintosh
+#include "macterm.h"
+#endif
 
 static void turn_on_face P_ ((struct frame *, int face_id));
 static void turn_off_face P_ ((struct frame *, int face_id));
 static void tty_show_cursor P_ ((void));
 static void tty_hide_cursor P_ ((void));
 
-#define max(a, b) ((a) > (b) ? (a) : (b))
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
 #define OUTPUT(a) \
      tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame)) - curY), cmputc)
 #define OUTPUT1(a) tputs (a, 1, cmputc)
 #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
 
-#define OUTPUT_IF(a)                                           \
-     if (a)                                                    \
-       tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame)) \
-                       - curY), cmputc);                       \
-     else                                                      \
-       (void) 0
+#define OUTPUT_IF(a)                                                   \
+     do {                                                              \
+       if (a)                                                          \
+         tputs (a, (int) (FRAME_HEIGHT (XFRAME (selected_frame))       \
+                         - curY), cmputc);                             \
+     } while (0)
      
-#define OUTPUT1_IF(a) if (a) tputs (a, 1, cmputc); else (void) 0
+#define OUTPUT1_IF(a) do { if (a) tputs (a, 1, cmputc); } while (0)
 
 /* Function to use to ring the bell.  */
 
@@ -142,6 +156,7 @@ void (*frame_up_to_date_hook) P_ ((struct frame *));
 
    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,
@@ -154,6 +169,7 @@ void (*mouse_position_hook) P_ ((FRAME_PTR *f, int insist,
    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
@@ -166,6 +182,7 @@ void (*frame_rehighlight_hook) P_ ((FRAME_PTR f));
    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
@@ -199,10 +216,12 @@ void (*set_vertical_scroll_bar_hook)
    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
@@ -216,6 +235,7 @@ void (*redeem_scroll_bar_hook) P_ ((struct window *window));
    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));
 
 /* Hook to call in estimate_mode_line_height, if any.  */
@@ -264,6 +284,27 @@ char *TS_cursor_invisible; /* "vi" */
 char *TS_set_window;           /* "wi" (4 params, start and end of window,
                                   each as vpos and hpos) */
 
+/* Value of the "NC" (no_color_video) capability, or 0 if not
+   present.  */
+
+static int TN_no_color_video;
+
+/* Meaning of bits in no_color_video.  Each bit set means that the
+   corresponding attribute cannot be combined with colors.  */
+
+enum no_color_bit
+{
+  NC_STANDOUT   = 1 << 0,
+  NC_UNDERLINE  = 1 << 1,
+  NC_REVERSE    = 1 << 2,
+  NC_BLINK      = 1 << 3,
+  NC_DIM        = 1 << 4,
+  NC_BOLD       = 1 << 5,
+  NC_INVIS      = 1 << 6,
+  NC_PROTECT    = 1 << 7,
+  NC_ALT_CHARSET = 1 << 8
+};
+
 /* "md" -- turn on bold (extra bright mode).  */
 
 char *TS_enter_bold_mode;
@@ -381,13 +422,16 @@ FRAME_PTR updating_frame;
 
 static int system_uses_terminfo;
 
+/* Flag used in tty_show/hide_cursor.  */
+
+static int tty_cursor_hidden;
+
 char *tparam ();
 
 extern char *tgetstr ();
 \f
 
 #ifdef WINDOWSNT
-
 /* We aren't X windows, but we aren't termcap either.  This makes me
    uncertain as to what value to use for frame.output_method.  For
    this file, we'll define FRAME_TERMCAP_P to be zero so that our
@@ -401,7 +445,7 @@ extern char *tgetstr ();
 void
 ring_bell ()
 {
-  if (! NILP (Vring_bell_function))
+  if (!NILP (Vring_bell_function))
     {
       Lisp_Object function;
 
@@ -412,105 +456,97 @@ ring_bell ()
         We don't specbind it, because that would carefully
         restore the bad value if there's an error
         and make the loop of errors happen anyway.  */
+      
       function = Vring_bell_function;
       Vring_bell_function = Qnil;
 
       call0 (function);
 
       Vring_bell_function = function;
-      return;
     }
-
-  if (! FRAME_TERMCAP_P (XFRAME (selected_frame)))
-    {
-      (*ring_bell_hook) ();
-      return;
-    }
-  OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
+  else if (!FRAME_TERMCAP_P (XFRAME (selected_frame)))
+    (*ring_bell_hook) ();
+  else
+    OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
 }
 
 void
 set_terminal_modes ()
 {
-  if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
+  if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
     {
-      (*set_terminal_modes_hook) ();
-      return;
+      OUTPUT_IF (TS_termcap_modes);
+      OUTPUT_IF (TS_cursor_visible);
+      OUTPUT_IF (TS_keypad_mode);
+      losecursor ();
     }
-  OUTPUT_IF (TS_termcap_modes);
-  OUTPUT_IF (TS_cursor_visible);
-  OUTPUT_IF (TS_keypad_mode);
-  losecursor ();
+  else
+    (*set_terminal_modes_hook) ();
 }
 
 void
 reset_terminal_modes ()
 {
-  if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
+  if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
     {
-      if (reset_terminal_modes_hook)
-       (*reset_terminal_modes_hook) ();
-      return;
-    }
-  if (TN_standout_width < 0)
-    turn_off_highlight ();
-  turn_off_insert ();
-  OUTPUT_IF (TS_end_keypad_mode);
-  OUTPUT_IF (TS_cursor_normal);
-  OUTPUT_IF (TS_end_termcap_modes);
-  OUTPUT_IF (TS_orig_pair);
-  /* Output raw CR so kernel can track the cursor hpos.  */
-  /* But on magic-cookie terminals this can erase an end-standout marker and
-     cause the rest of the frame to be in standout, so move down first.  */
-  if (TN_standout_width >= 0)
-    cmputc ('\n');
-  cmputc ('\r');
+      if (TN_standout_width < 0)
+       turn_off_highlight ();
+      turn_off_insert ();
+      OUTPUT_IF (TS_end_keypad_mode);
+      OUTPUT_IF (TS_cursor_normal);
+      OUTPUT_IF (TS_end_termcap_modes);
+      OUTPUT_IF (TS_orig_pair);
+      /* Output raw CR so kernel can track the cursor hpos.  */
+      /* But on magic-cookie terminals this can erase an end-standout
+        marker and cause the rest of the frame to be in standout, so
+        move down first.  */
+      if (TN_standout_width >= 0)
+       cmputc ('\n');
+      cmputc ('\r');
+    }
+  else if (reset_terminal_modes_hook)
+    (*reset_terminal_modes_hook) ();
 }
 
 void
 update_begin (f)
-     FRAME_PTR f;
+     struct frame *f;
 {
   updating_frame = f;
-  if (! FRAME_TERMCAP_P (updating_frame))
-    (*update_begin_hook) (f);
-  else
-    tty_hide_cursor ();
+  if (!FRAME_TERMCAP_P (f))
+    update_begin_hook (f);
 }
 
 void
 update_end (f)
-     FRAME_PTR f;
+     struct frame *f;
 {
-  if (! FRAME_TERMCAP_P (updating_frame))
+  if (FRAME_TERMCAP_P (f))
     {
-      (*update_end_hook) (f);
-      updating_frame = 0;
-      return;
+      if (!XWINDOW (selected_window)->cursor_off_p)
+       tty_show_cursor ();
+      turn_off_insert ();
+      background_highlight ();
+      standout_requested = 0;
     }
-
-  if (!XWINDOW (selected_window)->cursor_off_p)
-    tty_show_cursor ();
+  else
+    update_end_hook (f);
   
-  turn_off_insert ();
-  background_highlight ();
-  standout_requested = 0;
-  updating_frame = 0;
+  updating_frame = NULL;
 }
 
 void
 set_terminal_window (size)
      int size;
 {
-  if (FRAME_TERMCAP_P (updating_frame))
+  if (FRAME_TERMCAP_P (updating_frame))
     {
-      (*set_terminal_window_hook) (size);
-      return;
+      specified_window = size ? size : FRAME_HEIGHT (updating_frame);
+      if (scroll_region_ok)
+       set_scroll_region (0, specified_window);
     }
-  specified_window = size ? size : FRAME_HEIGHT (XFRAME (selected_frame));
-  if (!scroll_region_ok)
-    return;
-  set_scroll_region (0, specified_window);
+  else
+    set_terminal_window_hook (size);
 }
 
 void
@@ -521,26 +557,22 @@ set_scroll_region (start, stop)
   struct frame *sf = XFRAME (selected_frame);
   
   if (TS_set_scroll_region)
-    {
-      buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
-    }
+    buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
   else if (TS_set_scroll_region_1)
-    {
-      buf = tparam (TS_set_scroll_region_1, 0, 0,
-                   FRAME_HEIGHT (sf), start,
-                   FRAME_HEIGHT (sf) - stop,
-                   FRAME_HEIGHT (sf));
-    }
+    buf = tparam (TS_set_scroll_region_1, 0, 0,
+                 FRAME_HEIGHT (sf), start,
+                 FRAME_HEIGHT (sf) - stop,
+                 FRAME_HEIGHT (sf));
   else
-    {
-      buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (sf));
-    }
+    buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (sf));
+  
   OUTPUT (buf);
   xfree (buf);
   losecursor ();
 }
+
 \f
-void
+static void
 turn_on_insert ()
 {
   if (!insert_mode)
@@ -574,7 +606,7 @@ turn_off_highlight ()
     }
 }
 
-void
+static void
 turn_on_highlight ()
 {
   if (TN_standout_width < 0)
@@ -585,13 +617,26 @@ turn_on_highlight ()
     }
 }
 
+static void
+toggle_highlight ()
+{
+  if (standout_mode)
+    turn_off_highlight ();
+  else
+    turn_on_highlight ();
+}
+
 
 /* Make cursor invisible.  */
 
 static void
 tty_hide_cursor ()
 {
-  OUTPUT_IF (TS_cursor_invisible);
+  if (tty_cursor_hidden == 0)
+    {
+      tty_cursor_hidden = 1;
+      OUTPUT_IF (TS_cursor_invisible);
+    }
 }
 
 
@@ -600,8 +645,12 @@ tty_hide_cursor ()
 static void
 tty_show_cursor ()
 {
-  OUTPUT_IF (TS_cursor_normal);
-  OUTPUT_IF (TS_cursor_visible);
+  if (tty_cursor_hidden)
+    {
+      tty_cursor_hidden = 0;
+      OUTPUT_IF (TS_cursor_normal);
+      OUTPUT_IF (TS_cursor_visible);
+    }
 }
 
 
@@ -644,12 +693,13 @@ highlight_if_desired ()
 /* Write a standout marker or end-standout marker at the front of the line
    at vertical position vpos.  */
 
-void
+static void
 write_standout_marker (flag, vpos)
      int flag, vpos;
 {
-  if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
-              && !(TF_xs && TN_standout_width == 0)))
+  if (flag
+      || (TS_end_standout_mode && !TF_teleray && !se_is_so
+         && !(TF_xs && TN_standout_width == 0)))
     {
       cmgoto (vpos, 0);
       cmplus (TN_standout_width);
@@ -679,7 +729,7 @@ reassert_line_highlight (highlight, vpos)
   else if (chars_wasted && chars_wasted[vpos] == 0)
     /* For terminals with standout markers, write one on this line
        if there isn't one already.  */
-    write_standout_marker (highlight, vpos);
+    write_standout_marker (inverse_video ? !highlight : highlight, vpos);
 }
 
 /* Call this when about to modify line at position VPOS
@@ -921,55 +971,66 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
   struct glyph *src_start = src, *src_end = src + src_len;
   unsigned char *dst_start = dst, *dst_end = dst + dst_len;
   register GLYPH g;
-  unsigned int c;
-  unsigned char workbuf[4], *buf;
+  unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *buf;
   int len;
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
   int result;
   struct coding_system *coding;
 
-  coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
+  /* If terminal_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
            : &safe_terminal_coding);
 
   while (src < src_end)
     {
-      g = GLYPH_FROM_CHAR_GLYPH (*src);
-      
       /* We must skip glyphs to be padded for a wide character.  */
       if (! CHAR_GLYPH_PADDING_P (*src))
        {
-         struct frame *sf = XFRAME (selected_frame);
-         
-         c = src->u.ch.code;
-         if (! GLYPH_CHAR_VALID_P (c))
-           {
-             c = ' ';
-             g = MAKE_GLYPH (sf, c, GLYPH_FACE (sf, g));
-           }
-         if (COMPOSITE_CHAR_P (c))
+         g = GLYPH_FROM_CHAR_GLYPH (src[0]);
+
+         if (g < 0 || g >= tlen)
            {
-             /* If C is a composite character, we can display
-                only the first component.  */
-             g = cmpchar_table[COMPOSITE_CHAR_ID (c)]->glyph[0],
-             c = GLYPH_CHAR (sf, g);
+             /* This glyph doesn't has an entry in Vglyph_table.  */
+             if (! CHAR_VALID_P (src->u.ch, 0))
+               {
+                 len = 1;
+                 buf = " ";
+                 coding->src_multibyte = 0;
+               }
+             else
+               {
+                 len = CHAR_STRING (src->u.ch, workbuf);
+                 buf = workbuf;
+                 coding->src_multibyte = 1;
+               }
            }
-         if (c < tlen)
+         else
            {
-             /* G has an entry in Vglyph_table,
+             /* This glyph has an entry in Vglyph_table,
                 so process any alias before testing for simpleness.  */
              GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
-             c = GLYPH_CHAR (sf, g);
-           }
-         if (GLYPH_SIMPLE_P (tbase, tlen, g))
-           /* We set the multi-byte form of C at BUF.  */
-           len = CHAR_STRING (c, workbuf, buf);
-         else
-           {
-             /* We have a string in Vglyph_table.  */
-             len = GLYPH_LENGTH (tbase, g);
-             buf = GLYPH_STRING (tbase, g);
+
+             if (GLYPH_SIMPLE_P (tbase, tlen, g))
+               {
+                 /* We set the multi-byte form of a character in G
+                    (that should be an ASCII character) at
+                    WORKBUF.  */
+                 workbuf[0] = FAST_GLYPH_CHAR (g);
+                 len = 1;
+                 buf = workbuf;
+                 coding->src_multibyte = 0;
+               }
+             else
+               {
+                 /* We have a string in Vglyph_table.  */
+                 len = GLYPH_LENGTH (tbase, g);
+                 buf = GLYPH_STRING (tbase, g);
+                 coding->src_multibyte = STRING_MULTIBYTE (tbase[g]);
+               }
            }
          
          result = encode_coding (coding, buf, dst, len, dst_end - dst);
@@ -1008,6 +1069,8 @@ write_glyphs (string, len)
   int produced, consumed;
   struct frame *sf = XFRAME (selected_frame);
   struct frame *f = updating_frame ? updating_frame : sf;
+  unsigned char conversion_buffer[1024];
+  int conversion_buffer_size = sizeof conversion_buffer;
 
   if (write_glyphs_hook
       && ! FRAME_TERMCAP_P (f))
@@ -1016,8 +1079,8 @@ write_glyphs (string, len)
       return;
     }
 
-  highlight_if_desired ();
   turn_off_insert ();
+  tty_hide_cursor ();
 
   /* Don't dare write in last column of bottom line, if Auto-Wrap,
      since that would scroll the whole frame on some terminals.  */
@@ -1038,21 +1101,22 @@ write_glyphs (string, len)
   while (len > 0)
     {
       /* Identify a run of glyphs with the same face.  */
-      int face_id = string->u.ch.face_id;
+      int face_id = string->face_id;
       int n;
       
       for (n = 1; n < len; ++n)
-       if (string[n].u.ch.face_id != face_id)
+       if (string[n].face_id != face_id)
          break;
 
       /* Turn appearance modes of the face of the run on.  */
+      highlight_if_desired ();
       turn_on_face (f, face_id);
 
       while (n > 0)
        {
-         /* We use a shared conversion buffer of the current size
-            (1024 bytes at least).  Usually it is sufficient, but if
-            not, we just repeat the loop.  */
+         /* 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,
                                           n, conversion_buffer_size,
                                           &consumed);
@@ -1071,6 +1135,7 @@ write_glyphs (string, len)
 
       /* Turn appearance modes off.  */
       turn_off_face (f, face_id);
+      turn_off_highlight ();
     }
   
   /* We may have to output some codes to terminate the writing.  */
@@ -1101,7 +1166,7 @@ insert_glyphs (start, len)
      register int len;
 {
   char *buf;
-  GLYPH g;
+  struct glyph *glyph = NULL;
   struct frame *f, *sf;
 
   if (len <= 0)
@@ -1115,7 +1180,6 @@ insert_glyphs (start, len)
 
   sf = XFRAME (selected_frame);
   f = updating_frame ? updating_frame : sf;
-  highlight_if_desired ();
 
   if (TS_ins_multi_chars)
     {
@@ -1134,14 +1198,20 @@ insert_glyphs (start, len)
   while (len-- > 0)
     {
       int produced, consumed;
-      struct glyph glyph;
+      unsigned char conversion_buffer[1024];
+      int conversion_buffer_size = sizeof conversion_buffer;
 
       OUTPUT1_IF (TS_ins_char);
       if (!start)
-       g = SPACEGLYPH;
+       {
+         conversion_buffer[0] = SPACEGLYPH;
+         produced = 1;
+       }
       else
        {
-         g = GLYPH_FROM_CHAR_GLYPH (*start);
+         highlight_if_desired ();
+         turn_on_face (f, start->face_id);
+         glyph = start;
          ++start;
          /* We must open sufficient space for a character which
             occupies more than one column.  */
@@ -1150,18 +1220,17 @@ insert_glyphs (start, len)
              OUTPUT1_IF (TS_ins_char);
              start++, len--;
            }
-       }
 
-      if (len <= 0)
-       /* This is the last glyph.  */
-       terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
+         if (len <= 0)
+           /* This is the last glyph.  */
+           terminal_coding.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,
+                                          conversion_buffer_size, &consumed);
+       }
 
-      /* We use shared conversion buffer of the current size (1024
-        bytes at least).  It is surely sufficient for just one glyph.  */
-      SET_CHAR_GLYPH_FROM_GLYPH (glyph, g);
-      turn_on_face (f, glyph.u.ch.face_id);
-      produced = encode_terminal_code (&glyph, conversion_buffer,
-                                      1, conversion_buffer_size, &consumed);
       if (produced > 0)
        {
          fwrite (conversion_buffer, 1, produced, stdout);
@@ -1172,7 +1241,11 @@ insert_glyphs (start, len)
        }
 
       OUTPUT1_IF (TS_pad_inserted_char);
-      turn_off_face (f, glyph.u.ch.face_id);
+      if (start)
+       {
+         turn_off_face (f, glyph->face_id);
+         turn_off_highlight ();
+       }
     }
   
   cmcheckmagic ();
@@ -1431,16 +1504,6 @@ calculate_costs (frame)
   FRAME_COST_BAUD_RATE (frame) = baud_rate;
 
   scroll_region_cost = string_cost (f);
-#ifdef HAVE_X_WINDOWS
-  if (FRAME_X_P (frame))
-    {
-      do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*",
-                                       0, 0,
-                                       x_screen_planes (frame));
-      scroll_region_cost = 0;
-      return;
-    }
-#endif
 
   /* These variables are only used for terminal stuff.  They are allocated
      once for the terminal frame of X-windows emacs, but not used afterwards.
@@ -1754,9 +1817,9 @@ append_glyph (it)
     {
       glyph->type = CHAR_GLYPH;
       glyph->pixel_width = 1;
-      glyph->u.ch.code = it->c;
-      glyph->u.ch.face_id = it->face_id;
-      glyph->u.ch.padding_p = i > 0;
+      glyph->u.ch = it->c;
+      glyph->face_id = it->face_id;
+      glyph->padding_p = i > 0;
       glyph->charpos = CHARPOS (it->position);
       glyph->object = it->object;
       
@@ -1778,11 +1841,15 @@ 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);
   
-  /* Nothing but characters are supported on terminal frames.  */
-  xassert (it->what == IT_CHARACTER);
+  /* Nothing but characters are supported on terminal frames.  For a
+     composition sequence, it->c is the first character of the
+     sequence.  */
+  xassert (it->what == IT_CHARACTER
+          || it->what == IT_COMPOSITION);
 
   if (it->c >= 040 && it->c < 0177)
     {
@@ -1794,7 +1861,7 @@ produce_glyphs (it)
     it->pixel_width = it->nglyphs = 0;
   else if (it->c == '\t')
     {
-      int absolute_x = (it->current_x - it->prompt_width
+      int absolute_x = (it->current_x
                        + it->continuation_lines_width);
       int next_tab_x 
        = (((1 + absolute_x + it->tab_width - 1) 
@@ -1825,19 +1892,26 @@ produce_glyphs (it)
       it->pixel_width = nspaces;
       it->nglyphs = nspaces;
     }
+  else if (SINGLE_BYTE_CHAR_P (it->c))
+    {
+      /* Coming here means that it->c is from display table, thus we
+        must send the code as is to the terminal.  Although there's
+        no way to know how many columns it occupies on a screen, it
+        is a good assumption that a single byte code has 1-column
+        width.  */
+      it->pixel_width = it->nglyphs = 1;
+      if (it->glyph_row)
+       append_glyph (it);
+    }
   else
     {
-      /* A multi-byte character.  The display width is a per character
-        value for characters of set CHARSET_COMPOSITION; otherwise
-        it is fixed for all characters of the set.  Some of the 
-        glyphs may have to be ignored because they are already 
-        displayed in a continued line.  */
+      /* A multi-byte character.  The display width is fixed for all
+        characters of the set.  Some of the glyphs may have to be
+        ignored because they are already displayed in a continued
+        line.  */
       int charset = CHAR_CHARSET (it->c);
 
-      if (charset == CHARSET_COMPOSITION)
-       it->pixel_width = cmpchar_table[COMPOSITE_CHAR_ID (it->c)]->width;
-      else
-       it->pixel_width = CHARSET_WIDTH (charset);
+      it->pixel_width = CHARSET_WIDTH (charset);
       it->nglyphs = it->pixel_width;
       
       if (it->glyph_row)
@@ -1870,7 +1944,7 @@ produce_special_glyphs (it, what)
   temp_it.dp = NULL;
   temp_it.what = IT_CHARACTER;
   temp_it.len = 1;
-  temp_it.object = 0;
+  temp_it.object = make_number (0);
   bzero (&temp_it.current, sizeof temp_it.current);
 
   if (what == IT_CONTINUATION)
@@ -1881,7 +1955,7 @@ produce_special_glyphs (it, what)
          && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp))))
        {
          temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_CONTINUE_GLYPH (it->dp)));
-         temp_it.len = CHAR_LEN (temp_it.c);
+         temp_it.len = CHAR_BYTES (temp_it.c);
        }
       else
        temp_it.c = '\\';
@@ -1898,7 +1972,7 @@ produce_special_glyphs (it, what)
          && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp))))
        {
          temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_TRUNC_GLYPH (it->dp)));
-         temp_it.len = CHAR_LEN (temp_it.c);
+         temp_it.len = CHAR_BYTES (temp_it.c);
        }
       else
        temp_it.c = '$';
@@ -1932,6 +2006,15 @@ estimate_mode_line_height (f, face_id)
                                Faces
  ***********************************************************************/
 
+/* Value is non-zero if attribute ATTR may be used.  ATTR should be
+   one of the enumerators from enum no_color_bit, or a bit set built
+   from them.  Some display attributes may not be used together with
+   color; the termcap capability `NC' specifies which ones.  */
+
+#define MAY_USE_WITH_COLORS_P(ATTR)            \
+     (TN_max_colors > 0                                \
+      ? (TN_no_color_video & (ATTR)) == 0      \
+      : 1)
 
 /* Turn appearances of face FACE_ID on tty frame F on.  */
 
@@ -1941,45 +2024,93 @@ turn_on_face (f, face_id)
      int face_id;
 {
   struct face *face = FACE_FROM_ID (f, face_id);
+  long fg = face->foreground;
+  long bg = face->background;
 
-  xassert (face != NULL);
+  /* Do this first because TS_end_standout_mode may be the same
+     as TS_exit_attribute_mode, which turns all appearances off. */
+  if (MAY_USE_WITH_COLORS_P (NC_REVERSE))
+    {
+      if (TN_max_colors > 0)
+       {
+         if (fg >= 0 && bg >= 0)
+           {
+             /* If the terminal supports colors, we can set them
+                below without using reverse video.  The face's fg
+                and bg colors are set as they should appear on
+                the screen, i.e. they take the inverse-video'ness
+                of the face already into account.  */
+           }
+         else if (inverse_video)
+           {
+             if (fg == FACE_TTY_DEFAULT_FG_COLOR
+                 || bg == FACE_TTY_DEFAULT_BG_COLOR)
+               toggle_highlight ();
+           }
+         else
+           {
+             if (fg == FACE_TTY_DEFAULT_BG_COLOR
+                 || bg == FACE_TTY_DEFAULT_FG_COLOR)
+               toggle_highlight ();
+           }
+       }
+      else
+       {
+         /* If we can't display colors, use reverse video
+            if the face specifies that.  */
+         if (inverse_video)
+           {
+             if (fg == FACE_TTY_DEFAULT_FG_COLOR
+                 || bg == FACE_TTY_DEFAULT_BG_COLOR)
+               toggle_highlight ();
+           }
+         else
+           {
+             if (fg == FACE_TTY_DEFAULT_BG_COLOR
+                 || bg == FACE_TTY_DEFAULT_FG_COLOR)
+               toggle_highlight ();
+           }
+       }
+    }
 
   if (face->tty_bold_p)
-    OUTPUT1_IF (TS_enter_bold_mode);
+    {
+      if (MAY_USE_WITH_COLORS_P (NC_BOLD))
+       OUTPUT1_IF (TS_enter_bold_mode);
+    }
   else if (face->tty_dim_p)
-    OUTPUT1_IF (TS_enter_dim_mode);
+    if (MAY_USE_WITH_COLORS_P (NC_DIM))
+      OUTPUT1_IF (TS_enter_dim_mode);
 
   /* Alternate charset and blinking not yet used.  */
-  if (face->tty_alt_charset_p)
+  if (face->tty_alt_charset_p
+      && MAY_USE_WITH_COLORS_P (NC_ALT_CHARSET))
     OUTPUT1_IF (TS_enter_alt_charset_mode);
 
-  if (face->tty_blinking_p)
+  if (face->tty_blinking_p
+      && MAY_USE_WITH_COLORS_P (NC_BLINK))
     OUTPUT1_IF (TS_enter_blink_mode);
 
   if (face->tty_underline_p
       /* Don't underline if that's difficult.  */
-      && TN_magic_cookie_glitch_ul <= 0)
+      && TN_magic_cookie_glitch_ul <= 0
+      && MAY_USE_WITH_COLORS_P (NC_UNDERLINE))
     OUTPUT1_IF (TS_enter_underline_mode);
 
-  if (face->tty_reverse_p)
-    OUTPUT1_IF (TS_enter_reverse_mode);
-
   if (TN_max_colors > 0)
     {
       char *p;
       
-      if (face->foreground != FACE_TTY_DEFAULT_COLOR
-         && TS_set_foreground)
+      if (fg >= 0 && TS_set_foreground)
        {
-         p = tparam (TS_set_foreground, NULL, 0, (int) face->foreground);
+         p = tparam (TS_set_foreground, NULL, 0, (int) fg);
          OUTPUT (p);
          xfree (p);
        }
 
-      if (face->background != FACE_TTY_DEFAULT_COLOR
-         && TS_set_background)
+      if (bg >= 0 && TS_set_background)
        {
-         p = tparam (TS_set_background, NULL, 0, (int) face->background);
+         p = tparam (TS_set_background, NULL, 0, (int) bg);
          OUTPUT (p);
          xfree (p);
        }
@@ -1995,7 +2126,6 @@ turn_off_face (f, face_id)
      int face_id;
 {
   struct face *face = FACE_FROM_ID (f, face_id);
-  Lisp_Object entry;
 
   xassert (face != NULL);
 
@@ -2010,7 +2140,11 @@ turn_off_face (f, face_id)
          || face->tty_alt_charset_p
          || face->tty_blinking_p
          || face->tty_underline_p)
-       OUTPUT1_IF (TS_exit_attribute_mode);
+       {
+         OUTPUT1_IF (TS_exit_attribute_mode);
+         if (strcmp (TS_exit_attribute_mode, TS_end_standout_mode) == 0)
+           standout_mode = 0;
+       }
 
       if (face->tty_alt_charset_p)
        OUTPUT_IF (TS_exit_alt_charset_mode);
@@ -2030,8 +2164,10 @@ turn_off_face (f, face_id)
 
   /* Switch back to default colors.  */
   if (TN_max_colors > 0
-      && (face->foreground != FACE_TTY_DEFAULT_COLOR
-         || face->background != FACE_TTY_DEFAULT_COLOR))
+      && ((face->foreground != FACE_TTY_DEFAULT_COLOR
+          && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
+         || (face->background != FACE_TTY_DEFAULT_COLOR
+             && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
     OUTPUT1_IF (TS_orig_pair);
 }
   
@@ -2039,9 +2175,10 @@ turn_off_face (f, face_id)
 /* 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, 0, 0,
-  "Return non-nil if TTY can display colors.")
-     ()
+       0, 1, 0,
+       doc: /* Return non-nil if TTY can display colors on FRAME.  */)
+     (frame)
+     Lisp_Object frame;
 {
   return TN_max_colors > 0 ? Qt : Qnil;
 }
@@ -2095,6 +2232,7 @@ term_init (terminal_type)
 
   FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0;
   FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none;
+  TN_max_colors = 16;  /* Required to be non-zero for tty-display-color-p */
 
   return;
 #else  /* not WINDOWSNT */
@@ -2143,7 +2281,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   TS_clr_to_bottom = tgetstr ("cd", address);
   TS_clr_line = tgetstr ("ce", address);
   TS_clr_frame = tgetstr ("cl", address);
-  ColPosition = tgetstr ("ch", address);
+  ColPosition = NULL; /* tgetstr ("ch", address); */
   AbsPosition = tgetstr ("cm", address);
   CR = tgetstr ("cr", address);
   TS_set_scroll_region = tgetstr ("cs", address);
@@ -2212,18 +2350,28 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   MultiLeft = tgetstr ("LE", address);
   MultiRight = tgetstr ("RI", address);
 
-  /* SVr4/ANSI color suppert.  */
+  /* SVr4/ANSI color suppert.  If "op" isn't available, don't support
+     color because we can't switch back to the default foreground and
+     background.  */
   TS_orig_pair = tgetstr ("op", address);
-  TS_set_foreground = tgetstr ("AF", address);
-  TS_set_background = tgetstr ("AB", address);
-  if (!TS_set_foreground)
+  if (TS_orig_pair)
     {
-      /* SVr4.  */
-      TS_set_foreground = tgetstr ("Sf", address);
-      TS_set_background = tgetstr ("Sb", address);
+      TS_set_foreground = tgetstr ("AF", address);
+      TS_set_background = tgetstr ("AB", address);
+      if (!TS_set_foreground)
+       {
+         /* SVr4.  */
+         TS_set_foreground = tgetstr ("Sf", address);
+         TS_set_background = tgetstr ("Sb", address);
+       }
+      
+      TN_max_colors = tgetnum ("Co");
+      TN_max_pairs = tgetnum ("pa");
+      
+      TN_no_color_video = tgetnum ("NC");
+      if (TN_no_color_video == -1)
+       TN_no_color_video = 0;
     }
-  TN_max_colors = tgetnum ("Co");
-  TN_max_pairs = tgetnum ("pa");
 
   MagicWrap = tgetflag ("xn");
   /* Since we make MagicWrap terminals look like AutoWrap, we need to have
@@ -2461,8 +2609,8 @@ void
 syms_of_term ()
 {
   DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
-    "Non-nil means the system uses terminfo rather than termcap.\n\
-This variable can be used by terminal emulator packages.");
+    doc: /* Non-nil means the system uses terminfo rather than termcap.
+This variable can be used by terminal emulator packages.  */);
 #ifdef TERMINFO
   system_uses_terminfo = 1;
 #else
@@ -2470,8 +2618,8 @@ This variable can be used by terminal emulator packages.");
 #endif
 
   DEFVAR_LISP ("ring-bell-function", &Vring_bell_function,
-    "Non-nil means call this function to ring the bell.\n\
-The function should accept no arguments.");
+    doc: /* Non-nil means call this function to ring the bell.
+The function should accept no arguments.  */);
   Vring_bell_function = Qnil;
 
   defsubr (&Stty_display_color_p);