+
+ return Qnil;
+}
+
+\f
+/***********************************************************************
+ Character Display Information
+ ***********************************************************************/
+
+static void append_glyph P_ ((struct it *));
+
+
+/* Append glyphs to IT's glyph_row. Called from produce_glyphs for
+ terminal frames if IT->glyph_row != NULL. IT->c is the character
+ for which to produce glyphs; IT->face_id contains the character's
+ face. Padding glyphs are appended if IT->c has a IT->pixel_width >
+ 1. */
+
+static void
+append_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph, *end;
+ int i;
+
+ xassert (it->glyph_row);
+ glyph = (it->glyph_row->glyphs[it->area]
+ + it->glyph_row->used[it->area]);
+ end = it->glyph_row->glyphs[1 + it->area];
+
+ for (i = 0;
+ i < it->pixel_width && glyph < end;
+ ++i)
+ {
+ glyph->type = CHAR_GLYPH;
+ glyph->pixel_width = 1;
+ 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;
+
+ ++it->glyph_row->used[it->area];
+ ++glyph;
+ }
+}
+
+
+/* Produce glyphs for the display element described by IT. *IT
+ specifies what we want to produce a glyph for (character, image, ...),
+ and where in the glyph matrix we currently are (glyph row and hpos).
+ produce_glyphs fills in output fields of *IT with information such as the
+ pixel width and height of a character, and maybe output actual glyphs at
+ the same time if IT->glyph_row is non-null. See the explanation of
+ struct display_iterator in dispextern.h for an overview.
+
+ produce_glyphs also stores the result of glyph width, ascent
+ etc. computations in *IT.
+
+ IT->glyph_row may be null, in which case produce_glyphs does not
+ actually fill in the glyphs. This is used in the move_* functions
+ in xdisp.c for text width and height computations.
+
+ Callers usually don't call produce_glyphs directly;
+ instead they use the macro PRODUCE_GLYPHS. */
+
+void
+produce_glyphs (it)
+ struct it *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. 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 = 1;
+ if (it->glyph_row)
+ append_glyph (it);
+ }
+ else if (it->c == '\n')
+ it->pixel_width = it->nglyphs = 0;
+ else if (it->c == '\t')
+ {
+ int absolute_x = (it->current_x
+ + it->continuation_lines_width);
+ int next_tab_x
+ = (((1 + absolute_x + it->tab_width - 1)
+ / it->tab_width)
+ * it->tab_width);
+ int nspaces;
+
+ /* If part of the TAB has been displayed on the previous line
+ which is continued now, continuation_lines_width will have
+ been incremented already by the part that fitted on the
+ continued line. So, we will get the right number of spaces
+ here. */
+ nspaces = next_tab_x - absolute_x;
+
+ if (it->glyph_row)
+ {
+ int n = nspaces;
+
+ it->c = ' ';
+ it->pixel_width = it->len = 1;
+
+ while (n--)
+ append_glyph (it);
+
+ it->c = '\t';
+ }
+
+ 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
+ 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);
+
+ it->pixel_width = CHARSET_WIDTH (charset);
+ it->nglyphs = it->pixel_width;
+
+ if (it->glyph_row)
+ append_glyph (it);
+ }
+
+ /* Advance current_x by the pixel width as a convenience for
+ the caller. */
+ if (it->area == TEXT_AREA)
+ it->current_x += it->pixel_width;
+ it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0;
+ it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1;
+}
+
+
+/* Get information about special display element WHAT in an
+ environment described by IT. WHAT is one of IT_TRUNCATION or
+ IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
+ non-null glyph_row member. This function ensures that fields like
+ face_id, c, len of IT are left untouched. */
+
+void
+produce_special_glyphs (it, what)
+ struct it *it;
+ enum display_element_type what;
+{
+ struct it temp_it;
+
+ temp_it = *it;
+ temp_it.dp = NULL;
+ temp_it.what = IT_CHARACTER;
+ temp_it.len = 1;
+ temp_it.object = make_number (0);
+ bzero (&temp_it.current, sizeof temp_it.current);
+
+ if (what == IT_CONTINUATION)
+ {
+ /* Continuation glyph. */
+ if (it->dp
+ && INTEGERP (DISP_CONTINUE_GLYPH (it->dp))
+ && 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_BYTES (temp_it.c);
+ }
+ else
+ temp_it.c = '\\';
+
+ produce_glyphs (&temp_it);
+ it->pixel_width = temp_it.pixel_width;
+ it->nglyphs = temp_it.pixel_width;
+ }
+ else if (what == IT_TRUNCATION)
+ {
+ /* Truncation glyph. */
+ if (it->dp
+ && INTEGERP (DISP_TRUNC_GLYPH (it->dp))
+ && 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_BYTES (temp_it.c);
+ }
+ else
+ temp_it.c = '$';
+
+ produce_glyphs (&temp_it);
+ it->pixel_width = temp_it.pixel_width;
+ it->nglyphs = temp_it.pixel_width;
+ }
+ else
+ abort ();
+}
+
+
+/* Return an estimation of the pixel height of mode or top lines on
+ frame F. FACE_ID specifies what line's height to estimate. */
+
+int
+estimate_mode_line_height (f, face_id)
+ struct frame *f;
+ enum face_id face_id;
+{
+ if (estimate_mode_line_height_hook)
+ return estimate_mode_line_height_hook (f, face_id);
+ else
+ return 1;
+}
+
+
+\f
+/***********************************************************************
+ 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. */
+
+static void
+turn_on_face (f, face_id)
+ struct frame *f;
+ int face_id;
+{
+ struct face *face = FACE_FROM_ID (f, face_id);
+ long fg = face->foreground;
+ long bg = face->background;
+
+ /* 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)
+ {
+ if (MAY_USE_WITH_COLORS_P (NC_BOLD))
+ OUTPUT1_IF (TS_enter_bold_mode);
+ }
+ else if (face->tty_dim_p)
+ 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
+ && MAY_USE_WITH_COLORS_P (NC_ALT_CHARSET))
+ OUTPUT1_IF (TS_enter_alt_charset_mode);
+
+ if (face->tty_blinking_p
+ && MAY_USE_WITH_COLORS_P (NC_BLINK))
+ OUTPUT1_IF (TS_enter_blink_mode);
+
+ if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (NC_UNDERLINE))
+ OUTPUT1_IF (TS_enter_underline_mode);
+
+ if (TN_max_colors > 0)
+ {
+ char *p;
+
+ if (fg >= 0 && TS_set_foreground)
+ {
+ p = tparam (TS_set_foreground, NULL, 0, (int) fg);
+ OUTPUT (p);
+ xfree (p);
+ }
+
+ if (bg >= 0 && TS_set_background)
+ {
+ p = tparam (TS_set_background, NULL, 0, (int) bg);
+ OUTPUT (p);
+ xfree (p);
+ }
+ }
+}
+
+
+/* Turn off appearances of face FACE_ID on tty frame F. */
+
+static void
+turn_off_face (f, face_id)
+ struct frame *f;
+ int face_id;
+{
+ struct face *face = FACE_FROM_ID (f, face_id);
+
+ xassert (face != NULL);
+
+ if (TS_exit_attribute_mode)
+ {
+ /* Capability "me" will turn off appearance modes double-bright,
+ half-bright, reverse-video, standout, underline. It may or
+ may not turn off alt-char-mode. */
+ if (face->tty_bold_p
+ || face->tty_dim_p
+ || face->tty_reverse_p
+ || face->tty_alt_charset_p
+ || face->tty_blinking_p
+ || face->tty_underline_p)
+ {
+ 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);
+ }
+ else
+ {
+ /* If we don't have "me" we can only have those appearances
+ that have exit sequences defined. */
+ if (face->tty_alt_charset_p)
+ OUTPUT_IF (TS_exit_alt_charset_mode);
+
+ if (face->tty_underline_p)
+ OUTPUT_IF (TS_exit_underline_mode);
+ }
+
+ /* Switch back to default colors. */
+ if (TN_max_colors > 0
+ && ((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, 1, 0,
+ doc: /* Return non-nil if TTY can display colors on DISPLAY. */)
+ (display)
+ Lisp_Object display;
+{
+ return TN_max_colors > 0 ? Qt : Qnil;
+}
+
+/* Return the number of supported colors. */
+DEFUN ("tty-display-color-cells", Ftty_display_color_cells,
+ Stty_display_color_cells, 0, 1, 0,
+ doc: /* Return the number of colors supported by TTY on DISPLAY. */)
+ (display)
+ Lisp_Object display;
+{
+ return make_number (TN_max_colors);
+}
+
+#ifndef WINDOWSNT
+
+/* Save or restore the default color-related capabilities of this
+ terminal. */
+static void
+tty_default_color_capabilities (save)
+ int save;
+{
+ static char
+ *default_orig_pair, *default_set_foreground, *default_set_background;
+ static int default_max_colors, default_max_pairs, default_no_color_video;
+
+ if (save)
+ {
+ if (default_orig_pair)
+ xfree (default_orig_pair);
+ default_orig_pair = TS_orig_pair ? xstrdup (TS_orig_pair) : NULL;
+
+ if (default_set_foreground)
+ xfree (default_set_foreground);
+ default_set_foreground = TS_set_foreground ? xstrdup (TS_set_foreground)
+ : NULL;
+
+ if (default_set_background)
+ xfree (default_set_background);
+ default_set_background = TS_set_background ? xstrdup (TS_set_background)
+ : NULL;
+
+ default_max_colors = TN_max_colors;
+ default_max_pairs = TN_max_pairs;
+ default_no_color_video = TN_no_color_video;
+ }
+ else
+ {
+ TS_orig_pair = default_orig_pair;
+ TS_set_foreground = default_set_foreground;
+ TS_set_background = default_set_background;
+ TN_max_colors = default_max_colors;
+ TN_max_pairs = default_max_pairs;
+ TN_no_color_video = default_no_color_video;
+ }
+}
+
+/* Setup one of the standard tty color schemes according to MODE.
+ MODE's value is generally the number of colors which we want to
+ support; zero means set up for the default capabilities, the ones
+ we saw at term_init time; -1 means turn off color support. */
+void
+tty_setup_colors (mode)
+ int mode;
+{
+ switch (mode)
+ {
+ case -1: /* no colors at all */
+ TN_max_colors = 0;
+ TN_max_pairs = 0;
+ TN_no_color_video = 0;
+ TS_set_foreground = TS_set_background = TS_orig_pair = NULL;
+ break;
+ case 0: /* default colors, if any */
+ default:
+ tty_default_color_capabilities (0);
+ break;
+ case 8: /* 8 standard ANSI colors */
+ TS_orig_pair = "\033[0m";
+#ifdef TERMINFO
+ TS_set_foreground = "\033[3%p1%dm";
+ TS_set_background = "\033[4%p1%dm";
+#else
+ TS_set_foreground = "\033[3%dm";
+ TS_set_background = "\033[4%dm";
+#endif
+ TN_max_colors = 8;
+ TN_max_pairs = 64;
+ TN_no_color_video = 0;
+ break;
+ }
+}
+
+void
+set_tty_color_mode (f, val)
+ struct frame *f;
+ Lisp_Object val;
+{
+ Lisp_Object color_mode_spec, current_mode_spec;
+ Lisp_Object color_mode, current_mode;
+ int mode, old_mode;
+ extern Lisp_Object Qtty_color_mode;
+ Lisp_Object tty_color_mode_alist;
+
+ tty_color_mode_alist = Fintern_soft (build_string ("tty-color-mode-alist"),
+ Qnil);
+
+ if (NATNUMP (val))
+ color_mode = val;
+ else
+ {
+ if (NILP (tty_color_mode_alist))
+ color_mode_spec = Qnil;
+ else
+ color_mode_spec = Fassq (val, XSYMBOL (tty_color_mode_alist)->value);
+ current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist);
+
+ if (CONSP (color_mode_spec))
+ color_mode = XCDR (color_mode_spec);
+ else
+ color_mode = Qnil;
+ }
+ if (CONSP (current_mode_spec))
+ current_mode = XCDR (current_mode_spec);
+ else
+ current_mode = Qnil;
+ if (NATNUMP (color_mode))
+ mode = XINT (color_mode);
+ else
+ mode = 0; /* meaning default */
+ if (NATNUMP (current_mode))
+ old_mode = XINT (current_mode);
+ else
+ old_mode = 0;
+
+ if (mode != old_mode)
+ {
+ tty_setup_colors (mode);
+ /* This recomputes all the faces given the new color
+ definitions. */
+ call0 (intern ("tty-set-up-initial-frame-faces"));
+ redraw_frame (f);
+ }