Hi,

a few days ago, I wanted to figure out which TERM variable I should set for
my PuTTY which I use to manage Linux machines. That led me deep into the
terminfo universe, a world I had no idea was so complex. I initially
thought the modern solution would be to use a *-direct TERM string, since
it avoids obscure color table mangling and directly supports 38:2 & 48:2
SGRs with RGB values.

However, it turned out that *-direct's are nastily incompatible with almost
everything. When terminal colors were gradually evolving from 3bit, thru
4bit to 8bit, each step remained backward-compatible: for example, when a
program didn't recognize 256-color environment, the first 8 or 16 colors
still worked fine. But in *-direct environments, only 3bit color
compatibility is preserved, and ANY program assuming today's de-facto
standard (though not oficially standardized) of specifying 4bit or 8bit
colors, breaks badly in *-direct environment.

So I thought of a solution. Nowadays, software should recognize the RGB
terminfo cap and use color numbers according to the definition provided by
this cap. The problem is that the vast majority of software doesn't know
about RGB; it just assumes that color numbers match the traditional
8/16/256 schemes.

One workaround could be *-direct256 TERMs, but those have their own
drawback: they eat first 256 (although not common) RGB colors. My approach
is different. It relies on the fact that incompatible ncurses-based
programs typically rely on init_pair() and not init_extended_pair(), since
they don't need more than a signed int. In contrast, programs aware of RGB
cap which use 24bit color values, never use init_pair() but
init_extended_pair() instead.

That suggests a possible compatibility layer:

* Function init_pair() would evaluate RGB cap and when it defines color
numbers having more than 15 bits, it translates old-style color numbers to
its direct variants.

* Similarly, init_color() could remember custom RGB values (instead of
sending them to the terminal) and later translate old-style color numbers
to these custom direct RGB values provided.

And most importantly, this compatibility layer would be safe: it only
activates when a program makes an invalid call to color functions. It's so
because calling init_pair() when RGB cap says it's direct mode using > 15
bits is always invalid (such call can never address the entire color
space), so this translation can never break anything which already assumes
direct colors and will activate in 100% screwed up scenarios only, so it
will always help. And there are really plenty of apps which know nothing
about RGB cap and need help, because they display strange black or
black-on-black colors every time they want display bright colors (8-15) or
256 colors.

In general, I think there shouldn't be such an incompatibility gap as in
the transition from classic (or *-256color) to *-direct TERMs, even if
color numbers are not officially standardized.

So I'd like to ask your opinion: Would adding such a compatibility layer be
a good or bad idea?

Or alternatively, several other solutions come to my mind - for example,
make direct color space backwards compatible by defining it as not first 8,
but first 256 colors remaining old-style, because most apps don't need them
anyway (so just like xterm-direct256 so far), and for those apps which
really need them, reserve e.g. 25th bit which - when set - will activate
really full RGB palette including these 256 nearly-black colors. This could
be implemented to *-direct TERMs. Maybe even cleaner solution?

Best regards,

Jakub

Reply via email to