Support directly setting RGB fg/bg colors via ISO-8613-3 24-bit
ANSI color escapes:

  ESC[38;2;<r>;<g>;<b>m Select RGB foreground color
  ESC[48;2;<r>;<g>;<b>m Select RGB background color

The killer applications for me are vim in tmux. It'll not only modenize
their look and feeling, but also bring more eye friendly color schemes.

To avoid memory overheads and keep the patch non-intrusive, it takes the
approach to adapt the nearest color in the existing 4x4x4 (88-color mode)
or 6x6x6 (256-color mode) color cube to the new 24-bit RGB color.

The pros/cons are:

+) least memory footprint (close to 0)
   comparing to konsole, gnome-terminal etc. real 24-bit arrays

+) exact colors and excellent user feelings
   comparing to xterm, mlterm, etc. approximating to 256 palette

+) usable in both the existing 88/256-color modes

   Most vim GUI color schemes show up the same as gvim in rxvt-unicode's
   88-color mode, not to mention the 256-color mode. Typical applications
   only use one or two dozens of colors at the same time.

-) may impact existing 88/256-color users

   When 24-bit and 256-color applications run in the same window, either
   in parallel (in tmux) or one-after-the-other, the latter's appearance
   may be slightly impacted by the former, if they happen to use similar
   colors. It'll be a less problem when the remaining applications join
   the 24-bit camp in future.

-) may not be able to show 2+ close 24-bit colors

   RGB colors close to each other will likely fall into the same slot in
   the 4x4x4 or 6x6x6 color cube. If necessary, it could be improved
   effectively by implementing some collision avoidance logic.

The CPU overheads of adapto_truecolor() look ignoreable: I feel no
perceptable slow down when doing vim operations in 24-bit color mode.

A micro benchmark running a test script from [1]:

% time (for i in {1..100}; do 24-bit-color.sh; done)

vanilla rxvt-unicode
====================
  2.42s user 1.88s system 31% cpu 13.555 total
  2.59s user 1.74s system 31% cpu 13.615 total
  2.46s user 1.85s system 31% cpu 13.631 total

THIS PATCH (adapt 4x4x4/6x6x6 color cube to 24-bit)
===================================================
  2.33s user 1.97s system 31% cpu 13.598 total
  2.46s user 1.89s system 31% cpu 13.613 total
  2.51s user 1.82s system 31% cpu 13.556 total

https://github.com/spudowiar/rxvt-unicode (real 24-bit array)
=============================================================
  2.61s user 1.75s system 31% cpu 13.721 total
  2.48s user 1.82s system 31% cpu 13.566 total
  2.60s user 1.76s system 31% cpu 13.631 total

USE_256_COLORS is defined in all the above rxvt-unicode builds.

References:

[1] True Colour (16 million colours) support in various terminal
    applications and terminals
    https://gist.github.com/XVilka/8346728

[2] https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

CC: Saleem Rashid <[email protected]>
Signed-off-by: Fengguang Wu <[email protected]>
---
 doc/rxvt.1.pod |  4 ++++
 doc/rxvt.7.pod |  2 ++
 src/command.C  | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/rxvt.h     |  1 +
 4 files changed, 72 insertions(+)

diff --git a/doc/rxvt.1.pod b/doc/rxvt.1.pod
index 19317ef..7c8ec8a 100644
--- a/doc/rxvt.1.pod
+++ b/doc/rxvt.1.pod
@@ -1598,6 +1598,10 @@ high-intensity (potentially bold/blink) versions of the 
same, and 72 (or
 240 in 256 colour mode) colours arranged in an 4x4x4 (or 6x6x6) colour RGB
 cube plus a 8 (24) colour greyscale ramp.
 
+When applications set direct 24-bit fg/bg RGB colours through escapes
+C< ESC [ 38 ; 2 ; R ; G ; Bm > / C< ESC [ 48 ; 2; R ; G ; Bm >, 
B<@@RXVT_NAME@@>
+will adapt the nearest colour in the 4x4x4/6x6x6 cube to the 24-bit RGB colour.
+
 Here is a list of the ANSI colours with their names.
 
 =begin table
diff --git a/doc/rxvt.7.pod b/doc/rxvt.7.pod
index 7ee8b72..0c5d2b7 100644
--- a/doc/rxvt.7.pod
+++ b/doc/rxvt.7.pod
@@ -1605,6 +1605,8 @@ Character Attributes (SGR)
        B<< C<Pm = 36 / 46> >>  fg/bg Cyan
        B<< C<Pm = 37 / 47> >>  fg/bg White
        B<< C<Pm = 38;5 / 48;5> >>      set fg/bg to colour #m (ISO 8613-6)
+       B<< C<Pm = 38;2;R;G;B> >>       set fg to 24-bit colour #RGB (ISO 
8613-3)
+       B<< C<Pm = 48;2;R;G;B> >>       set bg to 24-bit colour #RGB (ISO 
8613-3)
        B<< C<Pm = 39 / 49> >>  fg/bg Default
        B<< C<Pm = 90 / 100> >> fg/bg Bright Black
        B<< C<Pm = 91 / 101> >> fg/bg Bright Red
diff --git a/src/command.C b/src/command.C
index ff41967..48973e4 100644
--- a/src/command.C
+++ b/src/command.C
@@ -3341,6 +3341,52 @@ rxvt_term::process_osc_seq ()
     }
 }
 
+/*
+ * Rule of thumb boundaries for segmenting the nonlinear RGB color space.
+ */
+#if USE_256_COLORS
+static unsigned int colorcube_map[5] = { 0x42, 0x77, 0x99, 0xc6, 0xec };
+#else
+static unsigned int colorcube_map[3] = { 0x5c, 0xb2, 0xe8 };
+#endif
+
+#define ARRAY_SIZE(a)   (sizeof(a)/sizeof(a[0]))
+#define COLORCUBE_SIZE  (ARRAY_SIZE(colorcube_map)+1)
+
+static unsigned int colorcube_index (unsigned int c)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE(colorcube_map); i++)
+    if (c < colorcube_map[i])
+      break;
+
+  return i;
+}
+
+/*
+ * Find the nearest color slot in the 4x4x4 or 6x6x6 color cube,
+ * adapt its value to the 24bit RGB color.
+ */
+unsigned int
+rxvt_term::adapto_truecolor (unsigned int r, unsigned int g, unsigned int b)
+{
+  unsigned int idx;
+
+  idx = minTermCOLOR + colorcube_index (r) * COLORCUBE_SIZE * COLORCUBE_SIZE +
+                       colorcube_index (g) * COLORCUBE_SIZE +
+                       colorcube_index (b);
+
+  pix_colors_focused [idx].free (this);
+  pix_colors_focused [idx].set (this, rgba (r * 0x0101,
+                                            g * 0x0101,
+                                            b * 0x0101));
+
+  // update_fade_color (idx, false); // who cares?
+
+  return idx;
+}
+
 void
 rxvt_term::process_color_seq (int report, int color, const char *str, char 
resp)
 {
@@ -3983,6 +4029,15 @@ rxvt_term::process_sgr_mode (unsigned int nargs, const 
int *arg)
                 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_fg);
                 i += 2;
               }
+            else if (nargs > i + 4 && arg[i + 1] == 2)
+              {
+                unsigned int r = arg[i + 2];
+                unsigned int g = arg[i + 3];
+                unsigned int b = arg[i + 4];
+                unsigned int idx = adapto_truecolor (r, g, b);
+                scr_color (idx, Color_fg);
+                i += 4;
+              }
             break;
           case 39:             /* default fg */
             scr_color (Color_fg, Color_fg);
@@ -4004,6 +4059,15 @@ rxvt_term::process_sgr_mode (unsigned int nargs, const 
int *arg)
                 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_bg);
                 i += 2;
               }
+            else if (nargs > i + 4 && arg[i + 1] == 2)
+              {
+                unsigned int r = arg[i + 2];
+                unsigned int g = arg[i + 3];
+                unsigned int b = arg[i + 4];
+                unsigned int idx = adapto_truecolor (r, g, b);
+                scr_color (idx, Color_bg);
+                i += 4;
+              }
             break;
           case 49:             /* default bg */
             scr_color (Color_bg, Color_bg);
@@ -4159,3 +4223,4 @@ void rxvt_term::pty_write ()
 
 /*----------------------- end-of-file (C source) -----------------------*/
 
+// vim:et:ts=2:sw=2
diff --git a/src/rxvt.h b/src/rxvt.h
index f97422d..8dabd37 100644
--- a/src/rxvt.h
+++ b/src/rxvt.h
@@ -1390,6 +1390,7 @@ struct rxvt_term : zero_initialized, rxvt_vars, 
rxvt_screen
   void process_osc_seq ();
   void process_color_seq (int report, int color, const char *str, char resp);
   void process_xterm_seq (int op, char *str, char resp);
+  unsigned int adapto_truecolor (unsigned int r, unsigned int g, unsigned int 
b);
   int privcases (int mode, unsigned long bit);
   void process_terminal_mode (int mode, int priv, unsigned int nargs, const 
int *arg);
   void process_sgr_mode (unsigned int nargs, const int *arg);
-- 
2.8.1


_______________________________________________
rxvt-unicode mailing list
[email protected]
http://lists.schmorp.de/mailman/listinfo/rxvt-unicode

Reply via email to