xref: /netbsd-src/lib/libcurses/resize.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: resize.c,v 1.17 2007/11/08 06:34:34 jdc Exp $	*/
2 
3 /*
4  * Copyright (c) 2001
5  *	Brett Lymn.
6  *
7  * This code has been donated to The NetBSD Foundation by the Author.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include <sys/cdefs.h>
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "@(#)resize.c   blymn 2001/08/26";
42 #else
43 __RCSID("$NetBSD: resize.c,v 1.17 2007/11/08 06:34:34 jdc Exp $");
44 #endif
45 #endif				/* not lint */
46 
47 #include <stdlib.h>
48 
49 #include "curses.h"
50 #include "curses_private.h"
51 
52 static int __resizeterm(WINDOW *win, int nlines, int ncols);
53 static int __resizewin(WINDOW *win, int nlines, int ncols);
54 
55 /*
56  * wresize --
57  *	Resize the given window to the new size.
58  */
59 int
60 wresize(WINDOW *win, int req_nlines, int req_ncols)
61 {
62 	int	nlines = req_nlines;
63 	int	ncols = req_ncols;
64 
65 	if (win == NULL)
66 		return ERR;
67 
68 #ifdef	DEBUG
69 	__CTRACE(__CTRACE_WINDOW, "wresize: (%p, %d, %d)\n",
70 	    win, nlines, ncols);
71 #endif
72 	nlines = req_nlines;
73 	ncols = req_ncols;
74 	if (win->orig == NULL) {
75 		/* bound "our" windows by the screen size */
76 		if (win == curscr || win == __virtscr || win == stdscr) {
77 			if (nlines > LINES)
78 				nlines = LINES;
79 			if (nlines < 1)
80 				nlines = 1;
81 			if (ncols > COLS)
82 				ncols = COLS;
83 			if (ncols < 1)
84 				ncols = 1;
85 		} else {
86 			if (win->begy > LINES)
87 				win->begy = 0;
88 			if (win->begy + nlines > LINES)
89 				nlines = 0;
90 			if (nlines <= 0)
91 				nlines += LINES - win->begy;
92 			if (nlines < 1)
93 				nlines = 1;
94 			if (win->begx > COLS)
95 				win->begx = 0;
96 			if (win->begx + ncols > COLS)
97 				ncols = 0;
98 			if (ncols <= 0)
99 				ncols += COLS - win->begx;
100 			if (ncols < 1)
101 				ncols = 1;
102 		}
103 	} else {
104 		/* subwins must fit inside the parent - check this */
105 		if (win->begy > win->orig->begy + win->orig->maxy)
106 			win->begy = win->orig->begy + win->orig->maxy - 1;
107 		if (win->begy + nlines > win->orig->begy + win->orig->maxy)
108 			nlines = 0;
109 		if (nlines <= 0)
110 			nlines += win->orig->begy + win->orig->maxy - win->begy;
111 		if (nlines < 1)
112 			nlines = 1;
113 		if (win->begx > win->orig->begx + win->orig->maxx)
114 			win->begx = win->orig->begx + win->orig->maxx - 1;
115 		if (win->begx + ncols > win->orig->begx + win->orig->maxx)
116 			ncols = 0;
117 		if (ncols <= 0)
118 			ncols += win->orig->begx + win->orig->maxx - win->begx;
119 		if (ncols < 1)
120 			ncols = 1;
121 	}
122 
123 	if ((__resizewin(win, nlines, ncols)) == ERR)
124 		return ERR;
125 
126 	win->reqy = req_nlines;
127 	win->reqx = req_ncols;
128 
129 	/* If someone resizes curscr, we must also resize __virtscr */
130 	if (win == curscr) {
131 		if ((__resizewin(__virtscr, nlines, ncols)) == ERR)
132 			return ERR;
133 		__virtscr->reqy = req_nlines;
134 		__virtscr->reqx = req_ncols;
135 	}
136 
137 	return OK;
138 }
139 
140 /*
141  * resizeterm --
142  *	Resize the terminal window, resizing the dependent windows.
143  */
144 int
145 resizeterm(int nlines, int ncols)
146 {
147 	WINDOW *win;
148 	struct __winlist *list;
149 
150 	  /* don't worry if things have not changed... we would like to
151 	     do this but some bastard programs update LINES and COLS before
152 	     calling resizeterm thus negating it's effect.
153 	if ((nlines == LINES) && (ncols == COLS))
154 	return OK;*/
155 
156 #ifdef	DEBUG
157 	__CTRACE(__CTRACE_WINDOW, "resizeterm: (%d, %d)\n", nlines, ncols);
158 #endif
159 
160 	if (__resizeterm(curscr, nlines, ncols) == ERR)
161 		return ERR;
162 	if (__resizeterm(__virtscr, nlines, ncols) == ERR)
163 		return ERR;
164 	if (__resizeterm(stdscr, nlines, ncols) == ERR)
165 		return ERR;
166 
167 	LINES = nlines;
168 	COLS = ncols;
169 
170 	  /* tweak the flags now that we have updated the LINES and COLS */
171 	for (list = _cursesi_screen->winlistp; list != NULL; list = list->nextp) {
172 		win = list->winp;
173 
174 		if (!(win->flags & __ISPAD))
175 			__swflags(win);
176 	}
177 
178 	wrefresh(curscr);
179 	return OK;
180 }
181 
182 /*
183  * __resizeterm
184  *	Setup window for resizing.
185  */
186 static int
187 __resizeterm(WINDOW *win, int nlines, int ncols)
188 {
189 	int newlines, newcols;
190 
191 	newlines = win->reqy;
192 	if (win->begy + newlines >= nlines)
193 		newlines = 0;
194 	if (newlines == 0)
195 		newlines = nlines - win->begy;
196 
197 	newcols = win->reqx;
198 	if (win->begx + newcols >= ncols)
199 		newcols = 0;
200 	if (newcols == 0)
201 		newcols = ncols - win->begx;
202 
203 	return __resizewin(win, newlines, newcols);
204 }
205 
206 /*
207  * __resizewin --
208  *	Resize the given window.
209  */
210 static int
211 __resizewin(WINDOW *win, int nlines, int ncols)
212 {
213 	__LINE			*lp, *olp, **newlines, *newlspace;
214 	__LDATA			*sp;
215 	__LDATA			*newwspace;
216 	int			 i, j;
217 	int			 y, x;
218 	WINDOW			*swin;
219 
220 #ifdef	DEBUG
221 	__CTRACE(__CTRACE_WINDOW, "resize: (%p, %d, %d)\n", win, nlines, ncols);
222 	__CTRACE(__CTRACE_WINDOW, "resize: win->wattr = %08x\n", win->wattr);
223 	__CTRACE(__CTRACE_WINDOW, "resize: win->flags = %#.4x\n", win->flags);
224 	__CTRACE(__CTRACE_WINDOW, "resize: win->maxy = %d\n", win->maxy);
225 	__CTRACE(__CTRACE_WINDOW, "resize: win->maxx = %d\n", win->maxx);
226 	__CTRACE(__CTRACE_WINDOW, "resize: win->begy = %d\n", win->begy);
227 	__CTRACE(__CTRACE_WINDOW, "resize: win->begx = %d\n", win->begx);
228 	__CTRACE(__CTRACE_WINDOW, "resize: win->scr_t = %d\n", win->scr_t);
229 	__CTRACE(__CTRACE_WINDOW, "resize: win->scr_b = %d\n", win->scr_b);
230 #endif
231 
232 	/*
233 	 * free up any non-spacing storage before we lose the
234 	 * pointers...
235 	 */
236 #ifdef HAVE_WCHAR
237 	__cursesi_win_free_nsp(win);
238 #endif
239 
240 	if (nlines <= 0 || ncols <= 0)
241 		nlines = ncols = 0;
242 	else {
243 		/* Reallocate line pointer array and line space. */
244 		newlines = realloc(win->lines, nlines * sizeof(__LINE *));
245 		if (newlines == NULL)
246 			return ERR;
247 		win->lines = newlines;
248 
249 		newlspace = realloc(win->lspace, nlines * sizeof(__LINE));
250 		if (newlspace == NULL)
251 			return ERR;
252 		win->lspace = newlspace;
253 	}
254 
255 	/* Don't allocate window and line space if it's a subwindow */
256 	if (win->orig == NULL) {
257 		/*
258 		 * Allocate window space in one chunk.
259 		 */
260 		if (ncols != 0) {
261 			newwspace = realloc(win->wspace,
262 					    ncols * nlines * sizeof(__LDATA));
263 			if (newwspace == NULL)
264 				return ERR;
265 			win->wspace = newwspace;
266 		}
267 
268 		/*
269 		 * Point line pointers to line space, and lines themselves into
270 		 * window space.
271 		 */
272 		for (lp = win->lspace, i = 0; i < nlines; i++, lp++) {
273 			win->lines[i] = lp;
274 			lp->line = &win->wspace[i * ncols];
275 #ifdef DEBUG
276 			lp->sentinel = SENTINEL_VALUE;
277 #endif
278 			lp->firstchp = &lp->firstch;
279 			lp->lastchp = &lp->lastch;
280 			lp->firstch = 0;
281 			lp->lastch = ncols - 1;
282 			lp->flags = __ISDIRTY;
283 		}
284 	} else {
285 
286 		win->ch_off = win->begx - win->orig->begx;
287 		  /* Point line pointers to line space. */
288 		for (lp = win->lspace, i = 0; i < nlines; i++, lp++) {
289 			win->lines[i] = lp;
290 			olp = win->orig->lines[i + win->begy - win->orig->begy];
291 			lp->line = &olp->line[win->ch_off];
292 #ifdef DEBUG
293 			lp->sentinel = SENTINEL_VALUE;
294 #endif
295 			lp->firstchp = &olp->firstch;
296 			lp->lastchp = &olp->lastch;
297 			lp->flags = __ISDIRTY;
298 		}
299 	}
300 
301 
302 	win->cury = win->curx = 0;
303 	win->maxy = nlines;
304 	win->maxx = ncols;
305 	win->scr_b = win->maxy - 1;
306 	__swflags(win);
307 
308 	  /*
309 	   * we must zot the window contents otherwise lines may pick
310 	   * up attributes from the previous line when the window is
311 	   * made smaller.  The client will redraw the window anyway
312 	   * so this is no big deal.
313 	   */
314 	for (i = 0; i < win->maxy; i++) {
315 		lp = win->lines[i];
316 		for (sp = lp->line, j = 0; j < win->maxx; j++, sp++) {
317 			sp->attr = 0;
318 #ifndef HAVE_WCHAR
319 			sp->ch = win->bch;
320 #else
321 			sp->ch = ( wchar_t )btowc(( int ) win->bch );
322 			sp->nsp = NULL;
323 			if (_cursesi_copy_nsp(win->bnsp, sp) == ERR)
324 				return ERR;
325 			SET_WCOL( *sp, 1 );
326 #endif /* HAVE_WCHAR */
327 		}
328 		lp->hash = __hash((char *)(void *)lp->line,
329 				  (size_t) (ncols * __LDATASIZE));
330 	}
331 
332 #ifdef DEBUG
333 	__CTRACE(__CTRACE_WINDOW, "resize: win->wattr = %08x\n", win->wattr);
334 	__CTRACE(__CTRACE_WINDOW, "resize: win->flags = %#.4x\n", win->flags);
335 	__CTRACE(__CTRACE_WINDOW, "resize: win->maxy = %d\n", win->maxy);
336 	__CTRACE(__CTRACE_WINDOW, "resize: win->maxx = %d\n", win->maxx);
337 	__CTRACE(__CTRACE_WINDOW, "resize: win->begy = %d\n", win->begy);
338 	__CTRACE(__CTRACE_WINDOW, "resize: win->begx = %d\n", win->begx);
339 	__CTRACE(__CTRACE_WINDOW, "resize: win->scr_t = %d\n", win->scr_t);
340 	__CTRACE(__CTRACE_WINDOW, "resize: win->scr_b = %d\n", win->scr_b);
341 #endif
342 
343 	if (win->orig == NULL) {
344 		/* bound subwindows to new size and fixup their pointers */
345 		for (swin = win->nextp; swin != win; swin = swin->nextp) {
346 			y = swin->reqy;
347 			if (swin->begy > win->begy + win->maxy)
348 				swin->begy = win->begy + win->maxy - 1;
349 			if (swin->begy + y > win->begy + win->maxy)
350 				y = 0;
351 			if (y <= 0)
352 				y += win->begy + win->maxy - swin->begy;
353 			if (y < 1)
354 				y = 1;
355 			x = swin->reqx;
356 			if (swin->begx > win->begx + win->maxx)
357 				swin->begx = win->begx + win->maxx - 1;
358 			if (swin->begx + x > win->begx + win->maxx)
359 				x = 0;
360 			if (x <= 0)
361 				x += win->begy + win->maxx - swin->begx;
362 			if (x < 1)
363 				x = 1;
364 			__resizewin(swin, y, x);
365 		}
366 	}
367 
368 	return OK;
369 }
370