xref: /netbsd-src/lib/libcurses/screen.c (revision 501cd18a74d52bfcca7d9e7e3b0d472bbc870558)
1 /*	$NetBSD: screen.c,v 1.28 2017/01/10 10:13:24 roy Exp $	*/
2 
3 /*
4  * Copyright (c) 1981, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)screen.c	8.2 (blymn) 11/27/2001";
36 #else
37 __RCSID("$NetBSD: screen.c,v 1.28 2017/01/10 10:13:24 roy Exp $");
38 #endif
39 #endif					/* not lint */
40 
41 #include <stdlib.h>
42 
43 #include "curses.h"
44 #include "curses_private.h"
45 
46 static int filtered;
47 
48 /* List of ripoffline calls */
49 #define	NRIPS	5
50 static struct ripoff {
51 	int	nlines;
52 	int	(*init)(WINDOW *, int);
53 } ripoffs[NRIPS];
54 static int nrips;
55 
56 /*
57  * filter has to be called before either initscr or newterm.
58  */
59 void
60 filter(void)
61 {
62 
63 	filtered = TRUE;
64 }
65 
66 /*
67  *ripoffline --
68  *	Ripoff a line from the top of bottom of stdscr.
69  *	Must be called before initscr or newterm.
70  */
71 int
72 ripoffline(int line, int (*init)(WINDOW *, int))
73 {
74 
75 	if (nrips >= NRIPS || init == NULL)
76 		return ERR; /* This makes sense, but not standards compliant. */
77 	if (line == 0)
78 		return OK;
79 	ripoffs[nrips].nlines = line < 0 ? -1 : 1;
80 	ripoffs[nrips++].init = init;
81 	return OK;
82 }
83 
84 /*
85  * set_term --
86  *      Change the term to the given screen.
87  *
88  */
89 SCREEN *
90 set_term(SCREEN *new)
91 {
92 	SCREEN *old_screen = _cursesi_screen;
93 
94 	if (_cursesi_screen != NULL) {
95 		  /* save changes made to the current screen... */
96 		old_screen->echoit = __echoit;
97 		old_screen->pfast = __pfast;
98 		old_screen->rawmode = __rawmode;
99 		old_screen->noqch = __noqch;
100 		old_screen->COLS = COLS;
101 		old_screen->LINES = LINES
102 		    + old_screen->ripped_top + old_screen->ripped_bottom;
103 		old_screen->COLORS = COLORS;
104 		old_screen->COLOR_PAIRS = COLOR_PAIRS;
105 		old_screen->GT = __GT;
106 		old_screen->NONL = __NONL;
107 		old_screen->UPPERCASE = __UPPERCASE;
108 	}
109 
110 	_cursesi_screen = new;
111 
112 	__echoit = new->echoit;
113         __pfast = new->pfast;
114 	__rawmode = new->rawmode;
115 	__noqch = new->noqch;
116 	COLS = new->COLS;
117 	LINES = new->LINES - new->ripped_top - new->ripped_bottom;
118 	COLORS = new->COLORS;
119 	COLOR_PAIRS = new->COLOR_PAIRS;
120 	__GT = new->GT;
121 	__NONL = new->NONL;
122 	__UPPERCASE = new->UPPERCASE;
123 
124 	_cursesi_resetterm(new);
125 
126 	curscr = new->curscr;
127 	clearok(curscr, new->clearok);
128 	stdscr = new->stdscr;
129 	__virtscr = new->__virtscr;
130 
131 	_cursesi_reset_acs(new);
132 #ifdef HAVE_WCHAR
133 	_cursesi_reset_wacs(new);
134 #endif /* HAVE_WCHAR */
135 
136 #ifdef DEBUG
137 	__CTRACE(__CTRACE_SCREEN, "set_term: LINES = %d, COLS = %d\n",
138 	    LINES, COLS);
139 #endif
140 
141 	return old_screen;
142 }
143 
144 /*
145  * newterm --
146  *      Set up a new screen.
147  *
148  */
149 SCREEN *
150 newterm(char *type, FILE *outfd, FILE *infd)
151 {
152 	SCREEN *new_screen;
153 	char *sp;
154 	int i;
155 
156 	sp = type;
157 	if (type == NULL && (sp = getenv("TERM")) == NULL)
158 		return NULL;
159 
160 	if ((new_screen = calloc(1, sizeof(SCREEN))) == NULL)
161 		return NULL;
162 
163 #ifdef DEBUG
164 	__CTRACE(__CTRACE_INIT, "newterm\n");
165 #endif
166 
167 	new_screen->infd = infd;
168 	new_screen->checkfd = fileno(infd);
169 	new_screen->outfd = outfd;
170 	new_screen->echoit = new_screen->nl = 1;
171 	new_screen->pfast = new_screen->rawmode = new_screen->noqch = 0;
172 	new_screen->filtered = filtered;
173 	filtered = FALSE; /* filter() must preceed each newterm() */
174 	new_screen->nca = A_NORMAL;
175 	new_screen->color_type = COLOR_NONE;
176 	new_screen->COLOR_PAIRS = 0;
177 	new_screen->old_mode = 2;
178 	new_screen->stdbuf = NULL;
179 	new_screen->stdscr = NULL;
180 	new_screen->curscr = NULL;
181 	new_screen->__virtscr = NULL;
182 	new_screen->curwin = 0;
183 	new_screen->notty = FALSE;
184 	new_screen->half_delay = FALSE;
185 	new_screen->resized = 0;
186 	new_screen->unget_len = 32;
187 
188 	if ((new_screen->unget_list =
189 	    malloc(sizeof(wchar_t) * new_screen->unget_len)) == NULL)
190 	{
191 		goto error_exit;
192 	}
193 	new_screen->unget_pos = 0;
194 
195 	if (_cursesi_gettmode(new_screen) == ERR)
196 		goto error_exit;
197 
198 	if (_cursesi_setterm((char *)sp, new_screen) == ERR)
199 		goto error_exit;
200 
201 	/* Need either homing or cursor motion for refreshes */
202 	if (!t_cursor_home(new_screen->term) &&
203 	    !t_cursor_address(new_screen->term))
204 		goto error_exit;
205 
206 	new_screen->winlistp = NULL;
207 
208 	if ((new_screen->curscr = __newwin(new_screen, 0,
209 	    0, 0, 0, FALSE)) == NULL)
210 		goto error_exit;
211 
212 	if ((new_screen->__virtscr = __newwin(new_screen, 0,
213 	    0, 0, 0, FALSE)) == NULL)
214 	{
215 		delwin(new_screen->curscr);
216 		goto error_exit;
217 	}
218 
219 	for (i = 0; i < nrips; i++) {
220 		const struct ripoff *r = &ripoffs[i];
221 		int nlines = r->nlines < 0 ? -r->nlines : r->nlines;
222 		WINDOW *w;
223 
224 		w = __newwin(new_screen, nlines, 0,
225 		    r->nlines < 0 ? LINES + r->nlines : new_screen->ripped_top,
226 		    0, FALSE);
227 		if (w != NULL) {
228 			if (r->nlines < 0)
229 				new_screen->ripped_bottom += nlines;
230 			else
231 				new_screen->ripped_top += nlines;
232 			LINES -= nlines;
233 		}
234 		r->init(w, COLS);
235 #ifdef DEBUG
236 		if (w != NULL)
237 			__CTRACE(__CTRACE_SCREEN,
238 			    "newterm: ripped %d lines from the %s\n",
239 			    nlines, r->nlines < 0 ? "bottom" : "top");
240 #endif
241 	}
242 	nrips = 0; /* Reset the stack. */
243 
244 	new_screen->stdscr = __newwin(new_screen, LINES, 0,
245 	    new_screen->ripped_top, 0, FALSE);
246 	if (new_screen->stdscr == NULL) {
247 		delwin(new_screen->curscr);
248 		delwin(new_screen->__virtscr);
249 		goto error_exit;
250 	}
251 
252 	clearok(new_screen->stdscr, 1);
253 
254 	__init_getch(new_screen);
255 	__init_acs(new_screen);
256 #ifdef HAVE_WCHAR
257 	__init_get_wch( new_screen );
258 	__init_wacs(new_screen);
259 #endif /* HAVE_WCHAR */
260 
261 	__set_stophandler();
262 	__set_winchhandler();
263 
264 	  /*
265 	   * bleh - it seems that apps expect the first newterm to set
266 	   * up the curses screen.... emulate this.
267 	   */
268 	if (_cursesi_screen == NULL || _cursesi_screen->endwin) {
269 		set_term(new_screen);
270 	}
271 
272 #ifdef DEBUG
273 	__CTRACE(__CTRACE_SCREEN, "newterm: LINES = %d, COLS = %d\n",
274 	    LINES, COLS);
275 #endif
276 	__startwin(new_screen);
277 
278 	return new_screen;
279 
280   error_exit:
281 	if (new_screen->term != NULL)
282 		(void)del_curterm(new_screen->term);
283 	free(new_screen->unget_list);
284 
285 	free(new_screen);
286 	return NULL;
287 }
288 
289 /*
290  * delscreen --
291  *   Free resources used by the given screen and destroy it.
292  *
293  */
294 void
295 delscreen(SCREEN *screen)
296 {
297         struct __winlist *list;
298 
299 #ifdef DEBUG
300 	__CTRACE(__CTRACE_SCREEN, "delscreen(%p)\n", screen);
301 #endif
302 	  /* free up the terminfo stuff */
303 	del_curterm(screen->term);
304 
305 	  /* walk the window list and kill all the parent windows */
306 	while ((list = screen->winlistp) != NULL) {
307 		delwin(list->winp);
308 		if (list == screen->winlistp)
309 			/* sanity - abort if window didn't remove itself */
310 			break;
311 	}
312 
313 	  /* free the storage of the keymaps */
314 	_cursesi_free_keymap(screen->base_keymap);
315 
316 	free(screen->stdbuf);
317 	free(screen->unget_list);
318 	if (_cursesi_screen == screen)
319 		_cursesi_screen = NULL;
320 	free(screen);
321 }
322