1275970Scy/**************************************************************************** 2275970Scy * Copyright 2018-2020,2021 Thomas E. Dickey * 3275970Scy * Copyright 1998-2016,2017 Free Software Foundation, Inc. * 4275970Scy * * 5275970Scy * Permission is hereby granted, free of charge, to any person obtaining a * 6275970Scy * copy of this software and associated documentation files (the * 7275970Scy * "Software"), to deal in the Software without restriction, including * 8275970Scy * without limitation the rights to use, copy, modify, merge, publish, * 9316722Sdelphij * distribute, distribute with modifications, sublicense, and/or sell * 10275970Scy * copies of the Software, and to permit persons to whom the Software is * 11275970Scy * furnished to do so, subject to the following conditions: * 12275970Scy * * 13275970Scy * The above copyright notice and this permission notice shall be included * 14275970Scy * in all copies or substantial portions of the Software. * 15275970Scy * * 16275970Scy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17275970Scy * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18275970Scy * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19275970Scy * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20275970Scy * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21275970Scy * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22275970Scy * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23275970Scy * * 24275970Scy * Except as contained in this notice, the name(s) of the above copyright * 25275970Scy * holders shall not be used in advertising or otherwise to promote the * 26275970Scy * sale, use or other dealings in this Software without prior written * 27275970Scy * authorization. * 28275970Scy ****************************************************************************/ 29275970Scy 30275970Scy/**************************************************************************** 31275970Scy * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 32275970Scy * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33275970Scy * and: Thomas E. Dickey 1996-on * 34275970Scy * and: Juergen Pfeifer 2009 * 35275970Scy ****************************************************************************/ 36275970Scy 37275970Scy/* lib_color.c 38275970Scy * 39275970Scy * Handles color emulation of SYS V curses 40275970Scy */ 41275970Scy 42275970Scy#define NEW_PAIR_INTERNAL 1 43275970Scy 44275970Scy#include <curses.priv.h> 45316722Sdelphij#include <new_pair.h> 46275970Scy#include <tic.h> 47275970Scy 48275970Scy#ifndef CUR 49275970Scy#define CUR SP_TERMTYPE 50275970Scy#endif 51275970Scy 52275970ScyMODULE_ID("$Id: lib_color.c,v 1.146 2021/02/14 00:17:09 tom Exp $") 53275970Scy 54275970Scy#ifdef USE_TERM_DRIVER 55275970Scy#define CanChange InfoOf(SP_PARM).canchange 56275970Scy#define DefaultPalette InfoOf(SP_PARM).defaultPalette 57275970Scy#define HasColor InfoOf(SP_PARM).hascolor 58275970Scy#define InitColor InfoOf(SP_PARM).initcolor 59275970Scy#define MaxColors InfoOf(SP_PARM).maxcolors 60275970Scy#define MaxPairs InfoOf(SP_PARM).maxpairs 61275970Scy#define UseHlsPalette (DefaultPalette == _nc_hls_palette) 62275970Scy#else 63275970Scy#define CanChange can_change 64275970Scy#define DefaultPalette (hue_lightness_saturation ? hls_palette : cga_palette) 65275970Scy#define HasColor has_color 66275970Scy#define InitColor initialize_color 67275970Scy#define MaxColors max_colors 68275970Scy#define MaxPairs max_pairs 69275970Scy#define UseHlsPalette (hue_lightness_saturation) 70275970Scy#endif 71275970Scy 72275970Scy#ifndef USE_TERM_DRIVER 73275970Scy/* 74275970Scy * These should be screen structure members. They need to be globals for 75275970Scy * historical reasons. So we assign them in start_color() and also in 76275970Scy * set_term()'s screen-switching logic. 77275970Scy */ 78275970Scy#if USE_REENTRANT 79275970ScyNCURSES_EXPORT(int) 80275970ScyNCURSES_PUBLIC_VAR(COLOR_PAIRS) (void) 81275970Scy{ 82275970Scy return SP ? SP->_pair_count : -1; 83275970Scy} 84275970ScyNCURSES_EXPORT(int) 85275970ScyNCURSES_PUBLIC_VAR(COLORS) (void) 86275970Scy{ 87275970Scy return SP ? SP->_color_count : -1; 88275970Scy} 89275970Scy#else 90275970ScyNCURSES_EXPORT_VAR(int) COLOR_PAIRS = 0; 91275970ScyNCURSES_EXPORT_VAR(int) COLORS = 0; 92275970Scy#endif 93275970Scy#endif /* !USE_TERM_DRIVER */ 94275970Scy 95275970Scy#define DATA(r,g,b) {r,g,b, 0,0,0, 0} 96275970Scy 97275970Scy#define TYPE_CALLOC(type,elts) typeCalloc(type, (unsigned)(elts)) 98275970Scy 99275970Scy#define MAX_PALETTE 8 100275970Scy 101275970Scy#define OkColorHi(n) (((n) < COLORS) && ((n) < maxcolors)) 102275970Scy#define InPalette(n) ((n) >= 0 && (n) < MAX_PALETTE) 103275970Scy 104/* 105 * Given a RGB range of 0..1000, we'll normally set the individual values 106 * to about 2/3 of the maximum, leaving full-range for bold/bright colors. 107 */ 108#define RGB_ON 680 109#define RGB_OFF 0 110/* *INDENT-OFF* */ 111static const color_t cga_palette[] = 112{ 113 /* R G B */ 114 DATA(RGB_OFF, RGB_OFF, RGB_OFF), /* COLOR_BLACK */ 115 DATA(RGB_ON, RGB_OFF, RGB_OFF), /* COLOR_RED */ 116 DATA(RGB_OFF, RGB_ON, RGB_OFF), /* COLOR_GREEN */ 117 DATA(RGB_ON, RGB_ON, RGB_OFF), /* COLOR_YELLOW */ 118 DATA(RGB_OFF, RGB_OFF, RGB_ON), /* COLOR_BLUE */ 119 DATA(RGB_ON, RGB_OFF, RGB_ON), /* COLOR_MAGENTA */ 120 DATA(RGB_OFF, RGB_ON, RGB_ON), /* COLOR_CYAN */ 121 DATA(RGB_ON, RGB_ON, RGB_ON), /* COLOR_WHITE */ 122}; 123 124static const color_t hls_palette[] = 125{ 126 /* H L S */ 127 DATA( 0, 0, 0), /* COLOR_BLACK */ 128 DATA( 120, 50, 100), /* COLOR_RED */ 129 DATA( 240, 50, 100), /* COLOR_GREEN */ 130 DATA( 180, 50, 100), /* COLOR_YELLOW */ 131 DATA( 330, 50, 100), /* COLOR_BLUE */ 132 DATA( 60, 50, 100), /* COLOR_MAGENTA */ 133 DATA( 300, 50, 100), /* COLOR_CYAN */ 134 DATA( 0, 50, 100), /* COLOR_WHITE */ 135}; 136 137#ifdef USE_TERM_DRIVER 138NCURSES_EXPORT_VAR(const color_t*) _nc_cga_palette = cga_palette; 139NCURSES_EXPORT_VAR(const color_t*) _nc_hls_palette = hls_palette; 140#endif 141 142/* *INDENT-ON* */ 143#if NCURSES_EXT_FUNCS 144/* 145 * These are called from _nc_do_color(), which in turn is called from 146 * vidattr - so we have to assume that sp may be null. 147 */ 148static int 149default_fg(NCURSES_SP_DCL0) 150{ 151 return (SP_PARM != 0) ? SP_PARM->_default_fg : COLOR_WHITE; 152} 153 154static int 155default_bg(NCURSES_SP_DCL0) 156{ 157 return SP_PARM != 0 ? SP_PARM->_default_bg : COLOR_BLACK; 158} 159#else 160#define default_fg(sp) COLOR_WHITE 161#define default_bg(sp) COLOR_BLACK 162#endif 163 164#ifndef USE_TERM_DRIVER 165/* 166 * SVr4 curses is known to interchange color codes (1,4) and (3,6), possibly 167 * to maintain compatibility with a pre-ANSI scheme. The same scheme is 168 * also used in the FreeBSD syscons. 169 */ 170static int 171toggled_colors(int c) 172{ 173 if (c < 16) { 174 static const int table[] = 175 {0, 4, 2, 6, 1, 5, 3, 7, 176 8, 12, 10, 14, 9, 13, 11, 15}; 177 c = table[c]; 178 } 179 return c; 180} 181#endif 182 183static void 184set_background_color(NCURSES_SP_DCLx int bg, NCURSES_SP_OUTC outc) 185{ 186#ifdef USE_TERM_DRIVER 187 CallDriver_3(SP_PARM, td_color, FALSE, bg, outc); 188#else 189 if (set_a_background) { 190 TPUTS_TRACE("set_a_background"); 191 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 192 TIPARM_1(set_a_background, bg), 193 1, outc); 194 } else { 195 TPUTS_TRACE("set_background"); 196 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 197 TIPARM_1(set_background, toggled_colors(bg)), 198 1, outc); 199 } 200#endif 201} 202 203static void 204set_foreground_color(NCURSES_SP_DCLx int fg, NCURSES_SP_OUTC outc) 205{ 206#ifdef USE_TERM_DRIVER 207 CallDriver_3(SP_PARM, td_color, TRUE, fg, outc); 208#else 209 if (set_a_foreground) { 210 TPUTS_TRACE("set_a_foreground"); 211 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 212 TIPARM_1(set_a_foreground, fg), 213 1, outc); 214 } else { 215 TPUTS_TRACE("set_foreground"); 216 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 217 TIPARM_1(set_foreground, toggled_colors(fg)), 218 1, outc); 219 } 220#endif 221} 222 223static void 224init_color_table(NCURSES_SP_DCL0) 225{ 226 const color_t *tp = DefaultPalette; 227 int n; 228 229 assert(tp != 0); 230 231 for (n = 0; n < COLORS; n++) { 232 if (InPalette(n)) { 233 SP_PARM->_color_table[n] = tp[n]; 234 } else { 235 SP_PARM->_color_table[n] = tp[n % MAX_PALETTE]; 236 if (UseHlsPalette) { 237 SP_PARM->_color_table[n].green = 100; 238 } else { 239 if (SP_PARM->_color_table[n].red) 240 SP_PARM->_color_table[n].red = 1000; 241 if (SP_PARM->_color_table[n].green) 242 SP_PARM->_color_table[n].green = 1000; 243 if (SP_PARM->_color_table[n].blue) 244 SP_PARM->_color_table[n].blue = 1000; 245 } 246 } 247 } 248} 249 250static bool 251init_direct_colors(NCURSES_SP_DCL0) 252{ 253 static NCURSES_CONST char name[] = "RGB"; 254 255 rgb_bits_t *result = &(SP_PARM->_direct_color); 256 257 result->value = 0; 258 259 if (COLORS >= 8) { 260 int n; 261 const char *s; 262 int width; 263 264 /* find the number of bits needed for the maximum color value */ 265 for (width = 0; (1 << width) - 1 < (COLORS - 1); ++width) { 266 ; 267 } 268 269 if ((n = tigetflag(name)) > 0) { 270 n = (width + 2) / 3; 271 result->bits.red = UChar(n); 272 result->bits.green = UChar(n); 273 result->bits.blue = UChar(width - (2 * n)); 274 } else if ((n = tigetnum(name)) > 0) { 275 result->bits.red = UChar(n); 276 result->bits.green = UChar(n); 277 result->bits.blue = UChar(n); 278 } else if ((s = tigetstr(name)) != 0 && VALID_STRING(s)) { 279 int red = n; 280 int green = n; 281 int blue = width - (2 * n); 282 283 switch (sscanf(s, "%d/%d/%d", &red, &green, &blue)) { 284 default: 285 blue = width - (2 * n); 286 /* FALLTHRU */ 287 case 1: 288 green = n; 289 /* FALLTHRU */ 290 case 2: 291 red = n; 292 /* FALLTHRU */ 293 case 3: 294 /* okay */ 295 break; 296 } 297 result->bits.red = UChar(red); 298 result->bits.green = UChar(green); 299 result->bits.blue = UChar(blue); 300 } 301 } 302 return (result->value != 0); 303} 304 305/* 306 * Reset the color pair, e.g., to whatever color pair 0 is. 307 */ 308static bool 309reset_color_pair(NCURSES_SP_DCL0) 310{ 311#ifdef USE_TERM_DRIVER 312 return CallDriver(SP_PARM, td_rescol); 313#else 314 bool result = FALSE; 315 316 (void) SP_PARM; 317 if (orig_pair != 0) { 318 (void) NCURSES_PUTP2("orig_pair", orig_pair); 319 result = TRUE; 320 } 321 return result; 322#endif 323} 324 325/* 326 * Reset color pairs and definitions. Actually we do both more to accommodate 327 * badly-written terminal descriptions than for the relatively rare case where 328 * someone has changed the color definitions. 329 */ 330NCURSES_EXPORT(bool) 331NCURSES_SP_NAME(_nc_reset_colors) (NCURSES_SP_DCL0) 332{ 333 int result = FALSE; 334 335 T((T_CALLED("_nc_reset_colors(%p)"), (void *) SP_PARM)); 336 if (SP_PARM->_color_defs > 0) 337 SP_PARM->_color_defs = -(SP_PARM->_color_defs); 338 if (reset_color_pair(NCURSES_SP_ARG)) 339 result = TRUE; 340 341#ifdef USE_TERM_DRIVER 342 result = CallDriver(SP_PARM, td_rescolors); 343#else 344 if (orig_colors != 0) { 345 NCURSES_PUTP2("orig_colors", orig_colors); 346 result = TRUE; 347 } 348#endif 349 returnBool(result); 350} 351 352#if NCURSES_SP_FUNCS 353NCURSES_EXPORT(bool) 354_nc_reset_colors(void) 355{ 356 return NCURSES_SP_NAME(_nc_reset_colors) (CURRENT_SCREEN); 357} 358#endif 359 360NCURSES_EXPORT(int) 361NCURSES_SP_NAME(start_color) (NCURSES_SP_DCL0) 362{ 363 int result = ERR; 364 365 T((T_CALLED("start_color(%p)"), (void *) SP_PARM)); 366 367 if (SP_PARM == 0) { 368 result = ERR; 369 } else if (SP_PARM->_coloron) { 370 result = OK; 371 } else { 372 int maxpairs = MaxPairs; 373 int maxcolors = MaxColors; 374 if (reset_color_pair(NCURSES_SP_ARG) != TRUE) { 375 set_foreground_color(NCURSES_SP_ARGx 376 default_fg(NCURSES_SP_ARG), 377 NCURSES_SP_NAME(_nc_outch)); 378 set_background_color(NCURSES_SP_ARGx 379 default_bg(NCURSES_SP_ARG), 380 NCURSES_SP_NAME(_nc_outch)); 381 } 382#if !NCURSES_EXT_COLORS 383 /* 384 * Without ext-colors, we cannot represent more than 256 color pairs. 385 */ 386 if (maxpairs > 256) 387 maxpairs = 256; 388#endif 389 390 if (maxpairs > 0 && maxcolors > 0) { 391 SP_PARM->_pair_limit = maxpairs; 392 393#if NCURSES_EXT_FUNCS 394 /* 395 * If using default colors, allocate extra space in table to 396 * allow for default-color as a component of a color-pair. 397 */ 398 SP_PARM->_pair_limit += (1 + (2 * maxcolors)); 399#if !NCURSES_EXT_COLORS 400 SP_PARM->_pair_limit = limit_PAIRS(SP_PARM->_pair_limit); 401#endif 402#endif /* NCURSES_EXT_FUNCS */ 403 SP_PARM->_pair_count = maxpairs; 404 SP_PARM->_color_count = maxcolors; 405#if !USE_REENTRANT 406 COLOR_PAIRS = maxpairs; 407 COLORS = maxcolors; 408#endif 409 410 ReservePairs(SP_PARM, 16); 411 if (SP_PARM->_color_pairs != 0) { 412 if (init_direct_colors(NCURSES_SP_ARG)) { 413 result = OK; 414 } else { 415 SP_PARM->_color_table = TYPE_CALLOC(color_t, maxcolors); 416 if (SP_PARM->_color_table != 0) { 417 MakeColorPair(SP_PARM->_color_pairs[0], 418 default_fg(NCURSES_SP_ARG), 419 default_bg(NCURSES_SP_ARG)); 420 init_color_table(NCURSES_SP_ARG); 421 422 result = OK; 423 } 424 } 425 if (result == OK) { 426 T(("started color: COLORS = %d, COLOR_PAIRS = %d", 427 COLORS, COLOR_PAIRS)); 428 429 SP_PARM->_coloron = 1; 430 } else if (SP_PARM->_color_pairs != 0) { 431 FreeAndNull(SP_PARM->_color_pairs); 432 } 433 } 434 } else { 435 result = OK; 436 } 437 } 438 returnCode(result); 439} 440 441#if NCURSES_SP_FUNCS 442NCURSES_EXPORT(int) 443start_color(void) 444{ 445 return NCURSES_SP_NAME(start_color) (CURRENT_SCREEN); 446} 447#endif 448 449/* This function was originally written by Daniel Weaver <danw@znyx.com> */ 450static void 451rgb2hls(int r, int g, int b, int *h, int *l, int *s) 452/* convert RGB to HLS system */ 453{ 454 int min, max, t; 455 456 if ((min = g < r ? g : r) > b) 457 min = b; 458 if ((max = g > r ? g : r) < b) 459 max = b; 460 461 /* calculate lightness */ 462 *l = ((min + max) / 20); 463 464 if (min == max) { /* black, white and all shades of gray */ 465 *h = 0; 466 *s = 0; 467 return; 468 } 469 470 /* calculate saturation */ 471 if (*l < 50) 472 *s = (((max - min) * 100) / (max + min)); 473 else 474 *s = (((max - min) * 100) / (2000 - max - min)); 475 476 /* calculate hue */ 477 if (r == max) 478 t = (120 + ((g - b) * 60) / (max - min)); 479 else if (g == max) 480 t = (240 + ((b - r) * 60) / (max - min)); 481 else 482 t = (360 + ((r - g) * 60) / (max - min)); 483 484 *h = (t % 360); 485} 486 487/* 488 * Change all cells which use(d) a given color pair to force a repaint. 489 */ 490NCURSES_EXPORT(void) 491_nc_change_pair(SCREEN *sp, int pair) 492{ 493 int y, x; 494 495 if (CurScreen(sp)->_clear) 496 return; 497#if NO_LEAKS 498 if (_nc_globals.leak_checking) 499 return; 500#endif 501 502 for (y = 0; y <= CurScreen(sp)->_maxy; y++) { 503 struct ldat *ptr = &(CurScreen(sp)->_line[y]); 504 bool changed = FALSE; 505 for (x = 0; x <= CurScreen(sp)->_maxx; x++) { 506 if (GetPair(ptr->text[x]) == pair) { 507 /* Set the old cell to zero to ensure it will be 508 updated on the next doupdate() */ 509 SetChar(ptr->text[x], 0, 0); 510 CHANGED_CELL(ptr, x); 511 changed = TRUE; 512 } 513 } 514 if (changed) 515 NCURSES_SP_NAME(_nc_make_oldhash) (NCURSES_SP_ARGx y); 516 } 517} 518 519NCURSES_EXPORT(void) 520_nc_reserve_pairs(SCREEN *sp, int want) 521{ 522 int have = sp->_pair_alloc; 523 524 if (have == 0) 525 have = 1; 526 while (have <= want) 527 have *= 2; 528 if (have > sp->_pair_limit) 529 have = sp->_pair_limit; 530 531 if (sp->_color_pairs == 0) { 532 sp->_color_pairs = TYPE_CALLOC(colorpair_t, have); 533 } else if (have > sp->_pair_alloc) { 534#if NCURSES_EXT_COLORS 535 colorpair_t *next; 536 537 if ((next = typeCalloc(colorpair_t, have)) == 0) 538 _nc_err_abort(MSG_NO_MEMORY); 539 memcpy(next, sp->_color_pairs, (size_t) sp->_pair_alloc * sizeof(*next)); 540 _nc_copy_pairs(sp, next, sp->_color_pairs, sp->_pair_alloc); 541 free(sp->_color_pairs); 542 sp->_color_pairs = next; 543#else 544 TYPE_REALLOC(colorpair_t, have, sp->_color_pairs); 545 if (sp->_color_pairs != 0) { 546 memset(sp->_color_pairs + sp->_pair_alloc, 0, 547 sizeof(colorpair_t) * (size_t) (have - sp->_pair_alloc)); 548 } 549#endif 550 } 551 if (sp->_color_pairs != 0) { 552 sp->_pair_alloc = have; 553 } 554} 555 556/* 557 * Extension (1997/1/18) - Allow negative f/b values to set default color 558 * values. 559 */ 560NCURSES_EXPORT(int) 561_nc_init_pair(SCREEN *sp, int pair, int f, int b) 562{ 563 static colorpair_t null_pair; 564 colorpair_t result = null_pair; 565 colorpair_t previous; 566 int maxcolors; 567 568 T((T_CALLED("init_pair(%p,%d,%d,%d)"), (void *) sp, pair, f, b)); 569 570 if (!ValidPair(sp, pair)) 571 returnCode(ERR); 572 573 maxcolors = MaxColors; 574 575 ReservePairs(sp, pair); 576 previous = sp->_color_pairs[pair]; 577#if NCURSES_EXT_FUNCS 578 if (sp->_default_color || sp->_assumed_color) { 579 bool isDefault = FALSE; 580 bool wasDefault = FALSE; 581 int default_pairs = sp->_default_pairs; 582 583 /* 584 * Map caller's color number, e.g., -1, 0, 1, .., 7, etc., into 585 * internal unsigned values which we will store in the _color_pairs[] 586 * table. 587 */ 588 if (isDefaultColor(f)) { 589 f = COLOR_DEFAULT; 590 isDefault = TRUE; 591 } else if (!OkColorHi(f)) { 592 returnCode(ERR); 593 } 594 595 if (isDefaultColor(b)) { 596 b = COLOR_DEFAULT; 597 isDefault = TRUE; 598 } else if (!OkColorHi(b)) { 599 returnCode(ERR); 600 } 601 602 /* 603 * Check if the table entry that we are going to init/update used 604 * default colors. 605 */ 606 if (isDefaultColor(FORE_OF(previous)) 607 || isDefaultColor(BACK_OF(previous))) 608 wasDefault = TRUE; 609 610 /* 611 * Keep track of the number of entries in the color pair table which 612 * used a default color. 613 */ 614 if (isDefault && !wasDefault) { 615 ++default_pairs; 616 } else if (wasDefault && !isDefault) { 617 --default_pairs; 618 } 619 620 /* 621 * As an extension, ncurses allows the pair number to exceed the 622 * terminal's color_pairs value for pairs using a default color. 623 * 624 * Note that updating a pair which used a default color with one 625 * that does not will decrement the count - and possibly interfere 626 * with sequentially adding new pairs. 627 */ 628 if (pair > (sp->_pair_count + default_pairs)) { 629 returnCode(ERR); 630 } 631 sp->_default_pairs = default_pairs; 632 } else 633#endif 634 { 635 if ((f < 0) || !OkColorHi(f) 636 || (b < 0) || !OkColorHi(b) 637 || (pair < 1)) { 638 returnCode(ERR); 639 } 640 } 641 642 /* 643 * When a pair's content is changed, replace its colors (if pair was 644 * initialized before a screen update is performed replacing original 645 * pair colors with the new ones). 646 */ 647 MakeColorPair(result, f, b); 648 if ((FORE_OF(previous) != 0 649 || BACK_OF(previous) != 0) 650 && !isSamePair(previous, result)) { 651 _nc_change_pair(sp, pair); 652 } 653 654 _nc_reset_color_pair(sp, pair, &result); 655 sp->_color_pairs[pair] = result; 656 _nc_set_color_pair(sp, pair, cpINIT); 657 658 if (GET_SCREEN_PAIR(sp) == pair) 659 SET_SCREEN_PAIR(sp, (int) (~0)); /* force attribute update */ 660 661#ifdef USE_TERM_DRIVER 662 CallDriver_3(sp, td_initpair, pair, f, b); 663#else 664 if (initialize_pair && InPalette(f) && InPalette(b)) { 665 const color_t *tp = DefaultPalette; 666 667 TR(TRACE_ATTRS, 668 ("initializing pair: pair = %d, fg=(%d,%d,%d), bg=(%d,%d,%d)", 669 (int) pair, 670 (int) tp[f].red, (int) tp[f].green, (int) tp[f].blue, 671 (int) tp[b].red, (int) tp[b].green, (int) tp[b].blue)); 672 673 NCURSES_PUTP2("initialize_pair", 674 TIPARM_7(initialize_pair, 675 pair, 676 (int) tp[f].red, 677 (int) tp[f].green, 678 (int) tp[f].blue, 679 (int) tp[b].red, 680 (int) tp[b].green, 681 (int) tp[b].blue)); 682 } 683#endif 684 685 returnCode(OK); 686} 687 688NCURSES_EXPORT(int) 689NCURSES_SP_NAME(init_pair) (NCURSES_SP_DCLx 690 NCURSES_PAIRS_T pair, 691 NCURSES_COLOR_T f, 692 NCURSES_COLOR_T b) 693{ 694 return _nc_init_pair(SP_PARM, pair, f, b); 695} 696 697#if NCURSES_SP_FUNCS 698NCURSES_EXPORT(int) 699init_pair(NCURSES_COLOR_T pair, NCURSES_COLOR_T f, NCURSES_COLOR_T b) 700{ 701 return NCURSES_SP_NAME(init_pair) (CURRENT_SCREEN, pair, f, b); 702} 703#endif 704 705#define okRGB(n) ((n) >= 0 && (n) <= 1000) 706 707NCURSES_EXPORT(int) 708_nc_init_color(SCREEN *sp, int color, int r, int g, int b) 709{ 710 int result = ERR; 711 int maxcolors; 712 713 T((T_CALLED("init_color(%p,%d,%d,%d,%d)"), 714 (void *) sp, 715 color, 716 r, g, b)); 717 718 if (sp == 0 || sp->_direct_color.value) 719 returnCode(result); 720 721 maxcolors = MaxColors; 722 723 if (InitColor 724 && sp->_coloron 725 && (color >= 0 && OkColorHi(color)) 726 && (okRGB(r) && okRGB(g) && okRGB(b))) { 727 728 sp->_color_table[color].init = 1; 729 sp->_color_table[color].r = r; 730 sp->_color_table[color].g = g; 731 sp->_color_table[color].b = b; 732 733 if (UseHlsPalette) { 734 rgb2hls(r, g, b, 735 &sp->_color_table[color].red, 736 &sp->_color_table[color].green, 737 &sp->_color_table[color].blue); 738 } else { 739 sp->_color_table[color].red = r; 740 sp->_color_table[color].green = g; 741 sp->_color_table[color].blue = b; 742 } 743 744#ifdef USE_TERM_DRIVER 745 CallDriver_4(sp, td_initcolor, color, r, g, b); 746#else 747 NCURSES_PUTP2("initialize_color", 748 TIPARM_4(initialize_color, color, r, g, b)); 749#endif 750 sp->_color_defs = max(color + 1, sp->_color_defs); 751 752 result = OK; 753 } 754 returnCode(result); 755} 756 757NCURSES_EXPORT(int) 758NCURSES_SP_NAME(init_color) (NCURSES_SP_DCLx 759 NCURSES_COLOR_T color, 760 NCURSES_COLOR_T r, 761 NCURSES_COLOR_T g, 762 NCURSES_COLOR_T b) 763{ 764 return _nc_init_color(SP_PARM, color, r, g, b); 765} 766 767#if NCURSES_SP_FUNCS 768NCURSES_EXPORT(int) 769init_color(NCURSES_COLOR_T color, 770 NCURSES_COLOR_T r, 771 NCURSES_COLOR_T g, 772 NCURSES_COLOR_T b) 773{ 774 return NCURSES_SP_NAME(init_color) (CURRENT_SCREEN, color, r, g, b); 775} 776#endif 777 778NCURSES_EXPORT(bool) 779NCURSES_SP_NAME(can_change_color) (NCURSES_SP_DCL) 780{ 781 int result = FALSE; 782 783 T((T_CALLED("can_change_color(%p)"), (void *) SP_PARM)); 784 785 if (HasTerminal(SP_PARM) && (CanChange != 0)) { 786 result = TRUE; 787 } 788 789 returnCode(result); 790} 791 792#if NCURSES_SP_FUNCS 793NCURSES_EXPORT(bool) 794can_change_color(void) 795{ 796 return NCURSES_SP_NAME(can_change_color) (CURRENT_SCREEN); 797} 798#endif 799 800NCURSES_EXPORT(bool) 801NCURSES_SP_NAME(has_colors) (NCURSES_SP_DCL0) 802{ 803 int code = FALSE; 804 805 (void) SP_PARM; 806 T((T_CALLED("has_colors(%p)"), (void *) SP_PARM)); 807 if (HasTerminal(SP_PARM)) { 808#ifdef USE_TERM_DRIVER 809 code = HasColor; 810#else 811 code = ((VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs) 812 && (((set_foreground != NULL) 813 && (set_background != NULL)) 814 || ((set_a_foreground != NULL) 815 && (set_a_background != NULL)) 816 || set_color_pair)) ? TRUE : FALSE); 817#endif 818 } 819 returnCode(code); 820} 821 822#if NCURSES_SP_FUNCS 823NCURSES_EXPORT(bool) 824has_colors(void) 825{ 826 return NCURSES_SP_NAME(has_colors) (CURRENT_SCREEN); 827} 828#endif 829 830static int 831_nc_color_content(SCREEN *sp, int color, int *r, int *g, int *b) 832{ 833 int result = ERR; 834 int maxcolors; 835 836 T((T_CALLED("color_content(%p,%d,%p,%p,%p)"), 837 (void *) sp, 838 color, 839 (void *) r, 840 (void *) g, 841 (void *) b)); 842 843 if (sp == 0) 844 returnCode(result); 845 846 maxcolors = MaxColors; 847 848 if (color < 0 || !OkColorHi(color) || !sp->_coloron) { 849 result = ERR; 850 } else { 851 int c_r, c_g, c_b; 852 853 if (sp->_direct_color.value) { 854 rgb_bits_t *work = &(sp->_direct_color); 855 856#define max_direct_color(name) ((1 << work->bits.name) - 1) 857#define value_direct_color(max) (1000 * ((color >> bitoff) & max)) / max 858 859 int max_r = max_direct_color(red); 860 int max_g = max_direct_color(green); 861 int max_b = max_direct_color(blue); 862 863 int bitoff = 0; 864 865 c_b = value_direct_color(max_b); 866 bitoff += work->bits.blue; 867 868 c_g = value_direct_color(max_g); 869 bitoff += work->bits.green; 870 871 c_r = value_direct_color(max_r); 872 873 } else { 874 c_r = sp->_color_table[color].red; 875 c_g = sp->_color_table[color].green; 876 c_b = sp->_color_table[color].blue; 877 } 878 879 if (r) 880 *r = c_r; 881 if (g) 882 *g = c_g; 883 if (b) 884 *b = c_b; 885 886 TR(TRACE_ATTRS, ("...color_content(%d,%d,%d,%d)", 887 color, c_r, c_g, c_b)); 888 result = OK; 889 } 890 returnCode(result); 891} 892 893NCURSES_EXPORT(int) 894NCURSES_SP_NAME(color_content) (NCURSES_SP_DCLx 895 NCURSES_COLOR_T color, 896 NCURSES_COLOR_T *r, 897 NCURSES_COLOR_T *g, 898 NCURSES_COLOR_T *b) 899{ 900 int my_r, my_g, my_b; 901 int rc = _nc_color_content(SP_PARM, color, &my_r, &my_g, &my_b); 902 if (rc == OK) { 903 *r = limit_COLOR(my_r); 904 *g = limit_COLOR(my_g); 905 *b = limit_COLOR(my_b); 906 } 907 return rc; 908} 909 910#if NCURSES_SP_FUNCS 911NCURSES_EXPORT(int) 912color_content(NCURSES_COLOR_T color, 913 NCURSES_COLOR_T *r, 914 NCURSES_COLOR_T *g, 915 NCURSES_COLOR_T *b) 916{ 917 return NCURSES_SP_NAME(color_content) (CURRENT_SCREEN, color, r, g, b); 918} 919#endif 920 921NCURSES_EXPORT(int) 922_nc_pair_content(SCREEN *sp, int pair, int *f, int *b) 923{ 924 int result; 925 926 T((T_CALLED("pair_content(%p,%d,%p,%p)"), 927 (void *) sp, 928 (int) pair, 929 (void *) f, 930 (void *) b)); 931 932 if (!ValidPair(sp, pair)) { 933 result = ERR; 934 } else { 935 int fg; 936 int bg; 937 938 ReservePairs(sp, pair); 939 fg = FORE_OF(sp->_color_pairs[pair]); 940 bg = BACK_OF(sp->_color_pairs[pair]); 941#if NCURSES_EXT_FUNCS 942 if (isDefaultColor(fg)) 943 fg = -1; 944 if (isDefaultColor(bg)) 945 bg = -1; 946#endif 947 948 if (f) 949 *f = fg; 950 if (b) 951 *b = bg; 952 953 TR(TRACE_ATTRS, ("...pair_content(%p,%d,%d,%d)", 954 (void *) sp, 955 (int) pair, 956 (int) fg, (int) bg)); 957 result = OK; 958 } 959 returnCode(result); 960} 961 962NCURSES_EXPORT(int) 963NCURSES_SP_NAME(pair_content) (NCURSES_SP_DCLx 964 NCURSES_PAIRS_T pair, 965 NCURSES_COLOR_T *f, 966 NCURSES_COLOR_T *b) 967{ 968 int my_f, my_b; 969 int rc = _nc_pair_content(SP_PARM, pair, &my_f, &my_b); 970 if (rc == OK) { 971 *f = limit_COLOR(my_f); 972 *b = limit_COLOR(my_b); 973 } 974 return rc; 975} 976 977#if NCURSES_SP_FUNCS 978NCURSES_EXPORT(int) 979pair_content(NCURSES_COLOR_T pair, NCURSES_COLOR_T *f, NCURSES_COLOR_T *b) 980{ 981 return NCURSES_SP_NAME(pair_content) (CURRENT_SCREEN, pair, f, b); 982} 983#endif 984 985NCURSES_EXPORT(void) 986NCURSES_SP_NAME(_nc_do_color) (NCURSES_SP_DCLx 987 int old_pair, 988 int pair, 989 int reverse, 990 NCURSES_SP_OUTC outc) 991{ 992#ifdef USE_TERM_DRIVER 993 CallDriver_4(SP_PARM, td_docolor, old_pair, pair, reverse, outc); 994#else 995 int fg = COLOR_DEFAULT; 996 int bg = COLOR_DEFAULT; 997 int old_fg = -1; 998 int old_bg = -1; 999 1000 if (!ValidPair(SP_PARM, pair)) { 1001 return; 1002 } else if (pair != 0) { 1003 if (set_color_pair) { 1004 TPUTS_TRACE("set_color_pair"); 1005 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 1006 TIPARM_1(set_color_pair, pair), 1007 1, outc); 1008 return; 1009 } else if (SP_PARM != 0) { 1010 if (_nc_pair_content(SP_PARM, pair, &fg, &bg) == ERR) 1011 return; 1012 } 1013 } 1014 1015 if (old_pair >= 0 1016 && SP_PARM != 0 1017 && _nc_pair_content(SP_PARM, old_pair, &old_fg, &old_bg) != ERR) { 1018 if ((isDefaultColor(fg) && !isDefaultColor(old_fg)) 1019 || (isDefaultColor(bg) && !isDefaultColor(old_bg))) { 1020#if NCURSES_EXT_FUNCS 1021 /* 1022 * A minor optimization - but extension. If "AX" is specified in 1023 * the terminal description, treat it as screen's indicator of ECMA 1024 * SGR 39 and SGR 49, and assume the two sequences are independent. 1025 */ 1026 if (SP_PARM->_has_sgr_39_49 1027 && isDefaultColor(old_bg) 1028 && !isDefaultColor(old_fg)) { 1029 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx "\033[39m", 1, outc); 1030 } else if (SP_PARM->_has_sgr_39_49 1031 && isDefaultColor(old_fg) 1032 && !isDefaultColor(old_bg)) { 1033 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx "\033[49m", 1, outc); 1034 } else 1035#endif 1036 reset_color_pair(NCURSES_SP_ARG); 1037 } 1038 } else { 1039 reset_color_pair(NCURSES_SP_ARG); 1040 if (old_pair < 0 && pair <= 0) 1041 return; 1042 } 1043 1044#if NCURSES_EXT_FUNCS 1045 if (isDefaultColor(fg)) 1046 fg = default_fg(NCURSES_SP_ARG); 1047 if (isDefaultColor(bg)) 1048 bg = default_bg(NCURSES_SP_ARG); 1049#endif 1050 1051 if (reverse) { 1052 int xx = fg; 1053 fg = bg; 1054 bg = xx; 1055 } 1056 1057 TR(TRACE_ATTRS, ("setting colors: pair = %d, fg = %d, bg = %d", pair, 1058 fg, bg)); 1059 1060 if (!isDefaultColor(fg)) { 1061 set_foreground_color(NCURSES_SP_ARGx fg, outc); 1062 } 1063 if (!isDefaultColor(bg)) { 1064 set_background_color(NCURSES_SP_ARGx bg, outc); 1065 } 1066#endif 1067} 1068 1069#if NCURSES_SP_FUNCS 1070NCURSES_EXPORT(void) 1071_nc_do_color(int old_pair, int pair, int reverse, NCURSES_OUTC outc) 1072{ 1073 SetSafeOutcWrapper(outc); 1074 NCURSES_SP_NAME(_nc_do_color) (CURRENT_SCREEN, 1075 old_pair, 1076 pair, 1077 reverse, 1078 _nc_outc_wrapper); 1079} 1080#endif 1081 1082#if NCURSES_EXT_COLORS 1083NCURSES_EXPORT(int) 1084NCURSES_SP_NAME(init_extended_pair) (NCURSES_SP_DCLx int pair, int f, int b) 1085{ 1086 return _nc_init_pair(SP_PARM, pair, f, b); 1087} 1088 1089NCURSES_EXPORT(int) 1090NCURSES_SP_NAME(init_extended_color) (NCURSES_SP_DCLx 1091 int color, 1092 int r, int g, int b) 1093{ 1094 return _nc_init_color(SP_PARM, color, r, g, b); 1095} 1096 1097NCURSES_EXPORT(int) 1098NCURSES_SP_NAME(extended_color_content) (NCURSES_SP_DCLx 1099 int color, 1100 int *r, int *g, int *b) 1101{ 1102 return _nc_color_content(SP_PARM, color, r, g, b); 1103} 1104 1105NCURSES_EXPORT(int) 1106NCURSES_SP_NAME(extended_pair_content) (NCURSES_SP_DCLx 1107 int pair, 1108 int *f, int *b) 1109{ 1110 return _nc_pair_content(SP_PARM, pair, f, b); 1111} 1112 1113NCURSES_EXPORT(void) 1114NCURSES_SP_NAME(reset_color_pairs) (NCURSES_SP_DCL0) 1115{ 1116 if (SP_PARM != 0) { 1117 if (SP_PARM->_color_pairs) { 1118 _nc_free_ordered_pairs(SP_PARM); 1119 free(SP_PARM->_color_pairs); 1120 SP_PARM->_color_pairs = 0; 1121 SP_PARM->_pair_alloc = 0; 1122 ReservePairs(SP_PARM, 16); 1123 clearok(CurScreen(SP_PARM), TRUE); 1124 touchwin(StdScreen(SP_PARM)); 1125 } 1126 } 1127} 1128 1129#if NCURSES_SP_FUNCS 1130NCURSES_EXPORT(int) 1131init_extended_pair(int pair, int f, int b) 1132{ 1133 return NCURSES_SP_NAME(init_extended_pair) (CURRENT_SCREEN, pair, f, b); 1134} 1135 1136NCURSES_EXPORT(int) 1137init_extended_color(int color, int r, int g, int b) 1138{ 1139 return NCURSES_SP_NAME(init_extended_color) (CURRENT_SCREEN, 1140 color, 1141 r, g, b); 1142} 1143 1144NCURSES_EXPORT(int) 1145extended_color_content(int color, int *r, int *g, int *b) 1146{ 1147 return NCURSES_SP_NAME(extended_color_content) (CURRENT_SCREEN, 1148 color, 1149 r, g, b); 1150} 1151 1152NCURSES_EXPORT(int) 1153extended_pair_content(int pair, int *f, int *b) 1154{ 1155 return NCURSES_SP_NAME(extended_pair_content) (CURRENT_SCREEN, pair, f, b); 1156} 1157 1158NCURSES_EXPORT(void) 1159reset_color_pairs(void) 1160{ 1161 NCURSES_SP_NAME(reset_color_pairs) (CURRENT_SCREEN); 1162} 1163#endif /* NCURSES_SP_FUNCS */ 1164#endif /* NCURSES_EXT_COLORS */ 1165