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