xref: /netbsd-src/lib/libcurses/newwin.c (revision 1ffa7b76c40339c17a0fb2a09fac93f287cfc046)
1 /*	$NetBSD: newwin.c,v 1.35 2003/04/08 05:56:01 jdc 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)newwin.c	8.3 (Berkeley) 7/27/94";
40 #else
41 __RCSID("$NetBSD: newwin.c,v 1.35 2003/04/08 05:56:01 jdc Exp $");
42 #endif
43 #endif				/* not lint */
44 
45 #include <stdlib.h>
46 
47 #include "curses.h"
48 #include "curses_private.h"
49 
50 extern struct __winlist	*winlistp;
51 
52 static WINDOW *__makenew(SCREEN *screen, int nlines, int ncols, int by,
53 			 int bx, int sub, int ispad);
54 static WINDOW *__subwin(WINDOW *orig, int nlines, int ncols, int by, int bx,
55 			 int ispad);
56 
57 /*
58  * derwin --
59  *      Create a new window in the same manner as subwin but (by, bx)
60  *      are relative to the origin of window orig instead of absolute.
61  */
62 WINDOW *
63 derwin(WINDOW *orig, int nlines, int ncols, int by, int bx)
64 {
65 	if (orig == NULL)
66 		return NULL;
67 
68 	return __subwin(orig, nlines, ncols, orig->begy + by, orig->begx + bx,
69 	    FALSE);
70 }
71 
72 /*
73  * subpad --
74  *      Create a new pad in the same manner as subwin but (by, bx)
75  *      are relative to the origin of window orig instead of absolute.
76  */
77 WINDOW *
78 subpad(WINDOW *orig, int nlines, int ncols, int by, int bx)
79 {
80 	if (orig == NULL)
81 		return NULL;
82 
83 	return __subwin(orig, nlines, ncols, orig->begy + by, orig->begx + bx,
84 	    TRUE);
85 }
86 
87 /*
88  * dupwin --
89  *      Create a copy of the given window.
90  */
91 WINDOW *
92 dupwin(WINDOW *win)
93 {
94 	WINDOW *new_one;
95 
96 	if ((new_one = __newwin(_cursesi_screen, win->maxy, win->maxx,
97 				win->begy, win->begx, FALSE)) == NULL)
98 		return NULL;
99 
100 	overwrite(win, new_one);
101 	return new_one;
102 }
103 
104 /*
105  * newwin --
106  *	Allocate space for and set up defaults for a new window.
107  */
108 WINDOW *
109 newwin(int nlines, int ncols, int by, int bx)
110 {
111 	return __newwin(_cursesi_screen, nlines, ncols, by, bx, FALSE);
112 }
113 
114 /*
115  * newpad --
116  *	Allocate space for and set up defaults for a new pad.
117  */
118 WINDOW *
119 newpad(int nlines, int ncols)
120 {
121 	if (nlines < 1 || ncols < 1)
122 		return NULL;
123 	return __newwin(_cursesi_screen, nlines, ncols, 0, 0, TRUE);
124 }
125 
126 WINDOW *
127 __newwin(SCREEN *screen, int nlines, int ncols, int by, int bx, int ispad)
128 {
129 	WINDOW *win;
130 	__LINE *lp;
131 	int     i, j;
132 	int	maxy, maxx;
133 	__LDATA *sp;
134 
135 	if (by < 0 || bx < 0)
136 		return (NULL);
137 
138 	maxy = nlines > 0 ? nlines : LINES - by + nlines;
139 	maxx = ncols > 0 ? ncols : COLS - bx + ncols;
140 
141 	if ((win = __makenew(screen, maxy, maxx, by, bx, 0, ispad)) == NULL)
142 		return (NULL);
143 
144 	win->nextp = win;
145 	win->ch_off = 0;
146 	win->orig = NULL;
147 	win->reqy = nlines;
148 	win->reqx = ncols;
149 
150 #ifdef DEBUG
151 	__CTRACE("newwin: win->ch_off = %d\n", win->ch_off);
152 #endif
153 
154 	for (i = 0; i < maxy; i++) {
155 		lp = win->lines[i];
156 		lp->flags = 0;
157 		for (sp = lp->line, j = 0; j < maxx; j++, sp++) {
158 			sp->ch = ' ';
159 			sp->bch = ' ';
160 			sp->attr = 0;
161 			if (__using_color)
162 				sp->battr = __default_color;
163 			else
164 				sp->battr = 0;
165 		}
166 		lp->hash = __hash((char *)(void *)lp->line,
167 		    (size_t) (ncols * __LDATASIZE));
168 	}
169 	return (win);
170 }
171 
172 WINDOW *
173 subwin(WINDOW *orig, int nlines, int ncols, int by, int bx)
174 {
175 	if (orig == NULL || orig->orig != NULL)
176 		return NULL;
177 
178 	return __subwin(orig, nlines, ncols, by, bx, TRUE);
179 }
180 
181 WINDOW *
182 __subwin(WINDOW *orig, int nlines, int ncols, int by, int bx, int ispad)
183 {
184 	int     i;
185 	__LINE *lp;
186 	WINDOW *win;
187 	int	maxy, maxx;
188 
189 	/* Make sure window fits inside the original one. */
190 #ifdef	DEBUG
191 	__CTRACE("subwin: (%p, %d, %d, %d, %d, %d)\n", orig, nlines, ncols,
192 	    by, bx, ispad);
193 #endif
194 	maxy = nlines > 0 ? nlines : orig->maxy + orig->begy - by + nlines;
195 	maxx = ncols > 0 ? ncols : orig->maxx + orig->begx - bx + ncols;
196 	if (by < orig->begy || bx < orig->begx
197 	    || by + maxy > orig->maxy + orig->begy
198 	    || bx + maxx > orig->maxx + orig->begx)
199 		return (NULL);
200 	if ((win = __makenew(_cursesi_screen, maxy, maxx,
201 			     by, bx, 1, ispad)) == NULL)
202 		return (NULL);
203 	win->reqy = nlines;
204 	win->reqx = ncols;
205 	win->nextp = orig->nextp;
206 	orig->nextp = win;
207 	win->orig = orig;
208 
209 	/* Initialize flags here so that refresh can also use __set_subwin. */
210 	for (lp = win->lspace, i = 0; i < win->maxy; i++, lp++)
211 		lp->flags = 0;
212 	__set_subwin(orig, win);
213 	return (win);
214 }
215 /*
216  * This code is shared with mvwin().
217  */
218 void
219 __set_subwin(WINDOW *orig, WINDOW *win)
220 {
221 	int     i;
222 	__LINE *lp, *olp;
223 
224 	win->ch_off = win->begx - orig->begx;
225 	/* Point line pointers to line space. */
226 	for (lp = win->lspace, i = 0; i < win->maxy; i++, lp++) {
227 		win->lines[i] = lp;
228 		olp = orig->lines[i + win->begy - orig->begy];
229 #ifdef DEBUG
230 		lp->sentinel = SENTINEL_VALUE;
231 #endif
232 		lp->line = &olp->line[win->ch_off];
233 		lp->firstchp = &olp->firstch;
234 		lp->lastchp = &olp->lastch;
235 		lp->hash = __hash((char *)(void *)lp->line,
236 		    (size_t) (win->maxx * __LDATASIZE));
237 	}
238 
239 #ifdef DEBUG
240 	__CTRACE("__set_subwin: win->ch_off = %d\n", win->ch_off);
241 #endif
242 }
243 /*
244  * __makenew --
245  *	Set up a window buffer and returns a pointer to it.
246  */
247 static WINDOW *
248 __makenew(SCREEN *screen, int nlines, int ncols, int by, int bx, int sub,
249 	int ispad)
250 {
251 	WINDOW			*win;
252 	__LINE			*lp;
253 	struct __winlist	*wlp, *wlp2;
254 	int			 i;
255 
256 
257 #ifdef	DEBUG
258 	__CTRACE("makenew: (%d, %d, %d, %d)\n", nlines, ncols, by, bx);
259 #endif
260 	if (nlines <= 0 || ncols <= 0)
261 		return NULL;
262 
263 	if ((win = malloc(sizeof(WINDOW))) == NULL)
264 		return (NULL);
265 #ifdef DEBUG
266 	__CTRACE("makenew: win = %p\n", win);
267 #endif
268 
269 	/* Set up line pointer array and line space. */
270 	if ((win->lines = malloc(nlines * sizeof(__LINE *))) == NULL) {
271 		free(win);
272 		return NULL;
273 	}
274 	if ((win->lspace = malloc(nlines * sizeof(__LINE))) == NULL) {
275 		free(win);
276 		free(win->lines);
277 		return NULL;
278 	}
279 	/* Don't allocate window and line space if it's a subwindow */
280 	if (!sub) {
281 		/*
282 		 * Allocate window space in one chunk.
283 		 */
284 		if ((win->wspace =
285 			malloc(ncols * nlines * sizeof(__LDATA))) == NULL) {
286 			free(win->lines);
287 			free(win->lspace);
288 			free(win);
289 			return NULL;
290 		}
291 		/*
292 		 * Append window to window list.
293 		 */
294 		if ((wlp = malloc(sizeof(struct __winlist))) == NULL) {
295 			free(win->wspace);
296 			free(win->lines);
297 			free(win->lspace);
298 			free(win);
299 			return NULL;
300 		}
301 		wlp->winp = win;
302 		wlp->nextp = NULL;
303 		if (screen->winlistp == NULL)
304 			screen->winlistp = wlp;
305 		else {
306 			wlp2 = screen->winlistp;
307 			while (wlp2->nextp != NULL)
308 				wlp2 = wlp2->nextp;
309 			wlp2->nextp = wlp;
310 		}
311 		/*
312 		 * Point line pointers to line space, and lines themselves into
313 		 * window space.
314 		 */
315 		for (lp = win->lspace, i = 0; i < nlines; i++, lp++) {
316 			win->lines[i] = lp;
317 			lp->line = &win->wspace[i * ncols];
318 #ifdef DEBUG
319 			lp->sentinel = SENTINEL_VALUE;
320 #endif
321 			lp->firstchp = &lp->firstch;
322 			lp->lastchp = &lp->lastch;
323 			lp->firstch = ncols;
324 			lp->lastch = 0;
325 		}
326 	}
327 #ifdef DEBUG
328 	__CTRACE("makenew: ncols = %d\n", ncols);
329 #endif
330 	win->cury = win->curx = 0;
331 	win->maxy = nlines;
332 	win->maxx = ncols;
333 	win->reqy = nlines;
334 	win->reqx = ncols;
335 
336 	win->begy = by;
337 	win->begx = bx;
338 	win->flags = (__IDLINE | __IDCHAR);
339 	win->delay = -1;
340 	win->wattr = 0;
341 	win->bch = ' ';
342 	if (__using_color)
343 		win->battr = __default_color;
344 	else
345 		win->battr = 0;
346 	win->scr_t = 0;
347 	win->scr_b = win->maxy - 1;
348 	if (ispad)
349 		win->flags |= __ISPAD;
350 	else
351 		__swflags(win);
352 #ifdef DEBUG
353 	__CTRACE("makenew: win->wattr = %08x\n", win->wattr);
354 	__CTRACE("makenew: win->flags = %#.4x\n", win->flags);
355 	__CTRACE("makenew: win->maxy = %d\n", win->maxy);
356 	__CTRACE("makenew: win->maxx = %d\n", win->maxx);
357 	__CTRACE("makenew: win->begy = %d\n", win->begy);
358 	__CTRACE("makenew: win->begx = %d\n", win->begx);
359 	__CTRACE("makenew: win->bch = %s\n", unctrl(win->bch));
360 	__CTRACE("makenew: win->battr = %08x\n", win->battr);
361 	__CTRACE("makenew: win->scr_t = %d\n", win->scr_t);
362 	__CTRACE("makenew: win->scr_b = %d\n", win->scr_b);
363 #endif
364 	return (win);
365 }
366 
367 void
368 __swflags(WINDOW *win)
369 {
370 	win->flags &= ~(__ENDLINE | __FULLWIN | __SCROLLWIN | __LEAVEOK);
371 	if (win->begx + win->maxx == COLS && !(win->flags & __ISPAD)) {
372 		win->flags |= __ENDLINE;
373 		if (win->begx == 0 && win->maxy == LINES && win->begy == 0)
374 			win->flags |= __FULLWIN;
375 		if (win->begy + win->maxy == LINES)
376 			win->flags |= __SCROLLWIN;
377 	}
378 }
379