1 /* Public Domain Curses */
2 
3 #include <curspriv.h>
4 
5 /*man-start**************************************************************
6 
7 color
8 -----
9 
10 ### Synopsis
11 
12     int start_color(void);
13     int init_pair(short pair, short fg, short bg);
14     int init_color(short color, short red, short green, short blue);
15     bool has_colors(void);
16     bool can_change_color(void);
17     int color_content(short color, short *red, short *green, short *blue);
18     int pair_content(short pair, short *fg, short *bg);
19 
20     int assume_default_colors(int f, int b);
21     int use_default_colors(void);
22 
23     int PDC_set_line_color(short color);
24 
25 ### Description
26 
27    To use these routines, start_color() must be called, usually
28    immediately after initscr(). Colors are always used in pairs,
29    referred to as color-pairs. A color-pair consists of a
30    foreground color and a background color. A color-pair is
31    initialized via init_pair(). After initialization, COLOR_PAIR(n)
32    can be used like any other video attribute.
33 
34    start_color() initializes eight basic colors (black, red, green,
35    yellow, blue, magenta, cyan, and white), and two global
36    variables; COLORS and COLOR_PAIRS (respectively defining the
37    maximum number of colors and color-pairs the terminal is capable
38    of displaying).
39 
40    init_pair() changes the definition of a color-pair. It takes
41    three arguments: the number of the color-pair to be redefined,
42    and the new values of the foreground and background colors. The
43    pair number must be between 0 and COLOR_PAIRS - 1, inclusive.
44    The foreground and background must be between 0 and COLORS - 1,
45    inclusive. If the color pair was previously initialized, the
46    screen is refreshed, and all occurrences of that color-pair are
47    changed to the new definition.
48 
49    has_colors() indicates if the terminal supports, and can
50    maniplulate color. It returns TRUE or FALSE.
51 
52    can_change_color() indicates if the terminal has the capability
53    to change the definition of its colors.
54 
55    pair_content() is used to determine what the colors of a given
56    color-pair consist of.
57 
58    assume_default_colors() and use_default_colors() emulate the
59    ncurses extensions of the same names. assume_default_colors(f,
60    b) is essentially the same as init_pair(0, f, b) (which isn't
61    allowed); it redefines the default colors. use_default_colors()
62    allows the use of -1 as a foreground or background color with
63    init_pair(), and calls assume_default_colors(-1, -1); -1
64    represents the foreground or background color that the terminal
65    had at startup. If the environment variable PDC_ORIGINAL_COLORS
66    is set at the time start_color() is called, that's equivalent to
67    calling use_default_colors().
68 
69    PDC_set_line_color() is used to set the color, globally, for
70    the color of the lines drawn for the attributes: A_UNDERLINE,
71    A_OVERLINE, A_LEFTLINE and A_RIGHTLINE. A value of -1 (the
72    default) indicates that the current foreground color should be
73    used.
74 
75    NOTE: COLOR_PAIR() and PAIR_NUMBER() are implemented as macros.
76 
77 ### Return Value
78 
79    All functions return OK on success and ERR on error, except for
80    has_colors() and can_change_colors(), which return TRUE or FALSE.
81 
82 ### Portability
83                              X/Open    BSD    SYS V
84     start_color                 Y       -      3.2
85     init_pair                   Y       -      3.2
86     init_color                  Y       -      3.2
87     has_colors                  Y       -      3.2
88     can_change_color            Y       -      3.2
89     color_content               Y       -      3.2
90     pair_content                Y       -      3.2
91     assume_default_colors       -       -       -
92     use_default_colors          -       -       -
93     PDC_set_line_color          -       -       -
94 
95 **man-end****************************************************************/
96 
97 #include <stdlib.h>
98 #include <string.h>
99 
100 int COLORS = 0;
101 int COLOR_PAIRS = PDC_COLOR_PAIRS;
102 
103 bool pdc_color_started = FALSE;
104 
105 /* pair_set[] tracks whether a pair has been set via init_pair() */
106 
107 static bool pair_set[PDC_COLOR_PAIRS];
108 static bool default_colors = FALSE;
109 static short first_col = 0;
110 
start_color(void)111 int start_color(void)
112 {
113     PDC_LOG(("start_color() - called\n"));
114 
115     if (SP->mono)
116         return ERR;
117 
118     pdc_color_started = TRUE;
119 
120     PDC_set_blink(FALSE);   /* Also sets COLORS */
121 
122     if (!default_colors && SP->orig_attr && getenv("PDC_ORIGINAL_COLORS"))
123         default_colors = TRUE;
124 
125     PDC_init_atrtab();
126 
127     memset(pair_set, 0, PDC_COLOR_PAIRS);
128 
129     return OK;
130 }
131 
_normalize(short * fg,short * bg)132 static void _normalize(short *fg, short *bg)
133 {
134     if (*fg == -1)
135         *fg = SP->orig_attr ? SP->orig_fore : COLOR_WHITE;
136 
137     if (*bg == -1)
138         *bg = SP->orig_attr ? SP->orig_back : COLOR_BLACK;
139 }
140 
init_pair(short pair,short fg,short bg)141 int init_pair(short pair, short fg, short bg)
142 {
143     PDC_LOG(("init_pair() - called: pair %d fg %d bg %d\n", pair, fg, bg));
144 
145     if (!pdc_color_started || pair < 1 || pair >= COLOR_PAIRS ||
146         fg < first_col || fg >= COLORS || bg < first_col || bg >= COLORS)
147         return ERR;
148 
149     _normalize(&fg, &bg);
150 
151     /* To allow the PDC_PRESERVE_SCREEN option to work, we only reset
152        curscr if this call to init_pair() alters a color pair created by
153        the user. */
154 
155     if (pair_set[pair])
156     {
157         short oldfg, oldbg;
158 
159         PDC_pair_content(pair, &oldfg, &oldbg);
160 
161         if (oldfg != fg || oldbg != bg)
162             curscr->_clear = TRUE;
163     }
164 
165     PDC_init_pair(pair, fg, bg);
166 
167     pair_set[pair] = TRUE;
168 
169     return OK;
170 }
171 
has_colors(void)172 bool has_colors(void)
173 {
174     PDC_LOG(("has_colors() - called\n"));
175 
176     return !(SP->mono);
177 }
178 
init_color(short color,short red,short green,short blue)179 int init_color(short color, short red, short green, short blue)
180 {
181     PDC_LOG(("init_color() - called\n"));
182 
183     if (color < 0 || color >= COLORS || !PDC_can_change_color() ||
184         red < 0 || red > 1000 || green < 0 || green > 1000 ||
185         blue < 0 || blue > 1000)
186         return ERR;
187 
188     return PDC_init_color(color, red, green, blue);
189 }
190 
color_content(short color,short * red,short * green,short * blue)191 int color_content(short color, short *red, short *green, short *blue)
192 {
193     PDC_LOG(("color_content() - called\n"));
194 
195     if (color < 0 || color >= COLORS || !red || !green || !blue)
196         return ERR;
197 
198     if (PDC_can_change_color())
199         return PDC_color_content(color, red, green, blue);
200     else
201     {
202         /* Simulated values for platforms that don't support palette
203            changing */
204 
205         short maxval = (color & 8) ? 1000 : 680;
206 
207         *red = (color & COLOR_RED) ? maxval : 0;
208         *green = (color & COLOR_GREEN) ? maxval : 0;
209         *blue = (color & COLOR_BLUE) ? maxval : 0;
210 
211         return OK;
212     }
213 }
214 
can_change_color(void)215 bool can_change_color(void)
216 {
217     PDC_LOG(("can_change_color() - called\n"));
218 
219     return PDC_can_change_color();
220 }
221 
pair_content(short pair,short * fg,short * bg)222 int pair_content(short pair, short *fg, short *bg)
223 {
224     PDC_LOG(("pair_content() - called\n"));
225 
226     if (pair < 0 || pair >= COLOR_PAIRS || !fg || !bg)
227         return ERR;
228 
229     return PDC_pair_content(pair, fg, bg);
230 }
231 
assume_default_colors(int f,int b)232 int assume_default_colors(int f, int b)
233 {
234     PDC_LOG(("assume_default_colors() - called: f %d b %d\n", f, b));
235 
236     if (f < -1 || f >= COLORS || b < -1 || b >= COLORS)
237         return ERR;
238 
239     if (pdc_color_started)
240     {
241         short fg, bg, oldfg, oldbg;
242 
243         fg = f;
244         bg = b;
245 
246         _normalize(&fg, &bg);
247 
248         PDC_pair_content(0, &oldfg, &oldbg);
249 
250         if (oldfg != fg || oldbg != bg)
251             curscr->_clear = TRUE;
252 
253         PDC_init_pair(0, fg, bg);
254     }
255 
256     return OK;
257 }
258 
use_default_colors(void)259 int use_default_colors(void)
260 {
261     PDC_LOG(("use_default_colors() - called\n"));
262 
263     default_colors = TRUE;
264     first_col = -1;
265 
266     return assume_default_colors(-1, -1);
267 }
268 
PDC_set_line_color(short color)269 int PDC_set_line_color(short color)
270 {
271     PDC_LOG(("PDC_set_line_color() - called: %d\n", color));
272 
273     if (color < -1 || color >= COLORS)
274         return ERR;
275 
276     SP->line_color = color;
277 
278     return OK;
279 }
280 
PDC_init_atrtab(void)281 void PDC_init_atrtab(void)
282 {
283     short i, fg, bg;
284 
285     if (pdc_color_started && !default_colors)
286     {
287         fg = COLOR_WHITE;
288         bg = COLOR_BLACK;
289     }
290     else
291         fg = bg = -1;
292 
293     _normalize(&fg, &bg);
294 
295     for (i = 0; i < PDC_COLOR_PAIRS; i++)
296         PDC_init_pair(i, fg, bg);
297 }
298