unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: "Rüdiger Sonderfeld" <ruediger@c-plusplus.de>
To: emacs-devel@gnu.org
Subject: [RFC] Add tty True Color support.
Date: Tue, 15 Oct 2013 19:24:49 +0200	[thread overview]
Message-ID: <1804432.oj6xPZ0dh6@descartes> (raw)

Some terminals support True Color (24bit RGB) values.  At least KDE's
Konsole, st, and iTerm2 support it.  This patch makes True Color
support available in Emacs.

So far there is no reliable way to detect True Color support in
terminals and the terminfo database lacks support.  I started a
discussion on the ncurses mailing list[1].  So far only Konsole is
supported by detecting the KONSOLE_DBUS_SESSION environment variable.
But this should be replaced by a more reliable method.

[1] https://lists.gnu.org/archive/html/bug-ncurses/2013-10/msg00007.html

* src/term.c (turn_on_face): Support True Color.
  (default_set_rgb_foreground): New variable.
  (default_set_rgb_background): New variable.
  (tty_default_color_capabilities): Save/restore set_rgb_*ground
  variables.
  (tty_setup_colors): Add support for True Color (16777216).
  (init_tty): Detect terminal True Color support.

* src/termchar.h (struct tty_display_info): Add TS_set_rgb_foreground,
  TS_set_rgb_background.

* src/xfaces.c (tty_lookup_color): Encode colors as True Color if
  supported on frame.

Signed-off-by: Rüdiger Sonderfeld <ruediger@c-plusplus.de>
---
 src/term.c     | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 src/termchar.h |   4 ++
 src/xfaces.c   | 103 ++++++++++++++++++++++++++++++--------------------
 3 files changed, 169 insertions(+), 54 deletions(-)

diff --git a/src/term.c b/src/term.c
index ee81c59..a71e8f9 100644
--- a/src/term.c
+++ b/src/term.c
@@ -1960,21 +1960,57 @@ struct fkey_table {
       const char *ts;
       char *p;
 
-      ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
-      if (fg >= 0 && ts)
-	{
-          p = tparam (ts, NULL, 0, fg, 0, 0, 0);
-	  OUTPUT (tty, p);
-	  xfree (p);
-	}
+      if (fg > 0 && fg & (1 << 24)) /* RGB color */
+        {
+          ts = tty->standout_mode ? tty->TS_set_rgb_background
+            : tty->TS_set_rgb_foreground;
+          if (ts)
+            {
+              const unsigned char r = (fg & 0xFF0000) >> 16,
+                g = (fg & 0x00FF00) >> 8,
+                b = (fg & 0x0000FF);
+              p = tparam (ts, NULL, 0, r, g, b, 0);
+              OUTPUT (tty, p);
+              xfree (p);
+            }
+        }
+      else
+        {
+          ts = tty->standout_mode ? tty->TS_set_background
+            : tty->TS_set_foreground;
+          if (fg >= 0 && 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 (bg >= 0 && ts)
-	{
-          p = tparam (ts, NULL, 0, bg, 0, 0, 0);
-	  OUTPUT (tty, p);
-	  xfree (p);
-	}
+      if (bg > 0 && bg & (1 << 24)) /* RGB color */
+        {
+          ts = tty->standout_mode ? tty->TS_set_rgb_foreground
+            : tty->TS_set_rgb_background;
+          if (ts)
+            {
+              const unsigned char r = (bg & 0xFF0000) >> 16,
+                g = (bg & 0x00FF00) >> 8,
+                b = (bg & 0x0000FF);
+              p = tparam (ts, NULL, 0, r, g, b, 0);
+              OUTPUT (tty, p);
+              xfree (p);
+            }
+        }
+      else
+        {
+          ts = tty->standout_mode ? tty->TS_set_foreground
+            : tty->TS_set_background;
+          if (bg >= 0 && ts)
+            {
+              p = tparam (ts, NULL, 0, bg, 0, 0, 0);
+              OUTPUT (tty, p);
+              xfree (p);
+            }
+        }
     }
 }
 
@@ -2090,6 +2126,8 @@ struct fkey_table {
 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.  */
@@ -2110,6 +2148,16 @@ struct fkey_table {
       default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
 			       : NULL;
 
+      xfree (default_set_rgb_foreground);
+      default_set_rgb_foreground = tty->TS_set_rgb_foreground
+                                   ? xstrdup (tty->TS_set_rgb_foreground)
+                                   : NULL;
+
+      xfree (default_set_rgb_background);
+      default_set_rgb_foreground = tty->TS_set_rgb_background
+                                   ? xstrdup (tty->TS_set_rgb_background)
+                                   : NULL;
+
       default_max_colors = tty->TN_max_colors;
       default_max_pairs = tty->TN_max_pairs;
       default_no_color_video = tty->TN_no_color_video;
@@ -2119,6 +2167,8 @@ struct fkey_table {
       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;
@@ -2143,6 +2193,7 @@ struct fkey_table {
 	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:
@@ -2157,10 +2208,29 @@ struct fkey_table {
 	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 = "\E[38;2;%p1%d;%p2%d;%p3%dm";
+        tty->TS_set_rgb_background = "\E[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 = "\E[38;2;%d;%d;%dm";
+        tty->TS_set_rgb_background = "\E[48;2;%d;%d;%dm";
+#endif
+        tty->TN_max_colors = 16777216;
+        /*tty->TN_max_pairs = 64; TODO */
+	tty->TN_no_color_video = 0;
+        break;
     }
 }
 
@@ -4227,6 +4297,24 @@ struct terminal *
       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 = "\E[38;2;%p1%d;%p2%d;%p3%dm";
+          tty->TS_set_rgb_background = "\E[48;2;%p1%d;%p2%d;%p3%dm";
+#else
+          tty->TS_set_rgb_foreground = "\E[38;2;%d;%d;%dm";
+          tty->TS_set_rgb_background = "\E[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);
diff --git a/src/termchar.h b/src/termchar.h
index feb89e0..6ef0c16 100644
--- a/src/termchar.h
+++ b/src/termchar.h
@@ -156,6 +156,10 @@ struct tty_display_info
   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. */
diff --git a/src/xfaces.c b/src/xfaces.c
index 828788b..3d53563 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -960,54 +960,77 @@ static struct face *realize_non_ascii_face (struct frame *, Lisp_Object,
   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)))
+  if (f->output_method == output_termcap
+      && f->output_data.tty->display_info->TS_set_rgb_foreground
+      && !NILP (Ffboundp (Qtty_color_standard_values)))
     {
-      Lisp_Object rgb;
-
-      if (! INTEGERP (XCAR (XCDR (color_desc))))
-	return 0;
+      /* Terminal supports 3 byte RGB colors. */
+      color_desc = call1 (Qtty_color_standard_values, color);
+      if (! parse_rgb_list (color_desc, tty_color))
+        return 0;
 
-      tty_color->pixel = XINT (XCAR (XCDR (color_desc)));
+      /* Map XColor to 3 byte values. */
+      tty_color->pixel = 1 << 24 /* Set bit 24 to mark RGB values. */
+                         | (tty_color->red / 257) << 16
+                         | (tty_color->green / 257) << 8
+                         | (tty_color->blue / 257);
 
-      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;
-	    }
-	}
+        *std_color = *tty_color;
 
       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;
+    {
+      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.  */
-- 
1.8.4




             reply	other threads:[~2013-10-15 17:24 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-10-15 17:24 Rüdiger Sonderfeld [this message]
2013-10-16 19:45 ` [RFC] Add tty True Color support Eli Zaretskii
2013-10-16 22:39   ` [RFC-2] " Rüdiger Sonderfeld
2013-10-17 16:56     ` Eli Zaretskii
2014-01-07 21:02 ` [RFC] " egmont
2014-01-07 23:18   ` Rüdiger Sonderfeld
2015-06-23 11:47     ` Judge_Dredd
2014-07-02 13:38 ` Judge_Dredd

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1804432.oj6xPZ0dh6@descartes \
    --to=ruediger@c-plusplus.de \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).