'NCurses 65536 Color Pairs

I have compiled NCurses 6.3 with the --enable-ext-colors and --enable-widec flags.

I then iterate across all background colors, for each foreground color:

void initColorPairs()
{
    for (int foregroundId = 0; foregroundId < 255; foregroundId++)
    {
        for (int backgroundId = 0; backgroundId < 255; backgroundId++)
        {
            init_extended_pair(
                getColorPairId(foregroundId, backgroundId),
                foregroundId,
                backgroundId);
        }
    }
};

This sets the macro COLOR_PAIRS to 65536.

...
std::cout << "initialized color pairs: " << COLOR_PAIRS << std::endl; //displays `initialized color pairs: 65536`
...

This is working perfectly.

I have a unique id for every color pair defined by this function:

int getColorPairId(int foregroundId, int backgroundId)
{
    return foregroundId + (backgroundId << 8);
};

This all appears to work perfectly. However, when trying to render each of these possible color pairs and printing them next to each other:

// visualize
std::string testText = "a";
for (int foregroundId = 0; foregroundId < 255; foregroundId++)
{
    for (int backgroundId = 0; backgroundId < 255; backgroundId++)
    {
        attr_on(COLOR_PAIR(getColorPairId(foregroundId, backgroundId)), NULL);
        mvprintw(foregroundId, backgroundId, testText.c_str());
    }
}

Instead of ending up with a screen full of each foreground color against each background color I end up with this: block of text of the letter "A", with only the foreground color changing across characters

It should be changing the background color with each character, but it only seems to change the foreground.

Strangely, if the colorId construction is reversed (foreground shifted over 8 bits instead of background), the background iterates instead of the foreground!

int getColorPairId(int foregroundId, int backgroundId)
{
    return backgroundId + (foregroundId << 8);
};

enter image description here



Solution 1:[1]

Without using the extended colors in the library interface, color pairs are limited to 32767 (signed 16-bit numbers).

That NULL in

attr_on(COLOR_PAIR(getColorPairId(foregroundId, backgroundId)), NULL);

should be used to pass the value of an integer (more than 16-bits) for the color pair, as mentioned in the Extensions section of the manual page, e.g.,

  • For functions which modify the color, e.g., wattr_set, if opts is set it is treated as a pointer to int, and used to set the color pair instead of the short pair parameter.

But in expanding the answer, I see that these calls are overlooked (probably because the color-pair is not an explicit parameter to these, but is a derived value within the body of the function):

The remaining functions which have opts, but do not manipulate color, e.g., wattr_on and wattr_off are not used by this implementation except to check that they are NULL.

The ncurses-examples (demo and test-programs) include a few using attr_on (see README), but those calls aren't using this particular extension (dots_xcurses would be a good place to do that – optionally of course).

picsmap uses the feature via setcchar:

    #define set_extended_pair(opts, color_pair) \
        if ((opts) != NULL) { \
            color_pair = *(const int*)(opts); \
        }

That macro is used in other functions (to allow those to be conditionally compiled with/without the feature):

new_pair.h:71:#define set_extended_pair(opts, color_pair) \                     
new_pair.h:78:#define set_extended_pair(opts, color_pair) \                     
base/lib_chgat.c:64:    set_extended_pair(opts, color_pair);                    
base/lib_colorset.c:54:    set_extended_pair(opts, color_pair);                 
base/lib_slkatr_set.c:58:    set_extended_pair(opts, color_pair);               
widechar/lib_cchar.c:63:    set_extended_pair(opts, color_pair);                
widechar/lib_vid_attr.c:101:    set_extended_pair(opts, color_pair);

For wattr_on.c, the chunk

if_EXT_COLORS({
    if (at & A_COLOR)
        win->_color = PairNumber(at);
});

(which extracts a color pair from the attribute parameter) would look like

if_EXT_COLORS({
    if (at & A_COLOR) {
        win->_color = PairNumber(at);
        set_extended_pair(opts, win->_color);
    }
});

wattr_set is handled properly:

#define wattr_set(win,a,p,opts) \                                               
        (NCURSES_OK_ADDR(win) \                                                 
         ? ((void)((win)->_attrs = ((a) & ~A_COLOR), \                          
                   (win)->_color = (opts) ? *(int *)(opts) : (p)), \            
            OK) \                                                               
         : ERR)

(No change would be needed for wattr_off, of course). X/Open Curses assumes that the attribute parameter at of wattr_on does not include bits for a color pair. ncurses does do this (because it uses the same layout for the attributes in narrow/wide libraries), so providing a use for the opts parameter is consistent – for ncurses.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1