1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1995-1998 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /* LINTLIBRARY */
30 
31 /*
32  * newwin.c
33  *
34  * XCurses Library
35  *
36  * Copyright 1990, 1995 by Mortice Kern Systems.  All rights reserved.
37  *
38  */
39 
40 #ifdef M_RCSID
41 #ifndef lint
42 static char rcsID[] =
43 "$Header: /team/ps/sun_xcurses/archive/local_changes/xcurses/src/lib/"
44 "libxcurses/src/libc/xcurses/rcs/newwin.c 1.11 1998/06/04 14:26:16 "
45 "cbates Exp $";
46 #endif
47 #endif
48 
49 #include <private.h>
50 #include <stdlib.h>
51 
52 #undef werase
53 
54 /*
55  * Create and return a pointer to a new window or pad.
56  *
57  * For a window, provide the dimensions and location of the upper
58  * left hand corner of the window.  If either dimension is zero (0)
59  * then the default sizes will be LINES-begy and COLS-begx.
60  *
61  * For a pad, provide the dimensions and -1 for begy and begx.
62  * If either dimension is zero (0) then the default sizes will be
63  * LINES and COLS.
64  *
65  * If parent is not null, then create a sub-window of the parent
66  * window.
67  */
68 WINDOW *
69 __m_newwin(WINDOW *parent,
70 	int nlines, int ncols, int begy, int begx)
71 {
72 	WINDOW	*w;
73 	int	x, y, dx, dy;
74 	int	isPad;
75 
76 	isPad = ((begy < 0) && (begx < 0)) ||
77 		(parent && (parent->_flags & W_IS_PAD));
78 
79 	if (parent == NULL) {
80 		/* Check for default dimensions. */
81 		if (nlines == 0) {
82 			nlines = lines;
83 			if (0 <= begy)
84 				nlines -= begy;
85 		}
86 		if (ncols == 0) {
87 			ncols = columns;
88 			if (0 <= begx)
89 				ncols -= begx;
90 		}
91 	} else {
92 		/*
93 		 * Make sure window dimensions remain within parent's
94 		 * window so that the new subwindow is a proper subset
95 		 * of the parent.
96 		 */
97 		if (begy < parent->_begy || begx < parent->_begx ||
98 			parent->_maxy < (begy-parent->_begy) + nlines ||
99 			parent->_maxx < (begx-parent->_begx) + ncols)
100 			goto error_1;
101 
102 		/*
103 		 * If either dimension is zero (0), use the max size
104 		 * for the dimension from the parent window less the
105 		 * subwindow's starting location.
106 		 */
107 		if (nlines == 0)
108 			nlines = parent->_maxy - (begy - parent->_begy);
109 		if (ncols == 0)
110 			ncols = parent->_maxx - (begx - parent->_begx);
111 	}
112 
113 	if (!isPad) {
114 		/* Check that a window fits on the screen. */
115 		if (0 <= begy) {
116 			if (lines < begy + nlines) {
117 				goto error_1;
118 			}
119 		}
120 		if (0 <= begx) {
121 			if (columns < begx + ncols) {
122 				goto error_1;
123 			}
124 		}
125 	}
126 
127 	w = (WINDOW *) calloc(1, sizeof (*w));
128 	if (w == NULL)
129 		goto error_1;
130 
131 	w->_first = (short *) calloc((size_t) (nlines + nlines),
132 		sizeof (*w->_first));
133 	if (w->_first == NULL)
134 		goto error_2;
135 
136 	w->_last = &w->_first[nlines];
137 
138 	w->_line = (cchar_t **) calloc((size_t) nlines, sizeof (*w->_line));
139 	if (w->_line == NULL)
140 		goto error_2;
141 
142 	/* Window rendition. */
143 	(void) setcchar(&w->_bg, L" ", WA_NORMAL, 0, (void *) 0);
144 	(void) setcchar(&w->_fg, L" ", WA_NORMAL, 0, (void *) 0);
145 	if (parent == NULL) {
146 		w->_base = (cchar_t *) malloc((size_t) (nlines * ncols) *
147 			sizeof (*w->_base));
148 		if (w->_base == NULL)
149 			goto error_2;
150 
151 		w->_line[0] = w->_base;
152 		for (y = 0; y < nlines; y++) {
153 			if (y)
154 				w->_line[y] = &w->_line[y-1][ncols];
155 			for (x = 0; x < ncols; ++x) {
156 				w->_line[y][x] = w->_bg;
157 			}
158 		}
159 	} else {
160 		/*
161 		 * The new window's origin (0,0) maps to (begy, begx) in the
162 		 * parent's window.  In effect, subwin() is a method by which
163 		 * a portion of a parent's window can be addressed using a
164 		 * (0,0) origin.
165 		 */
166 		dy = begy - parent->_begy;
167 		dx = begx - parent->_begx;
168 
169 		w->_base = NULL;
170 
171 		for (y = 0; y < nlines; ++y)
172 			w->_line[y] = &parent->_line[dy++][dx];
173 	}
174 
175 	w->_begy = (short) begy;
176 	w->_begx = (short) begx;
177 	w->_cury = w->_curx = 0;
178 	w->_maxy = (short) nlines;
179 	w->_maxx = (short) ncols;
180 	w->_parent = parent;
181 
182 	/* Software scroll region. */
183 	w->_top = 0;
184 	w->_bottom = (short) nlines;
185 	w->_scroll = 0;
186 
187 	/* Window initially blocks for input. */
188 	w->_vmin = 1;
189 	w->_vtime = 0;
190 	w->_flags = W_USE_TIMEOUT;
191 
192 	/* Determine window properties. */
193 	if (isPad) {
194 		/* This window is a PAD */
195 		w->_flags |= W_IS_PAD;	/* Inherit PAD attribute */
196 		if (((begy < 0) && (begx < 0)) ||
197 			(parent && !(parent->_flags & W_IS_PAD))) {
198 			/* Child of a normal window */
199 			w->_begy = w->_begx = 0;
200 			/*
201 			 * Map to upper left portion of
202 			 * display by default (???)
203 			 */
204 			w->_sminy = w->_sminx = 0;
205 			w->_smaxx = w->_maxx;
206 			w->_smaxy = w->_maxy;
207 		}
208 	} else if (begx + ncols == columns) {
209 		/* Writing to last column should trigger auto-margin wrap. */
210 		w->_flags |= W_END_LINE;
211 
212 		if (begx == 0) {
213 			w->_flags |= W_FULL_LINE;
214 
215 			if (begy == 0 && nlines == lines)
216 				w->_flags |= W_FULL_WINDOW;
217 		}
218 
219 		/* Will writing to bottom-right triggers scroll? */
220 		if (begy + nlines == lines)
221 			w->_flags |= W_SCROLL_WINDOW;
222 	}
223 
224 	/* Initial screen clear for full screen windows only. */
225 	if (w->_flags & W_FULL_WINDOW) {
226 		w->_flags |= W_CLEAR_WINDOW;
227 		/* Reset dirty region markers. */
228 		(void) wtouchln(w, 0, w->_maxy, 0);
229 	} else {
230 		if (!parent) {
231 			/* Do not erase sub windows */
232 			(void) werase(w);
233 		}
234 	}
235 
236 	return (w);
237 error_2:
238 	(void) delwin(w);
239 error_1:
240 	return (NULL);
241 }
242 
243 int
244 delwin(WINDOW *w)
245 {
246 	if (w == NULL)
247 		return (OK);
248 
249 
250 	if (w->_line != NULL) {
251 		if (w->_base != NULL)
252 			free(w->_base);
253 
254 		free(w->_line);
255 	}
256 
257 	if (w->_first != NULL)
258 		free(w->_first);
259 
260 	free(w);
261 
262 	return (OK);
263 }
264 
265 WINDOW *
266 derwin(WINDOW *parent,
267 	int nlines, int ncols, int begy, int begx)
268 {
269 	WINDOW	*w;
270 
271 	if (parent == NULL)
272 		return (NULL);
273 
274 	/* Absolute screen address. */
275 	begy += parent->_begy;
276 	begx += parent->_begx;
277 
278 	w = __m_newwin(parent, nlines, ncols, begy, begx);
279 
280 	return (w);
281 }
282 
283 WINDOW *
284 newwin(int nlines, int ncols, int begy, int begx)
285 {
286 	WINDOW	*w;
287 
288 	w = __m_newwin(NULL, nlines, ncols, begy, begx);
289 
290 	return (w);
291 }
292 
293 WINDOW *
294 subwin(WINDOW *parent, int nlines, int ncols, int begy, int begx)
295 {
296 	WINDOW	*w;
297 
298 	if (parent == NULL)
299 		return (NULL);
300 
301 	w = __m_newwin(parent, nlines, ncols, begy, begx);
302 
303 	return (w);
304 }
305