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