Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

256 colors, foreground and background

This is a tale of two scripts and is related to a previous question.

The two scripts are at http://gist.github.com/50692. The ansi.rb script displays all 256 colors on all 256 background colors. The ncurses.rb script displays all 256 foreground colors but the background displays the basic 16 and then seems to cycle through various attributes like blinking and reverse video.

So what gives? Is this the bug in ncurses that it uses a signed integer for color pairs? (ie 'tput colors' says 256 but 'tput pairs' says 32767 instead 65536) It seems like if that were the case the first half of the colors pairs would display properly but the second half would repeat or get into the attributes as the int wraps.

like image 376
pushcx Avatar asked Jan 24 '09 23:01

pushcx


2 Answers

The reason is because ncurses pre ABI 6, which includes the current version that most distributions including Debian and Amazon AMI use, COLOR_PAIR(n) cannot reference any defined pairs above 256. This is because the argument to COLOR_PAIR(n) is of type cchar_t . The lower 8 bits choose the color pair, and the rest are treated as bitflags ORed in for specific terminal attributes. This is why you see blink, inverse, underline, etc. when you attempt to go beyond pair number 255 in your sample code.

This is pretty unfortunate, and I plan to use a queue in my program to define colors on the fly using init_pair() and just overwrite the least recently used pairs as a compromise. I wrote the ncurses maintainer Thomas Dickey asking if there is a way to step outside of ncurses temporarily to write raw terminal codes and then return to ncurses. This was his reply:

Essentially you'd have to forget about screen-optimization and just do your own drawing using the functions listed in terminfo(3), e.g., tigetstr, mvcur, tputs.

You can exit temporarily from ncurses, but then have to repaint the screen. Otherwise ncurses will be confused about what is on the screen and where the cursor is.

This solution seems to present too many pitfalls, but if you absolutely need more than 256 simultaneous pairs in an ncurses program (not counting pairs you could fake with the inverse attribute), then this is what you'll have to do.

like image 182
Andy Avatar answered Oct 15 '22 06:10

Andy


I don't know Ruby at all, so can't provide a working example, but the ncurses.rb script should tell you something in that it's so much shorter than the ansi.rb script.

You're not setting up the colours, so it's just looping the default 16 colour palette with variations provided by the attributes such as blink underline, bold, etc.

You need to use int init_color(short color, short r, short g, short b) to initialize a color index with the RGB values (0 - 1000) and then set the colour pairs to use for display with int init_pair(short pair, short f, short b) before calling COLOR_PAIR(n).

For portability you should check bool has_colors(void) and bool can_change_color(void)

On my system the man pages for ncurses are invaluable.

like image 34
James Morris Avatar answered Oct 15 '22 05:10

James Morris