1/*	$NetBSD: background.c,v 1.33 2022/10/19 06:09:27 blymn 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 *
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: background.c,v 1.33 2022/10/19 06:09:27 blymn Exp $");
35#endif				/* not lint */
36
37#include <stdlib.h>
38#include "curses.h"
39#include "curses_private.h"
40
41/*
42 * bkgdset
43 *	Set new background attributes on stdscr.
44 */
45void
46bkgdset(chtype ch)
47{
48	wbkgdset(stdscr, ch);
49}
50
51/*
52 * bkgd --
53 *	Set new background attributes on stdscr and apply them to its
54 *	contents.
55 */
56int
57bkgd(chtype ch)
58{
59	return(wbkgd(stdscr, ch));
60}
61
62/*
63 * wbkgdset
64 *	Set new background attributes on the specified window.
65 */
66void
67wbkgdset(WINDOW *win, chtype ch)
68{
69	__CTRACE(__CTRACE_ATTR, "wbkgdset: (%p), '%s', %08x\n",
70	    win, unctrl(ch & __CHARTEXT), ch & __ATTRIBUTES);
71
72	/* Background character. */
73	if (ch & __CHARTEXT)
74		win->bch = (wchar_t) ch & __CHARTEXT;
75
76	/* Background attributes (check colour). */
77	if (__using_color && !(ch & __COLOR))
78		ch |= __default_color;
79	win->battr = (attr_t) ch & __ATTRIBUTES;
80}
81
82/*
83 * wbkgd --
84 *	Set new background attributes on the specified window and
85 *	apply them to its contents.
86 */
87int
88wbkgd(WINDOW *win, chtype ch)
89{
90	int y, x;
91
92	__CTRACE(__CTRACE_ATTR, "wbkgd: (%p), '%s', %08x\n",
93	    win, unctrl(ch & __CHARTEXT), ch & __ATTRIBUTES);
94	wbkgdset(win, ch);
95
96	for (y = 0; y < win->maxy; y++) {
97		for (x = 0; x < win->maxx; x++) {
98			__LDATA *cp = &win->alines[y]->line[x];
99
100			/* Update/switch background characters */
101			if (cp->cflags & CA_BACKGROUND)
102				cp->ch = win->bch;
103
104			/* Update/merge attributes */
105			cp->attr = win->battr | (cp->attr & __ALTCHARSET);
106#ifdef HAVE_WCHAR
107			cp->wcols = 1;
108#endif
109		}
110	}
111	__touchwin(win, 1);
112	return OK;
113}
114
115/*
116 * getbkgd --
117 *	Get current background attributes.
118 */
119chtype
120getbkgd(WINDOW *win)
121{
122	attr_t	battr;
123
124	/* Background attributes (check colour). */
125	battr = win->battr & A_ATTRIBUTES;
126	if (__using_color && ((battr & __COLOR) == __default_color))
127		battr &= ~__COLOR;
128
129	return ((chtype) ((win->bch & A_CHARTEXT) | battr));
130}
131
132
133#ifdef HAVE_WCHAR
134
135void
136bkgrndset(const cchar_t *wch)
137{
138	wbkgrndset(stdscr, wch);
139}
140
141
142int
143bkgrnd(const cchar_t *wch)
144{
145	return wbkgrnd(stdscr, wch);
146}
147
148
149int
150getbkgrnd(cchar_t *wch)
151{
152	return wgetbkgrnd(stdscr, wch);
153}
154
155
156void
157wbkgrndset(WINDOW *win, const cchar_t *wch)
158{
159	attr_t battr;
160	nschar_t *np, *tnp;
161	int i, wy, wx;
162	__LDATA obkgrnd, nbkgrnd;
163	__LINE *wlp;
164
165	__CTRACE(__CTRACE_ATTR, "wbkgrndset: (%p), '%s', %x\n",
166	    win, (const char *)wunctrl(wch), wch->attributes);
167
168	/* ignore multi-column characters */
169	if (!wch->elements || wcwidth(wch->vals[0]) > 1)
170		return;
171
172	/* get a copy of the old background, we will need it. */
173	obkgrnd.ch = win->bch;
174	obkgrnd.attr = win->battr;
175	obkgrnd.cflags = CA_BACKGROUND;
176	obkgrnd.wcols = win->wcols;
177	obkgrnd.nsp = NULL;
178	_cursesi_copy_nsp(win->bnsp, &obkgrnd);
179
180	/* Background character. */
181	tnp = np = win->bnsp;
182	if (wcwidth( wch->vals[0]))
183		win->bch = wch->vals[0];
184	else {
185		if (!np) {
186			np = malloc(sizeof(nschar_t));
187			if (!np)
188				return;
189			np->next = NULL;
190			win->bnsp = np;
191		}
192		np->ch = wch->vals[0];
193		tnp = np;
194		np = np->next;
195	}
196	/* add non-spacing characters */
197	if (wch->elements > 1) {
198		for (i = 1; i < wch->elements; i++) {
199			if ( !np ) {
200				np = malloc(sizeof(nschar_t));
201				if (!np)
202					return;
203				np->next = NULL;
204				if (tnp)
205					tnp->next = np;
206				else
207					win->bnsp = np;
208			}
209			np->ch = wch->vals[i];
210			tnp = np;
211			np = np->next;
212		}
213	}
214	/* clear the old non-spacing characters */
215	__cursesi_free_nsp(np);
216
217	/* Background attributes (check colour). */
218	battr = wch->attributes & WA_ATTRIBUTES;
219	if (__using_color && !( battr & __COLOR))
220		battr |= __default_color;
221	win->battr = battr;
222	win->wcols = 1;
223
224	nbkgrnd.ch = win->bch;
225	nbkgrnd.attr = win->battr;
226	nbkgrnd.cflags = CA_BACKGROUND;
227	nbkgrnd.wcols = win->wcols;
228	nbkgrnd.nsp = NULL;
229	_cursesi_copy_nsp(win->bnsp, &nbkgrnd);
230
231	/* if the background is already this char then skip updating */
232	if (_cursesi_celleq(&obkgrnd, &nbkgrnd))
233		return;
234
235	/*
236	 * Now do the dirty work of updating all the locations
237	 * that have the old background character with the new.
238	 */
239
240	for (wy = 0; wy < win->maxy; wy++) {
241		wlp = win->alines[wy];
242		for (wx = 0; wx < win->maxx; wx++) {
243			if (wlp->line[wx].cflags & CA_BACKGROUND) {
244				_cursesi_copy_wchar(&nbkgrnd, &wlp->line[wx]);
245			}
246		}
247	}
248	__touchwin(win, 0);
249
250}
251
252
253int
254wbkgrnd(WINDOW *win, const cchar_t *wch)
255{
256	__CTRACE(__CTRACE_ATTR, "wbkgrnd: (%p), '%s', %x\n",
257	    win, (const char *)wunctrl(wch), wch->attributes);
258
259	/* ignore multi-column characters */
260	if (!wch->elements || wcwidth( wch->vals[ 0 ]) > 1)
261		return ERR;
262
263	wbkgrndset(win, wch);
264	__touchwin(win, 1);
265	return OK;
266}
267
268
269int
270wgetbkgrnd(WINDOW *win, cchar_t *wch)
271{
272	nschar_t *np;
273
274	/* Background attributes (check colour). */
275	wch->attributes = win->battr & WA_ATTRIBUTES;
276	if (__using_color && ((wch->attributes & __COLOR) == __default_color))
277		wch->attributes &= ~__COLOR;
278	wch->vals[0] = win->bch;
279	wch->elements = 1;
280	np = win->bnsp;
281	if (np) {
282		while (np && wch->elements < CURSES_CCHAR_MAX) {
283			wch->vals[wch->elements++] = np->ch;
284			np = np->next;
285		}
286	}
287
288	return OK;
289}
290
291#else  /* !HAVE_WCHAR */
292
293void
294bkgrndset(const cchar_t *wch)
295{
296	return;
297}
298
299int
300bkgrnd(const cchar_t *wch)
301{
302	return ERR;
303}
304
305
306int
307getbkgrnd(cchar_t *wch)
308{
309	return ERR;
310}
311
312
313void
314wbkgrndset(WINDOW *win, const cchar_t *wch)
315{
316	return;
317}
318
319
320int
321wbkgrnd(WINDOW *win, const cchar_t *wch)
322{
323	return ERR;
324}
325
326
327int
328wgetbkgrnd(WINDOW *win, cchar_t *wch)
329{
330	return ERR;
331}
332
333#endif /* !HAVE_WCHAR */
334