1 /* $NetBSD: color.c,v 1.17 2002/01/02 10:38:27 blymn 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.17 2002/01/02 10:38:27 blymn Exp $"); 42 #endif /* not lint */ 43 44 #include "curses.h" 45 #include "curses_private.h" 46 47 /* Flags for colours and pairs */ 48 #define __USED 0x01 49 50 /* Attributes that clash with colours */ 51 attr_t __nca; 52 53 static void 54 __change_pair __P((short)); 55 /* 56 * has_colors -- 57 * Check if terminal has colours. 58 */ 59 bool 60 has_colors(void) 61 { 62 if (__tc_Co > 0 && __tc_pa > 0 && ((__tc_AF != NULL && 63 __tc_AB != NULL) || __tc_Ip != NULL || __tc_Ic != NULL || 64 (__tc_Sb != NULL && __tc_Sf != NULL))) 65 return(TRUE); 66 else 67 return(FALSE); 68 } 69 70 /* 71 * can_change_colors -- 72 * Check if terminal can change colours. 73 */ 74 bool 75 can_change_colors(void) 76 { 77 if (__tc_cc) 78 return(TRUE); 79 else 80 return(FALSE); 81 } 82 83 /* 84 * start_color -- 85 * Initialise colour support. 86 */ 87 int 88 start_color(void) 89 { 90 int i; 91 attr_t temp_nc; 92 93 if (has_colors() == FALSE) 94 return(ERR); 95 96 /* Max colours and colour pairs */ 97 if (__tc_Co == -1) 98 COLORS = 0; 99 else { 100 COLORS = __tc_Co > MAX_COLORS ? MAX_COLORS : __tc_Co; 101 if (__tc_pa == -1) { 102 COLOR_PAIRS = 0; 103 COLORS = 0; 104 } else { 105 COLOR_PAIRS = __tc_pa > MAX_PAIRS ? MAX_PAIRS : __tc_pa; 106 } 107 } 108 if (!COLORS) 109 return (ERR); 110 111 _cursesi_screen->COLORS = COLORS; 112 _cursesi_screen->COLOR_PAIRS = COLOR_PAIRS; 113 114 /* Reset terminal colour and colour pairs. */ 115 if (__tc_oc != NULL) 116 tputs(__tc_oc, 0, __cputchar); 117 if (__tc_op != NULL) { 118 tputs(__tc_op, 0, __cputchar); 119 curscr->wattr &= _cursesi_screen->mask_op; 120 } 121 122 /* Type of colour manipulation - ANSI/TEK/HP/other */ 123 if (__tc_AF != NULL && __tc_AB != NULL) 124 _cursesi_screen->color_type = COLOR_ANSI; 125 else if (__tc_Ip != NULL) 126 _cursesi_screen->color_type = COLOR_HP; 127 else if (__tc_Ic != NULL) 128 _cursesi_screen->color_type = COLOR_TEK; 129 else if (__tc_Sb != NULL && __tc_Sf != NULL) 130 _cursesi_screen->color_type = COLOR_OTHER; 131 else 132 return(ERR); /* Unsupported colour method */ 133 134 #ifdef DEBUG 135 __CTRACE("start_color: COLORS = %d, COLOR_PAIRS = %d", 136 COLORS, COLOR_PAIRS); 137 switch (_cursesi_screen->color_type) { 138 case COLOR_ANSI: 139 __CTRACE(" (ANSI style)\n"); 140 break; 141 case COLOR_HP: 142 __CTRACE(" (HP style)\n"); 143 break; 144 case COLOR_TEK: 145 __CTRACE(" (Tektronics style)\n"); 146 break; 147 case COLOR_OTHER: 148 __CTRACE(" (Other style)\n"); 149 break; 150 } 151 #endif 152 153 /* 154 * Attributes that cannot be used with color. 155 * Store these in an attr_t for wattrset()/wattron(). 156 */ 157 _cursesi_screen->nca = __NORMAL; 158 if (__tc_NC != -1) { 159 temp_nc = (attr_t) t_getnum(_cursesi_screen->cursesi_genbuf, "NC"); 160 if (temp_nc & 0x0001) 161 _cursesi_screen->nca |= __STANDOUT; 162 if (temp_nc & 0x0002) 163 _cursesi_screen->nca |= __UNDERSCORE; 164 if (temp_nc & 0x0004) 165 _cursesi_screen->nca |= __REVERSE; 166 if (temp_nc & 0x0008) 167 _cursesi_screen->nca |= __BLINK; 168 if (temp_nc & 0x0010) 169 _cursesi_screen->nca |= __DIM; 170 if (temp_nc & 0x0020) 171 _cursesi_screen->nca |= __BOLD; 172 if (temp_nc & 0x0040) 173 _cursesi_screen->nca |= __BLANK; 174 if (temp_nc & 0x0080) 175 _cursesi_screen->nca |= __PROTECT; 176 if (temp_nc & 0x0100) 177 _cursesi_screen->nca |= __ALTCHARSET; 178 } 179 #ifdef DEBUG 180 __CTRACE ("start_color: __nca = %d\n", _cursesi_screen->nca); 181 #endif 182 183 /* Set up initial 8 colours */ 184 if (COLORS >= COLOR_BLACK) 185 (void) init_color(COLOR_BLACK, 0, 0, 0); 186 if (COLORS >= COLOR_RED) 187 (void) init_color(COLOR_RED, 1000, 0, 0); 188 if (COLORS >= COLOR_GREEN) 189 (void) init_color(COLOR_GREEN, 0, 1000, 0); 190 if (COLORS >= COLOR_YELLOW) 191 (void) init_color(COLOR_YELLOW, 1000, 1000, 0); 192 if (COLORS >= COLOR_BLUE) 193 (void) init_color(COLOR_BLUE, 0, 0, 1000); 194 if (COLORS >= COLOR_MAGENTA) 195 (void) init_color(COLOR_MAGENTA, 1000, 0, 1000); 196 if (COLORS >= COLOR_CYAN) 197 (void) init_color(COLOR_CYAN, 0, 1000, 1000); 198 if (COLORS >= COLOR_WHITE) 199 (void) init_color(COLOR_WHITE, 1000, 1000, 1000); 200 201 /* Initialise other colours */ 202 for (i = 8; i < COLORS; i++) { 203 _cursesi_screen->colours[i].red = 0; 204 _cursesi_screen->colours[i].green = 0; 205 _cursesi_screen->colours[i].blue = 0; 206 _cursesi_screen->colours[i].flags = 0; 207 } 208 209 /* Initialise colour pairs to default (white on black) */ 210 for (i = 0; i < COLOR_PAIRS; i++) { 211 _cursesi_screen->colour_pairs[i].fore = COLOR_WHITE; 212 _cursesi_screen->colour_pairs[i].back = COLOR_BLACK; 213 _cursesi_screen->colour_pairs[i].flags = 0; 214 } 215 216 return(OK); 217 } 218 219 /* 220 * init_pair -- 221 * Set pair foreground and background colors. 222 */ 223 int 224 init_pair(short pair, short fore, short back) 225 { 226 int changed; 227 228 #ifdef DEBUG 229 __CTRACE("init_pair: %d, %d, %d\n", pair, fore, back); 230 #endif 231 232 if (pair < 0 || pair >= COLOR_PAIRS) 233 return (ERR); 234 if (fore < 0 || fore >= COLORS) 235 return (ERR); 236 if (back < 0 || back >= COLORS) 237 return (ERR); 238 239 if ((_cursesi_screen->colour_pairs[pair].flags & __USED) && 240 (fore != _cursesi_screen->colour_pairs[pair].fore || 241 back != _cursesi_screen->colour_pairs[pair].back)) 242 changed = 1; 243 else 244 changed = 0; 245 246 _cursesi_screen->colour_pairs[pair].flags |= __USED; 247 _cursesi_screen->colour_pairs[pair].fore = fore; 248 _cursesi_screen->colour_pairs[pair].back = back; 249 250 /* XXX: need to initialise HP style (Ip) */ 251 252 if (changed) 253 __change_pair(pair); 254 return (OK); 255 } 256 257 /* 258 * pair_content -- 259 * Get pair foreground and background colours. 260 */ 261 int 262 pair_content(short pair, short *forep, short *backp) 263 { 264 if (pair < 0 || pair >= _cursesi_screen->COLOR_PAIRS) 265 return(ERR); 266 267 *forep = _cursesi_screen->colour_pairs[pair].fore; 268 *backp = _cursesi_screen->colour_pairs[pair].back; 269 return(OK); 270 } 271 272 /* 273 * init_color -- 274 * Set colour red, green and blue values. 275 */ 276 int 277 init_color(short color, short red, short green, short blue) 278 { 279 #ifdef DEBUG 280 __CTRACE("init_color: %d, %d, %d, %d\n", color, red, green, blue); 281 #endif 282 if (color < 0 || color >= _cursesi_screen->COLOR_PAIRS) 283 return(ERR); 284 285 _cursesi_screen->colours[color].red = red; 286 _cursesi_screen->colours[color].green = green; 287 _cursesi_screen->colours[color].blue = blue; 288 /* XXX Not yet implemented */ 289 return(ERR); 290 /* XXX: need to initialise Tek style (Ic) and support HLS */ 291 } 292 293 /* 294 * color_content -- 295 * Get colour red, green and blue values. 296 */ 297 int 298 color_content(short color, short *redp, short *greenp, short *bluep) 299 { 300 if (color < 0 || color >= _cursesi_screen->COLORS) 301 return(ERR); 302 303 *redp = _cursesi_screen->colours[color].red; 304 *greenp = _cursesi_screen->colours[color].green; 305 *bluep = _cursesi_screen->colours[color].blue; 306 return(OK); 307 } 308 309 /* 310 * __set_color -- 311 * Set terminal foreground and background colours. 312 */ 313 void 314 __set_color(attr_t attr) 315 { 316 short pair; 317 318 pair = PAIR_NUMBER((u_int32_t)attr); 319 #ifdef DEBUG 320 __CTRACE("__set_color: %d, %d, %d\n", pair, 321 _cursesi_screen->pairs[pair].fore, 322 _cursesi_screen->pairs[pair].back); 323 #endif 324 switch (_cursesi_screen->color_type) { 325 /* Set ANSI forground and background colours */ 326 case COLOR_ANSI: 327 tputs(__parse_cap(_cursesi_screen->tc_AF, 328 _cursesi_screen->colour_pairs[pair].fore), 329 0, __cputchar); 330 tputs(__parse_cap(_cursesi_screen->tc_AB, 331 _cursesi_screen->colour_pairs[pair].back), 332 0, __cputchar); 333 break; 334 case COLOR_HP: 335 /* XXX: need to support HP style */ 336 break; 337 case COLOR_TEK: 338 /* XXX: need to support Tek style */ 339 break; 340 case COLOR_OTHER: 341 tputs(__parse_cap(_cursesi_screen->tc_Sf, 342 _cursesi_screen->colour_pairs[pair].fore), 343 0, __cputchar); 344 tputs(__parse_cap(_cursesi_screen->tc_Sb, 345 _cursesi_screen->colour_pairs[pair].back), 346 0, __cputchar); 347 break; 348 } 349 } 350 351 /* 352 * __restore_colors -- 353 * Redo color definitions after restarting 'curses' mode. 354 */ 355 void 356 __restore_colors(void) 357 { 358 if (__tc_cc != NULL) 359 switch (_cursesi_screen->color_type) { 360 case COLOR_HP: 361 /* XXX: need to re-initialise HP style (Ip) */ 362 break; 363 case COLOR_TEK: 364 /* XXX: need to re-initialise Tek style (Ic) */ 365 break; 366 } 367 } 368 369 /* 370 * __change_pair -- 371 * Mark dirty all positions using pair. 372 */ 373 void 374 __change_pair(short pair) 375 { 376 struct __winlist *wlp; 377 WINDOW *win; 378 int y, x; 379 380 381 for (wlp = __winlistp; wlp != NULL; wlp = wlp->nextp) { 382 #ifdef DEBUG 383 __CTRACE("__change_pair: win = %0.2o\n", wlp->winp); 384 #endif 385 if (wlp->winp == curscr) { 386 /* Reset colour attribute on curscr */ 387 #ifdef DEBUG 388 __CTRACE("__change_pair: win == curscr\n"); 389 #endif 390 for (y = 0; y < curscr->maxy; y++) 391 for (x = 0; x < curscr->maxx; x++) 392 if ((curscr->lines[y]->line[x].attr & 393 __COLOR) == COLOR_PAIR(pair)) 394 curscr->lines[y]->line[x].attr 395 &= ~__COLOR; 396 } else { 397 /* Mark dirty those positions with color pair "pair" */ 398 win = wlp->winp; 399 for (y = 0; y < win->maxy; y++) { 400 for (x = 0; x < win->maxx; x++) 401 if ((win->lines[y]->line[x].attr & 402 __COLOR) == COLOR_PAIR(pair)) { 403 if (!(win->lines[y]->flags & 404 __ISDIRTY)) 405 win->lines[y]->flags |= 406 __ISDIRTY; 407 /* 408 * firstchp/lastchp are shared 409 * between parent window and 410 * sub-window. 411 */ 412 if (*win->lines[y]->firstchp > 413 x) 414 *win->lines[y]->firstchp 415 = x; 416 if (*win->lines[y]->lastchp < x) 417 *win->lines[y]->lastchp 418 = x; 419 } 420 #ifdef DEBUG 421 if ((win->lines[y]->flags & __ISDIRTY)) 422 __CTRACE("__change_pair: first = %d, last = %d\n", *win->lines[y]->firstchp, *win->lines[y]->lastchp); 423 #endif 424 } 425 } 426 } 427 } 428