1 /* $OpenBSD: lib_vid_attr.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */
2
3 /****************************************************************************
4 * Copyright 2018-2020,2023 Thomas E. Dickey *
5 * Copyright 2002-2014,2017 Free Software Foundation, Inc. *
6 * *
7 * Permission is hereby granted, free of charge, to any person obtaining a *
8 * copy of this software and associated documentation files (the *
9 * "Software"), to deal in the Software without restriction, including *
10 * without limitation the rights to use, copy, modify, merge, publish, *
11 * distribute, distribute with modifications, sublicense, and/or sell *
12 * copies of the Software, and to permit persons to whom the Software is *
13 * furnished to do so, subject to the following conditions: *
14 * *
15 * The above copyright notice and this permission notice shall be included *
16 * in all copies or substantial portions of the Software. *
17 * *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
21 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
24 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
25 * *
26 * Except as contained in this notice, the name(s) of the above copyright *
27 * holders shall not be used in advertising or otherwise to promote the *
28 * sale, use or other dealings in this Software without prior written *
29 * authorization. *
30 ****************************************************************************/
31
32 /****************************************************************************
33 * Author: Thomas E. Dickey *
34 ****************************************************************************/
35
36 #include <curses.priv.h>
37
38 #ifndef CUR
39 #define CUR SP_TERMTYPE
40 #endif
41
42 MODULE_ID("$Id: lib_vid_attr.c,v 1.2 2023/10/17 09:52:09 nicm Exp $")
43
44 #define doPut(mode) \
45 TPUTS_TRACE(#mode); \
46 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx mode, 1, outc)
47
48 #define TurnOn(mask, mode) \
49 if ((turn_on & mask) && mode) { \
50 TPUTS_TRACE(#mode); \
51 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx mode, 1, outc); \
52 }
53
54 #define TurnOff(mask, mode) \
55 if ((turn_off & mask) && mode) { \
56 TPUTS_TRACE(#mode); \
57 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx mode, 1, outc); \
58 turn_off &= ~mask; \
59 }
60
61 /* if there is no current screen, assume we *can* do color */
62 #define SetColorsIf(why, old_attr, old_pair) \
63 if (can_color && (why)) { \
64 TR(TRACE_ATTRS, ("old pair = %d -- new pair = %d", old_pair, color_pair)); \
65 if ((color_pair != old_pair) \
66 || (fix_pair0 && (color_pair == 0)) \
67 || (reverse ^ ((old_attr & A_REVERSE) != 0))) { \
68 NCURSES_SP_NAME(_nc_do_color) (NCURSES_SP_ARGx \
69 old_pair, color_pair, \
70 reverse, outc); \
71 } \
72 }
73
74 #define set_color(mode, pair) \
75 mode &= ALL_BUT_COLOR; \
76 mode |= (attr_t) ColorPair(pair)
77
NCURSES_EXPORT(int)78 NCURSES_EXPORT(int)
79 NCURSES_SP_NAME(vid_puts) (NCURSES_SP_DCLx
80 attr_t newmode,
81 NCURSES_PAIRS_T pair_arg,
82 void *opts OPTIONAL_PAIR,
83 NCURSES_SP_OUTC outc)
84 {
85 int color_pair = pair_arg;
86 #if NCURSES_EXT_COLORS
87 static attr_t previous_attr = A_NORMAL;
88 static int previous_pair = 0;
89
90 attr_t turn_on, turn_off;
91 bool reverse = FALSE;
92 bool can_color = (SP_PARM == 0 || SP_PARM->_coloron);
93 #if NCURSES_EXT_FUNCS
94 bool fix_pair0 = (SP_PARM != 0 && SP_PARM->_coloron && !SP_PARM->_default_color);
95 #else
96 #define fix_pair0 FALSE
97 #endif
98
99 if (!IsValidTIScreen(SP_PARM))
100 returnCode(ERR);
101
102 newmode &= A_ATTRIBUTES;
103 set_extended_pair(opts, color_pair);
104 T((T_CALLED("vid_puts(%s,%d)"), _traceattr(newmode), color_pair));
105
106 /* this allows us to go on whether or not newterm() has been called */
107 if (SP_PARM) {
108 previous_attr = AttrOf(SCREEN_ATTRS(SP_PARM));
109 previous_pair = GetPair(SCREEN_ATTRS(SP_PARM));
110 }
111
112 TR(TRACE_ATTRS, ("previous attribute was %s, %d",
113 _traceattr(previous_attr), previous_pair));
114
115 #if !USE_XMC_SUPPORT
116 if ((SP_PARM != 0)
117 && (magic_cookie_glitch > 0))
118 newmode &= ~(SP_PARM->_xmc_suppress);
119 #endif
120
121 /*
122 * If we have a terminal that cannot combine color with video
123 * attributes, use the colors in preference.
124 */
125 if ((color_pair != 0
126 || fix_pair0)
127 && (no_color_video > 0)) {
128 /*
129 * If we had chosen the A_xxx definitions to correspond to the
130 * no_color_video mask, we could simply shift it up and mask off the
131 * attributes. But we did not (actually copied Solaris' definitions).
132 * However, this is still simpler/faster than a lookup table.
133 *
134 * The 63 corresponds to A_STANDOUT, A_UNDERLINE, A_REVERSE, A_BLINK,
135 * A_DIM, A_BOLD which are 1:1 with no_color_video. The bits that
136 * correspond to A_INVIS, A_PROTECT (192) must be shifted up 1 and
137 * A_ALTCHARSET (256) down 2 to line up. We use the NCURSES_BITS
138 * macro so this will work properly for the wide-character layout.
139 */
140 unsigned value = (unsigned) no_color_video;
141 attr_t mask = NCURSES_BITS((value & 63)
142 | ((value & 192) << 1)
143 | ((value & 256) >> 2), 8);
144
145 if ((mask & A_REVERSE) != 0
146 && (newmode & A_REVERSE) != 0) {
147 reverse = TRUE;
148 mask &= ~A_REVERSE;
149 }
150 newmode &= ~mask;
151 }
152
153 if (newmode == previous_attr
154 && color_pair == previous_pair)
155 returnCode(OK);
156
157 if (reverse) {
158 newmode &= ~A_REVERSE;
159 }
160
161 turn_off = (~newmode & previous_attr) & ALL_BUT_COLOR;
162 turn_on = (newmode & ~(previous_attr & TPARM_ATTR)) & ALL_BUT_COLOR;
163
164 SetColorsIf(((color_pair == 0) && !fix_pair0), previous_attr, previous_pair);
165
166 if (newmode == A_NORMAL) {
167 if ((previous_attr & A_ALTCHARSET) && exit_alt_charset_mode) {
168 doPut(exit_alt_charset_mode);
169 previous_attr &= ~A_ALTCHARSET;
170 }
171 if (previous_attr) {
172 if (exit_attribute_mode) {
173 doPut(exit_attribute_mode);
174 } else {
175 if (!SP_PARM || SP_PARM->_use_rmul) {
176 TurnOff(A_UNDERLINE, exit_underline_mode);
177 }
178 if (!SP_PARM || SP_PARM->_use_rmso) {
179 TurnOff(A_STANDOUT, exit_standout_mode);
180 }
181 #if USE_ITALIC
182 if (!SP_PARM || SP_PARM->_use_ritm) {
183 TurnOff(A_ITALIC, exit_italics_mode);
184 }
185 #endif
186 (void) turn_off;
187 }
188 previous_attr &= ALL_BUT_COLOR;
189 previous_pair = 0;
190 }
191
192 SetColorsIf((color_pair != 0) || fix_pair0, previous_attr, previous_pair);
193 } else if (set_attributes) {
194 if (turn_on || turn_off) {
195 TPUTS_TRACE("set_attributes");
196 NCURSES_SP_NAME(tputs) (NCURSES_SP_ARGx
197 TIPARM_9(set_attributes,
198 (newmode & A_STANDOUT) != 0,
199 (newmode & A_UNDERLINE) != 0,
200 (newmode & A_REVERSE) != 0,
201 (newmode & A_BLINK) != 0,
202 (newmode & A_DIM) != 0,
203 (newmode & A_BOLD) != 0,
204 (newmode & A_INVIS) != 0,
205 (newmode & A_PROTECT) != 0,
206 (newmode & A_ALTCHARSET) != 0),
207 1, outc);
208 previous_attr &= ALL_BUT_COLOR;
209 previous_pair = 0;
210 }
211 #if USE_ITALIC
212 if (!SP_PARM || SP_PARM->_use_ritm) {
213 if (turn_on & A_ITALIC) {
214 TurnOn(A_ITALIC, enter_italics_mode);
215 } else if (turn_off & A_ITALIC) {
216 TurnOff(A_ITALIC, exit_italics_mode);
217 }
218 (void) turn_off;
219 }
220 #endif
221 SetColorsIf((color_pair != 0) || fix_pair0, previous_attr, previous_pair);
222 } else {
223
224 TR(TRACE_ATTRS, ("turning %s off", _traceattr(turn_off)));
225
226 TurnOff(A_ALTCHARSET, exit_alt_charset_mode);
227
228 if (!SP_PARM || SP_PARM->_use_rmul) {
229 TurnOff(A_UNDERLINE, exit_underline_mode);
230 }
231
232 if (!SP_PARM || SP_PARM->_use_rmso) {
233 TurnOff(A_STANDOUT, exit_standout_mode);
234 }
235 #if USE_ITALIC
236 if (!SP_PARM || SP_PARM->_use_ritm) {
237 TurnOff(A_ITALIC, exit_italics_mode);
238 }
239 #endif
240 if (turn_off && exit_attribute_mode) {
241 doPut(exit_attribute_mode);
242 turn_on |= (newmode & ALL_BUT_COLOR);
243 previous_attr &= ALL_BUT_COLOR;
244 previous_pair = 0;
245 }
246 SetColorsIf((color_pair != 0) || fix_pair0, previous_attr, previous_pair);
247
248 TR(TRACE_ATTRS, ("turning %s on", _traceattr(turn_on)));
249 /* *INDENT-OFF* */
250 TurnOn(A_ALTCHARSET, enter_alt_charset_mode);
251 TurnOn(A_BLINK, enter_blink_mode);
252 TurnOn(A_BOLD, enter_bold_mode);
253 TurnOn(A_DIM, enter_dim_mode);
254 TurnOn(A_REVERSE, enter_reverse_mode);
255 TurnOn(A_STANDOUT, enter_standout_mode);
256 TurnOn(A_PROTECT, enter_protected_mode);
257 TurnOn(A_INVIS, enter_secure_mode);
258 TurnOn(A_UNDERLINE, enter_underline_mode);
259 #if USE_ITALIC
260 TurnOn(A_ITALIC, enter_italics_mode);
261 #endif
262 #if USE_WIDEC_SUPPORT && defined(enter_horizontal_hl_mode)
263 TurnOn(A_HORIZONTAL, enter_horizontal_hl_mode);
264 TurnOn(A_LEFT, enter_left_hl_mode);
265 TurnOn(A_LOW, enter_low_hl_mode);
266 TurnOn(A_RIGHT, enter_right_hl_mode);
267 TurnOn(A_TOP, enter_top_hl_mode);
268 TurnOn(A_VERTICAL, enter_vertical_hl_mode);
269 #endif
270 /* *INDENT-ON* */
271 }
272
273 if (reverse)
274 newmode |= A_REVERSE;
275
276 if (SP_PARM) {
277 SetAttr(SCREEN_ATTRS(SP_PARM), newmode);
278 SetPair(SCREEN_ATTRS(SP_PARM), color_pair);
279 } else {
280 previous_attr = newmode;
281 previous_pair = color_pair;
282 }
283
284 returnCode(OK);
285 #else
286 T((T_CALLED("vid_puts(%s,%d)"), _traceattr(newmode), color_pair));
287 (void) opts;
288 set_color(newmode, color_pair);
289 returnCode(NCURSES_SP_NAME(vidputs) (NCURSES_SP_ARGx newmode, outc));
290 #endif
291 }
292
293 #if NCURSES_SP_FUNCS
294 NCURSES_EXPORT(int)
vid_puts(attr_t newmode,NCURSES_PAIRS_T pair_arg,void * opts GCC_UNUSED,NCURSES_OUTC outc)295 vid_puts(attr_t newmode,
296 NCURSES_PAIRS_T pair_arg,
297 void *opts GCC_UNUSED,
298 NCURSES_OUTC outc)
299 {
300 SetSafeOutcWrapper(outc);
301 return NCURSES_SP_NAME(vid_puts) (CURRENT_SCREEN,
302 newmode,
303 pair_arg,
304 opts,
305 _nc_outc_wrapper);
306 }
307 #endif
308
309 #undef vid_attr
310 NCURSES_EXPORT(int)
NCURSES_SP_NAME(vid_attr)311 NCURSES_SP_NAME(vid_attr) (NCURSES_SP_DCLx
312 attr_t newmode,
313 NCURSES_PAIRS_T pair_arg,
314 void *opts)
315 {
316 T((T_CALLED("vid_attr(%s,%d)"), _traceattr(newmode), (int) pair_arg));
317 returnCode(NCURSES_SP_NAME(vid_puts) (NCURSES_SP_ARGx
318 newmode,
319 pair_arg,
320 opts,
321 NCURSES_SP_NAME(_nc_putchar)));
322 }
323
324 #if NCURSES_SP_FUNCS
325 NCURSES_EXPORT(int)
vid_attr(attr_t newmode,NCURSES_PAIRS_T pair_arg,void * opts)326 vid_attr(attr_t newmode, NCURSES_PAIRS_T pair_arg, void *opts)
327 {
328 return NCURSES_SP_NAME(vid_attr) (CURRENT_SCREEN, newmode, pair_arg, opts);
329 }
330 #endif
331
332 /*
333 * This implementation uses the same mask values for A_xxx and WA_xxx, so
334 * we can use termattrs() for part of the logic.
335 */
336 NCURSES_EXPORT(attr_t)
NCURSES_SP_NAME(term_attrs)337 NCURSES_SP_NAME(term_attrs) (NCURSES_SP_DCL0)
338 {
339 attr_t attrs = 0;
340
341 T((T_CALLED("term_attrs()")));
342 if (SP_PARM) {
343 attrs = NCURSES_SP_NAME(termattrs) (NCURSES_SP_ARG);
344
345 #if USE_WIDEC_SUPPORT && defined(enter_horizontal_hl_mode)
346 /* these are only supported for wide-character mode */
347 if (enter_horizontal_hl_mode)
348 attrs |= WA_HORIZONTAL;
349 if (enter_left_hl_mode)
350 attrs |= WA_LEFT;
351 if (enter_low_hl_mode)
352 attrs |= WA_LOW;
353 if (enter_right_hl_mode)
354 attrs |= WA_RIGHT;
355 if (enter_top_hl_mode)
356 attrs |= WA_TOP;
357 if (enter_vertical_hl_mode)
358 attrs |= WA_VERTICAL;
359 #endif
360 }
361
362 returnAttr(attrs);
363 }
364
365 #if NCURSES_SP_FUNCS
366 NCURSES_EXPORT(attr_t)
term_attrs(void)367 term_attrs(void)
368 {
369 return NCURSES_SP_NAME(term_attrs) (CURRENT_SCREEN);
370 }
371 #endif
372