lib_color.c revision 56639
1/**************************************************************************** 2 * Copyright (c) 1998 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29/**************************************************************************** 30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 ****************************************************************************/ 33 34/* lib_color.c 35 * 36 * Handles color emulation of SYS V curses 37 * 38 */ 39 40#include <curses.priv.h> 41 42#include <term.h> 43 44MODULE_ID("$Id: lib_color.c,v 1.36 1999/10/03 00:20:37 Philippe.Blain Exp $") 45 46/* 47 * These should be screen structure members. They need to be globals for 48 * hystorical reasons. So we assign them in start_color() and also in 49 * set_term()'s screen-switching logic. 50 */ 51int COLOR_PAIRS; 52int COLORS; 53 54/* 55 * Given a RGB range of 0..1000, we'll normally set the individual values 56 * to about 2/3 of the maximum, leaving full-range for bold/bright colors. 57 */ 58#define RGB_ON 680 59#define RGB_OFF 0 60 61static const color_t cga_palette[] = 62{ 63 /* R G B */ 64 {RGB_OFF, RGB_OFF, RGB_OFF}, /* COLOR_BLACK */ 65 {RGB_ON, RGB_OFF, RGB_OFF}, /* COLOR_RED */ 66 {RGB_OFF, RGB_ON, RGB_OFF}, /* COLOR_GREEN */ 67 {RGB_ON, RGB_ON, RGB_OFF}, /* COLOR_YELLOW */ 68 {RGB_OFF, RGB_OFF, RGB_ON}, /* COLOR_BLUE */ 69 {RGB_ON, RGB_OFF, RGB_ON}, /* COLOR_MAGENTA */ 70 {RGB_OFF, RGB_ON, RGB_ON}, /* COLOR_CYAN */ 71 {RGB_ON, RGB_ON, RGB_ON}, /* COLOR_WHITE */ 72}; 73static const color_t hls_palette[] = 74{ 75 /* H L S */ 76 {0, 0, 0}, /* COLOR_BLACK */ 77 {120, 50, 100}, /* COLOR_RED */ 78 {240, 50, 100}, /* COLOR_GREEN */ 79 {180, 50, 100}, /* COLOR_YELLOW */ 80 {330, 50, 100}, /* COLOR_BLUE */ 81 {60, 50, 100}, /* COLOR_MAGENTA */ 82 {300, 50, 100}, /* COLOR_CYAN */ 83 {0, 50, 100}, /* COLOR_WHITE */ 84}; 85 86/* 87 * SVr4 curses is known to interchange color codes (1,4) and (3,6), possibly 88 * to maintain compatibility with a pre-ANSI scheme. The same scheme is 89 * also used in the FreeBSD syscons. 90 */ 91static int toggled_colors(int c) 92{ 93 if (c < 16) { 94 static const int table[] = 95 { 0, 4, 2, 6, 1, 5, 3, 7, 96 8, 12, 10, 14, 9, 13, 11, 15}; 97 c = table[c]; 98 } 99 return c; 100} 101 102static void set_background_color(int bg, int (*outc)(int)) 103{ 104 if (set_a_background) 105 { 106 TPUTS_TRACE("set_a_background"); 107 tputs(tparm(set_a_background, bg), 1, outc); 108 } 109 else 110 { 111 TPUTS_TRACE("set_background"); 112 tputs(tparm(set_background, toggled_colors(bg)), 1, outc); 113 } 114} 115 116static void set_foreground_color(int fg, int (*outc)(int)) 117{ 118 if (set_a_foreground) 119 { 120 TPUTS_TRACE("set_a_foreground"); 121 tputs(tparm(set_a_foreground, fg), 1, outc); 122 } 123 else 124 { 125 TPUTS_TRACE("set_foreground"); 126 tputs(tparm(set_foreground, toggled_colors(fg)), 1, outc); 127 } 128} 129 130static bool set_original_colors(void) 131{ 132 if (orig_pair != 0) { 133 TPUTS_TRACE("orig_pair"); 134 putp(orig_pair); 135 return TRUE; 136 } 137 else if (orig_colors != NULL) 138 { 139 TPUTS_TRACE("orig_colors"); 140 putp(orig_colors); 141 return TRUE; 142 } 143 return FALSE; 144} 145 146int start_color(void) 147{ 148 T((T_CALLED("start_color()"))); 149 150 if (set_original_colors() != TRUE) 151 { 152 set_foreground_color(COLOR_WHITE, _nc_outch); 153 set_background_color(COLOR_BLACK, _nc_outch); 154 } 155 156 if (max_pairs != -1) 157 COLOR_PAIRS = SP->_pair_count = max_pairs; 158 else 159 returnCode(ERR); 160 if ((SP->_color_pairs = typeCalloc(unsigned short, max_pairs)) == 0) 161 returnCode(ERR); 162 SP->_color_pairs[0] = PAIR_OF(COLOR_WHITE, COLOR_BLACK); 163 if (max_colors != -1) 164 COLORS = SP->_color_count = max_colors; 165 else 166 returnCode(ERR); 167 SP->_coloron = 1; 168 169 if ((SP->_color_table = typeMalloc(color_t, COLORS)) == 0) 170 returnCode(ERR); 171 if (hue_lightness_saturation) 172 memcpy(SP->_color_table, hls_palette, sizeof(color_t) * COLORS); 173 else 174 memcpy(SP->_color_table, cga_palette, sizeof(color_t) * COLORS); 175 176 T(("started color: COLORS = %d, COLOR_PAIRS = %d", COLORS, COLOR_PAIRS)); 177 178 returnCode(OK); 179} 180 181/* This function was originally written by Daniel Weaver <danw@znyx.com> */ 182static void rgb2hls(short r, short g, short b, short *h, short *l, short *s) 183/* convert RGB to HLS system */ 184{ 185 short min, max, t; 186 187 if ((min = g < r ? g : r) > b) min = b; 188 if ((max = g > r ? g : r) < b) max = b; 189 190 /* calculate lightness */ 191 *l = (min + max) / 20; 192 193 if (min == max) /* black, white and all shades of gray */ 194 { 195 *h = 0; 196 *s = 0; 197 return; 198 } 199 200 /* calculate saturation */ 201 if (*l < 50) 202 *s = ((max - min) * 100) / (max + min); 203 else *s = ((max - min) * 100) / (2000 - max - min); 204 205 /* calculate hue */ 206 if (r == max) 207 t = 120 + ((g - b) * 60) / (max - min); 208 else 209 if (g == max) 210 t = 240 + ((b - r) * 60) / (max - min); 211 else 212 t = 360 + ((r - g) * 60) / (max - min); 213 214 *h = t % 360; 215} 216 217/* 218 * Extension (1997/1/18) - Allow negative f/b values to set default color 219 * values. 220 */ 221int init_pair(short pair, short f, short b) 222{ 223 unsigned result; 224 225 T((T_CALLED("init_pair(%d,%d,%d)"), pair, f, b)); 226 227 if ((pair < 1) || (pair >= COLOR_PAIRS)) 228 returnCode(ERR); 229 if (SP->_default_color) 230 { 231 if (f < 0) 232 f = C_MASK; 233 if (b < 0) 234 b = C_MASK; 235 if (f >= COLORS && f != C_MASK) 236 returnCode(ERR); 237 if (b >= COLORS && b != C_MASK) 238 returnCode(ERR); 239 } 240 else 241 if ((f < 0) || (f >= COLORS) 242 || (b < 0) || (b >= COLORS)) 243 returnCode(ERR); 244 245 /* 246 * When a pair's content is changed, replace its colors (if pair was 247 * initialized before a screen update is performed replacing original 248 * pair colors with the new ones). 249 */ 250 result = PAIR_OF(f,b); 251 if (SP->_color_pairs[pair] != 0 252 && SP->_color_pairs[pair] != result) { 253 int y, x; 254 attr_t z = COLOR_PAIR(pair); 255 256 for (y = 0; y <= curscr->_maxy; y++) { 257 struct ldat *ptr = &(curscr->_line[y]); 258 bool changed = FALSE; 259 for (x = 0; x <= curscr->_maxx; x++) { 260 if ((ptr->text[x] & A_COLOR) == z) { 261 /* Set the old cell to zero to ensure it will be 262 updated on the next doupdate() */ 263 ptr->text[x] = 0; 264 CHANGED_CELL(ptr,x); 265 changed = TRUE; 266 } 267 } 268 if (changed) 269 _nc_make_oldhash(y); 270 } 271 } 272 SP->_color_pairs[pair] = result; 273 274 if (initialize_pair) 275 { 276 const color_t *tp = hue_lightness_saturation ? hls_palette : cga_palette; 277 278 T(("initializing pair: pair = %d, fg=(%d,%d,%d), bg=(%d,%d,%d)", 279 pair, 280 tp[f].red, tp[f].green, tp[f].blue, 281 tp[b].red, tp[b].green, tp[b].blue)); 282 283 if (initialize_pair) 284 { 285 TPUTS_TRACE("initialize_pair"); 286 putp(tparm(initialize_pair, 287 pair, 288 tp[f].red, tp[f].green, tp[f].blue, 289 tp[b].red, tp[b].green, tp[b].blue)); 290 } 291 } 292 293 returnCode(OK); 294} 295 296int init_color(short color, short r, short g, short b) 297{ 298 T((T_CALLED("init_color(%d,%d,%d,%d)"), color, r, g, b)); 299 300 if (initialize_color == NULL) 301 returnCode(ERR); 302 303 if (color < 0 || color >= COLORS) 304 returnCode(ERR); 305 if (r < 0 || r > 1000 || g < 0 || g > 1000 || b < 0 || b > 1000) 306 returnCode(ERR); 307 308 if (hue_lightness_saturation) 309 rgb2hls(r, g, b, 310 &SP->_color_table[color].red, 311 &SP->_color_table[color].green, 312 &SP->_color_table[color].blue); 313 else 314 { 315 SP->_color_table[color].red = r; 316 SP->_color_table[color].green = g; 317 SP->_color_table[color].blue = b; 318 } 319 320 if (initialize_color) 321 { 322 TPUTS_TRACE("initialize_color"); 323 putp(tparm(initialize_color, color, r, g, b)); 324 } 325 returnCode(OK); 326} 327 328bool can_change_color(void) 329{ 330 T((T_CALLED("can_change_color()"))); 331 returnCode ((can_change != 0) ? TRUE : FALSE); 332} 333 334bool has_colors(void) 335{ 336 T((T_CALLED("has_colors()"))); 337 returnCode (((max_colors != -1) && (max_pairs != -1) 338 && (((set_foreground != NULL) 339 && (set_background != NULL)) 340 || ((set_a_foreground != NULL) 341 && (set_a_background != NULL)) 342 || set_color_pair)) ? TRUE : FALSE); 343} 344 345int color_content(short color, short *r, short *g, short *b) 346{ 347 T((T_CALLED("color_content(%d,%p,%p,%p)"), color, r, g, b)); 348 if (color < 0 || color >= COLORS) 349 returnCode(ERR); 350 351 if (r) *r = SP->_color_table[color].red; 352 if (g) *g = SP->_color_table[color].green; 353 if (b) *b = SP->_color_table[color].blue; 354 returnCode(OK); 355} 356 357int pair_content(short pair, short *f, short *b) 358{ 359 T((T_CALLED("pair_content(%d,%p,%p)"), pair, f, b)); 360 361 if ((pair < 0) || (pair >= COLOR_PAIRS)) 362 returnCode(ERR); 363 if (f) *f = ((SP->_color_pairs[pair] >> C_SHIFT) & C_MASK); 364 if (b) *b = (SP->_color_pairs[pair] & C_MASK); 365 366 returnCode(OK); 367} 368 369void _nc_do_color(int pair, bool reverse, int (*outc)(int)) 370{ 371 short fg, bg; 372 373 if (pair == 0) 374 { 375 if (orig_pair) 376 { 377 TPUTS_TRACE("orig_pair"); 378 tputs(orig_pair, 1, outc); 379 } 380 else if (set_color_pair) 381 { 382 TPUTS_TRACE("set_color_pair"); 383 tputs(tparm(set_color_pair, pair), 1, outc); 384 } 385 else 386 { 387 set_foreground_color(COLOR_WHITE, outc); 388 set_background_color(COLOR_BLACK, outc); 389 } 390 } 391 else 392 { 393 if (set_color_pair) 394 { 395 TPUTS_TRACE("set_color_pair"); 396 tputs(tparm(set_color_pair, pair), 1, outc); 397 } 398 else 399 { 400 pair_content(pair, &fg, &bg); 401 if (reverse) { 402 short xx = fg; 403 fg = bg; 404 bg = xx; 405 } 406 407 T(("setting colors: pair = %d, fg = %d, bg = %d", pair, fg, bg)); 408 409 if (fg == C_MASK || bg == C_MASK) 410 { 411 if (set_original_colors() != TRUE) 412 { 413 if (fg == C_MASK) 414 set_foreground_color(COLOR_WHITE, outc); 415 if (bg == C_MASK) 416 set_background_color(COLOR_BLACK, outc); 417 } 418 } 419 if (fg != C_MASK) 420 { 421 set_foreground_color(fg, outc); 422 } 423 if (bg != C_MASK) 424 { 425 set_background_color(bg, outc); 426 } 427 } 428 } 429} 430