1 /* $NetBSD: color.c,v 1.14 2001/01/05 22:57:56 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julian Coleman. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 __RCSID("$NetBSD: color.c,v 1.14 2001/01/05 22:57:56 christos Exp $"); 42 #endif /* not lint */ 43 44 #include "curses.h" 45 #include "curses_private.h" 46 47 /* the following is defined and set up in setterm.c */ 48 extern struct tinfo *_cursesi_genbuf; 49 50 /* Maximum colours */ 51 #define MAX_COLORS 64 52 /* Maximum colour pairs - determined by number of colour bits in attr_t */ 53 #define MAX_PAIRS 64 /* PAIR_NUMBER(__COLOR) + 1 */ 54 55 /* Flags for colours and pairs */ 56 #define __USED 0x01 57 58 /* List of colours */ 59 struct color { 60 short num; 61 short red; 62 short green; 63 short blue; 64 int flags; 65 } colors[MAX_COLORS]; 66 67 /* List of colour pairs */ 68 struct pair { 69 short fore; 70 short back; 71 int flags; 72 } pairs[MAX_PAIRS]; 73 74 /* Attributes that clash with colours */ 75 attr_t __nca; 76 77 /* Style of colour manipulation */ 78 #define COLOR_NONE 0 79 #define COLOR_ANSI 1 /* ANSI/DEC-style colour manipulation */ 80 #define COLOR_HP 2 /* HP-style colour manipulation */ 81 #define COLOR_TEK 3 /* Tektronix-style colour manipulation */ 82 #define COLOR_OTHER 4 /* None of the others but can set fore/back */ 83 int __color_type = COLOR_NONE; 84 85 static void 86 __change_pair __P((short)); 87 /* 88 * has_colors -- 89 * Check if terminal has colours. 90 */ 91 bool 92 has_colors(void) 93 { 94 if (__tc_Co > 0 && __tc_pa > 0 && ((__tc_AF != NULL && 95 __tc_AB != NULL) || __tc_Ip != NULL || __tc_Ic != NULL || 96 (__tc_Sb != NULL && __tc_Sf != NULL))) 97 return(TRUE); 98 else 99 return(FALSE); 100 } 101 102 /* 103 * can_change_colors -- 104 * Check if terminal can change colours. 105 */ 106 bool 107 can_change_colors(void) 108 { 109 if (__tc_cc) 110 return(TRUE); 111 else 112 return(FALSE); 113 } 114 115 /* 116 * start_color -- 117 * Initialise colour support. 118 */ 119 int 120 start_color(void) 121 { 122 int i; 123 attr_t temp_nc; 124 125 if (has_colors() == FALSE) 126 return(ERR); 127 128 /* Max colours and colour pairs */ 129 if (__tc_Co == -1) 130 COLORS = 0; 131 else { 132 COLORS = __tc_Co > MAX_COLORS ? MAX_COLORS : __tc_Co; 133 if (__tc_pa == -1) { 134 COLOR_PAIRS = 0; 135 COLORS = 0; 136 } else { 137 COLOR_PAIRS = __tc_pa > MAX_PAIRS ? MAX_PAIRS : __tc_pa; 138 } 139 } 140 if (!COLORS) 141 return (ERR); 142 143 /* Reset terminal colour and colour pairs. */ 144 if (__tc_oc != NULL) 145 tputs(__tc_oc, 0, __cputchar); 146 if (__tc_op != NULL) { 147 tputs(__tc_op, 0, __cputchar); 148 curscr->wattr &= __mask_op; 149 } 150 151 /* Type of colour manipulation - ANSI/TEK/HP/other */ 152 if (__tc_AF != NULL && __tc_AB != NULL) 153 __color_type = COLOR_ANSI; 154 else if (__tc_Ip != NULL) 155 __color_type = COLOR_HP; 156 else if (__tc_Ic != NULL) 157 __color_type = COLOR_TEK; 158 else if (__tc_Sb != NULL && __tc_Sf != NULL) 159 __color_type = COLOR_OTHER; 160 else 161 return(ERR); /* Unsupported colour method */ 162 163 #ifdef DEBUG 164 __CTRACE("start_color: COLORS = %d, COLOR_PAIRS = %d", 165 COLORS, COLOR_PAIRS); 166 switch (__color_type) { 167 case COLOR_ANSI: 168 __CTRACE(" (ANSI style)\n"); 169 break; 170 case COLOR_HP: 171 __CTRACE(" (HP style)\n"); 172 break; 173 case COLOR_TEK: 174 __CTRACE(" (Tektronics style)\n"); 175 break; 176 case COLOR_OTHER: 177 __CTRACE(" (Other style)\n"); 178 break; 179 } 180 #endif 181 182 /* 183 * Attributes that cannot be used with color. 184 * Store these in an attr_t for wattrset()/wattron(). 185 */ 186 __nca = __NORMAL; 187 if (__tc_NC != -1) { 188 temp_nc = (attr_t) t_getnum(_cursesi_genbuf, "NC"); 189 if (temp_nc & 0x0001) 190 __nca |= __STANDOUT; 191 if (temp_nc & 0x0002) 192 __nca |= __UNDERSCORE; 193 if (temp_nc & 0x0004) 194 __nca |= __REVERSE; 195 if (temp_nc & 0x0008) 196 __nca |= __BLINK; 197 if (temp_nc & 0x0010) 198 __nca |= __DIM; 199 if (temp_nc & 0x0020) 200 __nca |= __BOLD; 201 if (temp_nc & 0x0040) 202 __nca |= __BLANK; 203 if (temp_nc & 0x0080) 204 __nca |= __PROTECT; 205 if (temp_nc & 0x0100) 206 __nca |= __ALTCHARSET; 207 } 208 #ifdef DEBUG 209 __CTRACE ("start_color: __nca = %d\n", __nca); 210 #endif 211 212 /* Set up initial 8 colours */ 213 if (COLORS >= COLOR_BLACK) 214 (void) init_color(COLOR_BLACK, 0, 0, 0); 215 if (COLORS >= COLOR_RED) 216 (void) init_color(COLOR_RED, 1000, 0, 0); 217 if (COLORS >= COLOR_GREEN) 218 (void) init_color(COLOR_GREEN, 0, 1000, 0); 219 if (COLORS >= COLOR_YELLOW) 220 (void) init_color(COLOR_YELLOW, 1000, 1000, 0); 221 if (COLORS >= COLOR_BLUE) 222 (void) init_color(COLOR_BLUE, 0, 0, 1000); 223 if (COLORS >= COLOR_MAGENTA) 224 (void) init_color(COLOR_MAGENTA, 1000, 0, 1000); 225 if (COLORS >= COLOR_CYAN) 226 (void) init_color(COLOR_CYAN, 0, 1000, 1000); 227 if (COLORS >= COLOR_WHITE) 228 (void) init_color(COLOR_WHITE, 1000, 1000, 1000); 229 230 /* Initialise other colours */ 231 for (i = 8; i < COLORS; i++) { 232 colors[i].red = 0; 233 colors[i].green = 0; 234 colors[i].blue = 0; 235 colors[i].flags = 0; 236 } 237 238 /* Initialise colour pairs to default (white on black) */ 239 for (i = 0; i < COLOR_PAIRS; i++) { 240 pairs[i].fore = COLOR_WHITE; 241 pairs[i].back = COLOR_BLACK; 242 pairs[i].flags = 0; 243 } 244 245 return(OK); 246 } 247 248 /* 249 * init_pair -- 250 * Set pair foreground and background colors. 251 */ 252 int 253 init_pair(short pair, short fore, short back) 254 { 255 int changed; 256 257 #ifdef DEBUG 258 __CTRACE("init_pair: %d, %d, %d\n", pair, fore, back); 259 #endif 260 261 if (pair < 0 || pair >= COLOR_PAIRS) 262 return (ERR); 263 if (fore < 0 || fore >= COLORS) 264 return (ERR); 265 if (back < 0 || back >= COLORS) 266 return (ERR); 267 268 if ((pairs[pair].flags & __USED) && (fore != pairs[pair].fore || 269 back != pairs[pair].back)) 270 changed = 1; 271 else 272 changed = 0; 273 274 pairs[pair].flags |= __USED; 275 pairs[pair].fore = fore; 276 pairs[pair].back = back; 277 278 /* XXX: need to initialise HP style (Ip) */ 279 280 if (changed) 281 __change_pair(pair); 282 return (OK); 283 } 284 285 /* 286 * pair_content -- 287 * Get pair foreground and background colours. 288 */ 289 int 290 pair_content(short pair, short *forep, short *backp) 291 { 292 if (pair < 0 || pair >= COLOR_PAIRS) 293 return(ERR); 294 295 *forep = pairs[pair].fore; 296 *backp = pairs[pair].back; 297 return(OK); 298 } 299 300 /* 301 * init_color -- 302 * Set colour red, green and blue values. 303 */ 304 int 305 init_color(short color, short red, short green, short blue) 306 { 307 #ifdef DEBUG 308 __CTRACE("init_color: %d, %d, %d, %d\n", color, red, green, blue); 309 #endif 310 if (color < 0 || color >= COLORS) 311 return(ERR); 312 313 colors[color].red = red; 314 colors[color].green = green; 315 colors[color].blue = blue; 316 /* XXX Not yet implemented */ 317 return(ERR); 318 /* XXX: need to initialise Tek style (Ic) and support HLS */ 319 } 320 321 /* 322 * color_content -- 323 * Get colour red, green and blue values. 324 */ 325 int 326 color_content(short color, short *redp, short *greenp, short *bluep) 327 { 328 if (color < 0 || color >= COLORS) 329 return(ERR); 330 331 *redp = colors[color].red; 332 *greenp = colors[color].green; 333 *bluep = colors[color].blue; 334 return(OK); 335 } 336 337 /* 338 * __set_color -- 339 * Set terminal foreground and background colours. 340 */ 341 void 342 __set_color(attr_t attr) 343 { 344 short pair; 345 346 pair = PAIR_NUMBER((u_int32_t)attr); 347 #ifdef DEBUG 348 __CTRACE("__set_color: %d, %d, %d\n", pair, pairs[pair].fore, 349 pairs[pair].back); 350 #endif 351 switch (__color_type) { 352 /* Set ANSI forground and background colours */ 353 case COLOR_ANSI: 354 tputs(__parse_cap(__tc_AF, pairs[pair].fore), 0, __cputchar); 355 tputs(__parse_cap(__tc_AB, pairs[pair].back), 0, __cputchar); 356 break; 357 case COLOR_HP: 358 /* XXX: need to support HP style */ 359 break; 360 case COLOR_TEK: 361 /* XXX: need to support Tek style */ 362 break; 363 case COLOR_OTHER: 364 tputs(__parse_cap(__tc_Sf, pairs[pair].fore), 0, __cputchar); 365 tputs(__parse_cap(__tc_Sb, pairs[pair].back), 0, __cputchar); 366 break; 367 } 368 } 369 370 /* 371 * __restore_colors -- 372 * Redo color definitions after restarting 'curses' mode. 373 */ 374 void 375 __restore_colors(void) 376 { 377 if (__tc_cc != NULL) 378 switch (__color_type) { 379 case COLOR_HP: 380 /* XXX: need to re-initialise HP style (Ip) */ 381 break; 382 case COLOR_TEK: 383 /* XXX: need to re-initialise Tek style (Ic) */ 384 break; 385 } 386 } 387 388 /* 389 * __change_pair -- 390 * Mark dirty all positions using pair. 391 */ 392 void 393 __change_pair(short pair) 394 { 395 struct __winlist *wlp; 396 WINDOW *win; 397 int y, x; 398 399 400 for (wlp = __winlistp; wlp != NULL; wlp = wlp->nextp) { 401 #ifdef DEBUG 402 __CTRACE("__change_pair: win = %0.2o\n", wlp->winp); 403 #endif 404 if (wlp->winp == curscr) { 405 /* Reset colour attribute on curscr */ 406 #ifdef DEBUG 407 __CTRACE("__change_pair: win == curscr\n"); 408 #endif 409 for (y = 0; y < curscr->maxy; y++) 410 for (x = 0; x < curscr->maxx; x++) 411 if ((curscr->lines[y]->line[x].attr & 412 __COLOR) == COLOR_PAIR(pair)) 413 curscr->lines[y]->line[x].attr 414 &= ~__COLOR; 415 } else { 416 /* Mark dirty those positions with color pair "pair" */ 417 win = wlp->winp; 418 for (y = 0; y < win->maxy; y++) { 419 for (x = 0; x < win->maxx; x++) 420 if ((win->lines[y]->line[x].attr & 421 __COLOR) == COLOR_PAIR(pair)) { 422 if (!(win->lines[y]->flags & 423 __ISDIRTY)) 424 win->lines[y]->flags |= 425 __ISDIRTY; 426 /* 427 * firstchp/lastchp are shared 428 * between parent window and 429 * sub-window. 430 */ 431 if (*win->lines[y]->firstchp > 432 x) 433 *win->lines[y]->firstchp 434 = x; 435 if (*win->lines[y]->lastchp < x) 436 *win->lines[y]->lastchp 437 = x; 438 } 439 #ifdef DEBUG 440 if ((win->lines[y]->flags & __ISDIRTY)) 441 __CTRACE("__change_pair: first = %d, last = %d\n", *win->lines[y]->firstchp, *win->lines[y]->lastchp); 442 #endif 443 } 444 } 445 } 446 } 447