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