Home | History | Annotate | Line # | Download | only in libcurses
color.c revision 1.18
      1 /*	$NetBSD: color.c,v 1.18 2002/06/26 18:13:59 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.18 2002/06/26 18:13:59 christos 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->colour_pairs[pair].fore,
    322 		 _cursesi_screen->colour_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