Add Keywords header.
[bpt/emacs.git] / src / term.c
index c51f0eb..6cdfa8d 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,8 +19,7 @@ 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>
@@ -31,21 +30,33 @@ Boston, MA 02111-1307, USA.  */
 #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"
 
-#ifdef HAVE_TERMCAP_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));
@@ -146,6 +157,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,
@@ -158,6 +170,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
@@ -170,6 +183,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
@@ -203,10 +217,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
@@ -220,6 +236,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.  */
@@ -268,6 +285,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;
@@ -385,13 +423,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
@@ -405,7 +446,7 @@ extern char *tgetstr ();
 void
 ring_bell ()
 {
-  if (! NILP (Vring_bell_function))
+  if (!NILP (Vring_bell_function))
     {
       Lisp_Object function;
 
@@ -416,105 +457,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
@@ -525,26 +558,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)
@@ -578,7 +607,7 @@ turn_off_highlight ()
     }
 }
 
-void
+static void
 turn_on_highlight ()
 {
   if (TN_standout_width < 0)
@@ -589,13 +618,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);
+    }
 }
 
 
@@ -604,8 +646,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);
+    }
 }
 
 
@@ -648,12 +694,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);
@@ -683,7 +730,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
@@ -925,7 +972,6 @@ 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[MAX_MULTIBYTE_LENGTH], *buf;
   int len;
   register int tlen = GLYPH_TABLE_LENGTH;
@@ -933,7 +979,10 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
   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);
 
@@ -951,11 +1000,13 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
                {
                  len = 1;
                  buf = " ";
+                 coding->src_multibyte = 0;
                }
              else
                {
                  len = CHAR_STRING (src->u.ch, workbuf);
                  buf = workbuf;
+                 coding->src_multibyte = 1;
                }
            }
          else
@@ -966,15 +1017,20 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
 
              if (GLYPH_SIMPLE_P (tbase, tlen, g))
                {
-                 /* We set the multi-byte form of C at WORKBUF.  */
-                 len = CHAR_STRING (src->u.ch, workbuf);
+                 /* 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]);
                }
            }
          
@@ -1014,6 +1070,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))
@@ -1022,8 +1080,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.  */
@@ -1052,13 +1110,14 @@ write_glyphs (string, len)
          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);
@@ -1077,6 +1136,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.  */
@@ -1107,7 +1167,7 @@ insert_glyphs (start, len)
      register int len;
 {
   char *buf;
-  struct glyph *glyph;
+  struct glyph *glyph = NULL;
   struct frame *f, *sf;
 
   if (len <= 0)
@@ -1121,7 +1181,6 @@ insert_glyphs (start, len)
 
   sf = XFRAME (selected_frame);
   f = updating_frame ? updating_frame : sf;
-  highlight_if_desired ();
 
   if (TS_ins_multi_chars)
     {
@@ -1140,6 +1199,8 @@ insert_glyphs (start, len)
   while (len-- > 0)
     {
       int produced, consumed;
+      unsigned char conversion_buffer[1024];
+      int conversion_buffer_size = sizeof conversion_buffer;
 
       OUTPUT1_IF (TS_ins_char);
       if (!start)
@@ -1149,8 +1210,9 @@ insert_glyphs (start, len)
        }
       else
        {
+         highlight_if_desired ();
          turn_on_face (f, start->face_id);
-         glyph= start;
+         glyph = start;
          ++start;
          /* We must open sufficient space for a character which
             occupies more than one column.  */
@@ -1164,9 +1226,9 @@ insert_glyphs (start, len)
            /* This is the last glyph.  */
            terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
 
-         /* We use shared conversion buffer of the current size (1024
-            bytes at least).  It is surely sufficient for just one glyph.  */
-         produced = encode_terminal_code (&glyph, conversion_buffer, 1,
+         /* 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);
        }
 
@@ -1181,7 +1243,10 @@ insert_glyphs (start, len)
 
       OUTPUT1_IF (TS_pad_inserted_char);
       if (start)
-       turn_off_face (f, glyph->face_id);
+       {
+         turn_off_face (f, glyph->face_id);
+         turn_off_highlight ();
+       }
     }
   
   cmcheckmagic ();
@@ -1440,16 +1505,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.
@@ -1807,7 +1862,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) 
@@ -1838,6 +1893,17 @@ 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 fixed for all
@@ -1879,7 +1945,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)
@@ -1890,7 +1956,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 = '\\';
@@ -1907,7 +1973,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 = '$';
@@ -1941,6 +2007,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.  */
 
@@ -1950,51 +2025,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
-      || face->foreground == FACE_TTY_DEFAULT_BG_COLOR
-      || face->background == FACE_TTY_DEFAULT_FG_COLOR)
-    OUTPUT1_IF (TS_enter_reverse_mode);
-
   if (TN_max_colors > 0)
     {
       char *p;
       
-      if (face->foreground != FACE_TTY_DEFAULT_COLOR
-         && face->foreground != FACE_TTY_DEFAULT_FG_COLOR
-         && face->foreground != FACE_TTY_DEFAULT_BG_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
-         && face->background != FACE_TTY_DEFAULT_BG_COLOR
-         && face->background != FACE_TTY_DEFAULT_FG_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);
        }
@@ -2024,7 +2141,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);
@@ -2055,9 +2176,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,
+  "Return non-nil if TTY can display colors on FRAME.")
+     (frame)
+     Lisp_Object frame;
 {
   return TN_max_colors > 0 ? Qt : Qnil;
 }
@@ -2111,6 +2233,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 */
@@ -2159,7 +2282,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);
@@ -2242,8 +2365,13 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
          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;
     }
 
   MagicWrap = tgetflag ("xn");