xref: /netbsd-src/lib/libcurses/color.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: color.c,v 1.29 2004/03/22 18:57:38 jdc 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.29 2004/03/22 18:57:38 jdc Exp $");
42 #endif				/* not lint */
43 
44 #include "curses.h"
45 #include "curses_private.h"
46 
47 /* Have we initialised colours? */
48 int	__using_color = 0;
49 
50 /* Default colour number */
51 attr_t	__default_color = 0;
52 
53 /* Default colour pair values - white on black. */
54 struct __pair	__default_pair = {COLOR_WHITE, COLOR_BLACK, 0};
55 
56 /* Default colour values */
57 /* Flags for colours and pairs */
58 #define	__USED		0x01
59 
60 static void
61 __change_pair(short);
62 
63 /*
64  * has_colors --
65  *	Check if terminal has colours.
66  */
67 bool
68 has_colors(void)
69 {
70 	if (__tc_Co > 0 && __tc_pa > 0 && ((__tc_AF != NULL &&
71 	    __tc_AB != NULL) || __tc_Ip != NULL || __tc_Ic != NULL ||
72 	    (__tc_Sb != NULL && __tc_Sf != NULL)))
73 		return(TRUE);
74 	else
75 		return(FALSE);
76 }
77 
78 /*
79  * can_change_color --
80  *	Check if terminal can change colours.
81  */
82 bool
83 can_change_color(void)
84 {
85 	if (__tc_cc)
86 		return(TRUE);
87 	else
88 		return(FALSE);
89 }
90 
91 /*
92  * start_color --
93  *	Initialise colour support.
94  */
95 int
96 start_color(void)
97 {
98 	int			 i;
99 	attr_t			 temp_nc;
100 	struct __winlist	*wlp;
101 	WINDOW			*win;
102 	int			 y, x;
103 
104 	if (has_colors() == FALSE)
105 		return(ERR);
106 
107 	/* Max colours and colour pairs */
108 	if (__tc_Co == -1)
109 		COLORS = 0;
110 	else {
111 		COLORS = __tc_Co > MAX_COLORS ? MAX_COLORS : __tc_Co;
112 		if (__tc_pa == -1) {
113 			COLOR_PAIRS = 0;
114 			COLORS = 0;
115 		} else {
116 			COLOR_PAIRS = (__tc_pa > MAX_PAIRS - 1 ?
117 			    MAX_PAIRS - 1 : __tc_pa);
118 			 /* Use the last colour pair for curses default. */
119 			__default_color = COLOR_PAIR(MAX_PAIRS - 1);
120 		}
121 	}
122 	if (!COLORS)
123 		return (ERR);
124 
125 	_cursesi_screen->COLORS = COLORS;
126 	_cursesi_screen->COLOR_PAIRS = COLOR_PAIRS;
127 
128 	/* Reset terminal colour and colour pairs. */
129 	if (__tc_oc != NULL)
130 		tputs(__tc_oc, 0, __cputchar);
131 	if (__tc_op != NULL) {
132 		tputs(__tc_op, 0, __cputchar);
133 		curscr->wattr &= _cursesi_screen->mask_op;
134 	}
135 
136 	/* Type of colour manipulation - ANSI/TEK/HP/other */
137 	if (__tc_AF != NULL && __tc_AB != NULL)
138 		_cursesi_screen->color_type = COLOR_ANSI;
139 	else if (__tc_Ip != NULL)
140 		_cursesi_screen->color_type = COLOR_HP;
141 	else if (__tc_Ic != NULL)
142 		_cursesi_screen->color_type = COLOR_TEK;
143 	else if (__tc_Sb != NULL && __tc_Sf != NULL)
144 		_cursesi_screen->color_type = COLOR_OTHER;
145 	else
146 		return(ERR);		/* Unsupported colour method */
147 
148 #ifdef DEBUG
149 	__CTRACE("start_color: COLORS = %d, COLOR_PAIRS = %d",
150 	    COLORS, COLOR_PAIRS);
151 	switch (_cursesi_screen->color_type) {
152 	case COLOR_ANSI:
153 		__CTRACE(" (ANSI style)\n");
154 		break;
155 	case COLOR_HP:
156 		__CTRACE(" (HP style)\n");
157 		break;
158 	case COLOR_TEK:
159 		__CTRACE(" (Tektronics style)\n");
160 		break;
161 	case COLOR_OTHER:
162 		__CTRACE(" (Other style)\n");
163 		break;
164 	}
165 #endif
166 
167 	/*
168 	 * Attributes that cannot be used with color.
169 	 * Store these in an attr_t for wattrset()/wattron().
170 	 */
171 	_cursesi_screen->nca = __NORMAL;
172 	if (__tc_NC != -1) {
173 		temp_nc = (attr_t) t_getnum(_cursesi_screen->cursesi_genbuf, "NC");
174 		if (temp_nc & 0x0001)
175 			_cursesi_screen->nca |= __STANDOUT;
176 		if (temp_nc & 0x0002)
177 			_cursesi_screen->nca |= __UNDERSCORE;
178 		if (temp_nc & 0x0004)
179 			_cursesi_screen->nca |= __REVERSE;
180 		if (temp_nc & 0x0008)
181 			_cursesi_screen->nca |= __BLINK;
182 		if (temp_nc & 0x0010)
183 			_cursesi_screen->nca |= __DIM;
184 		if (temp_nc & 0x0020)
185 			_cursesi_screen->nca |= __BOLD;
186 		if (temp_nc & 0x0040)
187 			_cursesi_screen->nca |= __BLANK;
188 		if (temp_nc & 0x0080)
189 			_cursesi_screen->nca |= __PROTECT;
190 		if (temp_nc & 0x0100)
191 			_cursesi_screen->nca |= __ALTCHARSET;
192 	}
193 #ifdef DEBUG
194 	__CTRACE ("start_color: _cursesi_screen->nca = %08x\n",
195 	    _cursesi_screen->nca);
196 #endif
197 
198 	/* Set up initial 8 colours */
199 	if (COLORS >= COLOR_BLACK)
200 		(void) init_color(COLOR_BLACK, 0, 0, 0);
201 	if (COLORS >= COLOR_RED)
202 		(void) init_color(COLOR_RED, 1000, 0, 0);
203 	if (COLORS >= COLOR_GREEN)
204 		(void) init_color(COLOR_GREEN, 0, 1000, 0);
205 	if (COLORS >= COLOR_YELLOW)
206 		(void) init_color(COLOR_YELLOW, 1000, 1000, 0);
207 	if (COLORS >= COLOR_BLUE)
208 		(void) init_color(COLOR_BLUE, 0, 0, 1000);
209 	if (COLORS >= COLOR_MAGENTA)
210 		(void) init_color(COLOR_MAGENTA, 1000, 0, 1000);
211 	if (COLORS >= COLOR_CYAN)
212 		(void) init_color(COLOR_CYAN, 0, 1000, 1000);
213 	if (COLORS >= COLOR_WHITE)
214 		(void) init_color(COLOR_WHITE, 1000, 1000, 1000);
215 
216 	/* Initialise other colours */
217 	for (i = 8; i < COLORS; i++) {
218 		_cursesi_screen->colours[i].red = 0;
219 		_cursesi_screen->colours[i].green = 0;
220 		_cursesi_screen->colours[i].blue = 0;
221 		_cursesi_screen->colours[i].flags = 0;
222 	}
223 
224 	/* Initialise pair 0 to default colours. */
225 	_cursesi_screen->colour_pairs[0].fore = -1;
226 	_cursesi_screen->colour_pairs[0].back = -1;
227 	_cursesi_screen->colour_pairs[0].flags = 0;
228 
229 	/* Initialise user colour pairs to default (white on black) */
230 	for (i = 0; i < COLOR_PAIRS; i++) {
231 		_cursesi_screen->colour_pairs[i].fore = COLOR_WHITE;
232 		_cursesi_screen->colour_pairs[i].back = COLOR_BLACK;
233 		_cursesi_screen->colour_pairs[i].flags = 0;
234 	}
235 
236 	/* Initialise default colour pair. */
237 	_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].fore =
238 	    __default_pair.fore;
239 	_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].back =
240 	    __default_pair.back;
241 	_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].flags =
242 	    __default_pair.flags;
243 
244 	__using_color = 1;
245 
246 	/* Set all positions on all windows to curses default colours. */
247 	for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
248 		win = wlp->winp;
249 		if (wlp->winp == curscr) {
250 			/* Reset colour attribute on curscr */
251 			for (y = 0; y < curscr->maxy; y++)
252 				for (x = 0; x < curscr->maxx; x++) {
253 					if ((curscr->lines[y]->line[x].battr & __COLOR) == __default_color)
254 						curscr->lines[y]->line[x].battr &= ~__COLOR;
255 				}
256 		} else if (wlp->winp != __virtscr) {
257 			/* Set background attribute on other windows */
258 			if (!(win->battr & __COLOR))
259 				win->battr |= __default_color;
260 			for (y = 0; y < win->maxy; y++) {
261 				for (x = 0; x < win->maxx; x++)
262 					if (!(win->lines[y]->line[x].battr & __COLOR))
263 						win->lines[y]->line[x].battr |= __default_color;
264 			}
265 			__touchwin(win);
266 		}
267 	}
268 
269 	return(OK);
270 }
271 
272 /*
273  * init_pair --
274  *	Set pair foreground and background colors.
275  *	Our default colour ordering is ANSI - 1 = red, 4 = blue, 3 = yellow,
276  *	6 = cyan.  The older style (Sb/Sf) uses 1 = blue, 4 = red, 3 = cyan,
277  *	6 = yellow, so we swap them here and in pair_content().
278  */
279 int
280 init_pair(short pair, short fore, short back)
281 {
282 	int	changed;
283 
284 #ifdef DEBUG
285 	__CTRACE("init_pair: %d, %d, %d\n", pair, fore, back);
286 #endif
287 
288 	if (pair < 0 || pair >= COLOR_PAIRS)
289 		return (ERR);
290 	if (fore >= COLORS)
291 		return (ERR);
292 	if (back >= COLORS)
293 		return (ERR);
294 
295 	/* Swap red/blue and yellow/cyan */
296 	if (_cursesi_screen->color_type == COLOR_OTHER) {
297 		switch (fore) {
298 		case COLOR_RED:
299 			fore = COLOR_BLUE;
300 			break;
301 		case COLOR_BLUE:
302 			fore = COLOR_RED;
303 			break;
304 		case COLOR_YELLOW:
305 			fore = COLOR_CYAN;
306 			break;
307 		case COLOR_CYAN:
308 			fore = COLOR_YELLOW;
309 			break;
310 		}
311 		switch (back) {
312 		case COLOR_RED:
313 			back = COLOR_BLUE;
314 			break;
315 		case COLOR_BLUE:
316 			back = COLOR_RED;
317 			break;
318 		case COLOR_YELLOW:
319 			back = COLOR_CYAN;
320 			break;
321 		case COLOR_CYAN:
322 			back = COLOR_YELLOW;
323 			break;
324 		}
325 	}
326 
327 	if ((_cursesi_screen->colour_pairs[pair].flags & __USED) &&
328 	    (fore != _cursesi_screen->colour_pairs[pair].fore ||
329 	     back != _cursesi_screen->colour_pairs[pair].back))
330 		changed = 1;
331 	else
332 		changed = 0;
333 
334 	_cursesi_screen->colour_pairs[pair].flags |= __USED;
335 	_cursesi_screen->colour_pairs[pair].fore = fore;
336 	_cursesi_screen->colour_pairs[pair].back = back;
337 
338 	/* XXX: need to initialise HP style (Ip) */
339 
340 	if (changed)
341 		__change_pair(pair);
342 	return (OK);
343 }
344 
345 /*
346  * pair_content --
347  *	Get pair foreground and background colours.
348  */
349 int
350 pair_content(short pair, short *forep, short *backp)
351 {
352 	if (pair < 0 || pair > _cursesi_screen->COLOR_PAIRS)
353 		return(ERR);
354 
355 	*forep = _cursesi_screen->colour_pairs[pair].fore;
356 	*backp = _cursesi_screen->colour_pairs[pair].back;
357 
358 	/* Swap red/blue and yellow/cyan */
359 	if (_cursesi_screen->color_type == COLOR_OTHER) {
360 		switch (*forep) {
361 		case COLOR_RED:
362 			*forep = COLOR_BLUE;
363 			break;
364 		case COLOR_BLUE:
365 			*forep = COLOR_RED;
366 			break;
367 		case COLOR_YELLOW:
368 			*forep = COLOR_CYAN;
369 			break;
370 		case COLOR_CYAN:
371 			*forep = COLOR_YELLOW;
372 			break;
373 		}
374 		switch (*backp) {
375 		case COLOR_RED:
376 			*backp = COLOR_BLUE;
377 			break;
378 		case COLOR_BLUE:
379 			*backp = COLOR_RED;
380 			break;
381 		case COLOR_YELLOW:
382 			*backp = COLOR_CYAN;
383 			break;
384 		case COLOR_CYAN:
385 			*backp = COLOR_YELLOW;
386 			break;
387 		}
388 	}
389 	return(OK);
390 }
391 
392 /*
393  * init_color --
394  *	Set colour red, green and blue values.
395  */
396 int
397 init_color(short color, short red, short green, short blue)
398 {
399 #ifdef DEBUG
400 	__CTRACE("init_color: %d, %d, %d, %d\n", color, red, green, blue);
401 #endif
402 	if (color < 0 || color >= _cursesi_screen->COLORS)
403 		return(ERR);
404 
405 	_cursesi_screen->colours[color].red = red;
406 	_cursesi_screen->colours[color].green = green;
407 	_cursesi_screen->colours[color].blue = blue;
408 	/* XXX Not yet implemented */
409 	return(ERR);
410 	/* XXX: need to initialise Tek style (Ic) and support HLS */
411 }
412 
413 /*
414  * color_content --
415  *	Get colour red, green and blue values.
416  */
417 int
418 color_content(short color, short *redp, short *greenp, short *bluep)
419 {
420 	if (color < 0 || color >= _cursesi_screen->COLORS)
421 		return(ERR);
422 
423 	*redp = _cursesi_screen->colours[color].red;
424 	*greenp = _cursesi_screen->colours[color].green;
425 	*bluep = _cursesi_screen->colours[color].blue;
426 	return(OK);
427 }
428 
429 /*
430  * use_default_colors --
431  *	Use terminal default colours instead of curses default colour.
432   */
433 int
434 use_default_colors()
435 {
436 #ifdef DEBUG
437 	__CTRACE("use_default_colors\n");
438 #endif
439 
440 	return(assume_default_colors(-1, -1));
441 }
442 
443 /*
444  * assume_default_colors --
445  *	Set the default foreground and background colours.
446  */
447 int
448 assume_default_colors(short fore, short back)
449 {
450 #ifdef DEBUG
451 	__CTRACE("assume_default_colors: %d, %d\n", fore, back);
452 #endif
453 	/* Swap red/blue and yellow/cyan */
454 	if (_cursesi_screen->color_type == COLOR_OTHER) {
455 		switch (fore) {
456 		case COLOR_RED:
457 			fore = COLOR_BLUE;
458 			break;
459 		case COLOR_BLUE:
460 			fore = COLOR_RED;
461 			break;
462 		case COLOR_YELLOW:
463 			fore = COLOR_CYAN;
464 			break;
465 		case COLOR_CYAN:
466 			fore = COLOR_YELLOW;
467 			break;
468 		}
469 		switch (back) {
470 		case COLOR_RED:
471 			back = COLOR_BLUE;
472 			break;
473 		case COLOR_BLUE:
474 			back = COLOR_RED;
475 			break;
476 		case COLOR_YELLOW:
477 			back = COLOR_CYAN;
478 			break;
479 		case COLOR_CYAN:
480 			back = COLOR_YELLOW;
481 			break;
482 		}
483 	}
484 	__default_pair.fore = fore;
485 	__default_pair.back = back;
486 	__default_pair.flags = __USED;
487 
488 	if (COLOR_PAIRS) {
489 		_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].fore = fore;
490 		_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].back = back;
491 		_cursesi_screen->colour_pairs[PAIR_NUMBER(__default_color)].flags = __USED;
492 	}
493 
494 	/*
495 	 * If we've already called start_color(), make sure all instances
496 	 * of the curses default colour pair are dirty.
497 	 */
498 	if (__using_color)
499 		__change_pair(PAIR_NUMBER(__default_color));
500 
501 	return(OK);
502 }
503 
504 /*
505  * no_color_video --
506  *	Return attributes that cannot be combined with color.
507  */
508 attr_t
509 no_color_video(void)
510 {
511 	return(_cursesi_screen->nca);
512 }
513 
514 /*
515  * __set_color --
516  *	Set terminal foreground and background colours.
517  */
518 void
519 __set_color( /*ARGSUSED*/ WINDOW *win, attr_t attr)
520 {
521 	short	pair;
522 
523 	if ((curscr->wattr & __COLOR) == (attr & __COLOR))
524 		return;
525 
526 	pair = PAIR_NUMBER((u_int32_t)attr);
527 #ifdef DEBUG
528 	__CTRACE("__set_color: %d, %d, %d\n", pair,
529 		 _cursesi_screen->colour_pairs[pair].fore,
530 		 _cursesi_screen->colour_pairs[pair].back);
531 #endif
532 	switch (_cursesi_screen->color_type) {
533 	/* Set ANSI forground and background colours */
534 	case COLOR_ANSI:
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(__parse_cap(_cursesi_screen->tc_AF,
540 			    _cursesi_screen->colour_pairs[pair].fore),
541 			    0, __cputchar);
542 		if (_cursesi_screen->colour_pairs[pair].back >= 0)
543 			tputs(__parse_cap(_cursesi_screen->tc_AB,
544 			    _cursesi_screen->colour_pairs[pair].back),
545 			    0, __cputchar);
546 		break;
547 	case COLOR_HP:
548 		/* XXX: need to support HP style */
549 		break;
550 	case COLOR_TEK:
551 		/* XXX: need to support Tek style */
552 		break;
553 	case COLOR_OTHER:
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(__parse_cap(_cursesi_screen->tc_Sf,
559 			    _cursesi_screen->colour_pairs[pair].fore),
560 			    0, __cputchar);
561 		if (_cursesi_screen->colour_pairs[pair].back >= 0)
562 			tputs(__parse_cap(_cursesi_screen->tc_Sb,
563 			    _cursesi_screen->colour_pairs[pair].back),
564 			    0, __cputchar);
565 		break;
566 	}
567 	curscr->wattr &= ~__COLOR;
568 	curscr->wattr |= attr & __COLOR;
569 }
570 
571 /*
572  * __unset_color --
573  *	Clear terminal foreground and background colours.
574  */
575 void
576 __unset_color(WINDOW *win)
577 {
578 #ifdef DEBUG
579 	__CTRACE("__unset_color\n");
580 #endif
581 	switch (_cursesi_screen->color_type) {
582 	/* Clear ANSI forground and background colours */
583 	case COLOR_ANSI:
584 		if (__tc_op != NULL) {
585 			tputs(__tc_op, 0, __cputchar);
586 			win->wattr &= __mask_op;
587 		}
588 		break;
589 	case COLOR_HP:
590 		/* XXX: need to support HP style */
591 		break;
592 	case COLOR_TEK:
593 		/* XXX: need to support Tek style */
594 		break;
595 	case COLOR_OTHER:
596 		if (__tc_op != NULL) {
597 			tputs(__tc_op, 0, __cputchar);
598 			win->wattr &= __mask_op;
599 		}
600 		break;
601 	}
602 }
603 
604 /*
605  * __restore_colors --
606  *	Redo color definitions after restarting 'curses' mode.
607  */
608 void
609 __restore_colors(void)
610 {
611 	if (__tc_cc != 0)
612 		switch (_cursesi_screen->color_type) {
613 		case COLOR_HP:
614 			/* XXX: need to re-initialise HP style (Ip) */
615 			break;
616 		case COLOR_TEK:
617 			/* XXX: need to re-initialise Tek style (Ic) */
618 			break;
619 		}
620 }
621 
622 /*
623  * __change_pair --
624  *	Mark dirty all positions using pair.
625  */
626 void
627 __change_pair(short pair)
628 {
629 	struct __winlist	*wlp;
630 	WINDOW			*win;
631 	int			 y, x;
632 	__LINE			*lp;
633 	uint32_t		cl = COLOR_PAIR(pair);
634 
635 
636 	for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
637 #ifdef DEBUG
638 		__CTRACE("__change_pair: win = %p\n", wlp->winp);
639 #endif
640 		win = wlp->winp;
641 		if (win == __virtscr)
642 			continue;
643 
644 		if (win == curscr) {
645 			/* Reset colour attribute on curscr */
646 #ifdef DEBUG
647 			__CTRACE("__change_pair: win == curscr\n");
648 #endif
649 			for (y = 0; y < curscr->maxy; y++) {
650 				lp = curscr->lines[y];
651 				for (x = 0; x < curscr->maxx; x++) {
652 					if ((lp->line[x].attr & __COLOR) == cl)
653 						lp->line[x].attr &= ~__COLOR;
654 					if ((lp->line[x].battr & __COLOR) == cl)
655 						lp->line[x].battr &= ~__COLOR;
656 				}
657 			}
658 			continue;
659 		}
660 
661 		/* Mark dirty those positions with colour pair "pair" */
662 		for (y = 0; y < win->maxy; y++) {
663 			lp = curscr->lines[y];
664 			for (x = 0; x < win->maxx; x++)
665 				if ((lp->line[x].attr & __COLOR) == cl ||
666 				    (lp->line[x].battr & __COLOR) == cl) {
667 					if (!(lp->flags & __ISDIRTY))
668 						lp->flags |= __ISDIRTY;
669 					/*
670 					 * firstchp/lastchp are shared
671 					 * between parent window and
672 					 * sub-window.
673 					 */
674 					if (*lp->firstchp > x)
675 						*lp->firstchp = x;
676 					if (*lp->lastchp < x)
677 						*lp->lastchp = x;
678 				}
679 #ifdef DEBUG
680 			if ((win->lines[y]->flags & __ISDIRTY))
681 				__CTRACE("__change_pair: first = %d, last = %d\n", *win->lines[y]->firstchp, *win->lines[y]->lastchp);
682 #endif
683 		}
684 	}
685 }
686