xref: /netbsd-src/lib/libcurses/color.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*	$NetBSD: color.c,v 1.34 2009/07/22 16:57:14 roy 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  *
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.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: color.c,v 1.34 2009/07/22 16:57:14 roy Exp $");
35 #endif				/* not lint */
36 
37 #include "curses.h"
38 #include "curses_private.h"
39 
40 /* Have we initialised colours? */
41 int	__using_color = 0;
42 
43 /* Default colour number */
44 attr_t	__default_color = 0;
45 
46 /* Default colour pair values - white on black. */
47 struct __pair	__default_pair = {COLOR_WHITE, COLOR_BLACK, 0};
48 
49 /* Default colour values */
50 /* Flags for colours and pairs */
51 #define	__USED		0x01
52 
53 static void
54 __change_pair(short);
55 
56 /*
57  * has_colors --
58  *	Check if terminal has colours.
59  */
60 bool
61 has_colors(void)
62 {
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);
69 }
70 
71 /*
72  * can_change_color --
73  *	Check if terminal can change colours.
74  */
75 bool
76 can_change_color(void)
77 {
78 	if (__tc_cc)
79 		return(TRUE);
80 	else
81 		return(FALSE);
82 }
83 
84 /*
85  * start_color --
86  *	Initialise colour support.
87  */
88 int
89 start_color(void)
90 {
91 	int			 i;
92 	attr_t			 temp_nc;
93 	struct __winlist	*wlp;
94 	WINDOW			*win;
95 	int			 y, x;
96 
97 	if (has_colors() == FALSE)
98 		return(ERR);
99 
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);
113 		}
114 	}
115 	if (!COLORS)
116 		return (ERR);
117 
118 	_cursesi_screen->COLORS = COLORS;
119 	_cursesi_screen->COLOR_PAIRS = COLOR_PAIRS;
120 
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;
127 	}
128 
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 */
140 
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;
157 	}
158 #endif
159 
160 	/*
161 	 * Attributes that cannot be used with color.
162 	 * Store these in an attr_t for wattrset()/wattron().
163 	 */
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;
185 	}
186 #ifdef DEBUG
187 	__CTRACE(__CTRACE_COLOR, "start_color: _cursesi_screen->nca = %08x\n",
188 	    _cursesi_screen->nca);
189 #endif
190 
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);
208 
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;
215 	}
216 
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;
221 
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;
227 	}
228 
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;
236 
237 	__using_color = 1;
238 
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;
249 				}
250 			}
251 			__touchwin(win);
252 		}
253 	}
254 
255 	return(OK);
256 }
257 
258 /*
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().
264  */
265 int
266 init_pair(short pair, short fore, short back)
267 {
268 	int	changed;
269 
270 #ifdef DEBUG
271 	__CTRACE(__CTRACE_COLOR, "init_pair: %d, %d, %d\n", pair, fore, back);
272 #endif
273 
274 	if (pair < 0 || pair >= COLOR_PAIRS)
275 		return (ERR);
276 	if (fore >= COLORS)
277 		return (ERR);
278 	if (back >= COLORS)
279 		return (ERR);
280 
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;
296 		}
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;
310 		}
311 	}
312 
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;
319 
320 	_cursesi_screen->colour_pairs[pair].flags |= __USED;
321 	_cursesi_screen->colour_pairs[pair].fore = fore;
322 	_cursesi_screen->colour_pairs[pair].back = back;
323 
324 	/* XXX: need to initialise HP style (Ip) */
325 
326 	if (changed)
327 		__change_pair(pair);
328 	return (OK);
329 }
330 
331 /*
332  * pair_content --
333  *	Get pair foreground and background colours.
334  */
335 int
336 pair_content(short pair, short *forep, short *backp)
337 {
338 	if (pair < 0 || pair > _cursesi_screen->COLOR_PAIRS)
339 		return(ERR);
340 
341 	*forep = _cursesi_screen->colour_pairs[pair].fore;
342 	*backp = _cursesi_screen->colour_pairs[pair].back;
343 
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;
359 		}
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;
373 		}
374 	}
375 	return(OK);
376 }
377 
378 /*
379  * init_color --
380  *	Set colour red, green and blue values.
381  */
382 int
383 init_color(short color, short red, short green, short blue)
384 {
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);
391 
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 */
398 }
399 
400 /*
401  * color_content --
402  *	Get colour red, green and blue values.
403  */
404 int
405 color_content(short color, short *redp, short *greenp, short *bluep)
406 {
407 	if (color < 0 || color >= _cursesi_screen->COLORS)
408 		return(ERR);
409 
410 	*redp = _cursesi_screen->colours[color].red;
411 	*greenp = _cursesi_screen->colours[color].green;
412 	*bluep = _cursesi_screen->colours[color].blue;
413 	return(OK);
414 }
415 
416 /*
417  * use_default_colors --
418  *	Use terminal default colours instead of curses default colour.
419   */
420 int
421 use_default_colors()
422 {
423 #ifdef DEBUG
424 	__CTRACE(__CTRACE_COLOR, "use_default_colors\n");
425 #endif
426 
427 	return(assume_default_colors(-1, -1));
428 }
429 
430 /*
431  * assume_default_colors --
432  *	Set the default foreground and background colours.
433  */
434 int
435 assume_default_colors(short fore, short back)
436 {
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;
456 		}
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;
470 		}
471 	}
472 	__default_pair.fore = fore;
473 	__default_pair.back = back;
474 	__default_pair.flags = __USED;
475 
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;
480 	}
481 
482 	/*
483 	 * If we've already called start_color(), make sure all instances
484 	 * of the curses default colour pair are dirty.
485 	 */
486 	if (__using_color)
487 		__change_pair(PAIR_NUMBER(__default_color));
488 
489 	return(OK);
490 }
491 
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
497 /*
498  * no_color_attributes --
499  *	Return attributes that cannot be combined with color.
500  */
501 attr_t
502 no_color_attributes(void)
503 {
504 	return(_cursesi_screen->nca);
505 }
506 
507 /*
508  * __set_color --
509  *	Set terminal foreground and background colours.
510  */
511 void
512 __set_color( /*ARGSUSED*/ WINDOW *win, attr_t attr)
513 {
514 	short	pair;
515 
516 	if ((curscr->wattr & __COLOR) == (attr & __COLOR))
517 		return;
518 
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;
559 	}
560 	curscr->wattr &= ~__COLOR;
561 	curscr->wattr |= attr & __COLOR;
562 }
563 
564 /*
565  * __unset_color --
566  *	Clear terminal foreground and background colours.
567  */
568 void
569 __unset_color(WINDOW *win)
570 {
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;
580 		}
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;
592 		}
593 		break;
594 	}
595 }
596 
597 /*
598  * __restore_colors --
599  *	Redo color definitions after restarting 'curses' mode.
600  */
601 void
602 __restore_colors(void)
603 {
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;
612 		}
613 }
614 
615 /*
616  * __change_pair --
617  *	Mark dirty all positions using pair.
618  */
619 void
620 __change_pair(short pair)
621 {
622 	struct __winlist	*wlp;
623 	WINDOW			*win;
624 	int			 y, x;
625 	__LINE			*lp;
626 	uint32_t		cl = COLOR_PAIR(pair);
627 
628 
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;
648 				}
649 			}
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;
659 						/*
660 					 	* firstchp/lastchp are shared
661 					 	* between parent window and
662 					 	* sub-window.
663 					 	*/
664 						if (*lp->firstchp > x)
665 						*lp->firstchp = x;
666 						if (*lp->lastchp < x)
667 							*lp->lastchp = x;
668 					}
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
677 			}
678 		}
679 	}
680 }
681