#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: color.c,v 1.48 2024/07/11 07:13:41 blymn Exp $");
#endif
#include "curses.h"
#include "curses_private.h"
int __using_color = 0;
int __do_color_init = 0;
attr_t __default_color = 0;
struct __pair __default_pair = {COLOR_WHITE, COLOR_BLACK, 0};
#define __USED 0x01
static void
__change_pair(short);
static int
init_color_value(short, short, short, short);
bool
has_colors(void)
{
if (max_colors > 0 && max_pairs > 0 &&
((set_a_foreground != NULL && set_a_background != NULL) ||
initialize_pair != NULL || initialize_color != NULL ||
(set_background != NULL && set_foreground != NULL)))
return true;
else
return false;
}
bool
can_change_color(void)
{
return can_change ? true : false;
}
int
start_color(void)
{
int i;
attr_t temp_nc;
struct __winlist *wlp;
WINDOW *win;
int y, x;
if (has_colors() == FALSE)
return ERR;
if (max_colors == -1)
COLORS = 0;
else {
COLORS = max_colors > MAX_COLORS ? MAX_COLORS : max_colors;
if (max_pairs == -1) {
COLOR_PAIRS = 0;
COLORS = 0;
} else {
COLOR_PAIRS = (max_pairs > MAX_PAIRS - 1 ?
MAX_PAIRS - 1 : max_pairs);
#ifdef __OLD_DEFAULT_COLOR
__default_color = COLOR_PAIR(MAX_PAIRS - 1);
#else
__default_color = COLOR_PAIR(0);
#endif
}
}
if (!COLORS)
return ERR;
_cursesi_screen->COLORS = COLORS;
_cursesi_screen->COLOR_PAIRS = COLOR_PAIRS;
_cursesi_screen->curpair = -1;
if (orig_colors != NULL)
tputs(orig_colors, 0, __cputchar);
if (orig_pair != NULL) {
tputs(orig_pair, 0, __cputchar);
curscr->wattr &= _cursesi_screen->mask_op;
}
if (set_a_foreground != NULL && set_a_background != NULL)
_cursesi_screen->color_type = COLOR_ANSI;
else if (initialize_pair != NULL)
_cursesi_screen->color_type = COLOR_HP;
else if (initialize_color != NULL)
_cursesi_screen->color_type = COLOR_TEK;
else if (set_foreground != NULL && set_background != NULL)
_cursesi_screen->color_type = COLOR_OTHER;
else
return(ERR);
#ifdef DEBUG
__CTRACE(__CTRACE_COLOR, "start_color: COLORS = %d, COLOR_PAIRS = %d",
COLORS, COLOR_PAIRS);
switch (_cursesi_screen->color_type) {
case COLOR_ANSI:
__CTRACE(__CTRACE_COLOR, " (ANSI style)\n");
break;
case COLOR_HP:
__CTRACE(__CTRACE_COLOR, " (HP style)\n");
break;
case COLOR_TEK:
__CTRACE(__CTRACE_COLOR, " (Tektronics style)\n");
break;
case COLOR_OTHER:
__CTRACE(__CTRACE_COLOR, " (Other style)\n");
break;
}
#endif
_cursesi_screen->nca = __NORMAL;
if (no_color_video != -1) {
temp_nc = (attr_t)t_no_color_video(_cursesi_screen->term);
if (temp_nc & 0x0001)
_cursesi_screen->nca |= __STANDOUT;
if (temp_nc & 0x0002)
_cursesi_screen->nca |= __UNDERSCORE;
if (temp_nc & 0x0004)
_cursesi_screen->nca |= __REVERSE;
if (temp_nc & 0x0008)
_cursesi_screen->nca |= __BLINK;
if (temp_nc & 0x0010)
_cursesi_screen->nca |= __DIM;
if (temp_nc & 0x0020)
_cursesi_screen->nca |= __BOLD;
if (temp_nc & 0x0040)
_cursesi_screen->nca |= __BLANK;
if (temp_nc & 0x0080)
_cursesi_screen->nca |= __PROTECT;
if (temp_nc & 0x0100)
_cursesi_screen->nca |= __ALTCHARSET;
}
__CTRACE(__CTRACE_COLOR, "start_color: _cursesi_screen->nca = %08x\n",
_cursesi_screen->nca);
#define RGB_ON 680
if (COLORS >= COLOR_BLACK)
(void)init_color_value(COLOR_BLACK, 0, 0, 0);
if (COLORS >= COLOR_RED)
(void)init_color_value(COLOR_RED, RGB_ON, 0, 0);
if (COLORS >= COLOR_GREEN)
(void)init_color_value(COLOR_GREEN, 0, RGB_ON, 0);
if (COLORS >= COLOR_YELLOW)
(void)init_color_value(COLOR_YELLOW, RGB_ON, RGB_ON, 0);
if (COLORS >= COLOR_BLUE)
(void)init_color_value(COLOR_BLUE, 0, 0, RGB_ON);
if (COLORS >= COLOR_MAGENTA)
(void)init_color_value(COLOR_MAGENTA, RGB_ON, 0, RGB_ON);
if (COLORS >= COLOR_CYAN)
(void)init_color_value(COLOR_CYAN, 0, RGB_ON, RGB_ON);
if (COLORS >= COLOR_WHITE)
(void)init_color_value(COLOR_WHITE, RGB_ON, RGB_ON, RGB_ON);
for (i = 8; i < COLORS; i++) {
_cursesi_screen->colours[i].red = 0;
_cursesi_screen->colours[i].green = 0;
_cursesi_screen->colours[i].blue = 0;
_cursesi_screen->colours[i].flags = 0;
}
_cursesi_screen->colour_pairs[0].fore = -1;
_cursesi_screen->colour_pairs[0].back = -1;
_cursesi_screen->colour_pairs[0].flags = 0;
for (i = 0; i < COLOR_PAIRS; i++) {
_cursesi_screen->colour_pairs[i].fore = COLOR_WHITE;
_cursesi_screen->colour_pairs[i].back = COLOR_BLACK;
_cursesi_screen->colour_pairs[i].flags = 0;
}
_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].fore =
__default_pair.fore;
_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].back =
__default_pair.back;
_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].flags =
__default_pair.flags;
__using_color = 1;
__do_color_init = 1;
for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
win = wlp->winp;
if (wlp->winp != __virtscr && wlp->winp != curscr) {
win->battr |= __default_color;
for (y = 0; y < win->maxy; y++) {
win->alines[y]->flags |= __ISFORCED;
for (x = 0; x < win->maxx; x++) {
win->alines[y]->line[x].attr &= ~__COLOR;
win->alines[y]->line[x].attr |= __default_color;
}
}
__touchwin(win, 0);
}
}
return(OK);
}
int
init_pair(short pair, short fore, short back)
{
int changed;
__CTRACE(__CTRACE_COLOR, "init_pair: %d, %d, %d\n", pair, fore, back);
if (pair < 0 || pair >= COLOR_PAIRS)
return ERR;
if (pair == 0)
return OK;
if (fore >= COLORS)
return ERR;
if (back >= COLORS)
return ERR;
if (_cursesi_screen->color_type == COLOR_OTHER) {
switch (fore) {
case COLOR_RED:
fore = COLOR_BLUE;
break;
case COLOR_BLUE:
fore = COLOR_RED;
break;
case COLOR_YELLOW:
fore = COLOR_CYAN;
break;
case COLOR_CYAN:
fore = COLOR_YELLOW;
break;
}
switch (back) {
case COLOR_RED:
back = COLOR_BLUE;
break;
case COLOR_BLUE:
back = COLOR_RED;
break;
case COLOR_YELLOW:
back = COLOR_CYAN;
break;
case COLOR_CYAN:
back = COLOR_YELLOW;
break;
}
}
if ((_cursesi_screen->colour_pairs[pair].flags & __USED) &&
(fore != _cursesi_screen->colour_pairs[pair].fore ||
back != _cursesi_screen->colour_pairs[pair].back))
changed = 1;
else
changed = 0;
_cursesi_screen->colour_pairs[pair].flags |= __USED;
_cursesi_screen->colour_pairs[pair].fore = fore;
_cursesi_screen->colour_pairs[pair].back = back;
if (changed)
__change_pair(pair);
return OK;
}
int
pair_content(short pair, short *forep, short *backp)
{
if (pair < 0 || pair > _cursesi_screen->COLOR_PAIRS)
return ERR;
*forep = _cursesi_screen->colour_pairs[pair].fore;
*backp = _cursesi_screen->colour_pairs[pair].back;
if (_cursesi_screen->color_type == COLOR_OTHER) {
switch (*forep) {
case COLOR_RED:
*forep = COLOR_BLUE;
break;
case COLOR_BLUE:
*forep = COLOR_RED;
break;
case COLOR_YELLOW:
*forep = COLOR_CYAN;
break;
case COLOR_CYAN:
*forep = COLOR_YELLOW;
break;
}
switch (*backp) {
case COLOR_RED:
*backp = COLOR_BLUE;
break;
case COLOR_BLUE:
*backp = COLOR_RED;
break;
case COLOR_YELLOW:
*backp = COLOR_CYAN;
break;
case COLOR_CYAN:
*backp = COLOR_YELLOW;
break;
}
}
return OK;
}
static int
init_color_value(short color, short red, short green, short blue)
{
if (color < 0 || color >= _cursesi_screen->COLORS)
return ERR;
_cursesi_screen->colours[color].red = red;
_cursesi_screen->colours[color].green = green;
_cursesi_screen->colours[color].blue = blue;
return OK;
}
int
init_color(short color, short red, short green, short blue)
{
__CTRACE(__CTRACE_COLOR, "init_color: %d, %d, %d, %d\n",
color, red, green, blue);
if (init_color_value(color, red, green, blue) == ERR)
return ERR;
if (!can_change || t_initialize_color(_cursesi_screen->term) == NULL)
return ERR;
tputs(tiparm(t_initialize_color(_cursesi_screen->term),
color, red, green, blue), 0, __cputchar);
return OK;
}
int
color_content(short color, short *redp, short *greenp, short *bluep)
{
if (color < 0 || color >= _cursesi_screen->COLORS)
return ERR;
*redp = _cursesi_screen->colours[color].red;
*greenp = _cursesi_screen->colours[color].green;
*bluep = _cursesi_screen->colours[color].blue;
return OK;
}
int
use_default_colors(void)
{
__CTRACE(__CTRACE_COLOR, "use_default_colors\n");
return (assume_default_colors(-1, -1));
}
int
assume_default_colors(short fore, short back)
{
__CTRACE(__CTRACE_COLOR, "assume_default_colors: %d, %d\n",
fore, back);
__CTRACE(__CTRACE_COLOR,
"assume_default_colors: default_colour = %d, pair_number = %d\n",
__default_color, PAIR_NUMBER(__default_color));
if (_cursesi_screen->color_type == COLOR_OTHER) {
switch (fore) {
case COLOR_RED:
fore = COLOR_BLUE;
break;
case COLOR_BLUE:
fore = COLOR_RED;
break;
case COLOR_YELLOW:
fore = COLOR_CYAN;
break;
case COLOR_CYAN:
fore = COLOR_YELLOW;
break;
}
switch (back) {
case COLOR_RED:
back = COLOR_BLUE;
break;
case COLOR_BLUE:
back = COLOR_RED;
break;
case COLOR_YELLOW:
back = COLOR_CYAN;
break;
case COLOR_CYAN:
back = COLOR_YELLOW;
break;
}
}
__default_pair.fore = fore;
__default_pair.back = back;
__default_pair.flags = __USED;
if (COLOR_PAIRS) {
_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].fore = fore;
_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].back = back;
_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].flags = __USED;
}
if (__using_color)
__change_pair(PAIR_NUMBER(__default_color));
return(OK);
}
#ifdef __strong_alias
#undef no_color_video
__strong_alias(no_color_video, no_color_attributes)
#endif
attr_t
no_color_attributes(void)
{
return(_cursesi_screen->nca);
}
void
__set_color( WINDOW *win, attr_t attr)
{
short pair;
if ((__do_color_init != 1) &&
((curscr->wattr & __COLOR) == (attr & __COLOR)))
return;
pair = PAIR_NUMBER((uint32_t)attr);
if (pair == _cursesi_screen->curpair)
return;
__CTRACE(__CTRACE_COLOR, "__set_color: %d, %d, %d\n", pair,
_cursesi_screen->colour_pairs[pair].fore,
_cursesi_screen->colour_pairs[pair].back);
switch (_cursesi_screen->color_type) {
case COLOR_ANSI:
if (_cursesi_screen->colour_pairs[pair].fore < 0 ||
_cursesi_screen->colour_pairs[pair].back < 0)
__unset_color(curscr);
if (_cursesi_screen->colour_pairs[pair].fore >= 0)
tputs(tiparm(t_set_a_foreground(_cursesi_screen->term),
(int)_cursesi_screen->colour_pairs[pair].fore),
0, __cputchar);
if (_cursesi_screen->colour_pairs[pair].back >= 0)
tputs(tiparm(t_set_a_background(_cursesi_screen->term),
(int)_cursesi_screen->colour_pairs[pair].back),
0, __cputchar);
break;
case COLOR_HP:
break;
case COLOR_TEK:
break;
case COLOR_OTHER:
if (_cursesi_screen->colour_pairs[pair].fore < 0 ||
_cursesi_screen->colour_pairs[pair].back < 0)
__unset_color(curscr);
if (_cursesi_screen->colour_pairs[pair].fore >= 0)
tputs(tiparm(t_set_foreground(_cursesi_screen->term),
(int)_cursesi_screen->colour_pairs[pair].fore),
0, __cputchar);
if (_cursesi_screen->colour_pairs[pair].back >= 0)
tputs(tiparm(t_set_background(_cursesi_screen->term),
(int)_cursesi_screen->colour_pairs[pair].back),
0, __cputchar);
break;
}
_cursesi_screen->curpair = pair;
curscr->wattr &= ~__COLOR;
curscr->wattr |= attr & __COLOR;
}
void
__unset_color(WINDOW *win)
{
__CTRACE(__CTRACE_COLOR, "__unset_color\n");
switch (_cursesi_screen->color_type) {
case COLOR_ANSI:
if (orig_pair != NULL) {
tputs(orig_pair, 0, __cputchar);
win->wattr &= __mask_op;
}
break;
case COLOR_HP:
break;
case COLOR_TEK:
break;
case COLOR_OTHER:
if (orig_pair != NULL) {
tputs(orig_pair, 0, __cputchar);
win->wattr &= __mask_op;
}
break;
}
_cursesi_screen->curpair = -1;
}
void
__restore_colors(void)
{
_cursesi_screen->curpair = -1;
if (can_change != 0)
switch (_cursesi_screen->color_type) {
case COLOR_HP:
break;
case COLOR_TEK:
break;
}
}
void
__change_pair(short pair)
{
struct __winlist *wlp;
WINDOW *win;
int y, x;
__LINE *lp;
uint32_t cl = COLOR_PAIR(pair);
for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
__CTRACE(__CTRACE_COLOR, "__change_pair: win = %p\n",
wlp->winp);
win = wlp->winp;
if (win == __virtscr)
continue;
else if (win == curscr) {
__CTRACE(__CTRACE_COLOR,
"__change_pair: win == curscr\n");
for (y = 0; y < curscr->maxy; y++) {
lp = curscr->alines[y];
for (x = 0; x < curscr->maxx; x++) {
if ((lp->line[x].attr & __COLOR) == cl)
lp->line[x].attr &= ~__COLOR;
}
}
} else {
for (y = 0; y < win->maxy; y++) {
lp = win->alines[y];
for (x = 0; x < win->maxx; x++)
if ((lp->line[x].attr &
__COLOR) == cl) {
if (!(lp->flags & __ISDIRTY))
lp->flags |= __ISDIRTY;
if (*lp->firstchp > x)
*lp->firstchp = x;
if (*lp->lastchp < x)
*lp->lastchp = x;
}
#ifdef DEBUG
if ((win->alines[y]->flags & __ISDIRTY))
__CTRACE(__CTRACE_COLOR,
"__change_pair: first = %d, "
"last = %d\n",
*win->alines[y]->firstchp,
*win->alines[y]->lastchp);
#endif
}
}
}
}