+
+ return Qnil;
+}
+
+\f
+/***********************************************************************
+ Character Display Information
+ ***********************************************************************/
+
+static void append_glyph P_ ((struct it *));
+static void produce_stretch_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_STRETCH);
+
+ if (it->what == IT_STRETCH)
+ {
+ produce_stretch_glyph (it);
+ goto done;
+ }
+
+ /* 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);
+ }
+
+ done:
+ /* 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;
+}
+
+
+/* Produce a stretch glyph for iterator IT. IT->object is the value
+ of the glyph property displayed. The value must be a list
+ `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+ being recognized:
+
+ 1. `:width WIDTH' specifies that the space should be WIDTH *
+ canonical char width wide. WIDTH may be an integer or floating
+ point number.
+
+ 2. `:align-to HPOS' specifies that the space should be wide enough
+ to reach HPOS, a value in canonical character units. */
+
+static void
+produce_stretch_glyph (it)
+ struct it *it;
+{
+ /* (space :width WIDTH ...) */
+ Lisp_Object prop, plist;
+ int width = 0, align_to = -1;
+ int zero_width_ok_p = 0;
+ double tem;
+
+ /* List should start with `space'. */
+ xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+ plist = XCDR (it->object);
+
+ /* Compute the width of the stretch. */
+ if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
+ && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0))
+ {
+ /* Absolute width `:width WIDTH' specified and valid. */
+ zero_width_ok_p = 1;
+ width = (int)(tem + 0.5);
+ }
+ else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
+ && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to))
+ {
+ if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
+ align_to = (align_to < 0
+ ? 0
+ : align_to - window_box_left_offset (it->w, TEXT_AREA));
+ else if (align_to < 0)
+ align_to = window_box_left_offset (it->w, TEXT_AREA);
+ width = max (0, (int)(tem + 0.5) + align_to - it->current_x);
+ zero_width_ok_p = 1;
+ }
+ else
+ /* Nothing specified -> width defaults to canonical char width. */
+ width = FRAME_COLUMN_WIDTH (it->f);
+
+ if (width <= 0 && (width < 0 || !zero_width_ok_p))
+ width = 1;
+
+ if (width > 0 && it->glyph_row)
+ {
+ Lisp_Object o_object = it->object;
+ Lisp_Object object = it->stack[it->sp - 1].string;
+ int n = width;
+ int c = it->c;
+
+ if (!STRINGP (object))
+ object = it->w->buffer;
+ it->object = object;
+ it->c = ' ';
+ it->pixel_width = it->len = 1;
+ while (n--)
+ append_glyph (it);
+ it->object = o_object;
+ it->c = c;
+ }
+ it->pixel_width = width;
+ it->nglyphs = width;
+}
+
+
+/* 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 ();
+}
+
+
+\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 on frame F supports all of the
+ capabilities in CAPS simultaneously, with foreground and background
+ colors FG and BG. */
+
+int
+tty_capable_p (f, caps, fg, bg)
+ struct frame *f;
+ unsigned caps;
+ unsigned long fg, bg;
+{
+#define TTY_CAPABLE_P_TRY(cap, TS, NC_bit) \
+ if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(NC_bit))) \
+ return 0;
+
+ TTY_CAPABLE_P_TRY (TTY_CAP_INVERSE, TS_standout_mode, NC_REVERSE);
+ TTY_CAPABLE_P_TRY (TTY_CAP_UNDERLINE, TS_enter_underline_mode, NC_UNDERLINE);
+ TTY_CAPABLE_P_TRY (TTY_CAP_BOLD, TS_enter_bold_mode, NC_BOLD);
+ TTY_CAPABLE_P_TRY (TTY_CAP_DIM, TS_enter_dim_mode, NC_DIM);
+ TTY_CAPABLE_P_TRY (TTY_CAP_BLINK, TS_enter_blink_mode, NC_BLINK);
+ TTY_CAPABLE_P_TRY (TTY_CAP_ALT_CHARSET, TS_enter_alt_charset_mode, NC_ALT_CHARSET);
+
+ /* We can do it! */
+ return 1;
+}
+
+
+/* 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;
+{
+ /* Canonicalize all negative values of MODE. */
+ if (mode < -1)
+ mode = -1;
+
+ 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 (INTEGERP (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);
+
+ if (CONSP (color_mode_spec))
+ color_mode = XCDR (color_mode_spec);
+ else
+ color_mode = Qnil;
+ }
+
+ current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist);
+
+ if (CONSP (current_mode_spec))
+ current_mode = XCDR (current_mode_spec);
+ else
+ current_mode = Qnil;
+ if (INTEGERP (color_mode))
+ mode = XINT (color_mode);
+ else
+ mode = 0; /* meaning default */
+ if (INTEGERP (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);
+ }