1 /* $OpenBSD: lib_color.c,v 1.12 2023/10/17 09:52:08 nicm Exp $ */ 2 3 /**************************************************************************** 4 * Copyright 2018-2021,2022 Thomas E. Dickey * 5 * Copyright 1998-2016,2017 Free Software Foundation, Inc. * 6 * * 7 * Permission is hereby granted, free of charge, to any person obtaining a * 8 * copy of this software and associated documentation files (the * 9 * "Software"), to deal in the Software without restriction, including * 10 * without limitation the rights to use, copy, modify, merge, publish, * 11 * distribute, distribute with modifications, sublicense, and/or sell * 12 * copies of the Software, and to permit persons to whom the Software is * 13 * furnished to do so, subject to the following conditions: * 14 * * 15 * The above copyright notice and this permission notice shall be included * 16 * in all copies or substantial portions of the Software. * 17 * * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 21 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 24 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 25 * * 26 * Except as contained in this notice, the name(s) of the above copyright * 27 * holders shall not be used in advertising or otherwise to promote the * 28 * sale, use or other dealings in this Software without prior written * 29 * authorization. * 30 ****************************************************************************/ 31 32 /**************************************************************************** 33 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 34 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 35 * and: Thomas E. Dickey 1996-on * 36 * and: Juergen Pfeifer 2009 * 37 ****************************************************************************/ 38 39 /* lib_color.c 40 * 41 * Handles color emulation of SYS V curses 42 */ 43 44 #define NEW_PAIR_INTERNAL 1 45 46 #include <curses.priv.h> 47 #include <new_pair.h> 48 #include <tic.h> 49 50 #ifndef CUR 51 #define CUR SP_TERMTYPE 52 #endif 53 54 MODULE_ID("$Id: lib_color.c,v 1.12 2023/10/17 09:52:08 nicm Exp $") 55 56 #ifdef USE_TERM_DRIVER 57 #define CanChange InfoOf(SP_PARM).canchange 58 #define DefaultPalette InfoOf(SP_PARM).defaultPalette 59 #define HasColor InfoOf(SP_PARM).hascolor 60 #define InitColor InfoOf(SP_PARM).initcolor 61 #define MaxColors InfoOf(SP_PARM).maxcolors 62 #define MaxPairs InfoOf(SP_PARM).maxpairs 63 #define UseHlsPalette (DefaultPalette == _nc_hls_palette) 64 #else 65 #define CanChange can_change 66 #define DefaultPalette (hue_lightness_saturation ? hls_palette : cga_palette) 67 #define HasColor has_color 68 #define InitColor initialize_color 69 #define MaxColors max_colors 70 #define MaxPairs max_pairs 71 #define UseHlsPalette (hue_lightness_saturation) 72 #endif 73 74 #ifndef USE_TERM_DRIVER 75 /* 76 * These should be screen structure members. They need to be globals for 77 * historical reasons. So we assign them in start_color() and also in 78 * set_term()'s screen-switching logic. 79 */ 80 #if USE_REENTRANT 81 NCURSES_EXPORT(int) 82 NCURSES_PUBLIC_VAR(COLOR_PAIRS) (void) 83 { 84 return SP ? SP->_pair_count : -1; 85 } 86 NCURSES_EXPORT(int) 87 NCURSES_PUBLIC_VAR(COLORS) (void) 88 { 89 return SP ? SP->_color_count : -1; 90 } 91 #else 92 NCURSES_EXPORT_VAR(int) COLOR_PAIRS = 0; 93 NCURSES_EXPORT_VAR(int) COLORS = 0; 94 #endif 95 #endif /* !USE_TERM_DRIVER */ 96 97 #define DATA(r,g,b) {r,g,b, 0,0,0, 0} 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 #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 */ 148 static int 149 default_fg(NCURSES_SP_DCL0) 150 { 151 return (SP_PARM != 0) ? SP_PARM->_default_fg : COLOR_WHITE; 152 } 153 154 static int 155 default_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 */ 170 static int 171 toggled_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 183 static void 184 set_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 203 static void 204 set_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 223 static void 224 init_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 250 static bool 251 init_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 (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 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 TYPE_CALLOC(color_t, maxcolors, SP_PARM->_color_table); 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 442 NCURSES_EXPORT(int) 443 start_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> */ 450 static void 451 rgb2hls(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 */ 490 NCURSES_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 519 NCURSES_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 TYPE_CALLOC(colorpair_t, have, sp->_color_pairs); 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 */ 560 NCURSES_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 688 NCURSES_EXPORT(int) 689 NCURSES_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 698 NCURSES_EXPORT(int) 699 init_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 707 NCURSES_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 757 NCURSES_EXPORT(int) 758 NCURSES_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 768 NCURSES_EXPORT(int) 769 init_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 778 NCURSES_EXPORT(bool) 779 NCURSES_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 793 NCURSES_EXPORT(bool) 794 can_change_color(void) 795 { 796 return NCURSES_SP_NAME(can_change_color) (CURRENT_SCREEN); 797 } 798 #endif 799 800 NCURSES_EXPORT(bool) 801 NCURSES_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 823 NCURSES_EXPORT(bool) 824 has_colors(void) 825 { 826 return NCURSES_SP_NAME(has_colors) (CURRENT_SCREEN); 827 } 828 #endif 829 830 static int 831 _nc_color_content(SCREEN *sp, int color, int *r, int *g, int *b) 832 { 833 int result = ERR; 834 835 T((T_CALLED("color_content(%p,%d,%p,%p,%p)"), 836 (void *) sp, 837 color, 838 (void *) r, 839 (void *) g, 840 (void *) b)); 841 842 if (sp != 0) { 843 int maxcolors = MaxColors; 844 845 if (color >= 0 && OkColorHi(color) && sp->_coloron) { 846 int c_r, c_g, c_b; 847 848 if (sp->_direct_color.value) { 849 rgb_bits_t *work = &(sp->_direct_color); 850 851 #define max_direct_color(name) ((1 << work->bits.name) - 1) 852 #define value_direct_color(max) (1000 * ((color >> bitoff) & max)) / max 853 854 int max_r = max_direct_color(red); 855 int max_g = max_direct_color(green); 856 int max_b = max_direct_color(blue); 857 858 int bitoff = 0; 859 860 c_b = value_direct_color(max_b); 861 bitoff += work->bits.blue; 862 863 c_g = value_direct_color(max_g); 864 bitoff += work->bits.green; 865 866 c_r = value_direct_color(max_r); 867 868 } else { 869 c_r = sp->_color_table[color].red; 870 c_g = sp->_color_table[color].green; 871 c_b = sp->_color_table[color].blue; 872 } 873 874 if (r) 875 *r = c_r; 876 if (g) 877 *g = c_g; 878 if (b) 879 *b = c_b; 880 881 TR(TRACE_ATTRS, ("...color_content(%d,%d,%d,%d)", 882 color, c_r, c_g, c_b)); 883 result = OK; 884 } 885 } 886 if (result != OK) { 887 if (r) 888 *r = 0; 889 if (g) 890 *g = 0; 891 if (b) 892 *b = 0; 893 } 894 returnCode(result); 895 } 896 897 NCURSES_EXPORT(int) 898 NCURSES_SP_NAME(color_content) (NCURSES_SP_DCLx 899 NCURSES_COLOR_T color, 900 NCURSES_COLOR_T *r, 901 NCURSES_COLOR_T *g, 902 NCURSES_COLOR_T *b) 903 { 904 int my_r, my_g, my_b; 905 int rc = _nc_color_content(SP_PARM, color, &my_r, &my_g, &my_b); 906 if (rc == OK) { 907 *r = limit_COLOR(my_r); 908 *g = limit_COLOR(my_g); 909 *b = limit_COLOR(my_b); 910 } 911 return rc; 912 } 913 914 #if NCURSES_SP_FUNCS 915 NCURSES_EXPORT(int) 916 color_content(NCURSES_COLOR_T color, 917 NCURSES_COLOR_T *r, 918 NCURSES_COLOR_T *g, 919 NCURSES_COLOR_T *b) 920 { 921 return NCURSES_SP_NAME(color_content) (CURRENT_SCREEN, color, r, g, b); 922 } 923 #endif 924 925 NCURSES_EXPORT(int) 926 _nc_pair_content(SCREEN *sp, int pair, int *f, int *b) 927 { 928 int result; 929 930 T((T_CALLED("pair_content(%p,%d,%p,%p)"), 931 (void *) sp, 932 (int) pair, 933 (void *) f, 934 (void *) b)); 935 936 if (!ValidPair(sp, pair)) { 937 result = ERR; 938 } else { 939 int fg; 940 int bg; 941 942 ReservePairs(sp, pair); 943 fg = FORE_OF(sp->_color_pairs[pair]); 944 bg = BACK_OF(sp->_color_pairs[pair]); 945 #if NCURSES_EXT_FUNCS 946 if (isDefaultColor(fg)) 947 fg = -1; 948 if (isDefaultColor(bg)) 949 bg = -1; 950 #endif 951 952 if (f) 953 *f = fg; 954 if (b) 955 *b = bg; 956 957 TR(TRACE_ATTRS, ("...pair_content(%p,%d,%d,%d)", 958 (void *) sp, 959 (int) pair, 960 (int) fg, (int) bg)); 961 result = OK; 962 } 963 returnCode(result); 964 } 965 966 NCURSES_EXPORT(int) 967 NCURSES_SP_NAME(pair_content) (NCURSES_SP_DCLx 968 NCURSES_PAIRS_T pair, 969 NCURSES_COLOR_T *f, 970 NCURSES_COLOR_T *b) 971 { 972 int my_f, my_b; 973 int rc = _nc_pair_content(SP_PARM, pair, &my_f, &my_b); 974 if (rc == OK) { 975 *f = limit_COLOR(my_f); 976 *b = limit_COLOR(my_b); 977 } 978 return rc; 979 } 980 981 #if NCURSES_SP_FUNCS 982 NCURSES_EXPORT(int) 983 pair_content(NCURSES_COLOR_T pair, NCURSES_COLOR_T *f, NCURSES_COLOR_T *b) 984 { 985 return NCURSES_SP_NAME(pair_content) (CURRENT_SCREEN, pair, f, b); 986 } 987 #endif 988 989 NCURSES_EXPORT(void) 990 NCURSES_SP_NAME(_nc_do_color) (NCURSES_SP_DCLx 991 int old_pair, 992 int pair, 993 int reverse, 994 NCURSES_SP_OUTC outc) 995 { 996 #ifdef USE_TERM_DRIVER 997 CallDriver_4(SP_PARM, td_docolor, old_pair, pair, reverse, outc); 998 #else 999 int fg = COLOR_DEFAULT; 1000 int bg = COLOR_DEFAULT; 1001 int old_fg = -1; 1002 int old_bg = -1; 1003 1004 if (!ValidPair(SP_PARM, pair)) { 1005 return; 1006 } else if (pair != 0) { 1007 if (set_color_pair) { 1008 TPUTS_TRACE("set_color_pair"); 1009 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx 1010 TIPARM_1(set_color_pair, pair), 1011 1, outc); 1012 return; 1013 } else if (SP_PARM != 0) { 1014 if (_nc_pair_content(SP_PARM, pair, &fg, &bg) == ERR) 1015 return; 1016 } 1017 } 1018 1019 if (old_pair >= 0 1020 && SP_PARM != 0 1021 && _nc_pair_content(SP_PARM, old_pair, &old_fg, &old_bg) != ERR) { 1022 if ((isDefaultColor(fg) && !isDefaultColor(old_fg)) 1023 || (isDefaultColor(bg) && !isDefaultColor(old_bg))) { 1024 #if NCURSES_EXT_FUNCS 1025 /* 1026 * A minor optimization - but extension. If "AX" is specified in 1027 * the terminal description, treat it as screen's indicator of ECMA 1028 * SGR 39 and SGR 49, and assume the two sequences are independent. 1029 */ 1030 if (SP_PARM->_has_sgr_39_49 1031 && isDefaultColor(old_bg) 1032 && !isDefaultColor(old_fg)) { 1033 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx "\033[39m", 1, outc); 1034 } else if (SP_PARM->_has_sgr_39_49 1035 && isDefaultColor(old_fg) 1036 && !isDefaultColor(old_bg)) { 1037 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx "\033[49m", 1, outc); 1038 } else 1039 #endif 1040 reset_color_pair(NCURSES_SP_ARG); 1041 } 1042 } else { 1043 reset_color_pair(NCURSES_SP_ARG); 1044 if (old_pair < 0 && pair <= 0) 1045 return; 1046 } 1047 1048 #if NCURSES_EXT_FUNCS 1049 if (isDefaultColor(fg)) 1050 fg = default_fg(NCURSES_SP_ARG); 1051 if (isDefaultColor(bg)) 1052 bg = default_bg(NCURSES_SP_ARG); 1053 #endif 1054 1055 if (reverse) { 1056 int xx = fg; 1057 fg = bg; 1058 bg = xx; 1059 } 1060 1061 TR(TRACE_ATTRS, ("setting colors: pair = %d, fg = %d, bg = %d", pair, 1062 fg, bg)); 1063 1064 if (!isDefaultColor(fg)) { 1065 set_foreground_color(NCURSES_SP_ARGx fg, outc); 1066 } 1067 if (!isDefaultColor(bg)) { 1068 set_background_color(NCURSES_SP_ARGx bg, outc); 1069 } 1070 #endif 1071 } 1072 1073 #if NCURSES_SP_FUNCS 1074 NCURSES_EXPORT(void) 1075 _nc_do_color(int old_pair, int pair, int reverse, NCURSES_OUTC outc) 1076 { 1077 SetSafeOutcWrapper(outc); 1078 NCURSES_SP_NAME(_nc_do_color) (CURRENT_SCREEN, 1079 old_pair, 1080 pair, 1081 reverse, 1082 _nc_outc_wrapper); 1083 } 1084 #endif 1085 1086 #if NCURSES_EXT_COLORS 1087 NCURSES_EXPORT(int) 1088 NCURSES_SP_NAME(init_extended_pair) (NCURSES_SP_DCLx int pair, int f, int b) 1089 { 1090 return _nc_init_pair(SP_PARM, pair, f, b); 1091 } 1092 1093 NCURSES_EXPORT(int) 1094 NCURSES_SP_NAME(init_extended_color) (NCURSES_SP_DCLx 1095 int color, 1096 int r, int g, int b) 1097 { 1098 return _nc_init_color(SP_PARM, color, r, g, b); 1099 } 1100 1101 NCURSES_EXPORT(int) 1102 NCURSES_SP_NAME(extended_color_content) (NCURSES_SP_DCLx 1103 int color, 1104 int *r, int *g, int *b) 1105 { 1106 return _nc_color_content(SP_PARM, color, r, g, b); 1107 } 1108 1109 NCURSES_EXPORT(int) 1110 NCURSES_SP_NAME(extended_pair_content) (NCURSES_SP_DCLx 1111 int pair, 1112 int *f, int *b) 1113 { 1114 return _nc_pair_content(SP_PARM, pair, f, b); 1115 } 1116 1117 NCURSES_EXPORT(void) 1118 NCURSES_SP_NAME(reset_color_pairs) (NCURSES_SP_DCL0) 1119 { 1120 if (SP_PARM != 0) { 1121 if (SP_PARM->_color_pairs) { 1122 _nc_free_ordered_pairs(SP_PARM); 1123 free(SP_PARM->_color_pairs); 1124 SP_PARM->_color_pairs = 0; 1125 SP_PARM->_pair_alloc = 0; 1126 ReservePairs(SP_PARM, 16); 1127 clearok(CurScreen(SP_PARM), TRUE); 1128 touchwin(StdScreen(SP_PARM)); 1129 } 1130 } 1131 } 1132 1133 #if NCURSES_SP_FUNCS 1134 NCURSES_EXPORT(int) 1135 init_extended_pair(int pair, int f, int b) 1136 { 1137 return NCURSES_SP_NAME(init_extended_pair) (CURRENT_SCREEN, pair, f, b); 1138 } 1139 1140 NCURSES_EXPORT(int) 1141 init_extended_color(int color, int r, int g, int b) 1142 { 1143 return NCURSES_SP_NAME(init_extended_color) (CURRENT_SCREEN, 1144 color, 1145 r, g, b); 1146 } 1147 1148 NCURSES_EXPORT(int) 1149 extended_color_content(int color, int *r, int *g, int *b) 1150 { 1151 return NCURSES_SP_NAME(extended_color_content) (CURRENT_SCREEN, 1152 color, 1153 r, g, b); 1154 } 1155 1156 NCURSES_EXPORT(int) 1157 extended_pair_content(int pair, int *f, int *b) 1158 { 1159 return NCURSES_SP_NAME(extended_pair_content) (CURRENT_SCREEN, pair, f, b); 1160 } 1161 1162 NCURSES_EXPORT(void) 1163 reset_color_pairs(void) 1164 { 1165 NCURSES_SP_NAME(reset_color_pairs) (CURRENT_SCREEN); 1166 } 1167 #endif /* NCURSES_SP_FUNCS */ 1168 #endif /* NCURSES_EXT_COLORS */ 1169