Support 24-bit direct colors on text terminals

* src/term.c (init_tty): Use 24-bit terminal colors if corresponding
foreground and background functions are present in terminal type
definition.
* src/tparam.h: Define prototype for tigetstr.

* lisp/term/tty-colors.el (tty-color-define): Convert color palette
index to pixel value on 16.7M color terminals.
(tty-color-24bit): New function to convert color palette index to
pixel value on 16.7M color terminals.
(tty-color-desc): Don't approximate colors on 16.7M color terminals.
* lisp/term/xterm.el (xterm-register-default-colors): Define all named
TTY colors on 16.7M color terminals.

* doc/misc/efaq.texi (Colors on a TTY): Add instructions on how to
enable direct color TTY mode.
* etc/NEWS: Mention direct color TTY mode and point to FAQ.
This commit is contained in:
Rami Ylimäki 2017-02-18 13:04:55 +02:00 committed by Eli Zaretskii
parent 464a51ed46
commit e463e5762b
6 changed files with 82 additions and 2 deletions

View file

@ -1491,6 +1491,39 @@ exhibits all the colors Emacs knows about on the current display.
Syntax highlighting is on by default since version 22.1.
Emacs 26.1 and later support direct color mode in terminals. If Emacs
finds Terminfo capabilities @samp{setb24} and @samp{setf24}, 24-bit
direct color mode is used. The capability strings are expected to
take one 24-bit pixel value as argument and transform the pixel to a
string that can be used to send 24-bit colors to the terminal.
There aren't yet any standard terminal type definitions that would
support the capabilities, but Emacs can be invoked with a custom
definition as shown below.
@example
$ cat terminfo-24bit.src
# Use colon separators.
xterm-24bit|xterm with 24-bit direct color mode,
use=xterm-256color,
setb24=\E[48:2:%p1%@{65536@}%/%d:%p1%@{256@}%/%@{255@}%&%d:%p1%@{255@}%&%dm,
setf24=\E[38:2:%p1%@{65536@}%/%d:%p1%@{256@}%/%@{255@}%&%d:%p1%@{255@}%&%dm,
# Use semicolon separators.
xterm-24bits|xterm with 24-bit direct color mode,
use=xterm-256color,
setb24=\E[48;2;%p1%@{65536@}%/%d;%p1%@{256@}%/%@{255@}%&%d;%p1%@{255@}%&%dm,
setf24=\E[38;2;%p1%@{65536@}%/%d;%p1%@{256@}%/%@{255@}%&%d;%p1%@{255@}%&%dm,
$ tic -x -o ~/.terminfo terminfo-24bit.src
$ TERM=xterm-24bit emacs -nw
@end example
Currently there's no standard way to determine whether a terminal
supports direct color mode. If such standard arises later on, support
for @samp{setb24} and @samp{setf24} may be removed.
@node Debugging a customization file
@section How do I debug a @file{.emacs} file?
@cindex Debugging @file{.emacs} file

View file

@ -77,6 +77,12 @@ modern init systems such as systemd, which manage many of the traditional
aspects of daemon behavior themselves. '--old-daemon' is now an alias
for '--daemon'.
+++
** Emacs now supports 24-bit colors on capable text terminals
Terminal is automatically initialized to use 24-bit colors if the
required capabilities are found in terminfo. See the FAQ node
"Colors on a TTY" for more information.
* Changes in Emacs 26.1

View file

@ -824,6 +824,15 @@ A canonicalized color name is all-lower case, with any blanks removed."
(replace-regexp-in-string " +" "" (downcase color))
color)))
(defun tty-color-24bit (rgb)
"Return pixel value on 24-bit terminals. Return nil if RGB is
nil or not on 24-bit terminal."
(when (and rgb (= (display-color-cells) 16777216))
(let ((r (lsh (car rgb) -8))
(g (lsh (cadr rgb) -8))
(b (lsh (nth 2 rgb) -8)))
(logior (lsh r 16) (lsh g 8) b))))
(defun tty-color-define (name index &optional rgb frame)
"Specify a tty color by its NAME, terminal INDEX and RGB values.
NAME is a string, INDEX is typically a small integer used to send to
@ -840,7 +849,10 @@ If FRAME is not specified or is nil, it defaults to the selected frame."
(and rgb (or (not (listp rgb)) (/= (length rgb) 3))))
(error "Invalid specification for tty color \"%s\"" name))
(tty-modify-color-alist
(append (list (tty-color-canonicalize name) index) rgb) frame))
(append (list (tty-color-canonicalize name)
(or (tty-color-24bit rgb) index))
rgb)
frame))
(defun tty-color-clear (&optional _frame)
"Clear the list of supported tty colors for frame FRAME.
@ -1013,7 +1025,10 @@ might need to be approximated if it is not supported directly."
(let ((color (tty-color-canonicalize color)))
(or (assoc color (tty-color-alist frame))
(let ((rgb (tty-color-standard-values color)))
(and rgb (tty-color-approximate rgb frame)))))))
(and rgb
(let ((pixel (tty-color-24bit rgb)))
(or (and pixel (cons color (cons pixel rgb)))
(tty-color-approximate rgb frame)))))))))
(defun tty-color-gray-shades (&optional display)
"Return the number of gray colors supported by DISPLAY's terminal.

View file

@ -930,6 +930,14 @@ versions of xterm."
;; are more colors to support, compute them now.
(when (> ncolors 0)
(cond
((= ncolors 16777200) ; 24-bit xterm
;; all named tty colors
(let ((idx (length xterm-standard-colors)))
(mapc (lambda (color)
(unless (assoc (car color) xterm-standard-colors)
(tty-color-define (car color) idx (cdr color))
(setq idx (1+ idx))))
color-name-rgb-alist)))
((= ncolors 240) ; 256-color xterm
;; 216 non-gray colors first
(let ((r 0) (g 0) (b 0))

View file

@ -4131,6 +4131,20 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
tty->TN_max_colors = tgetnum ("Co");
#ifdef TERMINFO
/* Non-standard support for 24-bit colors. */
{
const char* fg = tigetstr ("setf24");
const char* bg = tigetstr ("setb24");
if (fg && bg && fg != (char *)-1 && bg != (char *)-1)
{
tty->TS_set_foreground = fg;
tty->TS_set_background = bg;
tty->TN_max_colors = 16777216;
}
}
#endif
tty->TN_no_color_video = tgetnum ("NC");
if (tty->TN_no_color_video == -1)
tty->TN_no_color_video = 0;

View file

@ -36,4 +36,8 @@ extern char PC;
extern char *BC;
extern char *UP;
#ifdef TERMINFO
char *tigetstr(const char *);
#endif
#endif /* EMACS_TPARAM_H */