color.c revision 1.11 1 /* $NetBSD: color.c,v 1.11 2000/04/29 00:43:36 mycroft 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.11 2000/04/29 00:43:36 mycroft Exp $");
42 #endif /* not lint */
43
44 #include "curses.h"
45 #include "curses_private.h"
46
47 /* the following is defined and set up in setterm.c */
48 extern struct tinfo *_cursesi_genbuf;
49
50 /* Maximum colours */
51 #define MAX_COLORS 64
52 /* Maximum colour pairs - determined by number of colour bits in attr_t */
53 #define MAX_PAIRS 64 /* PAIR_NUMBER(__COLOR) + 1 */
54
55 /* Flags for colours and pairs */
56 #define __USED 0x01
57
58 /* List of colours */
59 struct color {
60 short num;
61 short red;
62 short green;
63 short blue;
64 int flags;
65 } colors[MAX_COLORS];
66
67 /* List of colour pairs */
68 struct pair {
69 short fore;
70 short back;
71 int flags;
72 } pairs[MAX_PAIRS];
73
74 /* Attributes that clash with colours */
75 attr_t __nca;
76
77 /* Style of colour manipulation */
78 #define COLOR_NONE 0
79 #define COLOR_ANSI 1 /* ANSI/DEC-style colour manipulation */
80 #define COLOR_HP 2 /* HP-style colour manipulation */
81 #define COLOR_TEK 3 /* Tektronix-style colour manipulation */
82 #define COLOR_OTHER 4 /* None of the others but can set fore/back */
83 int __color_type = COLOR_NONE;
84
85 static void
86 __change_pair __P((short));
87 /*
88 * has_colors --
89 * Check if terminal has colours.
90 */
91 bool
92 has_colors(void)
93 {
94 if (cO > 0)
95 return(TRUE);
96 else
97 return(FALSE);
98 }
99
100 /*
101 * can_change_colors --
102 * Check if terminal can change colours.
103 */
104 bool
105 can_change_colors(void)
106 {
107 if (CC)
108 return(TRUE);
109 else
110 return(FALSE);
111 }
112
113 /*
114 * start_color --
115 * Initialise colour support.
116 */
117 int
118 start_color(void)
119 {
120 int i;
121 attr_t temp_nc;
122
123 if (has_colors() == FALSE)
124 return(ERR);
125
126 /* Max colours and colour pairs */
127 if (cO == -1)
128 COLORS = 0;
129 else {
130 COLORS = cO > MAX_COLORS ? MAX_COLORS : cO;
131 if (PA == -1) {
132 COLOR_PAIRS = 0;
133 COLORS = 0;
134 } else {
135 COLOR_PAIRS = PA > MAX_PAIRS ? MAX_PAIRS : PA;
136 }
137 }
138 if (!COLORS)
139 return (ERR);
140
141 /* Reset terminal colour and colour pairs. */
142 if (OC != NULL)
143 tputs(OC, 0, __cputchar);
144 if (OP != NULL) {
145 tputs(OP, 0, __cputchar);
146 curscr->wattr &= __mask_OP;
147 }
148
149 /* Type of colour manipulation - ANSI/TEK/HP/other */
150 if (af != NULL && ab != NULL)
151 __color_type = COLOR_ANSI;
152 else if (iP != NULL)
153 __color_type = COLOR_HP;
154 else if (iC != NULL)
155 __color_type = COLOR_TEK;
156 else if (sB != NULL && sF != NULL)
157 __color_type = COLOR_OTHER;
158 else
159 return(ERR); /* Unsupported colour method */
160
161 #ifdef DEBUG
162 __CTRACE("start_color: COLORS = %d, COLOR_PAIRS = %d",
163 COLORS, COLOR_PAIRS);
164 switch (__color_type) {
165 case COLOR_ANSI:
166 __CTRACE(" (ANSI style)\n");
167 break;
168 case COLOR_HP:
169 __CTRACE(" (HP style)\n");
170 break;
171 case COLOR_TEK:
172 __CTRACE(" (Tektronics style)\n");
173 break;
174 case COLOR_OTHER:
175 __CTRACE(" (Other style)\n");
176 break;
177 }
178 #endif
179
180 /*
181 * Attributes that cannot be used with color.
182 * Store these in an attr_t for wattrset()/wattron().
183 */
184 __nca = __NORMAL;
185 if (nc != -1) {
186 temp_nc = (attr_t) t_getnum(_cursesi_genbuf, "NC");
187 if (temp_nc & 0x0001)
188 __nca |= __STANDOUT;
189 if (temp_nc & 0x0002)
190 __nca |= __UNDERSCORE;
191 if (temp_nc & 0x0004)
192 __nca |= __REVERSE;
193 if (temp_nc & 0x0008)
194 __nca |= __BLINK;
195 if (temp_nc & 0x0010)
196 __nca |= __DIM;
197 if (temp_nc & 0x0020)
198 __nca |= __BOLD;
199 if (temp_nc & 0x0040)
200 __nca |= __BLANK;
201 if (temp_nc & 0x0080)
202 __nca |= __PROTECT;
203 if (temp_nc & 0x0100)
204 __nca |= __ALTCHARSET;
205 }
206 #ifdef DEBUG
207 __CTRACE ("start_color: __nca = %d\n", __nca);
208 #endif
209
210 /* Set up initial 8 colours */
211 if (COLORS >= COLOR_BLACK)
212 (void) init_color(COLOR_BLACK, 0, 0, 0);
213 if (COLORS >= COLOR_RED)
214 (void) init_color(COLOR_RED, 1000, 0, 0);
215 if (COLORS >= COLOR_GREEN)
216 (void) init_color(COLOR_GREEN, 0, 1000, 0);
217 if (COLORS >= COLOR_YELLOW)
218 (void) init_color(COLOR_YELLOW, 1000, 1000, 0);
219 if (COLORS >= COLOR_BLUE)
220 (void) init_color(COLOR_BLUE, 0, 0, 1000);
221 if (COLORS >= COLOR_MAGENTA)
222 (void) init_color(COLOR_MAGENTA, 1000, 0, 1000);
223 if (COLORS >= COLOR_CYAN)
224 (void) init_color(COLOR_CYAN, 0, 1000, 1000);
225 if (COLORS >= COLOR_WHITE)
226 (void) init_color(COLOR_WHITE, 1000, 1000, 1000);
227
228 /* Initialise other colours */
229 for (i = 8; i < COLORS; i++) {
230 colors[i].red = 0;
231 colors[i].green = 0;
232 colors[i].blue = 0;
233 colors[i].flags = 0;
234 }
235
236 /* Initialise colour pairs to default (white on black) */
237 for (i = 0; i < COLOR_PAIRS; i++) {
238 pairs[i].fore = COLOR_WHITE;
239 pairs[i].back = COLOR_BLACK;
240 pairs[i].flags = 0;
241 }
242
243 return(OK);
244 }
245
246 /*
247 * init_pair --
248 * Set pair foreground and background colors.
249 */
250 int
251 init_pair(short pair, short fore, short back)
252 {
253 int changed;
254
255 #ifdef DEBUG
256 __CTRACE("init_pair: %d, %d, %d\n", pair, fore, back);
257 #endif
258
259 if (pair < 0 || pair >= COLOR_PAIRS)
260 return (ERR);
261 if (fore < 0 || fore >= COLORS)
262 return (ERR);
263 if (back < 0 || back >= COLORS)
264 return (ERR);
265
266 if ((pairs[pair].flags & __USED) && (fore != pairs[pair].fore ||
267 back != pairs[pair].back))
268 changed = 1;
269 else
270 changed = 0;
271
272 pairs[pair].flags |= __USED;
273 pairs[pair].fore = fore;
274 pairs[pair].back = back;
275
276 /* XXX: need to initialise HP style (iP) */
277
278 if (changed)
279 __change_pair(pair);
280 return (OK);
281 }
282
283 /*
284 * pair_content --
285 * Get pair foreground and background colours.
286 */
287 int
288 pair_content(short pair, short *forep, short *backp)
289 {
290 if (pair < 0 || pair >= COLOR_PAIRS)
291 return(ERR);
292
293 *forep = pairs[pair].fore;
294 *backp = pairs[pair].back;
295 return(OK);
296 }
297
298 /*
299 * init_color --
300 * Set colour red, green and blue values.
301 */
302 int
303 init_color(short color, short red, short green, short blue)
304 {
305 #ifdef DEBUG
306 __CTRACE("init_color: %d, %d, %d, %d\n", color, red, green, blue);
307 #endif
308 if (color < 0 || color >= COLORS)
309 return(ERR);
310
311 colors[color].red = red;
312 colors[color].green = green;
313 colors[color].blue = blue;
314 /* XXX Not yet implemented */
315 return(ERR);
316 /* XXX: need to initialise Tek style (iC) and support HLS */
317 }
318
319 /*
320 * color_content --
321 * Get colour red, green and blue values.
322 */
323 int
324 color_content(short color, short *redp, short *greenp, short *bluep)
325 {
326 if (color < 0 || color >= COLORS)
327 return(ERR);
328
329 *redp = colors[color].red;
330 *greenp = colors[color].green;
331 *bluep = colors[color].blue;
332 return(OK);
333 }
334
335 /*
336 * __set_color --
337 * Set terminal foreground and background colours.
338 */
339 void
340 __set_color(attr_t attr)
341 {
342 short pair;
343
344 pair = PAIR_NUMBER(attr);
345 #ifdef DEBUG
346 __CTRACE("__set_color: %d, %d, %d\n", pair, pairs[pair].fore,
347 pairs[pair].back);
348 #endif
349 switch (__color_type) {
350 /* Set ANSI forground and background colours */
351 case COLOR_ANSI:
352 tputs(__parse_cap(af, pairs[pair].fore), 0, __cputchar);
353 tputs(__parse_cap(ab, pairs[pair].back), 0, __cputchar);
354 break;
355 case COLOR_HP:
356 /* XXX: need to support HP style */
357 break;
358 case COLOR_TEK:
359 /* XXX: need to support Tek style */
360 break;
361 case COLOR_OTHER:
362 tputs(__parse_cap(sF, pairs[pair].fore), 0, __cputchar);
363 tputs(__parse_cap(sB, pairs[pair].back), 0, __cputchar);
364 break;
365 }
366 }
367
368 /*
369 * __restore_colors --
370 * Redo color definitions after restarting 'curses' mode.
371 */
372 void
373 __restore_colors(void)
374 {
375 if (CC != NULL)
376 switch (__color_type) {
377 case COLOR_HP:
378 /* XXX: need to re-initialise HP style (iP) */
379 break;
380 case COLOR_TEK:
381 /* XXX: need to re-initialise Tek style (iC) */
382 break;
383 }
384 }
385
386 /*
387 * __change_pair --
388 * Mark dirty all positions using pair.
389 */
390 void
391 __change_pair(short pair)
392 {
393 struct __winlist *wlp;
394 WINDOW *win;
395 int y, x;
396
397
398 for (wlp = __winlistp; wlp != NULL; wlp = wlp->nextp) {
399 #ifdef DEBUG
400 __CTRACE("__change_pair: win = %0.2o\n", wlp->winp);
401 #endif
402 if (wlp->winp == curscr) {
403 /* Reset colour attribute on curscr */
404 #ifdef DEBUG
405 __CTRACE("__change_pair: win == curscr\n");
406 #endif
407 for (y = 0; y < curscr->maxy; y++)
408 for (x = 0; x < curscr->maxx; x++)
409 if ((curscr->lines[y]->line[x].attr &
410 __COLOR) == COLOR_PAIR(pair))
411 curscr->lines[y]->line[x].attr
412 &= ~__COLOR;
413 } else {
414 /* Mark dirty those positions with color pair "pair" */
415 win = wlp->winp;
416 for (y = 0; y < win->maxy; y++) {
417 for (x = 0; x < win->maxx; x++)
418 if ((win->lines[y]->line[x].attr &
419 __COLOR) == COLOR_PAIR(pair)) {
420 if (!(win->lines[y]->flags &
421 __ISDIRTY))
422 win->lines[y]->flags |=
423 __ISDIRTY;
424 /*
425 * firstchp/lastchp are shared
426 * between parent window and
427 * sub-window.
428 */
429 if (*win->lines[y]->firstchp >
430 x)
431 *win->lines[y]->firstchp
432 = x;
433 if (*win->lines[y]->lastchp < x)
434 *win->lines[y]->lastchp
435 = x;
436 }
437 #ifdef DEBUG
438 if ((win->lines[y]->flags & __ISDIRTY))
439 __CTRACE("__change_pair: first = %d, last = %d\n", *win->lines[y]->firstchp, *win->lines[y]->lastchp);
440 #endif
441 }
442 }
443 }
444 }
445