xref: /netbsd-src/lib/libcurses/newwin.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: newwin.c,v 1.36 2003/06/09 06:58:11 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.36 2003/06/09 06:58:11 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 		if (ispad)
157 			lp->flags = __ISDIRTY;
158 		else
159 			lp->flags = 0;
160 		for (sp = lp->line, j = 0; j < maxx; j++, sp++) {
161 			sp->ch = ' ';
162 			sp->bch = ' ';
163 			sp->attr = 0;
164 			if (__using_color)
165 				sp->battr = __default_color;
166 			else
167 				sp->battr = 0;
168 		}
169 		lp->hash = __hash((char *)(void *)lp->line,
170 		    (size_t) (ncols * __LDATASIZE));
171 	}
172 	return (win);
173 }
174 
175 WINDOW *
176 subwin(WINDOW *orig, int nlines, int ncols, int by, int bx)
177 {
178 	if (orig == NULL || orig->orig != NULL)
179 		return NULL;
180 
181 	return __subwin(orig, nlines, ncols, by, bx, TRUE);
182 }
183 
184 WINDOW *
185 __subwin(WINDOW *orig, int nlines, int ncols, int by, int bx, int ispad)
186 {
187 	int     i;
188 	__LINE *lp;
189 	WINDOW *win;
190 	int	maxy, maxx;
191 
192 	/* Make sure window fits inside the original one. */
193 #ifdef	DEBUG
194 	__CTRACE("subwin: (%p, %d, %d, %d, %d, %d)\n", orig, nlines, ncols,
195 	    by, bx, ispad);
196 #endif
197 	maxy = nlines > 0 ? nlines : orig->maxy + orig->begy - by + nlines;
198 	maxx = ncols > 0 ? ncols : orig->maxx + orig->begx - bx + ncols;
199 	if (by < orig->begy || bx < orig->begx
200 	    || by + maxy > orig->maxy + orig->begy
201 	    || bx + maxx > orig->maxx + orig->begx)
202 		return (NULL);
203 	if ((win = __makenew(_cursesi_screen, maxy, maxx,
204 			     by, bx, 1, ispad)) == NULL)
205 		return (NULL);
206 	win->reqy = nlines;
207 	win->reqx = ncols;
208 	win->nextp = orig->nextp;
209 	orig->nextp = win;
210 	win->orig = orig;
211 
212 	/* Initialize flags here so that refresh can also use __set_subwin. */
213 	for (lp = win->lspace, i = 0; i < win->maxy; i++, lp++)
214 		lp->flags = 0;
215 	__set_subwin(orig, win);
216 	return (win);
217 }
218 /*
219  * This code is shared with mvwin().
220  */
221 void
222 __set_subwin(WINDOW *orig, WINDOW *win)
223 {
224 	int     i;
225 	__LINE *lp, *olp;
226 
227 	win->ch_off = win->begx - orig->begx;
228 	/* Point line pointers to line space. */
229 	for (lp = win->lspace, i = 0; i < win->maxy; i++, lp++) {
230 		win->lines[i] = lp;
231 		olp = orig->lines[i + win->begy - orig->begy];
232 #ifdef DEBUG
233 		lp->sentinel = SENTINEL_VALUE;
234 #endif
235 		lp->line = &olp->line[win->ch_off];
236 		lp->firstchp = &olp->firstch;
237 		lp->lastchp = &olp->lastch;
238 		lp->hash = __hash((char *)(void *)lp->line,
239 		    (size_t) (win->maxx * __LDATASIZE));
240 	}
241 
242 #ifdef DEBUG
243 	__CTRACE("__set_subwin: win->ch_off = %d\n", win->ch_off);
244 #endif
245 }
246 /*
247  * __makenew --
248  *	Set up a window buffer and returns a pointer to it.
249  */
250 static WINDOW *
251 __makenew(SCREEN *screen, int nlines, int ncols, int by, int bx, int sub,
252 	int ispad)
253 {
254 	WINDOW			*win;
255 	__LINE			*lp;
256 	struct __winlist	*wlp, *wlp2;
257 	int			 i;
258 
259 
260 #ifdef	DEBUG
261 	__CTRACE("makenew: (%d, %d, %d, %d)\n", nlines, ncols, by, bx);
262 #endif
263 	if (nlines <= 0 || ncols <= 0)
264 		return NULL;
265 
266 	if ((win = malloc(sizeof(WINDOW))) == NULL)
267 		return (NULL);
268 #ifdef DEBUG
269 	__CTRACE("makenew: win = %p\n", win);
270 #endif
271 
272 	/* Set up line pointer array and line space. */
273 	if ((win->lines = malloc(nlines * sizeof(__LINE *))) == NULL) {
274 		free(win);
275 		return NULL;
276 	}
277 	if ((win->lspace = malloc(nlines * sizeof(__LINE))) == NULL) {
278 		free(win);
279 		free(win->lines);
280 		return NULL;
281 	}
282 	/* Don't allocate window and line space if it's a subwindow */
283 	if (!sub) {
284 		/*
285 		 * Allocate window space in one chunk.
286 		 */
287 		if ((win->wspace =
288 			malloc(ncols * nlines * sizeof(__LDATA))) == NULL) {
289 			free(win->lines);
290 			free(win->lspace);
291 			free(win);
292 			return NULL;
293 		}
294 		/*
295 		 * Append window to window list.
296 		 */
297 		if ((wlp = malloc(sizeof(struct __winlist))) == NULL) {
298 			free(win->wspace);
299 			free(win->lines);
300 			free(win->lspace);
301 			free(win);
302 			return NULL;
303 		}
304 		wlp->winp = win;
305 		wlp->nextp = NULL;
306 		if (screen->winlistp == NULL)
307 			screen->winlistp = wlp;
308 		else {
309 			wlp2 = screen->winlistp;
310 			while (wlp2->nextp != NULL)
311 				wlp2 = wlp2->nextp;
312 			wlp2->nextp = wlp;
313 		}
314 		/*
315 		 * Point line pointers to line space, and lines themselves into
316 		 * window space.
317 		 */
318 		for (lp = win->lspace, i = 0; i < nlines; i++, lp++) {
319 			win->lines[i] = lp;
320 			lp->line = &win->wspace[i * ncols];
321 #ifdef DEBUG
322 			lp->sentinel = SENTINEL_VALUE;
323 #endif
324 			lp->firstchp = &lp->firstch;
325 			lp->lastchp = &lp->lastch;
326 			if (ispad) {
327 				lp->firstch = 0;
328 				lp->lastch = ncols;
329 			} else {
330 				lp->firstch = ncols;
331 				lp->lastch = 0;
332 			}
333 		}
334 	}
335 #ifdef DEBUG
336 	__CTRACE("makenew: ncols = %d\n", ncols);
337 #endif
338 	win->cury = win->curx = 0;
339 	win->maxy = nlines;
340 	win->maxx = ncols;
341 	win->reqy = nlines;
342 	win->reqx = ncols;
343 
344 	win->begy = by;
345 	win->begx = bx;
346 	win->flags = (__IDLINE | __IDCHAR);
347 	win->delay = -1;
348 	win->wattr = 0;
349 	win->bch = ' ';
350 	if (__using_color)
351 		win->battr = __default_color;
352 	else
353 		win->battr = 0;
354 	win->scr_t = 0;
355 	win->scr_b = win->maxy - 1;
356 	if (ispad)
357 		win->flags |= __ISPAD;
358 	else
359 		__swflags(win);
360 #ifdef DEBUG
361 	__CTRACE("makenew: win->wattr = %08x\n", win->wattr);
362 	__CTRACE("makenew: win->flags = %#.4x\n", win->flags);
363 	__CTRACE("makenew: win->maxy = %d\n", win->maxy);
364 	__CTRACE("makenew: win->maxx = %d\n", win->maxx);
365 	__CTRACE("makenew: win->begy = %d\n", win->begy);
366 	__CTRACE("makenew: win->begx = %d\n", win->begx);
367 	__CTRACE("makenew: win->bch = %s\n", unctrl(win->bch));
368 	__CTRACE("makenew: win->battr = %08x\n", win->battr);
369 	__CTRACE("makenew: win->scr_t = %d\n", win->scr_t);
370 	__CTRACE("makenew: win->scr_b = %d\n", win->scr_b);
371 #endif
372 	return (win);
373 }
374 
375 void
376 __swflags(WINDOW *win)
377 {
378 	win->flags &= ~(__ENDLINE | __FULLWIN | __SCROLLWIN | __LEAVEOK);
379 	if (win->begx + win->maxx == COLS && !(win->flags & __ISPAD)) {
380 		win->flags |= __ENDLINE;
381 		if (win->begx == 0 && win->maxy == LINES && win->begy == 0)
382 			win->flags |= __FULLWIN;
383 		if (win->begy + win->maxy == LINES)
384 			win->flags |= __SCROLLWIN;
385 	}
386 }
387