xref: /netbsd-src/lib/libcurses/color.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: color.c,v 1.33 2008/04/28 20:23:01 martin 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.33 2008/04/28 20:23:01 martin 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->lines[y]->line[x].attr &= ~__COLOR;
248 					win->lines[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 /*
493  * no_color_video --
494  *	Return attributes that cannot be combined with color.
495  */
496 attr_t
497 no_color_video(void)
498 {
499 	return(_cursesi_screen->nca);
500 }
501 
502 /*
503  * __set_color --
504  *	Set terminal foreground and background colours.
505  */
506 void
507 __set_color( /*ARGSUSED*/ WINDOW *win, attr_t attr)
508 {
509 	short	pair;
510 
511 	if ((curscr->wattr & __COLOR) == (attr & __COLOR))
512 		return;
513 
514 	pair = PAIR_NUMBER((u_int32_t)attr);
515 #ifdef DEBUG
516 	__CTRACE(__CTRACE_COLOR, "__set_color: %d, %d, %d\n", pair,
517 		 _cursesi_screen->colour_pairs[pair].fore,
518 		 _cursesi_screen->colour_pairs[pair].back);
519 #endif
520 	switch (_cursesi_screen->color_type) {
521 	/* Set ANSI forground and background colours */
522 	case COLOR_ANSI:
523 		if (_cursesi_screen->colour_pairs[pair].fore < 0 ||
524 		    _cursesi_screen->colour_pairs[pair].back < 0)
525 			__unset_color(curscr);
526 		if (_cursesi_screen->colour_pairs[pair].fore >= 0)
527 			tputs(__parse_cap(_cursesi_screen->tc_AF,
528 			    _cursesi_screen->colour_pairs[pair].fore),
529 			    0, __cputchar);
530 		if (_cursesi_screen->colour_pairs[pair].back >= 0)
531 			tputs(__parse_cap(_cursesi_screen->tc_AB,
532 			    _cursesi_screen->colour_pairs[pair].back),
533 			    0, __cputchar);
534 		break;
535 	case COLOR_HP:
536 		/* XXX: need to support HP style */
537 		break;
538 	case COLOR_TEK:
539 		/* XXX: need to support Tek style */
540 		break;
541 	case COLOR_OTHER:
542 		if (_cursesi_screen->colour_pairs[pair].fore < 0 ||
543 		    _cursesi_screen->colour_pairs[pair].back < 0)
544 			__unset_color(curscr);
545 		if (_cursesi_screen->colour_pairs[pair].fore >= 0)
546 			tputs(__parse_cap(_cursesi_screen->tc_Sf,
547 			    _cursesi_screen->colour_pairs[pair].fore),
548 			    0, __cputchar);
549 		if (_cursesi_screen->colour_pairs[pair].back >= 0)
550 			tputs(__parse_cap(_cursesi_screen->tc_Sb,
551 			    _cursesi_screen->colour_pairs[pair].back),
552 			    0, __cputchar);
553 		break;
554 	}
555 	curscr->wattr &= ~__COLOR;
556 	curscr->wattr |= attr & __COLOR;
557 }
558 
559 /*
560  * __unset_color --
561  *	Clear terminal foreground and background colours.
562  */
563 void
564 __unset_color(WINDOW *win)
565 {
566 #ifdef DEBUG
567 	__CTRACE(__CTRACE_COLOR, "__unset_color\n");
568 #endif
569 	switch (_cursesi_screen->color_type) {
570 	/* Clear ANSI forground and background colours */
571 	case COLOR_ANSI:
572 		if (__tc_op != NULL) {
573 			tputs(__tc_op, 0, __cputchar);
574 			win->wattr &= __mask_op;
575 		}
576 		break;
577 	case COLOR_HP:
578 		/* XXX: need to support HP style */
579 		break;
580 	case COLOR_TEK:
581 		/* XXX: need to support Tek style */
582 		break;
583 	case COLOR_OTHER:
584 		if (__tc_op != NULL) {
585 			tputs(__tc_op, 0, __cputchar);
586 			win->wattr &= __mask_op;
587 		}
588 		break;
589 	}
590 }
591 
592 /*
593  * __restore_colors --
594  *	Redo color definitions after restarting 'curses' mode.
595  */
596 void
597 __restore_colors(void)
598 {
599 	if (__tc_cc != 0)
600 		switch (_cursesi_screen->color_type) {
601 		case COLOR_HP:
602 			/* XXX: need to re-initialise HP style (Ip) */
603 			break;
604 		case COLOR_TEK:
605 			/* XXX: need to re-initialise Tek style (Ic) */
606 			break;
607 		}
608 }
609 
610 /*
611  * __change_pair --
612  *	Mark dirty all positions using pair.
613  */
614 void
615 __change_pair(short pair)
616 {
617 	struct __winlist	*wlp;
618 	WINDOW			*win;
619 	int			 y, x;
620 	__LINE			*lp;
621 	uint32_t		cl = COLOR_PAIR(pair);
622 
623 
624 	for (wlp = _cursesi_screen->winlistp; wlp != NULL; wlp = wlp->nextp) {
625 #ifdef DEBUG
626 		__CTRACE(__CTRACE_COLOR, "__change_pair: win = %p\n",
627 		    wlp->winp);
628 #endif
629 		win = wlp->winp;
630 		if (win == __virtscr)
631 			continue;
632 		else if (win == curscr) {
633 			/* Reset colour attribute on curscr */
634 #ifdef DEBUG
635 			__CTRACE(__CTRACE_COLOR,
636 			    "__change_pair: win == curscr\n");
637 #endif
638 			for (y = 0; y < curscr->maxy; y++) {
639 				lp = curscr->lines[y];
640 				for (x = 0; x < curscr->maxx; x++) {
641 					if ((lp->line[x].attr & __COLOR) == cl)
642 						lp->line[x].attr &= ~__COLOR;
643 				}
644 			}
645 		} else {
646 			/* Mark dirty those positions with colour pair "pair" */
647 			for (y = 0; y < win->maxy; y++) {
648 				lp = win->lines[y];
649 				for (x = 0; x < win->maxx; x++)
650 					if ((lp->line[x].attr &
651 					    __COLOR) == cl) {
652 						if (!(lp->flags & __ISDIRTY))
653 							lp->flags |= __ISDIRTY;
654 						/*
655 					 	* firstchp/lastchp are shared
656 					 	* between parent window and
657 					 	* sub-window.
658 					 	*/
659 						if (*lp->firstchp > x)
660 						*lp->firstchp = x;
661 						if (*lp->lastchp < x)
662 							*lp->lastchp = x;
663 					}
664 #ifdef DEBUG
665 				if ((win->lines[y]->flags & __ISDIRTY))
666 					__CTRACE(__CTRACE_COLOR,
667 					    "__change_pair: first = %d, "
668 					    "last = %d\n",
669 					    *win->lines[y]->firstchp,
670 					    *win->lines[y]->lastchp);
671 #endif
672 			}
673 		}
674 	}
675 }
676