xref: /netbsd-src/lib/libcurses/attributes.c (revision 6348e3f32a4431b45d07e1da16fd7b12725a45e7)
1 /*	$NetBSD: attributes.c,v 1.36 2024/12/23 02:58:03 blymn Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 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: attributes.c,v 1.36 2024/12/23 02:58:03 blymn Exp $");
35 #endif				/* not lint */
36 
37 #include "curses.h"
38 #include "curses_private.h"
39 
40 static int __wattr_off(WINDOW *, attr_t);
41 static int __wattr_on(WINDOW *, attr_t);
42 static void __wcolor_set(WINDOW *, attr_t);
43 
44 
45 #ifndef _CURSES_USE_MACROS
46 #ifdef HAVE_WCHAR
47 /*
48  * attr_get --
49  *	Get wide attributes and color pair from stdscr
50  */
51 /* ARGSUSED */
52 int
53 attr_get(attr_t *attr, short *pair, void *opts)
54 {
55 	return wattr_get(stdscr, attr, pair, opts);
56 }
57 
58 /*
59  * attr_on --
60  *	Test and set wide attributes on stdscr
61  */
62 /* ARGSUSED */
63 int
64 attr_on(attr_t attr, void *opts)
65 {
66 	return wattr_on(stdscr, attr, opts);
67 }
68 
69 /*
70  * attr_off --
71  *	Test and unset wide attributes on stdscr
72  */
73 /* ARGSUSED */
74 int
75 attr_off(attr_t attr, void *opts)
76 {
77 	return wattr_off(stdscr, attr, opts);
78 }
79 
80 /*
81  * attr_set --
82  *	Set wide attributes and color pair on stdscr
83  */
84 /* ARGSUSED */
85 int
86 attr_set(attr_t attr, short pair, void *opts)
87 {
88 	return wattr_set(stdscr, attr, pair, opts);
89 }
90 
91 /*
92  * color_set --
93  *	Set color pair on stdscr
94  */
95 /* ARGSUSED */
96 int
97 color_set(short pair, void *opts)
98 {
99 	return wcolor_set(stdscr, pair, opts);
100 }
101 #endif /* HAVE_WCHAR */
102 
103 /*
104  * attron --
105  *	Test and set attributes on stdscr
106  */
107 int
108 attron(int attr)
109 {
110 	return wattron(stdscr, attr);
111 }
112 
113 /*
114  * attroff --
115  *	Test and unset attributes on stdscr.
116  */
117 int
118 attroff(int attr)
119 {
120 	return wattroff(stdscr, attr);
121 }
122 
123 /*
124  * attrset --
125  *	Set specific attribute modes.
126  *	Unset others.  On stdscr.
127  */
128 int
129 attrset(int attr)
130 {
131 	return wattrset(stdscr, attr);
132 }
133 #endif	/* _CURSES_USE_MACROS */
134 
135 
136 #ifdef HAVE_WCHAR
137 /*
138  * wattr_get --
139  *	Get wide attributes and colour pair from window
140  *	Note that attributes also includes colour.
141  */
142 /* ARGSUSED */
143 int
144 wattr_get(WINDOW *win, attr_t *attr, short *pair, void *opts)
145 {
146 	if (__predict_false(win == NULL))
147 		return ERR;
148 
149 	__CTRACE(__CTRACE_ATTR, "wattr_get: win %p\n", win);
150 	if (attr != NULL) {
151 		*attr = win->wattr;
152 #ifdef HAVE_WCHAR
153 		*attr &= WA_ATTRIBUTES;
154 #endif
155 	}
156 
157 	if (pair != NULL)
158 		*pair = PAIR_NUMBER(win->wattr);
159 	return OK;
160 }
161 
162 /*
163  * wattr_on --
164  *	Test and set wide attributes on window
165  */
166 int
167 wattr_on(WINDOW *win, attr_t attr, void *opts)
168 {
169 	if (__predict_false(opts != NULL))
170 		return ERR;
171 
172 	return __wattr_on(win, attr);
173 }
174 
175 /*
176  * wattr_off --
177  *	Test and unset wide attributes on window
178  *
179  *	Note that the 'me' sequence unsets all attributes.  We handle
180  *	which attributes should really be set in refresh.c:makech().
181  */
182 int
183 wattr_off(WINDOW *win, attr_t attr, void *opts)
184 {
185 	if (__predict_false(opts != NULL))
186 		return ERR;
187 
188 	return __wattr_off(win, attr);
189 }
190 
191 
192 /*
193  * wattr_set --
194  *	Set wide attributes and color pair on window
195  */
196 int
197 wattr_set(WINDOW *win, attr_t attr, short pair, void *opts)
198 {
199 	__CTRACE(__CTRACE_ATTR, "wattr_set: win %p, attr %08x, pair %d\n",
200 	    win, attr, pair);
201 
202 	if (__predict_false(opts != NULL))
203 		return ERR;
204 
205 	/*
206 	 * This overwrites any colour setting from the attributes
207 	 * and is compatible with ncurses.
208 	 */
209 	attr = (attr & ~__COLOR) | COLOR_PAIR(pair);
210 
211 	__wattr_off(win, WA_ATTRIBUTES);
212 	__wattr_on(win, attr);
213 	return OK;
214 }
215 
216 /*
217  * wcolor_set --
218  *	Set color pair on window
219  */
220 /* ARGSUSED */
221 int
222 wcolor_set(WINDOW *win, short pair, void *opts)
223 {
224 	__CTRACE(__CTRACE_COLOR, "wolor_set: win %p, pair %d\n", win, pair);
225 
226 	if (__predict_false(opts != NULL))
227 		return ERR;
228 
229 	__wcolor_set(win, (attr_t) COLOR_PAIR(pair));
230 	return OK;
231 }
232 #endif /* HAVE_WCHAR */
233 
234 
235 /*
236  * getattrs --
237  *	Get window attributes.
238  */
239 chtype
240 getattrs(WINDOW *win)
241 {
242 	if (__predict_false(win == NULL))
243 		return ERR;
244 
245 	__CTRACE(__CTRACE_ATTR, "getattrs: win %p\n", win);
246 	return((chtype) win->wattr);
247 }
248 
249 /*
250  * wattron --
251  *	Test and set attributes.
252  */
253 int
254 wattron(WINDOW *win, int attr)
255 {
256 	__CTRACE(__CTRACE_ATTR, "wattron: win %p, attr %08x\n", win, attr);
257 	return __wattr_on(win, (attr_t) attr);
258 }
259 
260 /*
261  * wattroff --
262  *	Test and unset attributes.
263  */
264 int
265 wattroff(WINDOW *win, int attr)
266 {
267 	__CTRACE(__CTRACE_ATTR, "wattroff: win %p, attr %08x\n", win, attr);
268 	return __wattr_off(win, (attr_t) attr);
269 }
270 
271 /*
272  * wattrset --
273  *	Set specific attribute modes.
274  *	Unset others.
275  */
276 int
277 wattrset(WINDOW *win, int attr)
278 {
279 	__CTRACE(__CTRACE_ATTR, "wattrset: win %p, attr %08x\n", win, attr);
280 	__wattr_off(win, __ATTRIBUTES);
281 	__wattr_on(win, (attr_t) attr);
282 	return OK;
283 }
284 
285 /*
286  * termattrs --
287  *	Get terminal attributes
288  */
289 chtype
290 termattrs(void)
291 {
292 	chtype ch = 0;
293 
294 	__CTRACE(__CTRACE_ATTR, "termattrs\n");
295 	if (exit_attribute_mode != NULL) {
296 	__CTRACE(__CTRACE_ATTR, "termattrs: have exit attribute mode\n");
297 		if (enter_blink_mode != NULL)
298 			ch |= __BLINK;
299 		if (enter_bold_mode != NULL)
300 			ch |= __BOLD;
301 		if (enter_dim_mode != NULL)
302 			ch |= __DIM;
303 		if (enter_secure_mode != NULL)
304 			ch |= __BLANK;
305 		if (enter_protected_mode != NULL)
306 			ch |= __PROTECT;
307 		if (enter_reverse_mode != NULL)
308 			ch |= __REVERSE;
309 	}
310 	if (enter_standout_mode != NULL && exit_standout_mode != NULL)
311 		ch |= __STANDOUT;
312 	if (enter_underline_mode != NULL && exit_underline_mode != NULL)
313 		ch |= __UNDERSCORE;
314 	if (enter_alt_charset_mode != NULL && exit_alt_charset_mode != NULL)
315 		ch |= __ALTCHARSET;
316 
317 	return ch;
318 }
319 
320 
321 #ifdef HAVE_WCHAR
322 /*
323  * term_attrs --
324  *	Get terminal wide attributes
325  */
326 attr_t
327 term_attrs(void)
328 {
329 	attr_t attr = 0;
330 
331 	__CTRACE(__CTRACE_ATTR, "term_attrs\n");
332 	if (exit_attribute_mode != NULL) {
333 		if (enter_blink_mode != NULL)
334 			attr |= __BLINK;
335 		if (enter_bold_mode != NULL)
336 			attr |= __BOLD;
337 		if (enter_dim_mode != NULL)
338 			attr |= __DIM;
339 		if (enter_secure_mode != NULL)
340 			attr |= __BLANK;
341 		if (enter_protected_mode != NULL)
342 			attr |= __PROTECT;
343 		if (enter_reverse_mode != NULL)
344 			attr |= __REVERSE;
345 #ifdef HAVE_WCHAR
346 		if (enter_low_hl_mode != NULL)
347 			attr |= WA_LOW;
348 		if (enter_top_hl_mode != NULL)
349 			attr |= WA_TOP;
350 		if (enter_left_hl_mode != NULL)
351 			attr |= WA_LEFT;
352 		if (enter_right_hl_mode != NULL)
353 			attr |= WA_RIGHT;
354 		if (enter_horizontal_hl_mode != NULL)
355 			attr |= WA_HORIZONTAL;
356 		if (enter_vertical_hl_mode != NULL)
357 			attr |= WA_VERTICAL;
358 #endif /* HAVE_WCHAR */
359 	}
360 	if (enter_standout_mode != NULL && exit_standout_mode != NULL)
361 		attr |= __STANDOUT;
362 	if (enter_underline_mode != NULL && exit_underline_mode != NULL)
363 		attr |= __UNDERSCORE;
364 	if (enter_alt_charset_mode != NULL && exit_alt_charset_mode != NULL)
365 		attr |= __ALTCHARSET;
366 
367 	return attr;
368 }
369 #endif /* HAVE_WCHAR */
370 
371 
372 static int
373 __wattr_on(WINDOW *win, attr_t attr)
374 {
375 	const TERMINAL *t;
376 
377 	if (__predict_false(win == NULL))
378 		return ERR;
379 
380 	t = win->screen->term;
381 
382 	__CTRACE(__CTRACE_ATTR, "wattr_on: win %p, attr %08x\n", win, attr);
383 	/* If can enter modes, set the relevant attribute bits. */
384 	if (t_exit_attribute_mode(t) != NULL) {
385 		if (attr & __BLINK && t_enter_blink_mode(t) != NULL)
386 			win->wattr |= __BLINK;
387 		if (attr & __BOLD && t_enter_bold_mode(t) != NULL)
388 			win->wattr |= __BOLD;
389 		if (attr & __DIM && t_enter_dim_mode(t) != NULL)
390 			win->wattr |= __DIM;
391 		if (attr & __BLANK && t_enter_secure_mode(t) != NULL)
392 			win->wattr |= __BLANK;
393 		if (attr & __PROTECT && t_enter_protected_mode(t) != NULL)
394 			win->wattr |= __PROTECT;
395 		if (attr & __REVERSE && t_enter_reverse_mode(t) != NULL)
396 			win->wattr |= __REVERSE;
397 #ifdef HAVE_WCHAR
398 		if (attr & WA_LOW && t_enter_low_hl_mode(t) != NULL)
399 			win->wattr |= WA_LOW;
400 		if (attr & WA_TOP && t_enter_top_hl_mode(t) != NULL)
401 			win->wattr |= WA_TOP;
402 		if (attr & WA_LEFT && t_enter_left_hl_mode(t) != NULL)
403 			win->wattr |= WA_LEFT;
404 		if (attr & WA_RIGHT && t_enter_right_hl_mode(t) != NULL)
405 			win->wattr |= WA_RIGHT;
406 		if (attr & WA_HORIZONTAL && t_enter_horizontal_hl_mode(t) != NULL)
407 			win->wattr |= WA_HORIZONTAL;
408 		if (attr & WA_VERTICAL && t_enter_vertical_hl_mode(t) != NULL)
409 			win->wattr |= WA_VERTICAL;
410 #endif /* HAVE_WCHAR */
411 	}
412 	if (attr & __STANDOUT && t_enter_standout_mode(t) != NULL &&
413 	    t_exit_standout_mode(t) != NULL)
414 		wstandout(win);
415 	if (attr & __UNDERSCORE && t_enter_underline_mode(t) != NULL &&
416 	    t_exit_underline_mode(t) != NULL)
417 		wunderscore(win);
418 	if (attr & __COLOR)
419 		__wcolor_set(win, attr);
420 	return OK;
421 }
422 
423 
424 static int
425 __wattr_off(WINDOW *win, attr_t attr)
426 {
427 	const TERMINAL *t;
428 
429 	if (__predict_false(win == NULL))
430 		return ERR;
431 
432 	t = win->screen->term;
433 
434 	__CTRACE(__CTRACE_ATTR, "wattr_off: win %p, attr %08x\n", win, attr);
435 	/* If can do exit modes, unset the relevant attribute bits. */
436 	if (t_exit_attribute_mode(t) != NULL) {
437 		if (attr & __BLINK)
438 			win->wattr &= ~__BLINK;
439 		if (attr & __BOLD)
440 			win->wattr &= ~__BOLD;
441 		if (attr & __DIM)
442 			win->wattr &= ~__DIM;
443 		if (attr & __BLANK)
444 			win->wattr &= ~__BLANK;
445 		if (attr & __PROTECT)
446 			win->wattr &= ~__PROTECT;
447 		if (attr & __REVERSE)
448 			win->wattr &= ~__REVERSE;
449 #ifdef HAVE_WCHAR
450 		if (attr & WA_LOW)
451 			win->wattr &= ~WA_LOW;
452 		if (attr & WA_TOP)
453 			win->wattr &= ~WA_TOP;
454 		if (attr & WA_LEFT)
455 			win->wattr &= ~WA_LEFT;
456 		if (attr & WA_RIGHT)
457 			win->wattr &= ~WA_RIGHT;
458 		if (attr & WA_HORIZONTAL)
459 			win->wattr &= ~WA_HORIZONTAL;
460 		if (attr & WA_VERTICAL)
461 			win->wattr &= ~WA_VERTICAL;
462 #endif /* HAVE_WCHAR */
463 	}
464 	if (attr & __STANDOUT)
465 		wstandend(win);
466 	if (attr & __UNDERSCORE)
467 		wunderend(win);
468 	if (attr & __COLOR) {
469 		if (max_colors != 0)
470 			win->wattr &= ~__COLOR;
471 	}
472 	return OK;
473 }
474 
475 
476 static void
477 __wcolor_set(WINDOW *win, attr_t attr)
478 {
479 	const TERMINAL *t;
480 
481 	if (__predict_false(win == NULL))
482 		return;
483 
484 	t = win->screen->term;
485 
486 	/* If another color pair is set, turn that off first. */
487 	win->wattr &= ~__COLOR;
488 	/* If can do color video, set the color pair bits. */
489 	if (t_max_colors(t) != 0)
490 		win->wattr |= attr & __COLOR;
491 }
492