1 /* $NetBSD: color.c,v 1.37 2011/01/06 11:29:40 blymn 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.37 2011/01/06 11:29:40 blymn 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 (max_colors
> 0 && max_pairs
> 0 &&
64 ((set_a_foreground
!= NULL
&& set_a_background
!= NULL
) ||
65 initialize_pair
!= NULL
|| initialize_color
!= NULL
||
66 (set_background
!= NULL
&& set_foreground
!= NULL
)))
74 * Check if terminal can change colours.
77 can_change_color(void)
87 * Initialise colour support.
94 struct __winlist
*wlp
;
98 if (has_colors() == FALSE
)
101 /* Max colours and colour pairs */
102 if (max_colors
== -1)
105 COLORS
= max_colors
> MAX_COLORS
? MAX_COLORS
: max_colors
;
106 if (max_pairs
== -1) {
110 COLOR_PAIRS
= (max_pairs
> MAX_PAIRS
- 1 ?
111 MAX_PAIRS
- 1 : max_pairs
);
112 /* Use the last colour pair for curses default. */
113 __default_color
= COLOR_PAIR(MAX_PAIRS
- 1);
119 _cursesi_screen
->COLORS
= COLORS
;
120 _cursesi_screen
->COLOR_PAIRS
= COLOR_PAIRS
;
122 /* Reset terminal colour and colour pairs. */
123 if (orig_colors
!= NULL
)
124 tputs(orig_colors
, 0, __cputchar
);
125 if (orig_pair
!= NULL
) {
126 tputs(orig_pair
, 0, __cputchar
);
127 curscr
->wattr
&= _cursesi_screen
->mask_op
;
130 /* Type of colour manipulation - ANSI/TEK/HP/other */
131 if (set_a_foreground
!= NULL
&& set_a_background
!= NULL
)
132 _cursesi_screen
->color_type
= COLOR_ANSI
;
133 else if (initialize_pair
!= NULL
)
134 _cursesi_screen
->color_type
= COLOR_HP
;
135 else if (initialize_color
!= NULL
)
136 _cursesi_screen
->color_type
= COLOR_TEK
;
137 else if (set_foreground
!= NULL
&& set_background
!= NULL
)
138 _cursesi_screen
->color_type
= COLOR_OTHER
;
140 return(ERR
); /* Unsupported colour method */
143 __CTRACE(__CTRACE_COLOR
, "start_color: COLORS = %d, COLOR_PAIRS = %d",
144 COLORS
, COLOR_PAIRS
);
145 switch (_cursesi_screen
->color_type
) {
147 __CTRACE(__CTRACE_COLOR
, " (ANSI style)\n");
150 __CTRACE(__CTRACE_COLOR
, " (HP style)\n");
153 __CTRACE(__CTRACE_COLOR
, " (Tektronics style)\n");
156 __CTRACE(__CTRACE_COLOR
, " (Other style)\n");
162 * Attributes that cannot be used with color.
163 * Store these in an attr_t for wattrset()/wattron().
165 _cursesi_screen
->nca
= __NORMAL
;
166 if (no_color_video
!= -1) {
167 temp_nc
= (attr_t
) t_no_color_video(_cursesi_screen
->term
);
168 if (temp_nc
& 0x0001)
169 _cursesi_screen
->nca
|= __STANDOUT
;
170 if (temp_nc
& 0x0002)
171 _cursesi_screen
->nca
|= __UNDERSCORE
;
172 if (temp_nc
& 0x0004)
173 _cursesi_screen
->nca
|= __REVERSE
;
174 if (temp_nc
& 0x0008)
175 _cursesi_screen
->nca
|= __BLINK
;
176 if (temp_nc
& 0x0010)
177 _cursesi_screen
->nca
|= __DIM
;
178 if (temp_nc
& 0x0020)
179 _cursesi_screen
->nca
|= __BOLD
;
180 if (temp_nc
& 0x0040)
181 _cursesi_screen
->nca
|= __BLANK
;
182 if (temp_nc
& 0x0080)
183 _cursesi_screen
->nca
|= __PROTECT
;
184 if (temp_nc
& 0x0100)
185 _cursesi_screen
->nca
|= __ALTCHARSET
;
188 __CTRACE(__CTRACE_COLOR
, "start_color: _cursesi_screen->nca = %08x\n",
189 _cursesi_screen
->nca
);
192 /* Set up initial 8 colours */
193 if (COLORS
>= COLOR_BLACK
)
194 (void) init_color(COLOR_BLACK
, 0, 0, 0);
195 if (COLORS
>= COLOR_RED
)
196 (void) init_color(COLOR_RED
, 1000, 0, 0);
197 if (COLORS
>= COLOR_GREEN
)
198 (void) init_color(COLOR_GREEN
, 0, 1000, 0);
199 if (COLORS
>= COLOR_YELLOW
)
200 (void) init_color(COLOR_YELLOW
, 1000, 1000, 0);
201 if (COLORS
>= COLOR_BLUE
)
202 (void) init_color(COLOR_BLUE
, 0, 0, 1000);
203 if (COLORS
>= COLOR_MAGENTA
)
204 (void) init_color(COLOR_MAGENTA
, 1000, 0, 1000);
205 if (COLORS
>= COLOR_CYAN
)
206 (void) init_color(COLOR_CYAN
, 0, 1000, 1000);
207 if (COLORS
>= COLOR_WHITE
)
208 (void) init_color(COLOR_WHITE
, 1000, 1000, 1000);
210 /* Initialise other colours */
211 for (i
= 8; i
< COLORS
; i
++) {
212 _cursesi_screen
->colours
[i
].red
= 0;
213 _cursesi_screen
->colours
[i
].green
= 0;
214 _cursesi_screen
->colours
[i
].blue
= 0;
215 _cursesi_screen
->colours
[i
].flags
= 0;
218 /* Initialise pair 0 to default colours. */
219 _cursesi_screen
->colour_pairs
[0].fore
= -1;
220 _cursesi_screen
->colour_pairs
[0].back
= -1;
221 _cursesi_screen
->colour_pairs
[0].flags
= 0;
223 /* Initialise user colour pairs to default (white on black) */
224 for (i
= 0; i
< COLOR_PAIRS
; i
++) {
225 _cursesi_screen
->colour_pairs
[i
].fore
= COLOR_WHITE
;
226 _cursesi_screen
->colour_pairs
[i
].back
= COLOR_BLACK
;
227 _cursesi_screen
->colour_pairs
[i
].flags
= 0;
230 /* Initialise default colour pair. */
231 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].fore
=
233 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].back
=
235 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].flags
=
236 __default_pair
.flags
;
240 /* Set all positions on all windows to curses default colours. */
241 for (wlp
= _cursesi_screen
->winlistp
; wlp
!= NULL
; wlp
= wlp
->nextp
) {
243 if (wlp
->winp
!= __virtscr
&& wlp
->winp
!= curscr
) {
244 /* Set color attribute on other windows */
245 win
->battr
|= __default_color
;
246 for (y
= 0; y
< win
->maxy
; y
++) {
247 for (x
= 0; x
< win
->maxx
; x
++) {
248 win
->alines
[y
]->line
[x
].attr
&= ~__COLOR
;
249 win
->alines
[y
]->line
[x
].attr
|= __default_color
;
261 * Set pair foreground and background colors.
262 * Our default colour ordering is ANSI - 1 = red, 4 = blue, 3 = yellow,
263 * 6 = cyan. The older style (Sb/Sf) uses 1 = blue, 4 = red, 3 = cyan,
264 * 6 = yellow, so we swap them here and in pair_content().
267 init_pair(short pair
, short fore
, short back
)
272 __CTRACE(__CTRACE_COLOR
, "init_pair: %d, %d, %d\n", pair
, fore
, back
);
275 if (pair
< 0 || pair
>= COLOR_PAIRS
)
278 if (pair
== 0) /* Ignore request for pair 0, it is default. */
286 /* Swap red/blue and yellow/cyan */
287 if (_cursesi_screen
->color_type
== COLOR_OTHER
) {
318 if ((_cursesi_screen
->colour_pairs
[pair
].flags
& __USED
) &&
319 (fore
!= _cursesi_screen
->colour_pairs
[pair
].fore
||
320 back
!= _cursesi_screen
->colour_pairs
[pair
].back
))
325 _cursesi_screen
->colour_pairs
[pair
].flags
|= __USED
;
326 _cursesi_screen
->colour_pairs
[pair
].fore
= fore
;
327 _cursesi_screen
->colour_pairs
[pair
].back
= back
;
329 /* XXX: need to initialise HP style (Ip) */
338 * Get pair foreground and background colours.
341 pair_content(short pair
, short *forep
, short *backp
)
343 if (pair
< 0 || pair
> _cursesi_screen
->COLOR_PAIRS
)
346 *forep
= _cursesi_screen
->colour_pairs
[pair
].fore
;
347 *backp
= _cursesi_screen
->colour_pairs
[pair
].back
;
349 /* Swap red/blue and yellow/cyan */
350 if (_cursesi_screen
->color_type
== COLOR_OTHER
) {
362 *forep
= COLOR_YELLOW
;
376 *backp
= COLOR_YELLOW
;
385 * Set colour red, green and blue values.
388 init_color(short color
, short red
, short green
, short blue
)
391 __CTRACE(__CTRACE_COLOR
, "init_color: %d, %d, %d, %d\n",
392 color
, red
, green
, blue
);
394 if (color
< 0 || color
>= _cursesi_screen
->COLORS
)
397 _cursesi_screen
->colours
[color
].red
= red
;
398 _cursesi_screen
->colours
[color
].green
= green
;
399 _cursesi_screen
->colours
[color
].blue
= blue
;
400 /* XXX Not yet implemented */
402 /* XXX: need to initialise Tek style (Ic) and support HLS */
407 * Get colour red, green and blue values.
410 color_content(short color
, short *redp
, short *greenp
, short *bluep
)
412 if (color
< 0 || color
>= _cursesi_screen
->COLORS
)
415 *redp
= _cursesi_screen
->colours
[color
].red
;
416 *greenp
= _cursesi_screen
->colours
[color
].green
;
417 *bluep
= _cursesi_screen
->colours
[color
].blue
;
422 * use_default_colors --
423 * Use terminal default colours instead of curses default colour.
429 __CTRACE(__CTRACE_COLOR
, "use_default_colors\n");
432 return(assume_default_colors(-1, -1));
436 * assume_default_colors --
437 * Set the default foreground and background colours.
440 assume_default_colors(short fore
, short back
)
443 __CTRACE(__CTRACE_COLOR
, "assume_default_colors: %d, %d\n",
445 __CTRACE(__CTRACE_COLOR
, "assume_default_colors: default_colour = %d, pair_number = %d\n", __default_color
, PAIR_NUMBER(__default_color
));
448 /* Swap red/blue and yellow/cyan */
449 if (_cursesi_screen
->color_type
== COLOR_OTHER
) {
479 __default_pair
.fore
= fore
;
480 __default_pair
.back
= back
;
481 __default_pair
.flags
= __USED
;
484 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].fore
= fore
;
485 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].back
= back
;
486 _cursesi_screen
->colour_pairs
[PAIR_NUMBER(__default_color
)].flags
= __USED
;
490 * If we've already called start_color(), make sure all instances
491 * of the curses default colour pair are dirty.
494 __change_pair(PAIR_NUMBER(__default_color
));
499 /* no_color_video is a terminfo macro, but we need to retain binary compat */
500 #ifdef __strong_alias
501 #undef no_color_video
502 __strong_alias(no_color_video
, no_color_attributes
)
505 * no_color_attributes --
506 * Return attributes that cannot be combined with color.
509 no_color_attributes(void)
511 return(_cursesi_screen
->nca
);
516 * Set terminal foreground and background colours.
519 __set_color( /*ARGSUSED*/ WINDOW
*win
, attr_t attr
)
523 if ((curscr
->wattr
& __COLOR
) == (attr
& __COLOR
))
526 pair
= PAIR_NUMBER((u_int32_t
)attr
);
528 __CTRACE(__CTRACE_COLOR
, "__set_color: %d, %d, %d\n", pair
,
529 _cursesi_screen
->colour_pairs
[pair
].fore
,
530 _cursesi_screen
->colour_pairs
[pair
].back
);
532 switch (_cursesi_screen
->color_type
) {
533 /* Set ANSI forground and background colours */
535 if (_cursesi_screen
->colour_pairs
[pair
].fore
< 0 ||
536 _cursesi_screen
->colour_pairs
[pair
].back
< 0)
537 __unset_color(curscr
);
538 if (_cursesi_screen
->colour_pairs
[pair
].fore
>= 0)
539 tputs(vtparm(t_set_a_foreground(_cursesi_screen
->term
),
540 _cursesi_screen
->colour_pairs
[pair
].fore
),
542 if (_cursesi_screen
->colour_pairs
[pair
].back
>= 0)
543 tputs(vtparm(t_set_a_background(_cursesi_screen
->term
),
544 _cursesi_screen
->colour_pairs
[pair
].back
),
548 /* XXX: need to support HP style */
551 /* XXX: need to support Tek style */
554 if (_cursesi_screen
->colour_pairs
[pair
].fore
< 0 ||
555 _cursesi_screen
->colour_pairs
[pair
].back
< 0)
556 __unset_color(curscr
);
557 if (_cursesi_screen
->colour_pairs
[pair
].fore
>= 0)
558 tputs(vtparm(t_set_foreground(_cursesi_screen
->term
),
559 _cursesi_screen
->colour_pairs
[pair
].fore
),
561 if (_cursesi_screen
->colour_pairs
[pair
].back
>= 0)
562 tputs(vtparm(t_set_background(_cursesi_screen
->term
),
563 _cursesi_screen
->colour_pairs
[pair
].back
),
567 curscr
->wattr
&= ~__COLOR
;
568 curscr
->wattr
|= attr
& __COLOR
;
573 * Clear terminal foreground and background colours.
576 __unset_color(WINDOW
*win
)
579 __CTRACE(__CTRACE_COLOR
, "__unset_color\n");
581 switch (_cursesi_screen
->color_type
) {
582 /* Clear ANSI forground and background colours */
584 if (orig_pair
!= NULL
) {
585 tputs(orig_pair
, 0, __cputchar
);
586 win
->wattr
&= __mask_op
;
590 /* XXX: need to support HP style */
593 /* XXX: need to support Tek style */
596 if (orig_pair
!= NULL
) {
597 tputs(orig_pair
, 0, __cputchar
);
598 win
->wattr
&= __mask_op
;
605 * __restore_colors --
606 * Redo color definitions after restarting 'curses' mode.
609 __restore_colors(void)
612 switch (_cursesi_screen
->color_type
) {
614 /* XXX: need to re-initialise HP style (Ip) */
617 /* XXX: need to re-initialise Tek style (Ic) */
624 * Mark dirty all positions using pair.
627 __change_pair(short pair
)
629 struct __winlist
*wlp
;
633 uint32_t cl
= COLOR_PAIR(pair
);
636 for (wlp
= _cursesi_screen
->winlistp
; wlp
!= NULL
; wlp
= wlp
->nextp
) {
638 __CTRACE(__CTRACE_COLOR
, "__change_pair: win = %p\n",
642 if (win
== __virtscr
)
644 else if (win
== curscr
) {
645 /* Reset colour attribute on curscr */
647 __CTRACE(__CTRACE_COLOR
,
648 "__change_pair: win == curscr\n");
650 for (y
= 0; y
< curscr
->maxy
; y
++) {
651 lp
= curscr
->alines
[y
];
652 for (x
= 0; x
< curscr
->maxx
; x
++) {
653 if ((lp
->line
[x
].attr
& __COLOR
) == cl
)
654 lp
->line
[x
].attr
&= ~__COLOR
;
658 /* Mark dirty those positions with colour pair "pair" */
659 for (y
= 0; y
< win
->maxy
; y
++) {
661 for (x
= 0; x
< win
->maxx
; x
++)
662 if ((lp
->line
[x
].attr
&
664 if (!(lp
->flags
& __ISDIRTY
))
665 lp
->flags
|= __ISDIRTY
;
667 * firstchp/lastchp are shared
668 * between parent window and
671 if (*lp
->firstchp
> x
)
673 if (*lp
->lastchp
< x
)
677 if ((win
->alines
[y
]->flags
& __ISDIRTY
))
678 __CTRACE(__CTRACE_COLOR
,
679 "__change_pair: first = %d, "
681 *win
->alines
[y
]->firstchp
,
682 *win
->alines
[y
]->lastchp
);