-
-
Save choppsv1/36aacdd696d505566088 to your computer and use it in GitHub Desktop.
| This diff is a modified version of a diff written by Rüdiger Sonderfeld. | |
| The original diff can be found here: | |
| http://emacs.1067599.n5.nabble.com/RFC-Add-tty-True-Color-support-tt299962.html | |
| To enable the feature one must set one of 2 environment variables either | |
| ITERM_24BIT or KONSOLE_DBUS_SESSION. The former will enable ITU T.416 mode, the | |
| latter will use semi-colon seperators used by other terminals (and also | |
| supported by iterm development branch). | |
| I've added ITERM_24BIT as an environment variable to set that will cause emacs | |
| to use the : seperated values as specified by ITU T.416. These are apparently | |
| better to use and supported by iterm development branch. | |
| Other chagnes: | |
| - modified map_tty_color to set the color into the pixel field. | |
| - modified the colors defined to be the standard X11 list. | |
| - modified tty-color-desc to add missing colors on demand. | |
| *** ./lisp/term/xterm.el.orig 2014-06-20 13:28:33.000000000 -0400 | |
| --- ./lisp/term/xterm.el 2015-02-23 07:01:48.000000000 -0500 | |
| *************** | |
| *** 674,679 **** | |
| --- 674,688 ---- | |
| ;; are more colors to support, compute them now. | |
| (when (> ncolors 0) | |
| (cond | |
| + ((= (display-color-cells (selected-frame)) 16777216) ; 24-bit xterm | |
| + (let ((idx (length xterm-standard-colors))) | |
| + ;; Insert standard X colors after the standard xterm ones | |
| + (mapc (lambda (color) | |
| + (if (not (assoc (car color) xterm-standard-colors)) | |
| + (progn | |
| + (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)) | |
| *** ./src/dispextern.h.orig 2014-09-15 23:13:46.000000000 -0400 | |
| --- ./src/dispextern.h 2015-02-23 07:01:48.000000000 -0500 | |
| *************** | |
| *** 1739,1747 **** | |
| INLINE bool | |
| face_tty_specified_color (unsigned long color) | |
| { | |
| ! return color < FACE_TTY_DEFAULT_BG_COLOR; | |
| } | |
| /* Non-zero if FACE was realized for unibyte use. */ | |
| #define FACE_UNIBYTE_P(FACE) ((FACE)->charset < 0) | |
| --- 1739,1753 ---- | |
| INLINE bool | |
| face_tty_specified_color (unsigned long color) | |
| { | |
| ! return (color < FACE_TTY_DEFAULT_BG_COLOR); | |
| } | |
| + INLINE bool | |
| + face_tty_specified_24_bit_color (unsigned long color) | |
| + { | |
| + /* 24 bit colors have 24th but not 25th bit set */ | |
| + return ((color & (0x03 << 24)) == (0x01 << 24)); | |
| + } | |
| /* Non-zero if FACE was realized for unibyte use. */ | |
| #define FACE_UNIBYTE_P(FACE) ((FACE)->charset < 0) | |
| *** ./src/term.c.orig 2014-06-04 11:47:40.000000000 -0400 | |
| --- ./src/term.c 2015-02-23 07:01:48.000000000 -0500 | |
| *************** | |
| *** 1915,1932 **** | |
| const char *ts; | |
| char *p; | |
| ! ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground; | |
| if (face_tty_specified_color (fg) && ts) | |
| { | |
| ! p = tparam (ts, NULL, 0, fg, 0, 0, 0); | |
| OUTPUT (tty, p); | |
| xfree (p); | |
| } | |
| ! ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background; | |
| if (face_tty_specified_color (bg) && ts) | |
| { | |
| ! p = tparam (ts, NULL, 0, bg, 0, 0, 0); | |
| OUTPUT (tty, p); | |
| xfree (p); | |
| } | |
| --- 1915,1954 ---- | |
| const char *ts; | |
| char *p; | |
| ! if (face_tty_specified_24_bit_color(fg)) | |
| ! ts = tty->standout_mode ? tty->TS_set_rgb_background : tty->TS_set_rgb_foreground; | |
| ! else | |
| ! ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground; | |
| if (face_tty_specified_color (fg) && ts) | |
| { | |
| ! if (!face_tty_specified_24_bit_color(fg)) | |
| ! p = tparam (ts, NULL, 0, fg, 0, 0, 0); | |
| ! else | |
| ! { | |
| ! const unsigned char r = (fg >> 16) & 0xFF, | |
| ! g = (fg >> 8) & 0xFF, | |
| ! b = fg & 0xFF; | |
| ! p = tparam (ts, NULL, 0, (int)r, (int)g, (int)b, 0); | |
| ! } | |
| OUTPUT (tty, p); | |
| xfree (p); | |
| } | |
| ! if (face_tty_specified_24_bit_color(bg)) | |
| ! ts = tty->standout_mode ? tty->TS_set_rgb_foreground : tty->TS_set_rgb_background; | |
| ! else | |
| ! ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background; | |
| if (face_tty_specified_color (bg) && ts) | |
| { | |
| ! if (!face_tty_specified_24_bit_color(bg)) | |
| ! p = tparam (ts, NULL, 0, bg, 0, 0, 0); | |
| ! else | |
| ! { | |
| ! const unsigned char r = (bg >> 16) & 0xFF, | |
| ! g = (bg >> 8) & 0xFF, | |
| ! b = bg & 0xFF; | |
| ! p = tparam (ts, NULL, 0, (int)r, (int)g, (int)b, 0); | |
| ! } | |
| OUTPUT (tty, p); | |
| xfree (p); | |
| } | |
| *************** | |
| *** 2028,2033 **** | |
| --- 2050,2057 ---- | |
| struct terminal *t = get_tty_terminal (terminal, 0); | |
| if (!t) | |
| return make_number (0); | |
| + else if (t->display_info.tty->TS_set_rgb_foreground) | |
| + return make_number (16777216); /* 24 bit True Color */ | |
| else | |
| return make_number (t->display_info.tty->TN_max_colors); | |
| } | |
| *************** | |
| *** 2043,2048 **** | |
| --- 2067,2074 ---- | |
| static char *default_orig_pair; | |
| static char *default_set_foreground; | |
| static char *default_set_background; | |
| + static char *default_set_rgb_foreground; | |
| + static char *default_set_rgb_background; | |
| /* Save or restore the default color-related capabilities of this | |
| terminal. */ | |
| *************** | |
| *** 2055,2060 **** | |
| --- 2081,2088 ---- | |
| dupstring (&default_orig_pair, tty->TS_orig_pair); | |
| dupstring (&default_set_foreground, tty->TS_set_foreground); | |
| dupstring (&default_set_background, tty->TS_set_background); | |
| + dupstring (&default_set_rgb_foreground, tty->TS_set_rgb_foreground); | |
| + dupstring (&default_set_rgb_background, tty->TS_set_rgb_background); | |
| default_max_colors = tty->TN_max_colors; | |
| default_max_pairs = tty->TN_max_pairs; | |
| default_no_color_video = tty->TN_no_color_video; | |
| *************** | |
| *** 2064,2069 **** | |
| --- 2092,2099 ---- | |
| tty->TS_orig_pair = default_orig_pair; | |
| tty->TS_set_foreground = default_set_foreground; | |
| tty->TS_set_background = default_set_background; | |
| + tty->TS_set_rgb_foreground = default_set_rgb_foreground; | |
| + tty->TS_set_rgb_background = default_set_rgb_background; | |
| tty->TN_max_colors = default_max_colors; | |
| tty->TN_max_pairs = default_max_pairs; | |
| tty->TN_no_color_video = default_no_color_video; | |
| *************** | |
| *** 2088,2093 **** | |
| --- 2118,2124 ---- | |
| tty->TN_max_pairs = 0; | |
| tty->TN_no_color_video = 0; | |
| tty->TS_set_foreground = tty->TS_set_background = tty->TS_orig_pair = NULL; | |
| + tty->TS_set_rgb_foreground = tty->TS_set_rgb_background = NULL; | |
| break; | |
| case 0: /* default colors, if any */ | |
| default: | |
| *************** | |
| *** 2102,2111 **** | |
| --- 2133,2161 ---- | |
| tty->TS_set_foreground = "\033[3%dm"; | |
| tty->TS_set_background = "\033[4%dm"; | |
| #endif | |
| + tty->TS_set_rgb_foreground = NULL; | |
| + tty->TS_set_rgb_background = NULL; | |
| tty->TN_max_colors = 8; | |
| tty->TN_max_pairs = 64; | |
| tty->TN_no_color_video = 0; | |
| break; | |
| + case 16777216: /* RGB colors */ | |
| + tty->TS_orig_pair = "\033[0m"; | |
| + #ifdef TERMINFO | |
| + tty->TS_set_foreground = "\033[3%p1%dm"; | |
| + tty->TS_set_background = "\033[4%p1%dm"; | |
| + tty->TS_set_rgb_foreground = "\033[38;2;%p1%d;%p2%d;%p3%dm"; | |
| + tty->TS_set_rgb_background = "\033[48;2;%p1%d;%p2%d;%p3%dm"; | |
| + #else | |
| + tty->TS_set_foreground = "\033[3%dm"; | |
| + tty->TS_set_background = "\033[4%dm"; | |
| + tty->TS_set_rgb_foreground = "\033[38;2;%d;%d;%dm"; | |
| + tty->TS_set_rgb_background = "\033[48;2;%d;%d;%dm"; | |
| + #endif | |
| + tty->TN_max_colors = 16777216; | |
| + /*tty->TN_max_pairs = 64; TODO */ | |
| + tty->TN_no_color_video = 0; | |
| + break; | |
| } | |
| } | |
| *************** | |
| *** 4201,4206 **** | |
| --- 4251,4286 ---- | |
| tty->TN_no_color_video = tgetnum ("NC"); | |
| if (tty->TN_no_color_video == -1) | |
| tty->TN_no_color_video = 0; | |
| + | |
| + /* TODO Reliable way to detect: Konsole, iTerm2, st */ | |
| + if (getenv ("KONSOLE_DBUS_SESSION")) | |
| + { | |
| + /* TODO This should be extracted from terminfo/termcap. */ | |
| + #ifdef TERMINFO | |
| + tty->TS_set_rgb_foreground = "\033[38;2;%p1%d;%p2%d;%p3%dm"; | |
| + tty->TS_set_rgb_background = "\033[48;2;%p1%d;%p2%d;%p3%dm"; | |
| + #else | |
| + tty->TS_set_rgb_foreground = "\033[38;2;%d;%d;%dm"; | |
| + tty->TS_set_rgb_background = "\033[48;2;%d;%d;%dm"; | |
| + #endif | |
| + } | |
| + else if (getenv ("ITERM_24BIT")) | |
| + { | |
| + /* XXX chopps use ITU T.421 ':' separator */ | |
| + /* TODO This should be extracted from terminfo/termcap. */ | |
| + #ifdef TERMINFO | |
| + tty->TS_set_rgb_foreground = "\033[38:2:%p1%d:%p2%d:%p3%dm"; | |
| + tty->TS_set_rgb_background = "\033[48:2:%p1%d:%p2%d:%p3%dm"; | |
| + #else | |
| + tty->TS_set_rgb_foreground = "\033[38:2:%d:%d:%dm"; | |
| + tty->TS_set_rgb_background = "\033[48:2:%d:%d:%dm"; | |
| + #endif | |
| + } | |
| + else | |
| + { | |
| + tty->TS_set_rgb_foreground = NULL; | |
| + tty->TS_set_rgb_background = NULL; | |
| + } | |
| } | |
| tty_default_color_capabilities (tty, 1); | |
| *** ./src/termchar.h.orig 2014-03-21 01:34:40.000000000 -0400 | |
| --- ./src/termchar.h 2015-02-23 07:01:48.000000000 -0500 | |
| *************** | |
| *** 157,162 **** | |
| --- 157,166 ---- | |
| const char *TS_set_foreground; | |
| const char *TS_set_background; | |
| + /* Support for 24bit RGB color terminals. */ | |
| + const char *TS_set_rgb_foreground; | |
| + const char *TS_set_rgb_background; | |
| + | |
| int TF_hazeltine; /* termcap hz flag. */ | |
| int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */ | |
| int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */ | |
| *** ./src/xfaces.c.orig 2014-10-09 12:07:28.000000000 -0400 | |
| --- ./src/xfaces.c 2015-02-23 07:02:06.000000000 -0500 | |
| *************** | |
| *** 382,388 **** | |
| /* TTY color-related functions (defined in tty-colors.el). */ | |
| ! static Lisp_Object Qtty_color_desc, Qtty_color_by_index, Qtty_color_standard_values; | |
| /* The name of the function used to compute colors on TTYs. */ | |
| --- 382,388 ---- | |
| /* TTY color-related functions (defined in tty-colors.el). */ | |
| ! static Lisp_Object Qtty_color_desc, Qtty_color_by_index, Qtty_color_standard_values, Qtty_color_canonicalize; | |
| /* The name of the function used to compute colors on TTYs. */ | |
| *************** | |
| *** 943,996 **** | |
| if (!STRINGP (color) || NILP (Ffboundp (Qtty_color_desc))) | |
| return 0; | |
| ! XSETFRAME (frame, f); | |
| ! color_desc = call2 (Qtty_color_desc, color, frame); | |
| ! if (CONSP (color_desc) && CONSP (XCDR (color_desc))) | |
| { | |
| ! Lisp_Object rgb; | |
| ! if (! INTEGERP (XCAR (XCDR (color_desc)))) | |
| ! return 0; | |
| ! tty_color->pixel = XINT (XCAR (XCDR (color_desc))); | |
| ! rgb = XCDR (XCDR (color_desc)); | |
| ! if (! parse_rgb_list (rgb, tty_color)) | |
| ! return 0; | |
| ! /* Should we fill in STD_COLOR too? */ | |
| ! if (std_color) | |
| ! { | |
| ! /* Default STD_COLOR to the same as TTY_COLOR. */ | |
| ! *std_color = *tty_color; | |
| ! /* Do a quick check to see if the returned descriptor is | |
| ! actually _exactly_ equal to COLOR, otherwise we have to | |
| ! lookup STD_COLOR separately. If it's impossible to lookup | |
| ! a standard color, we just give up and use TTY_COLOR. */ | |
| ! if ((!STRINGP (XCAR (color_desc)) | |
| ! || NILP (Fstring_equal (color, XCAR (color_desc)))) | |
| ! && !NILP (Ffboundp (Qtty_color_standard_values))) | |
| ! { | |
| ! /* Look up STD_COLOR separately. */ | |
| ! rgb = call1 (Qtty_color_standard_values, color); | |
| ! if (! parse_rgb_list (rgb, std_color)) | |
| ! return 0; | |
| ! } | |
| ! } | |
| ! return 1; | |
| } | |
| - else if (NILP (Fsymbol_value (intern ("tty-defined-color-alist")))) | |
| - /* We were called early during startup, and the colors are not | |
| - yet set up in tty-defined-color-alist. Don't return a failure | |
| - indication, since this produces the annoying "Unable to | |
| - load color" messages in the *Messages* buffer. */ | |
| - return 1; | |
| - else | |
| - /* tty-color-desc seems to have returned a bad value. */ | |
| - return 0; | |
| } | |
| /* A version of defined_color for non-X frames. */ | |
| --- 943,1022 ---- | |
| if (!STRINGP (color) || NILP (Ffboundp (Qtty_color_desc))) | |
| return 0; | |
| ! if (f->output_method == output_termcap | |
| ! && f->output_data.tty->display_info->TS_set_rgb_foreground | |
| ! && !NILP (Ffboundp (Qtty_color_standard_values))) | |
| ! { | |
| ! /* Terminal supports 3 byte RGB colors. */ | |
| ! if (!NILP (Ffboundp (Qtty_color_canonicalize))) | |
| ! color = call1(Qtty_color_canonicalize, color); | |
| ! | |
| ! color_desc = call1 (Qtty_color_standard_values, color); | |
| ! if (! parse_rgb_list (color_desc, tty_color)) | |
| ! return 0; | |
| ! | |
| ! /* Map XColor to 3 byte values. */ | |
| ! tty_color->pixel = 1 << 24 /* Set bit 24 to mark RGB values. */ | |
| ! | (tty_color->red / 256) << 16 | |
| ! | (tty_color->green / 256) << 8 | |
| ! | (tty_color->blue / 256); | |
| ! | |
| ! if (std_color) | |
| ! *std_color = *tty_color; | |
| ! return 1; | |
| ! } | |
| ! else | |
| { | |
| ! XSETFRAME (frame, f); | |
| ! color_desc = call2 (Qtty_color_desc, color, frame); | |
| ! if (CONSP (color_desc) && CONSP (XCDR (color_desc))) | |
| ! { | |
| ! Lisp_Object rgb; | |
| ! if (! INTEGERP (XCAR (XCDR (color_desc)))) | |
| ! return 0; | |
| ! tty_color->pixel = XINT (XCAR (XCDR (color_desc))); | |
| ! rgb = XCDR (XCDR (color_desc)); | |
| ! if (! parse_rgb_list (rgb, tty_color)) | |
| ! return 0; | |
| ! /* Should we fill in STD_COLOR too? */ | |
| ! if (std_color) | |
| ! { | |
| ! /* Default STD_COLOR to the same as TTY_COLOR. */ | |
| ! *std_color = *tty_color; | |
| ! /* Do a quick check to see if the returned descriptor is | |
| ! actually _exactly_ equal to COLOR, otherwise we have to | |
| ! lookup STD_COLOR separately. If it's impossible to lookup | |
| ! a standard color, we just give up and use TTY_COLOR. */ | |
| ! if ((!STRINGP (XCAR (color_desc)) | |
| ! || NILP (Fstring_equal (color, XCAR (color_desc)))) | |
| ! && !NILP (Ffboundp (Qtty_color_standard_values))) | |
| ! { | |
| ! /* Look up STD_COLOR separately. */ | |
| ! rgb = call1 (Qtty_color_standard_values, color); | |
| ! if (! parse_rgb_list (rgb, std_color)) | |
| ! return 0; | |
| ! } | |
| ! } | |
| ! | |
| ! return 1; | |
| ! } | |
| ! else if (NILP (Fsymbol_value (intern ("tty-defined-color-alist")))) | |
| ! /* We were called early during startup, and the colors are not | |
| ! yet set up in tty-defined-color-alist. Don't return a failure | |
| ! indication, since this produces the annoying "Unable to | |
| ! load color" messages in the *Messages* buffer. */ | |
| ! return 1; | |
| ! else | |
| ! /* tty-color-desc seems to have returned a bad value. */ | |
| ! return 0; | |
| } | |
| } | |
| /* A version of defined_color for non-X frames. */ | |
| *************** | |
| *** 1008,1014 **** | |
| color_def->green = 0; | |
| if (*color_name) | |
| ! status = tty_lookup_color (f, build_string (color_name), color_def, NULL); | |
| if (color_def->pixel == FACE_TTY_DEFAULT_COLOR && *color_name) | |
| { | |
| --- 1034,1042 ---- | |
| color_def->green = 0; | |
| if (*color_name) | |
| ! { | |
| ! status = tty_lookup_color (f, build_string (color_name), color_def, NULL); | |
| ! } | |
| if (color_def->pixel == FACE_TTY_DEFAULT_COLOR && *color_name) | |
| { | |
| *************** | |
| *** 5780,5785 **** | |
| --- 5808,5814 ---- | |
| unsigned long default_pixel = | |
| foreground_p ? FACE_TTY_DEFAULT_FG_COLOR : FACE_TTY_DEFAULT_BG_COLOR; | |
| unsigned long pixel = default_pixel; | |
| + XColor true_color; | |
| #ifdef MSDOS | |
| unsigned long default_other_pixel = | |
| foreground_p ? FACE_TTY_DEFAULT_BG_COLOR : FACE_TTY_DEFAULT_FG_COLOR; | |
| *************** | |
| *** 5798,5804 **** | |
| { | |
| /* Associations in tty-defined-color-alist are of the form | |
| (NAME INDEX R G B). We need the INDEX part. */ | |
| ! pixel = XINT (XCAR (XCDR (def))); | |
| } | |
| if (pixel == default_pixel && STRINGP (color)) | |
| --- 5827,5844 ---- | |
| { | |
| /* Associations in tty-defined-color-alist are of the form | |
| (NAME INDEX R G B). We need the INDEX part. */ | |
| ! if (f->output_method == output_termcap | |
| ! && f->output_data.tty->display_info->TS_set_rgb_foreground | |
| ! && parse_rgb_list (XCDR (XCDR(def)), &true_color)) | |
| ! { | |
| ! /* Map XColor to 3 byte values. */ | |
| ! pixel = 1 << 24 /* Set bit 24 to mark RGB values. */ | |
| ! | (true_color.red / 256) << 16 | |
| ! | (true_color.green / 256) << 8 | |
| ! | (true_color.blue / 256); | |
| ! } | |
| ! else | |
| ! pixel = XINT (XCAR (XCDR (def))); | |
| } | |
| if (pixel == default_pixel && STRINGP (color)) | |
| *************** | |
| *** 6460,6465 **** | |
| --- 6500,6506 ---- | |
| DEFSYM (Qwindow_divider, "window-divider"); | |
| DEFSYM (Qwindow_divider_first_pixel, "window-divider-first-pixel"); | |
| DEFSYM (Qwindow_divider_last_pixel, "window-divider-last-pixel"); | |
| + DEFSYM (Qtty_color_canonicalize, "tty-color-canonicalize"); | |
| DEFSYM (Qtty_color_desc, "tty-color-desc"); | |
| DEFSYM (Qtty_color_standard_values, "tty-color-standard-values"); | |
| DEFSYM (Qtty_color_by_index, "tty-color-by-index"); |
Whoops, nevermind, it's working now - for those who come along later, check that your $TERM isn't set to something silly like xterm-256color. Simply xterm worked for me in gnome-terminal.
everybody who contributed to this patch is doing God's work
Could you explain why there's
tty->TS_set_rgb_foreground = "\033[38;2;%p1%d;%p2%d;%p3%dm";
vs
tty->TS_set_rgb_foreground = "\033[38;2;%d;%d;%dm";
?
It looks like the former also prints some pointers, but I can't imagine why...
It looks like tmux's true color support is hard coded to use the latter snippet: tmux/tmux@427b820
Oh, spoke too soon. Just read src/tparam.c.
So, in the ifdef TERMINFO case, we're using %pN to substitute positional params (corresponding to red, green and blue values). But, if I'm reading this right, when TERMINFO isn't defined, we still print the params in the same order. If I understood that correctly, why bother with the #ifdef?
(I'd like to get this upstreamed, but I think I should first understand the current state of this patch.)
How do you apply the patch? I'm sorry, I'm a noob at this.
What file do I have to apply it to?
I applied this patch and now terminal emacs is 2-tone when I set either environment variable. Is there a setting or a --configure flag I need to massage somewhere?