1 /* $NetBSD: color.c,v 1.33 2008/04/28 20:23:01 martin Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: color.c,v 1.33 2008/04/28 20:23:01 martin Exp $");
38 #include "curses_private.h"
40 /* Have we initialised colours? */
41 int __using_color
= 0;
43 /* Default colour number */
44 attr_t __default_color
= 0;
46 /* Default colour pair values - white on black. */
47 struct __pair __default_pair
= {COLOR_WHITE
, COLOR_BLACK
, 0};
49 /* Default colour values */
50 /* Flags for colours and pairs */
58 * Check if terminal has colours.
63 if (__tc_Co
> 0 && __tc_pa
> 0 && ((__tc_AF
!= NULL
&&
64 __tc_AB
!= NULL
) || __tc_Ip
!= NULL
|| __tc_Ic
!= NULL
||
65 (__tc_Sb
!= NULL
&& __tc_Sf
!= NULL
)))
73 * Check if terminal can change colours.
76 can_change_color(void)
86 * Initialise colour support.
93 struct __winlist
*wlp
;
97 if (has_colors() == FALSE
)
100 /* Max colours and colour pairs */
104 COLORS
= __tc_Co
> MAX_COLORS
? MAX_COLORS
: __tc_Co
;
109 COLOR_PAIRS
= (__tc_pa
> MAX_PAIRS
- 1 ?
110 MAX_PAIRS
- 1 : __tc_pa
);
111 /* Use the last colour pair for curses default. */
112 __default_color
= COLOR_PAIR(MAX_PAIRS
- 1);
118 _cursesi_screen
->COLORS
= COLORS
;
119 _cursesi_screen
->COLOR_PAIRS
= COLOR_PAIRS
;
121 /* Reset terminal colour and colour pairs. */
123 tputs(__tc_oc
, 0, __cputchar
);
124 if (__tc_op
!= NULL
) {
125 tputs(__tc_op
, 0, __cputchar
);
126 curscr
->wattr
&= _cursesi_screen
->mask_op
;
129 /* Type of colour manipulation - ANSI/TEK/HP/other */
130 if (__tc_AF
!= NULL
&& __tc_AB
!= NULL
)
131 _cursesi_screen
->color_type
= COLOR_ANSI
;
132 else if (__tc_Ip
!= NULL
)
133 _cursesi_screen
->color_type
= COLOR_HP
;
134 else if (__tc_Ic
!= NULL
)
135 _cursesi_screen
->color_type
= COLOR_TEK
;
136 else if (__tc_Sb
!= NULL
&& __tc_Sf
!= NULL
)
137 _cursesi_screen
->color_type
= COLOR_OTHER
;
139 return(ERR
); /* Unsupported colour method */
142 __CTRACE(__CTRACE_COLOR
, "start_color: COLORS = %d, COLOR_PAIRS = %d",
143 COLORS
, COLOR_PAIRS
);
144 switch (_cursesi_screen
->color_type
) {
146 __CTRACE(__CTRACE_COLOR
, " (ANSI style)\n");
149 __CTRACE(__CTRACE_COLOR
, " (HP style)\n");
152 __CTRACE(__CTRACE_COLOR
, " (Tektronics style)\n");
155 __CTRACE(__CTRACE_COLOR
, " (Other style)\n");
161 * Attributes that cannot be used with color.
162 * Store these in an attr_t for wattrset()/wattron().
164 _cursesi_screen
->nca
= __NORMAL
;
166 temp_nc
= (attr_t
) t_getnum(_cursesi_screen
->cursesi_genbuf
, "NC");
167 if (temp_nc
& 0x0001)
168 _cursesi_screen
->nca
|= __STANDOUT
;
169 if (temp_nc
& 0x0002)
170 _cursesi_screen
->nca
|= __UNDERSCORE
;
171 if (temp_nc
& 0x0004)
172 _cursesi_screen
->nca
|= __REVERSE
;
173 if (temp_nc
& 0x0008)
174 _cursesi_screen
->nca
|= __BLINK
;
175 if (temp_nc
& 0x0010)
176 _cursesi_screen
->nca
|= __DIM
;
177 if (temp_nc
& 0x0020)
178 _cursesi_screen
->nca
|= __BOLD
;
179 if (temp_nc
& 0x0040)
180 _cursesi_screen
->nca
|= __BLANK
;
181 if (temp_nc
& 0x0080)
182 _cursesi_screen
->nca
|= __PROTECT
;
183 if (temp_nc
& 0x0100)
184 _cursesi_screen
->nca
|= __ALTCHARSET
;
187 __CTRACE(__CTRACE_COLOR
, "start_color: _cursesi_screen->nca = %08x\n",
188 _cursesi_screen
->nca
);
191 /* Set up initial 8 colours */
192 if (COLORS
>= COLOR_BLACK
)
193 (void) init_color(COLOR_BLACK
, 0, 0, 0);
194 if (COLORS
>= COLOR_RED
)
195 (void) init_color(COLOR_RED
, 1000, 0, 0);
196 if (COLORS
>= COLOR_GREEN
)
197 (void) init_color(COLOR_GREEN
, 0, 1000, 0);
198 if (COLORS
>= COLOR_YELLOW
)
199 (void) init_color(COLOR_YELLOW
, 1000, 1000, 0);
200 if (COLORS
>= COLOR_BLUE
)
201 (void) init_color(COLOR_BLUE
, 0, 0, 1000);
202 if (COLORS
>= COLOR_MAGENTA
)
203 (void) init_color(COLOR_MAGENTA
, 1000, 0, 1000);
204 if (COLORS
>= COLOR_CYAN
)
205 (void) init_color(COLOR_CYAN
, 0, 1000, 1000);
206 if (COLORS
>= COLOR_WHITE
)
207 (void) init_color(COLOR_WHITE
, 1000, 1000, 1000);
209 /* Initialise other colours */
210 for (i
= 8; i
< COLORS
; i
++) {
211 _cursesi_screen
->colours
[i
].red
= 0;
212 _cursesi_screen
->colours
[i
].green
= 0;
213 _cursesi_screen
->colours
[i
].blue
= 0;
214 _cursesi_screen
->colours
[i
].flags
= 0;
217 /* Initialise pair 0 to default colours. */
218 _cursesi_screen
->colour_pairs
[0].fore
= -1;
219 _cursesi_screen
->colour_pairs
[0].back
= -1;
220 _cursesi_screen
->colour_pairs
[0].flags
= 0;
222 /* Initialise user colour pairs to default (white on black) */
223 for (i
= 0; i
< COLOR_PAIRS
; i
++) {
224 _cursesi_screen
->colour_pairs
[i
].fore
= COLOR_WHITE
;
225 _cursesi_screen
->colour_pairs
[i
].back
= COLOR_BLACK
;
226 _cursesi_screen
->colour_pairs
[i
].flags
= 0;
229 /* Initialise default colour pair. */
230 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].fore
=
232 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].back
=
234 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].flags
=
235 __default_pair
.flags
;
239 /* Set all positions on all windows to curses default colours. */
240 for (wlp
= _cursesi_screen
->winlistp
; wlp
!= NULL
; wlp
= wlp
->nextp
) {
242 if (wlp
->winp
!= __virtscr
&& wlp
->winp
!= curscr
) {
243 /* Set color attribute on other windows */
244 win
->battr
|= __default_color
;
245 for (y
= 0; y
< win
->maxy
; y
++) {
246 for (x
= 0; x
< win
->maxx
; x
++) {
247 win
->alines
[y
]->line
[x
].attr
&= ~__COLOR
;
248 win
->alines
[y
]->line
[x
].attr
|= __default_color
;
260 * Set pair foreground and background colors.
261 * Our default colour ordering is ANSI - 1 = red, 4 = blue, 3 = yellow,
262 * 6 = cyan. The older style (Sb/Sf) uses 1 = blue, 4 = red, 3 = cyan,
263 * 6 = yellow, so we swap them here and in pair_content().
266 init_pair(short pair
, short fore
, short back
)
271 __CTRACE(__CTRACE_COLOR
, "init_pair: %d, %d, %d\n", pair
, fore
, back
);
274 if (pair
< 0 || pair
>= COLOR_PAIRS
)
281 /* Swap red/blue and yellow/cyan */
282 if (_cursesi_screen
->color_type
== COLOR_OTHER
) {
313 if ((_cursesi_screen
->colour_pairs
[pair
].flags
& __USED
) &&
314 (fore
!= _cursesi_screen
->colour_pairs
[pair
].fore
||
315 back
!= _cursesi_screen
->colour_pairs
[pair
].back
))
320 _cursesi_screen
->colour_pairs
[pair
].flags
|= __USED
;
321 _cursesi_screen
->colour_pairs
[pair
].fore
= fore
;
322 _cursesi_screen
->colour_pairs
[pair
].back
= back
;
324 /* XXX: need to initialise HP style (Ip) */
333 * Get pair foreground and background colours.
336 pair_content(short pair
, short *forep
, short *backp
)
338 if (pair
< 0 || pair
> _cursesi_screen
->COLOR_PAIRS
)
341 *forep
= _cursesi_screen
->colour_pairs
[pair
].fore
;
342 *backp
= _cursesi_screen
->colour_pairs
[pair
].back
;
344 /* Swap red/blue and yellow/cyan */
345 if (_cursesi_screen
->color_type
== COLOR_OTHER
) {
357 *forep
= COLOR_YELLOW
;
371 *backp
= COLOR_YELLOW
;
380 * Set colour red, green and blue values.
383 init_color(short color
, short red
, short green
, short blue
)
386 __CTRACE(__CTRACE_COLOR
, "init_color: %d, %d, %d, %d\n",
387 color
, red
, green
, blue
);
389 if (color
< 0 || color
>= _cursesi_screen
->COLORS
)
392 _cursesi_screen
->colours
[color
].red
= red
;
393 _cursesi_screen
->colours
[color
].green
= green
;
394 _cursesi_screen
->colours
[color
].blue
= blue
;
395 /* XXX Not yet implemented */
397 /* XXX: need to initialise Tek style (Ic) and support HLS */
402 * Get colour red, green and blue values.
405 color_content(short color
, short *redp
, short *greenp
, short *bluep
)
407 if (color
< 0 || color
>= _cursesi_screen
->COLORS
)
410 *redp
= _cursesi_screen
->colours
[color
].red
;
411 *greenp
= _cursesi_screen
->colours
[color
].green
;
412 *bluep
= _cursesi_screen
->colours
[color
].blue
;
417 * use_default_colors --
418 * Use terminal default colours instead of curses default colour.
424 __CTRACE(__CTRACE_COLOR
, "use_default_colors\n");
427 return(assume_default_colors(-1, -1));
431 * assume_default_colors --
432 * Set the default foreground and background colours.
435 assume_default_colors(short fore
, short back
)
438 __CTRACE(__CTRACE_COLOR
, "assume_default_colors: %d, %d\n",
441 /* Swap red/blue and yellow/cyan */
442 if (_cursesi_screen
->color_type
== COLOR_OTHER
) {
472 __default_pair
.fore
= fore
;
473 __default_pair
.back
= back
;
474 __default_pair
.flags
= __USED
;
477 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].fore
= fore
;
478 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].back
= back
;
479 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].flags
= __USED
;
483 * If we've already called start_color(), make sure all instances
484 * of the curses default colour pair are dirty.
487 __change_pair(PAIR_NUMBER(__default_color
));
492 /* no_color_video is a terminfo macro, but we need to retain binary compat */
493 #ifdef __strong_alias
494 #undef no_color_video
495 __strong_alias(no_color_video
, no_color_attributes
)
498 * no_color_attributes --
499 * Return attributes that cannot be combined with color.
502 no_color_attributes(void)
504 return(_cursesi_screen
->nca
);
509 * Set terminal foreground and background colours.
512 __set_color( /*ARGSUSED*/ WINDOW
*win
, attr_t attr
)
516 if ((curscr
->wattr
& __COLOR
) == (attr
& __COLOR
))
519 pair
= PAIR_NUMBER((u_int32_t
)attr
);
521 __CTRACE(__CTRACE_COLOR
, "__set_color: %d, %d, %d\n", pair
,
522 _cursesi_screen
->colour_pairs
[pair
].fore
,
523 _cursesi_screen
->colour_pairs
[pair
].back
);
525 switch (_cursesi_screen
->color_type
) {
526 /* Set ANSI forground and background colours */
528 if (_cursesi_screen
->colour_pairs
[pair
].fore
< 0 ||
529 _cursesi_screen
->colour_pairs
[pair
].back
< 0)
530 __unset_color(curscr
);
531 if (_cursesi_screen
->colour_pairs
[pair
].fore
>= 0)
532 tputs(__parse_cap(_cursesi_screen
->tc_AF
,
533 _cursesi_screen
->colour_pairs
[pair
].fore
),
535 if (_cursesi_screen
->colour_pairs
[pair
].back
>= 0)
536 tputs(__parse_cap(_cursesi_screen
->tc_AB
,
537 _cursesi_screen
->colour_pairs
[pair
].back
),
541 /* XXX: need to support HP style */
544 /* XXX: need to support Tek style */
547 if (_cursesi_screen
->colour_pairs
[pair
].fore
< 0 ||
548 _cursesi_screen
->colour_pairs
[pair
].back
< 0)
549 __unset_color(curscr
);
550 if (_cursesi_screen
->colour_pairs
[pair
].fore
>= 0)
551 tputs(__parse_cap(_cursesi_screen
->tc_Sf
,
552 _cursesi_screen
->colour_pairs
[pair
].fore
),
554 if (_cursesi_screen
->colour_pairs
[pair
].back
>= 0)
555 tputs(__parse_cap(_cursesi_screen
->tc_Sb
,
556 _cursesi_screen
->colour_pairs
[pair
].back
),
560 curscr
->wattr
&= ~__COLOR
;
561 curscr
->wattr
|= attr
& __COLOR
;
566 * Clear terminal foreground and background colours.
569 __unset_color(WINDOW
*win
)
572 __CTRACE(__CTRACE_COLOR
, "__unset_color\n");
574 switch (_cursesi_screen
->color_type
) {
575 /* Clear ANSI forground and background colours */
577 if (__tc_op
!= NULL
) {
578 tputs(__tc_op
, 0, __cputchar
);
579 win
->wattr
&= __mask_op
;
583 /* XXX: need to support HP style */
586 /* XXX: need to support Tek style */
589 if (__tc_op
!= NULL
) {
590 tputs(__tc_op
, 0, __cputchar
);
591 win
->wattr
&= __mask_op
;
598 * __restore_colors --
599 * Redo color definitions after restarting 'curses' mode.
602 __restore_colors(void)
605 switch (_cursesi_screen
->color_type
) {
607 /* XXX: need to re-initialise HP style (Ip) */
610 /* XXX: need to re-initialise Tek style (Ic) */
617 * Mark dirty all positions using pair.
620 __change_pair(short pair
)
622 struct __winlist
*wlp
;
626 uint32_t cl
= COLOR_PAIR(pair
);
629 for (wlp
= _cursesi_screen
->winlistp
; wlp
!= NULL
; wlp
= wlp
->nextp
) {
631 __CTRACE(__CTRACE_COLOR
, "__change_pair: win = %p\n",
635 if (win
== __virtscr
)
637 else if (win
== curscr
) {
638 /* Reset colour attribute on curscr */
640 __CTRACE(__CTRACE_COLOR
,
641 "__change_pair: win == curscr\n");
643 for (y
= 0; y
< curscr
->maxy
; y
++) {
644 lp
= curscr
->alines
[y
];
645 for (x
= 0; x
< curscr
->maxx
; x
++) {
646 if ((lp
->line
[x
].attr
& __COLOR
) == cl
)
647 lp
->line
[x
].attr
&= ~__COLOR
;
651 /* Mark dirty those positions with colour pair "pair" */
652 for (y
= 0; y
< win
->maxy
; y
++) {
654 for (x
= 0; x
< win
->maxx
; x
++)
655 if ((lp
->line
[x
].attr
&
657 if (!(lp
->flags
& __ISDIRTY
))
658 lp
->flags
|= __ISDIRTY
;
660 * firstchp/lastchp are shared
661 * between parent window and
664 if (*lp
->firstchp
> x
)
666 if (*lp
->lastchp
< x
)
670 if ((win
->alines
[y
]->flags
& __ISDIRTY
))
671 __CTRACE(__CTRACE_COLOR
,
672 "__change_pair: first = %d, "
674 *win
->alines
[y
]->firstchp
,
675 *win
->alines
[y
]->lastchp
);