150276Speter/****************************************************************************
2174993Srafan * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/* lib_color.c
3650276Speter *
3750276Speter * Handles color emulation of SYS V curses
3850276Speter */
3950276Speter
4050276Speter#include <curses.priv.h>
4150276Speter
4250276Speter#include <term.h>
4362449Speter#include <tic.h>
4450276Speter
45174993SrafanMODULE_ID("$Id: lib_color.c,v 1.85 2007/04/07 17:07:28 tom Exp $")
4650276Speter
4750276Speter/*
4850276Speter * These should be screen structure members.  They need to be globals for
4962449Speter * historical reasons.  So we assign them in start_color() and also in
5050276Speter * set_term()'s screen-switching logic.
5150276Speter */
52174993Srafan#if USE_REENTRANT
53174993SrafanNCURSES_EXPORT(int)
54174993SrafanNCURSES_PUBLIC_VAR(COLOR_PAIRS) (void)
55174993Srafan{
56174993Srafan    return SP ? SP->_pair_count : -1;
57174993Srafan}
58174993SrafanNCURSES_EXPORT(int)
59174993SrafanNCURSES_PUBLIC_VAR(COLORS) (void)
60174993Srafan{
61174993Srafan    return SP ? SP->_color_count : -1;
62174993Srafan}
63174993Srafan#else
6497049SpeterNCURSES_EXPORT_VAR(int) COLOR_PAIRS = 0;
6597049SpeterNCURSES_EXPORT_VAR(int) COLORS = 0;
66174993Srafan#endif
6750276Speter
68166124Srafan#define DATA(r,g,b) {r,g,b, 0,0,0, 0}
69166124Srafan
70166124Srafan#define TYPE_CALLOC(type,elts) typeCalloc(type, (unsigned)(elts))
71166124Srafan
72174993Srafan#define MAX_PALETTE	8
73174993Srafan
74166124Srafan#define OkColorHi(n)	(((n) < COLORS) && ((n) < max_colors))
75174993Srafan#define InPalette(n)	((n) >= 0 && (n) < MAX_PALETTE)
76166124Srafan
7750276Speter/*
7850276Speter * Given a RGB range of 0..1000, we'll normally set the individual values
7950276Speter * to about 2/3 of the maximum, leaving full-range for bold/bright colors.
8050276Speter */
8150276Speter#define RGB_ON  680
8250276Speter#define RGB_OFF 0
8362449Speter/* *INDENT-OFF* */
8450276Speterstatic const color_t cga_palette[] =
8550276Speter{
8662449Speter    /*  R               G               B */
87166124Srafan    DATA(RGB_OFF,	RGB_OFF,	RGB_OFF),	/* COLOR_BLACK */
88166124Srafan    DATA(RGB_ON,	RGB_OFF,	RGB_OFF),	/* COLOR_RED */
89166124Srafan    DATA(RGB_OFF,	RGB_ON,		RGB_OFF),	/* COLOR_GREEN */
90166124Srafan    DATA(RGB_ON,	RGB_ON,		RGB_OFF),	/* COLOR_YELLOW */
91166124Srafan    DATA(RGB_OFF,	RGB_OFF,	RGB_ON),	/* COLOR_BLUE */
92166124Srafan    DATA(RGB_ON,	RGB_OFF,	RGB_ON),	/* COLOR_MAGENTA */
93166124Srafan    DATA(RGB_OFF,	RGB_ON,		RGB_ON),	/* COLOR_CYAN */
94166124Srafan    DATA(RGB_ON,	RGB_ON,		RGB_ON),	/* COLOR_WHITE */
9550276Speter};
9662449Speter
9750276Speterstatic const color_t hls_palette[] =
9850276Speter{
99166124Srafan    /*  	H       L       S */
100166124Srafan    DATA(	0,	0,	0),		/* COLOR_BLACK */
101166124Srafan    DATA(	120,	50,	100),		/* COLOR_RED */
102166124Srafan    DATA(	240,	50,	100),		/* COLOR_GREEN */
103166124Srafan    DATA(	180,	50,	100),		/* COLOR_YELLOW */
104166124Srafan    DATA(	330,	50,	100),		/* COLOR_BLUE */
105166124Srafan    DATA(	60,	50,	100),		/* COLOR_MAGENTA */
106166124Srafan    DATA(	300,	50,	100),		/* COLOR_CYAN */
107166124Srafan    DATA(	0,	50,	100),		/* COLOR_WHITE */
10850276Speter};
10962449Speter/* *INDENT-ON* */
11050276Speter
11166963Speter#if NCURSES_EXT_FUNCS
11250276Speter/*
11362449Speter * These are called from _nc_do_color(), which in turn is called from
11462449Speter * vidattr - so we have to assume that SP may be null.
11562449Speter */
11697049Speterstatic int
11797049Speterdefault_fg(void)
11862449Speter{
11962449Speter    return (SP != 0) ? SP->_default_fg : COLOR_WHITE;
12062449Speter}
12162449Speter
12262449Speterstatic int
12362449Speterdefault_bg(void)
12462449Speter{
12562449Speter    return SP != 0 ? SP->_default_bg : COLOR_BLACK;
12662449Speter}
12762449Speter#else
12862449Speter#define default_fg() COLOR_WHITE
12962449Speter#define default_bg() COLOR_BLACK
13062449Speter#endif
13162449Speter
13262449Speter/*
13350276Speter * SVr4 curses is known to interchange color codes (1,4) and (3,6), possibly
13450276Speter * to maintain compatibility with a pre-ANSI scheme.  The same scheme is
13550276Speter * also used in the FreeBSD syscons.
13650276Speter */
13797049Speterstatic int
13897049Spetertoggled_colors(int c)
13950276Speter{
14050276Speter    if (c < 16) {
14150276Speter	static const int table[] =
14262449Speter	{0, 4, 2, 6, 1, 5, 3, 7,
14376726Speter	 8, 12, 10, 14, 9, 13, 11, 15};
14450276Speter	c = table[c];
14550276Speter    }
14650276Speter    return c;
14750276Speter}
14850276Speter
14962449Speterstatic void
15062449Speterset_background_color(int bg, int (*outc) (int))
15150276Speter{
15262449Speter    if (set_a_background) {
15362449Speter	TPUTS_TRACE("set_a_background");
154166124Srafan	tputs(TPARM_1(set_a_background, bg), 1, outc);
15562449Speter    } else {
15662449Speter	TPUTS_TRACE("set_background");
157166124Srafan	tputs(TPARM_1(set_background, toggled_colors(bg)), 1, outc);
15862449Speter    }
15950276Speter}
16050276Speter
16162449Speterstatic void
16262449Speterset_foreground_color(int fg, int (*outc) (int))
16350276Speter{
16462449Speter    if (set_a_foreground) {
16562449Speter	TPUTS_TRACE("set_a_foreground");
166166124Srafan	tputs(TPARM_1(set_a_foreground, fg), 1, outc);
16762449Speter    } else {
16862449Speter	TPUTS_TRACE("set_foreground");
169166124Srafan	tputs(TPARM_1(set_foreground, toggled_colors(fg)), 1, outc);
17062449Speter    }
17150276Speter}
17250276Speter
173166124Srafanstatic void
174166124Srafaninit_color_table(void)
17550276Speter{
176166124Srafan    const color_t *tp;
17762449Speter    int n;
17850276Speter
17962449Speter    tp = (hue_lightness_saturation) ? hls_palette : cga_palette;
18062449Speter    for (n = 0; n < COLORS; n++) {
181174993Srafan	if (InPalette(n)) {
18262449Speter	    SP->_color_table[n] = tp[n];
18362449Speter	} else {
184174993Srafan	    SP->_color_table[n] = tp[n % MAX_PALETTE];
18562449Speter	    if (hue_lightness_saturation) {
18662449Speter		SP->_color_table[n].green = 100;
18762449Speter	    } else {
18862449Speter		if (SP->_color_table[n].red)
18962449Speter		    SP->_color_table[n].red = 1000;
19062449Speter		if (SP->_color_table[n].green)
19162449Speter		    SP->_color_table[n].green = 1000;
19262449Speter		if (SP->_color_table[n].blue)
19362449Speter		    SP->_color_table[n].blue = 1000;
19462449Speter	    }
19562449Speter	}
19662449Speter    }
197166124Srafan}
19850276Speter
199166124Srafan/*
200166124Srafan * Reset the color pair, e.g., to whatever color pair 0 is.
201166124Srafan */
202166124Srafanstatic bool
203166124Srafanreset_color_pair(void)
204166124Srafan{
205166124Srafan    bool result = FALSE;
20662449Speter
207166124Srafan    if (orig_pair != 0) {
208166124Srafan	TPUTS_TRACE("orig_pair");
209166124Srafan	putp(orig_pair);
210166124Srafan	result = TRUE;
211166124Srafan    }
212166124Srafan    return result;
21350276Speter}
21450276Speter
215166124Srafan/*
216166124Srafan * Reset color pairs and definitions.  Actually we do both more to accommodate
217166124Srafan * badly-written terminal descriptions than for the relatively rare case where
218166124Srafan * someone has changed the color definitions.
219166124Srafan */
220166124Srafanbool
221166124Srafan_nc_reset_colors(void)
222166124Srafan{
223166124Srafan    int result = FALSE;
224166124Srafan
225166124Srafan    T((T_CALLED("_nc_reset_colors()")));
226166124Srafan    if (SP->_color_defs > 0)
227166124Srafan	SP->_color_defs = -(SP->_color_defs);
228166124Srafan
229166124Srafan    if (reset_color_pair())
230166124Srafan	result = TRUE;
231166124Srafan    if (orig_colors != 0) {
232166124Srafan	TPUTS_TRACE("orig_colors");
233166124Srafan	putp(orig_colors);
234166124Srafan	result = TRUE;
235166124Srafan    }
236166124Srafan    returnBool(result);
237166124Srafan}
238166124Srafan
239166124SrafanNCURSES_EXPORT(int)
240166124Srafanstart_color(void)
241166124Srafan{
242166124Srafan    int result = ERR;
243166124Srafan
244166124Srafan    T((T_CALLED("start_color()")));
245166124Srafan
246166124Srafan    if (SP == 0) {
247166124Srafan	result = ERR;
248166124Srafan    } else if (SP->_coloron) {
249166124Srafan	result = OK;
250166124Srafan    } else {
251166124Srafan
252166124Srafan	if (reset_color_pair() != TRUE) {
253166124Srafan	    set_foreground_color(default_fg(), _nc_outch);
254166124Srafan	    set_background_color(default_bg(), _nc_outch);
255166124Srafan	}
256166124Srafan
257166124Srafan	if (max_pairs > 0 && max_colors > 0) {
258174993Srafan	    SP->_pair_count = max_pairs;
259174993Srafan	    SP->_color_count = max_colors;
260174993Srafan#if !USE_REENTRANT
261174993Srafan	    COLOR_PAIRS = max_pairs;
262174993Srafan	    COLORS = max_colors;
263174993Srafan#endif
264166124Srafan
265166124Srafan	    if ((SP->_color_pairs = TYPE_CALLOC(colorpair_t,
266166124Srafan						max_pairs)) != 0) {
267166124Srafan		if ((SP->_color_table = TYPE_CALLOC(color_t,
268166124Srafan						    max_colors)) != 0) {
269166124Srafan		    SP->_color_pairs[0] = PAIR_OF(default_fg(), default_bg());
270166124Srafan		    init_color_table();
271166124Srafan
272166124Srafan		    T(("started color: COLORS = %d, COLOR_PAIRS = %d",
273166124Srafan		       COLORS, COLOR_PAIRS));
274166124Srafan
275166124Srafan		    SP->_coloron = 1;
276166124Srafan		    result = OK;
277166124Srafan		} else if (SP->_color_pairs != 0) {
278166124Srafan		    FreeAndNull(SP->_color_pairs);
279166124Srafan		}
280166124Srafan	    }
281166124Srafan	} else {
282166124Srafan	    result = OK;
283166124Srafan	}
284166124Srafan    }
285166124Srafan    returnCode(result);
286166124Srafan}
287166124Srafan
28850276Speter/* This function was originally written by Daniel Weaver <danw@znyx.com> */
28962449Speterstatic void
29062449Speterrgb2hls(short r, short g, short b, short *h, short *l, short *s)
29150276Speter/* convert RGB to HLS system */
29250276Speter{
29350276Speter    short min, max, t;
29450276Speter
29562449Speter    if ((min = g < r ? g : r) > b)
29662449Speter	min = b;
29762449Speter    if ((max = g > r ? g : r) < b)
29862449Speter	max = b;
29950276Speter
30050276Speter    /* calculate lightness */
30150276Speter    *l = (min + max) / 20;
30250276Speter
30362449Speter    if (min == max) {		/* black, white and all shades of gray */
30450276Speter	*h = 0;
30550276Speter	*s = 0;
30650276Speter	return;
30750276Speter    }
30850276Speter
30950276Speter    /* calculate saturation */
31050276Speter    if (*l < 50)
31150276Speter	*s = ((max - min) * 100) / (max + min);
31262449Speter    else
31362449Speter	*s = ((max - min) * 100) / (2000 - max - min);
31450276Speter
31550276Speter    /* calculate hue */
31650276Speter    if (r == max)
31750276Speter	t = 120 + ((g - b) * 60) / (max - min);
31862449Speter    else if (g == max)
31962449Speter	t = 240 + ((b - r) * 60) / (max - min);
32050276Speter    else
32162449Speter	t = 360 + ((r - g) * 60) / (max - min);
32250276Speter
32350276Speter    *h = t % 360;
32450276Speter}
32550276Speter
32650276Speter/*
32750276Speter * Extension (1997/1/18) - Allow negative f/b values to set default color
32850276Speter * values.
32950276Speter */
33076726SpeterNCURSES_EXPORT(int)
33197049Speterinit_pair(short pair, short f, short b)
33250276Speter{
333166124Srafan    colorpair_t result;
33450276Speter
33562449Speter    T((T_CALLED("init_pair(%d,%d,%d)"), pair, f, b));
33650276Speter
337166124Srafan    if ((pair < 0) || (pair >= COLOR_PAIRS) || SP == 0 || !SP->_coloron)
33862449Speter	returnCode(ERR);
33966963Speter#if NCURSES_EXT_FUNCS
34062449Speter    if (SP->_default_color) {
34162449Speter	if (f < 0)
342166124Srafan	    f = COLOR_DEFAULT;
34362449Speter	if (b < 0)
344166124Srafan	    b = COLOR_DEFAULT;
345166124Srafan	if (!OkColorHi(f) && !isDefaultColor(f))
34662449Speter	    returnCode(ERR);
347166124Srafan	if (!OkColorHi(b) && !isDefaultColor(b))
34862449Speter	    returnCode(ERR);
34962449Speter    } else
35062449Speter#endif
35162449Speter    {
352166124Srafan	if ((f < 0) || !OkColorHi(f)
353166124Srafan	    || (b < 0) || !OkColorHi(b)
35462449Speter	    || (pair < 1))
35562449Speter	    returnCode(ERR);
35662449Speter    }
35750276Speter
35862449Speter    /*
35962449Speter     * When a pair's content is changed, replace its colors (if pair was
36062449Speter     * initialized before a screen update is performed replacing original
36162449Speter     * pair colors with the new ones).
36262449Speter     */
36362449Speter    result = PAIR_OF(f, b);
36462449Speter    if (SP->_color_pairs[pair] != 0
36562449Speter	&& SP->_color_pairs[pair] != result) {
36662449Speter	int y, x;
36750276Speter
36862449Speter	for (y = 0; y <= curscr->_maxy; y++) {
36962449Speter	    struct ldat *ptr = &(curscr->_line[y]);
37062449Speter	    bool changed = FALSE;
37162449Speter	    for (x = 0; x <= curscr->_maxx; x++) {
372166124Srafan		if (GetPair(ptr->text[x]) == pair) {
37362449Speter		    /* Set the old cell to zero to ensure it will be
37462449Speter		       updated on the next doupdate() */
37597049Speter		    SetChar(ptr->text[x], 0, 0);
37662449Speter		    CHANGED_CELL(ptr, x);
37762449Speter		    changed = TRUE;
37850276Speter		}
37950276Speter	    }
38062449Speter	    if (changed)
38162449Speter		_nc_make_oldhash(y);
38250276Speter	}
38362449Speter    }
38462449Speter    SP->_color_pairs[pair] = result;
385166124Srafan    if (GET_SCREEN_PAIR(SP) == pair)
386166124Srafan	SET_SCREEN_PAIR(SP, (chtype) (~0));	/* force attribute update */
38750276Speter
388174993Srafan    if (initialize_pair && InPalette(f) && InPalette(b)) {
38962449Speter	const color_t *tp = hue_lightness_saturation ? hls_palette : cga_palette;
39050276Speter
391174993Srafan	TR(TRACE_ATTRS,
392174993Srafan	   ("initializing pair: pair = %d, fg=(%d,%d,%d), bg=(%d,%d,%d)",
393174993Srafan	    pair,
394174993Srafan	    tp[f].red, tp[f].green, tp[f].blue,
395174993Srafan	    tp[b].red, tp[b].green, tp[b].blue));
39650276Speter
397166124Srafan	TPUTS_TRACE("initialize_pair");
398166124Srafan	putp(TPARM_7(initialize_pair,
399166124Srafan		     pair,
400166124Srafan		     tp[f].red, tp[f].green, tp[f].blue,
401166124Srafan		     tp[b].red, tp[b].green, tp[b].blue));
40262449Speter    }
40350276Speter
40462449Speter    returnCode(OK);
40550276Speter}
40650276Speter
407166124Srafan#define okRGB(n) ((n) >= 0 && (n) <= 1000)
408166124Srafan
40976726SpeterNCURSES_EXPORT(int)
41097049Speterinit_color(short color, short r, short g, short b)
41150276Speter{
412166124Srafan    int result = ERR;
413166124Srafan
41462449Speter    T((T_CALLED("init_color(%d,%d,%d,%d)"), color, r, g, b));
41550276Speter
416166124Srafan    if (initialize_color != NULL
417166124Srafan	&& SP != 0
418166124Srafan	&& SP->_coloron
419166124Srafan	&& (color >= 0 && OkColorHi(color))
420166124Srafan	&& (okRGB(r) && okRGB(g) && okRGB(b))) {
42150276Speter
422166124Srafan	SP->_color_table[color].init = 1;
423166124Srafan	SP->_color_table[color].r = r;
424166124Srafan	SP->_color_table[color].g = g;
425166124Srafan	SP->_color_table[color].b = b;
42650276Speter
427166124Srafan	if (hue_lightness_saturation) {
428166124Srafan	    rgb2hls(r, g, b,
429166124Srafan		    &SP->_color_table[color].red,
430166124Srafan		    &SP->_color_table[color].green,
431166124Srafan		    &SP->_color_table[color].blue);
432166124Srafan	} else {
433166124Srafan	    SP->_color_table[color].red = r;
434166124Srafan	    SP->_color_table[color].green = g;
435166124Srafan	    SP->_color_table[color].blue = b;
436166124Srafan	}
43750276Speter
43862449Speter	TPUTS_TRACE("initialize_color");
439166124Srafan	putp(TPARM_4(initialize_color, color, r, g, b));
440166124Srafan	SP->_color_defs = max(color + 1, SP->_color_defs);
441166124Srafan	result = OK;
44262449Speter    }
443166124Srafan    returnCode(result);
44450276Speter}
44550276Speter
44676726SpeterNCURSES_EXPORT(bool)
44762449Spetercan_change_color(void)
44850276Speter{
44962449Speter    T((T_CALLED("can_change_color()")));
45062449Speter    returnCode((can_change != 0) ? TRUE : FALSE);
45150276Speter}
45250276Speter
45376726SpeterNCURSES_EXPORT(bool)
45462449Speterhas_colors(void)
45550276Speter{
45662449Speter    T((T_CALLED("has_colors()")));
45762449Speter    returnCode((VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
45876726Speter		&& (((set_foreground != NULL)
45976726Speter		     && (set_background != NULL))
46076726Speter		    || ((set_a_foreground != NULL)
46176726Speter			&& (set_a_background != NULL))
46276726Speter		    || set_color_pair)) ? TRUE : FALSE);
46350276Speter}
46450276Speter
46576726SpeterNCURSES_EXPORT(int)
46697049Spetercolor_content(short color, short *r, short *g, short *b)
46750276Speter{
468166124Srafan    int result;
469166124Srafan
47050276Speter    T((T_CALLED("color_content(%d,%p,%p,%p)"), color, r, g, b));
471166124Srafan    if (color < 0 || !OkColorHi(color) || SP == 0 || !SP->_coloron) {
472166124Srafan	result = ERR;
473166124Srafan    } else {
474166124Srafan	NCURSES_COLOR_T c_r = SP->_color_table[color].red;
475166124Srafan	NCURSES_COLOR_T c_g = SP->_color_table[color].green;
476166124Srafan	NCURSES_COLOR_T c_b = SP->_color_table[color].blue;
47750276Speter
478166124Srafan	if (r)
479166124Srafan	    *r = c_r;
480166124Srafan	if (g)
481166124Srafan	    *g = c_g;
482166124Srafan	if (b)
483166124Srafan	    *b = c_b;
484166124Srafan
485174993Srafan	TR(TRACE_ATTRS, ("...color_content(%d,%d,%d,%d)",
486174993Srafan			 color, c_r, c_g, c_b));
487166124Srafan	result = OK;
488166124Srafan    }
489166124Srafan    returnCode(result);
49050276Speter}
49150276Speter
49276726SpeterNCURSES_EXPORT(int)
49397049Speterpair_content(short pair, short *f, short *b)
49450276Speter{
495166124Srafan    int result;
496166124Srafan
49762449Speter    T((T_CALLED("pair_content(%d,%p,%p)"), pair, f, b));
49850276Speter
499166124Srafan    if ((pair < 0) || (pair >= COLOR_PAIRS) || SP == 0 || !SP->_coloron) {
500166124Srafan	result = ERR;
501166124Srafan    } else {
502166124Srafan	NCURSES_COLOR_T fg = ((SP->_color_pairs[pair] >> C_SHIFT) & C_MASK);
503166124Srafan	NCURSES_COLOR_T bg = (SP->_color_pairs[pair] & C_MASK);
50450276Speter
505166124Srafan#if NCURSES_EXT_FUNCS
506166124Srafan	if (fg == COLOR_DEFAULT)
507166124Srafan	    fg = -1;
508166124Srafan	if (bg == COLOR_DEFAULT)
509166124Srafan	    bg = -1;
510166124Srafan#endif
511166124Srafan
512166124Srafan	if (f)
513166124Srafan	    *f = fg;
514166124Srafan	if (b)
515166124Srafan	    *b = bg;
516166124Srafan
517174993Srafan	TR(TRACE_ATTRS, ("...pair_content(%d,%d,%d)", pair, fg, bg));
518166124Srafan	result = OK;
519166124Srafan    }
520166124Srafan    returnCode(result);
52150276Speter}
52250276Speter
52376726SpeterNCURSES_EXPORT(void)
524166124Srafan_nc_do_color(short old_pair, short pair, bool reverse, int (*outc) (int))
52550276Speter{
526166124Srafan    NCURSES_COLOR_T fg = COLOR_DEFAULT;
527166124Srafan    NCURSES_COLOR_T bg = COLOR_DEFAULT;
52862449Speter    NCURSES_COLOR_T old_fg, old_bg;
52950276Speter
53062449Speter    if (pair < 0 || pair >= COLOR_PAIRS) {
53162449Speter	return;
53262449Speter    } else if (pair != 0) {
53362449Speter	if (set_color_pair) {
53450276Speter	    TPUTS_TRACE("set_color_pair");
535166124Srafan	    tputs(TPARM_1(set_color_pair, pair), 1, outc);
53662449Speter	    return;
53762449Speter	} else if (SP != 0) {
538166124Srafan	    pair_content((short) pair, &fg, &bg);
53950276Speter	}
54062449Speter    }
54162449Speter
542166124Srafan    if (old_pair >= 0
543166124Srafan	&& SP != 0
544166124Srafan	&& pair_content(old_pair, &old_fg, &old_bg) != ERR) {
545166124Srafan	if ((isDefaultColor(fg) && !isDefaultColor(old_fg))
546166124Srafan	    || (isDefaultColor(bg) && !isDefaultColor(old_bg))) {
54766963Speter#if NCURSES_EXT_FUNCS
54862449Speter	    /*
54962449Speter	     * A minor optimization - but extension.  If "AX" is specified in
55062449Speter	     * the terminal description, treat it as screen's indicator of ECMA
55162449Speter	     * SGR 39 and SGR 49, and assume the two sequences are independent.
55262449Speter	     */
553166124Srafan	    if (SP->_has_sgr_39_49
554166124Srafan		&& isDefaultColor(old_bg)
555166124Srafan		&& !isDefaultColor(old_fg)) {
55662449Speter		tputs("\033[39m", 1, outc);
557166124Srafan	    } else if (SP->_has_sgr_39_49
558166124Srafan		       && isDefaultColor(old_fg)
559166124Srafan		       && !isDefaultColor(old_bg)) {
56062449Speter		tputs("\033[49m", 1, outc);
56162449Speter	    } else
56262449Speter#endif
563166124Srafan		reset_color_pair();
56450276Speter	}
56562449Speter    } else {
566166124Srafan	reset_color_pair();
56762449Speter	if (old_pair < 0)
56862449Speter	    return;
56950276Speter    }
57050276Speter
57166963Speter#if NCURSES_EXT_FUNCS
572166124Srafan    if (isDefaultColor(fg))
57362449Speter	fg = default_fg();
574166124Srafan    if (isDefaultColor(bg))
57562449Speter	bg = default_bg();
57662449Speter#endif
57750276Speter
57862449Speter    if (reverse) {
57962449Speter	NCURSES_COLOR_T xx = fg;
58062449Speter	fg = bg;
58162449Speter	bg = xx;
58250276Speter    }
58362449Speter
58476726Speter    TR(TRACE_ATTRS, ("setting colors: pair = %d, fg = %d, bg = %d", pair,
58576726Speter		     fg, bg));
58662449Speter
587166124Srafan    if (!isDefaultColor(fg)) {
58862449Speter	set_foreground_color(fg, outc);
58962449Speter    }
590166124Srafan    if (!isDefaultColor(bg)) {
59162449Speter	set_background_color(bg, outc);
59262449Speter    }
59350276Speter}
594