/* terminal control module for terminals described by TERMCAP
- Copyright (C) 1985, 86, 87, 93, 94, 95, 98
+ Copyright (C) 1985, 86, 87, 93, 94, 95, 98, 2000, 2001
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#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));
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;
\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
update_end (f)
FRAME_PTR f;
{
- if (! FRAME_TERMCAP_P (updating_frame))
+ if (! FRAME_TERMCAP_P (f))
{
(*update_end_hook) (f);
updating_frame = 0;
}
}
+static void
+toggle_highlight ()
+{
+ if (standout_mode)
+ turn_off_highlight ();
+ else
+ turn_on_highlight ();
+}
+
/* Make cursor invisible. */
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
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))
{
- 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);
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))
return;
}
- highlight_if_desired ();
turn_off_insert ();
/* Don't dare write in last column of bottom line, if Auto-Wrap,
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);
/* Turn appearance modes off. */
turn_off_face (f, face_id);
+ turn_off_highlight ();
}
/* We may have to output some codes to terminate the writing. */
register int len;
{
char *buf;
- GLYPH g;
+ struct glyph *glyph = NULL;
struct frame *f, *sf;
if (len <= 0)
sf = XFRAME (selected_frame);
f = updating_frame ? updating_frame : sf;
- highlight_if_desired ();
if (TS_ins_multi_chars)
{
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. */
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);
}
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 ();
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.
{
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;
{
/* 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)
{
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)
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)
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)
&& 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 = '\\';
&& 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 = '$';
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. */
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);
}
|| 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);
/* 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);
}
/* 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;
}
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 */
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);
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");