How do I get a bright white background color with ncurses?

Viewed 2744

How do I get a bright white background with black text on it in ncurses, similar to the title-bar in nano? All I can seem to achieve despite following the advice in another question (which has to do with getting bright white text on a black background, the opposite of what I want to achieve), is an ugly beige-colored background.

Images:

GNU nano's titlebar, what I want.

enter image description here

What I get with the program below. (Build with gcc -lncursesw -I/usr/include minimal_example.c)

enter image description here

#include <locale.h>
#include <ncurses.h>

int main() {
    setlocale(LC_ALL, "");
    // Initialize curses library
    initscr();
    // Enable colors
    start_color();
    // Attempt recommendation in https://stackoverflow.com/questions/1896162/how-to-get-a-brightwhite-color-in-ncurses and other places on the web
    use_default_colors();
    // Make the COLOR_PAIR 0xFF refer to a white foreground, black background window.
    // Using -1 will not work in my case, because I want the opposite of the default (black text  on white bg), not the default (white text on black bg).
    init_pair(0xFF, COLOR_BLACK, COLOR_WHITE);
    refresh();
    // Get our term height and width.
    int x;
    int y;
    // & not required because this is a macro
    getmaxyx(stdscr, y, x); 
    // Create a new window.
    // TODO: Resize the window when the term resizes.
    WINDOW *window = newwin(y,x,0,0);
    // Try some other attributes recommended online, no dice. Putting this after the call to wbkgd() just makes the text look strange, does not change the background.
    wattron(window,A_BOLD|A_STANDOUT);
    // Set window color.
    wbkgd(window, COLOR_PAIR(0xff));
    // Draw a nice box around the window.
    box(window, 0, 0); 
    // Write some text.
    mvwprintw(window, 1, 1, "背景:不白");
    wrefresh(window);

    // Wait for keypress to exit.
    getch(); 
    // De-initialize ncurses.
    endwin();
    return 0;
}

I thought that perhaps there was something wrong with my terminal configuration (termite), but I was able to reproduce the problem in xfce4-terminal and xterm, both using the default configurations. The only way to fix this is to set my color7 and color15 to the same color as foreground, which obviously I do not want to do because that is non-standard and I want to distribute the larger application this code is used in.

(xfce4-terminal with the bug) enter image description here

3 Answers

Colors in terminal emulators are a bit of a mess. Your problem is that that gray background really is "white" according to your terminal! Check out this table on Wikipedia. See how gray-looking the "White" row is across all the different terminal emulators? What you really want is "bright white", which is beyond the 8 initial colors. The problem is that, according to curses:

Some terminals support more than the eight (8) “ANSI” colors. There are no standard names for those additional colors.

So you just have to use them by number and hope that everyone's terminal conforms to the tables on Wikipedia (I think most do).

init_pair(0xFF, COLOR_BLACK, COLORS > 15 ? 15 : COLOR_WHITE);

That's all you need, so you can get rid of all that other use_default_colors and A_BOLD stuff.


Old answer:

The curs_color manual says

Note that setting an implicit background color via a color pair affects only character cells that a character write operation explicitly touches.

...

The A_BLINK attribute should in theory cause the background to go bright.

Indeed, if you just change

wbkgd(window, COLOR_PAIR(0xff) | A_BLINK);

You get a bright white background, but only in areas where text was drawn (including the window border). I'm not sure how to get the same effect over the entire window background, but hopefully this can get you started.

My recommendation is to define the bright colors (9 to 15) if there are at least 16 colors and can_change_color() returns true. Otherwise fall back to non-bright colors:

#include <stdlib.h>
#include <locale.h>
#include <ncurses.h>

#define PAIR_BW       1
#define BRIGHT_WHITE  15

int main(void) {
    int rows, cols;

    setlocale(LC_ALL, "");
    initscr();

    start_color();
    use_default_colors();
    if (can_change_color() && COLORS >= 16)
        init_color(BRIGHT_WHITE, 1000,1000,1000);

    if (COLORS >= 16) {
        init_pair(PAIR_BW, COLOR_BLACK, BRIGHT_WHITE);
    } else {
        init_pair(PAIR_BW, COLOR_BLACK, COLOR_WHITE);
    }

    refresh();
    getmaxyx(stdscr, rows, cols); 
    WINDOW *window = newwin(rows,cols,0,0);
    wbkgd(window, COLOR_PAIR(PAIR_BW));
    box(window, 0, 0); 
    mvwprintw(window, 1, 1, "背景:不白");
    wrefresh(window);

    getch(); 
    endwin();
    return EXIT_SUCCESS;
}

This is tested to work in Gnome Terminal 3.18.3 and XTerm 322, and it should work in all color-capable terminals if using ncursesw (although on some weird ones you might still get the non-bright-white background).

This change (assuming TERM=xterm-256color) does what was asked:

> diff -u foo.c foo2.c
--- foo.c       2017-10-06 15:59:56.000000000 -0400
+++ foo2.c      2017-10-06 16:10:11.893529758 -0400
@@ -7,10 +7,9 @@
     initscr();
     // Enable colors
     start_color();
-    // Attempt recommendation in https://stackoverflow.com/questions/1896162/how-to-get-a-brightwhite-color-in-ncurses and other places on the web
-    use_default_colors();
-    // Make the COLOR_PAIR 0xFF refer to a white foreground, black background window.
-    // Using -1 will not work in my case, because I want the opposite of the default (black text  on white bg), not the default (white text on black bg).
+    // redefine colors, using the initc capability in TERM=xterm-256color
+    init_color(COLOR_BLACK, 0, 0, 0);
+    init_color(COLOR_WHITE, 999, 999, 999);
     init_pair(0xFF, COLOR_BLACK, COLOR_WHITE);
     refresh();
     // Get our term height and width.

But nano doesn't do that. You might find it helpful to read its source-code, to see that it solves the problem by using the terminal's default colors.

Related