snj doesn't like my accent, so use proper English month names.
[netbsd-mini2440.git] / lib / libcurses / color.c
blob617b5911f34125f6420cadb4c90f47604c2013c8
1 /* $NetBSD: color.c,v 1.33 2008/04/28 20:23:01 martin Exp $ */
3 /*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julian Coleman.
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.
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>
33 #ifndef lint
34 __RCSID("$NetBSD: color.c,v 1.33 2008/04/28 20:23:01 martin Exp $");
35 #endif /* not lint */
37 #include "curses.h"
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 */
51 #define __USED 0x01
53 static void
54 __change_pair(short);
57 * has_colors --
58 * Check if terminal has colours.
60 bool
61 has_colors(void)
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)))
66 return(TRUE);
67 else
68 return(FALSE);
72 * can_change_color --
73 * Check if terminal can change colours.
75 bool
76 can_change_color(void)
78 if (__tc_cc)
79 return(TRUE);
80 else
81 return(FALSE);
85 * start_color --
86 * Initialise colour support.
88 int
89 start_color(void)
91 int i;
92 attr_t temp_nc;
93 struct __winlist *wlp;
94 WINDOW *win;
95 int y, x;
97 if (has_colors() == FALSE)
98 return(ERR);
100 /* Max colours and colour pairs */
101 if (__tc_Co == -1)
102 COLORS = 0;
103 else {
104 COLORS = __tc_Co > MAX_COLORS ? MAX_COLORS : __tc_Co;
105 if (__tc_pa == -1) {
106 COLOR_PAIRS = 0;
107 COLORS = 0;
108 } else {
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);
115 if (!COLORS)
116 return (ERR);
118 _cursesi_screen->COLORS = COLORS;
119 _cursesi_screen->COLOR_PAIRS = COLOR_PAIRS;
121 /* Reset terminal colour and colour pairs. */
122 if (__tc_oc != NULL)
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;
138 else
139 return(ERR); /* Unsupported colour method */
141 #ifdef DEBUG
142 __CTRACE(__CTRACE_COLOR, "start_color: COLORS = %d, COLOR_PAIRS = %d",
143 COLORS, COLOR_PAIRS);
144 switch (_cursesi_screen->color_type) {
145 case COLOR_ANSI:
146 __CTRACE(__CTRACE_COLOR, " (ANSI style)\n");
147 break;
148 case COLOR_HP:
149 __CTRACE(__CTRACE_COLOR, " (HP style)\n");
150 break;
151 case COLOR_TEK:
152 __CTRACE(__CTRACE_COLOR, " (Tektronics style)\n");
153 break;
154 case COLOR_OTHER:
155 __CTRACE(__CTRACE_COLOR, " (Other style)\n");
156 break;
158 #endif
161 * Attributes that cannot be used with color.
162 * Store these in an attr_t for wattrset()/wattron().
164 _cursesi_screen->nca = __NORMAL;
165 if (__tc_NC != -1) {
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;
186 #ifdef DEBUG
187 __CTRACE(__CTRACE_COLOR, "start_color: _cursesi_screen->nca = %08x\n",
188 _cursesi_screen->nca);
189 #endif
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 =
231 __default_pair.fore;
232 _cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].back =
233 __default_pair.back;
234 _cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].flags =
235 __default_pair.flags;
237 __using_color = 1;
239 /* Set all positions on all windows to curses default colours. */
240 for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
241 win = wlp->winp;
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;
251 __touchwin(win);
255 return(OK);
259 * init_pair --
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)
268 int changed;
270 #ifdef DEBUG
271 __CTRACE(__CTRACE_COLOR, "init_pair: %d, %d, %d\n", pair, fore, back);
272 #endif
274 if (pair < 0 || pair >= COLOR_PAIRS)
275 return (ERR);
276 if (fore >= COLORS)
277 return (ERR);
278 if (back >= COLORS)
279 return (ERR);
281 /* Swap red/blue and yellow/cyan */
282 if (_cursesi_screen->color_type == COLOR_OTHER) {
283 switch (fore) {
284 case COLOR_RED:
285 fore = COLOR_BLUE;
286 break;
287 case COLOR_BLUE:
288 fore = COLOR_RED;
289 break;
290 case COLOR_YELLOW:
291 fore = COLOR_CYAN;
292 break;
293 case COLOR_CYAN:
294 fore = COLOR_YELLOW;
295 break;
297 switch (back) {
298 case COLOR_RED:
299 back = COLOR_BLUE;
300 break;
301 case COLOR_BLUE:
302 back = COLOR_RED;
303 break;
304 case COLOR_YELLOW:
305 back = COLOR_CYAN;
306 break;
307 case COLOR_CYAN:
308 back = COLOR_YELLOW;
309 break;
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))
316 changed = 1;
317 else
318 changed = 0;
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) */
326 if (changed)
327 __change_pair(pair);
328 return (OK);
332 * pair_content --
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)
339 return(ERR);
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) {
346 switch (*forep) {
347 case COLOR_RED:
348 *forep = COLOR_BLUE;
349 break;
350 case COLOR_BLUE:
351 *forep = COLOR_RED;
352 break;
353 case COLOR_YELLOW:
354 *forep = COLOR_CYAN;
355 break;
356 case COLOR_CYAN:
357 *forep = COLOR_YELLOW;
358 break;
360 switch (*backp) {
361 case COLOR_RED:
362 *backp = COLOR_BLUE;
363 break;
364 case COLOR_BLUE:
365 *backp = COLOR_RED;
366 break;
367 case COLOR_YELLOW:
368 *backp = COLOR_CYAN;
369 break;
370 case COLOR_CYAN:
371 *backp = COLOR_YELLOW;
372 break;
375 return(OK);
379 * init_color --
380 * Set colour red, green and blue values.
383 init_color(short color, short red, short green, short blue)
385 #ifdef DEBUG
386 __CTRACE(__CTRACE_COLOR, "init_color: %d, %d, %d, %d\n",
387 color, red, green, blue);
388 #endif
389 if (color < 0 || color >= _cursesi_screen->COLORS)
390 return(ERR);
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 */
396 return(ERR);
397 /* XXX: need to initialise Tek style (Ic) and support HLS */
401 * color_content --
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)
408 return(ERR);
410 *redp = _cursesi_screen->colours[color].red;
411 *greenp = _cursesi_screen->colours[color].green;
412 *bluep = _cursesi_screen->colours[color].blue;
413 return(OK);
417 * use_default_colors --
418 * Use terminal default colours instead of curses default colour.
421 use_default_colors()
423 #ifdef DEBUG
424 __CTRACE(__CTRACE_COLOR, "use_default_colors\n");
425 #endif
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)
437 #ifdef DEBUG
438 __CTRACE(__CTRACE_COLOR, "assume_default_colors: %d, %d\n",
439 fore, back);
440 #endif
441 /* Swap red/blue and yellow/cyan */
442 if (_cursesi_screen->color_type == COLOR_OTHER) {
443 switch (fore) {
444 case COLOR_RED:
445 fore = COLOR_BLUE;
446 break;
447 case COLOR_BLUE:
448 fore = COLOR_RED;
449 break;
450 case COLOR_YELLOW:
451 fore = COLOR_CYAN;
452 break;
453 case COLOR_CYAN:
454 fore = COLOR_YELLOW;
455 break;
457 switch (back) {
458 case COLOR_RED:
459 back = COLOR_BLUE;
460 break;
461 case COLOR_BLUE:
462 back = COLOR_RED;
463 break;
464 case COLOR_YELLOW:
465 back = COLOR_CYAN;
466 break;
467 case COLOR_CYAN:
468 back = COLOR_YELLOW;
469 break;
472 __default_pair.fore = fore;
473 __default_pair.back = back;
474 __default_pair.flags = __USED;
476 if (COLOR_PAIRS) {
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.
486 if (__using_color)
487 __change_pair(PAIR_NUMBER(__default_color));
489 return(OK);
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)
496 #endif
498 * no_color_attributes --
499 * Return attributes that cannot be combined with color.
501 attr_t
502 no_color_attributes(void)
504 return(_cursesi_screen->nca);
508 * __set_color --
509 * Set terminal foreground and background colours.
511 void
512 __set_color( /*ARGSUSED*/ WINDOW *win, attr_t attr)
514 short pair;
516 if ((curscr->wattr & __COLOR) == (attr & __COLOR))
517 return;
519 pair = PAIR_NUMBER((u_int32_t)attr);
520 #ifdef DEBUG
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);
524 #endif
525 switch (_cursesi_screen->color_type) {
526 /* Set ANSI forground and background colours */
527 case COLOR_ANSI:
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),
534 0, __cputchar);
535 if (_cursesi_screen->colour_pairs[pair].back >= 0)
536 tputs(__parse_cap(_cursesi_screen->tc_AB,
537 _cursesi_screen->colour_pairs[pair].back),
538 0, __cputchar);
539 break;
540 case COLOR_HP:
541 /* XXX: need to support HP style */
542 break;
543 case COLOR_TEK:
544 /* XXX: need to support Tek style */
545 break;
546 case COLOR_OTHER:
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),
553 0, __cputchar);
554 if (_cursesi_screen->colour_pairs[pair].back >= 0)
555 tputs(__parse_cap(_cursesi_screen->tc_Sb,
556 _cursesi_screen->colour_pairs[pair].back),
557 0, __cputchar);
558 break;
560 curscr->wattr &= ~__COLOR;
561 curscr->wattr |= attr & __COLOR;
565 * __unset_color --
566 * Clear terminal foreground and background colours.
568 void
569 __unset_color(WINDOW *win)
571 #ifdef DEBUG
572 __CTRACE(__CTRACE_COLOR, "__unset_color\n");
573 #endif
574 switch (_cursesi_screen->color_type) {
575 /* Clear ANSI forground and background colours */
576 case COLOR_ANSI:
577 if (__tc_op != NULL) {
578 tputs(__tc_op, 0, __cputchar);
579 win->wattr &= __mask_op;
581 break;
582 case COLOR_HP:
583 /* XXX: need to support HP style */
584 break;
585 case COLOR_TEK:
586 /* XXX: need to support Tek style */
587 break;
588 case COLOR_OTHER:
589 if (__tc_op != NULL) {
590 tputs(__tc_op, 0, __cputchar);
591 win->wattr &= __mask_op;
593 break;
598 * __restore_colors --
599 * Redo color definitions after restarting 'curses' mode.
601 void
602 __restore_colors(void)
604 if (__tc_cc != 0)
605 switch (_cursesi_screen->color_type) {
606 case COLOR_HP:
607 /* XXX: need to re-initialise HP style (Ip) */
608 break;
609 case COLOR_TEK:
610 /* XXX: need to re-initialise Tek style (Ic) */
611 break;
616 * __change_pair --
617 * Mark dirty all positions using pair.
619 void
620 __change_pair(short pair)
622 struct __winlist *wlp;
623 WINDOW *win;
624 int y, x;
625 __LINE *lp;
626 uint32_t cl = COLOR_PAIR(pair);
629 for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
630 #ifdef DEBUG
631 __CTRACE(__CTRACE_COLOR, "__change_pair: win = %p\n",
632 wlp->winp);
633 #endif
634 win = wlp->winp;
635 if (win == __virtscr)
636 continue;
637 else if (win == curscr) {
638 /* Reset colour attribute on curscr */
639 #ifdef DEBUG
640 __CTRACE(__CTRACE_COLOR,
641 "__change_pair: win == curscr\n");
642 #endif
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;
650 } else {
651 /* Mark dirty those positions with colour pair "pair" */
652 for (y = 0; y < win->maxy; y++) {
653 lp = win->alines[y];
654 for (x = 0; x < win->maxx; x++)
655 if ((lp->line[x].attr &
656 __COLOR) == cl) {
657 if (!(lp->flags & __ISDIRTY))
658 lp->flags |= __ISDIRTY;
660 * firstchp/lastchp are shared
661 * between parent window and
662 * sub-window.
664 if (*lp->firstchp > x)
665 *lp->firstchp = x;
666 if (*lp->lastchp < x)
667 *lp->lastchp = x;
669 #ifdef DEBUG
670 if ((win->alines[y]->flags & __ISDIRTY))
671 __CTRACE(__CTRACE_COLOR,
672 "__change_pair: first = %d, "
673 "last = %d\n",
674 *win->alines[y]->firstchp,
675 *win->alines[y]->lastchp);
676 #endif