xref: /openbsd/lib/libcurses/base/lib_newwin.c (revision c7ef0cfc)
1 /*	$OpenBSD: lib_newwin.c,v 1.7 2023/10/17 09:52:08 nicm Exp $	*/
2 
3 /****************************************************************************
4  * Copyright 2020,2021 Thomas E. Dickey                                     *
5  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
6  *                                                                          *
7  * Permission is hereby granted, free of charge, to any person obtaining a  *
8  * copy of this software and associated documentation files (the            *
9  * "Software"), to deal in the Software without restriction, including      *
10  * without limitation the rights to use, copy, modify, merge, publish,      *
11  * distribute, distribute with modifications, sublicense, and/or sell       *
12  * copies of the Software, and to permit persons to whom the Software is    *
13  * furnished to do so, subject to the following conditions:                 *
14  *                                                                          *
15  * The above copyright notice and this permission notice shall be included  *
16  * in all copies or substantial portions of the Software.                   *
17  *                                                                          *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
21  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
24  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
25  *                                                                          *
26  * Except as contained in this notice, the name(s) of the above copyright   *
27  * holders shall not be used in advertising or otherwise to promote the     *
28  * sale, use or other dealings in this Software without prior written       *
29  * authorization.                                                           *
30  ****************************************************************************/
31 
32 /****************************************************************************
33  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
34  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
35  *     and: Thomas E. Dickey                        1996-on                 *
36  *     and: Juergen Pfeifer                         2009                    *
37  ****************************************************************************/
38 
39 /*
40 **	lib_newwin.c
41 **
42 **	The routines newwin(), subwin() and their dependent
43 **
44 */
45 
46 #include <curses.priv.h>
47 #include <stddef.h>
48 
49 MODULE_ID("$Id: lib_newwin.c,v 1.7 2023/10/17 09:52:08 nicm Exp $")
50 
51 #define window_is(name) ((sp)->_##name == win)
52 
53 #if USE_REENTRANT
54 #define remove_window(name) \
55 		sp->_##name = 0
56 #else
57 #define remove_window(name) \
58 		sp->_##name = 0; \
59 		if (win == name) \
60 		    name = 0
61 #endif
62 
63 static void
remove_window_from_screen(WINDOW * win)64 remove_window_from_screen(WINDOW *win)
65 {
66     SCREEN *sp;
67 
68 #ifdef USE_SP_WINDOWLIST
69     if ((sp = _nc_screen_of(win)) != 0) {
70 	if (window_is(curscr)) {
71 	    remove_window(curscr);
72 	} else if (window_is(stdscr)) {
73 	    remove_window(stdscr);
74 	} else if (window_is(newscr)) {
75 	    remove_window(newscr);
76 	}
77     }
78 #else
79     for (each_screen(sp)) {
80 	if (window_is(curscr)) {
81 	    remove_window(curscr);
82 	    break;
83 	} else if (window_is(stdscr)) {
84 	    remove_window(stdscr);
85 	    break;
86 	} else if (window_is(newscr)) {
87 	    remove_window(newscr);
88 	    break;
89 	}
90     }
91 #endif
92 }
93 
94 NCURSES_EXPORT(int)
_nc_freewin(WINDOW * win)95 _nc_freewin(WINDOW *win)
96 {
97     int result = ERR;
98 #ifdef USE_SP_WINDOWLIST
99     SCREEN *sp = _nc_screen_of(win);	/* pretend this is parameter */
100 #endif
101 
102     T((T_CALLED("_nc_freewin(%p)"), (void *) win));
103 
104     if (win != 0) {
105 
106 	if (_nc_nonsp_try_global(curses) == 0) {
107 	    WINDOWLIST *p, *q;
108 
109 	    q = 0;
110 	    for (each_window(sp, p)) {
111 
112 		if (&(p->win) == win) {
113 		    remove_window_from_screen(win);
114 		    if (q == 0)
115 			WindowList(sp) = p->next;
116 		    else
117 			q->next = p->next;
118 
119 		    if (!IS_SUBWIN(win)) {
120 			int i;
121 
122 			for (i = 0; i <= win->_maxy; i++)
123 			    FreeIfNeeded(win->_line[i].text);
124 		    }
125 		    free(win->_line);
126 		    free(p);
127 
128 		    result = OK;
129 		    T(("...deleted win=%p", (void *) win));
130 		    break;
131 		}
132 		q = p;
133 	    }
134 	    _nc_nonsp_unlock_global(curses);
135 	}
136     }
137     returnCode(result);
138 }
139 
140 NCURSES_EXPORT(WINDOW *)
NCURSES_SP_NAME(newwin)141 NCURSES_SP_NAME(newwin) (NCURSES_SP_DCLx
142 			 int num_lines, int num_columns, int begy, int begx)
143 {
144     WINDOW *win;
145     NCURSES_CH_T *ptr;
146     int i;
147 
148     T((T_CALLED("newwin(%p, %d,%d,%d,%d)"), (void *) SP_PARM, num_lines, num_columns,
149        begy, begx));
150 
151     if (begy < 0
152 	|| begx < 0
153 	|| num_lines < 0
154 	|| num_columns < 0
155 	|| SP_PARM == 0)
156 	returnWin(0);
157 
158     if (num_lines == 0)
159 	num_lines = SP_PARM->_lines_avail - begy;
160     if (num_columns == 0)
161 	num_columns = screen_columns(SP_PARM) - begx;
162 
163     win = NCURSES_SP_NAME(_nc_makenew) (NCURSES_SP_ARGx
164 					num_lines, num_columns, begy, begx, 0);
165     if (win == 0)
166 	returnWin(0);
167 
168     for (i = 0; i < num_lines; i++) {
169 	win->_line[i].text = typeCalloc(NCURSES_CH_T, (unsigned) num_columns);
170 	if (win->_line[i].text == 0) {
171 	    (void) _nc_freewin(win);
172 	    returnWin(0);
173 	}
174 	for (ptr = win->_line[i].text;
175 	     ptr < win->_line[i].text + num_columns;
176 	     ptr++)
177 	    SetChar(*ptr, BLANK_TEXT, BLANK_ATTR);
178     }
179 
180     returnWin(win);
181 }
182 
183 #if NCURSES_SP_FUNCS
184 NCURSES_EXPORT(WINDOW *)
newwin(int num_lines,int num_columns,int begy,int begx)185 newwin(int num_lines, int num_columns, int begy, int begx)
186 {
187     WINDOW *win;
188     _nc_sp_lock_global(curses);
189     win = NCURSES_SP_NAME(newwin) (CURRENT_SCREEN,
190 				   num_lines, num_columns, begy, begx);
191     _nc_sp_unlock_global(curses);
192     return (win);
193 }
194 #endif
195 
196 NCURSES_EXPORT(WINDOW *)
derwin(WINDOW * orig,int num_lines,int num_columns,int begy,int begx)197 derwin(WINDOW *orig, int num_lines, int num_columns, int begy, int begx)
198 {
199     WINDOW *win;
200     int i;
201     int flags = _SUBWIN;
202 #if NCURSES_SP_FUNCS
203     SCREEN *sp = _nc_screen_of(orig);
204 #endif
205 
206     T((T_CALLED("derwin(%p,%d,%d,%d,%d)"), (void *) orig, num_lines, num_columns,
207        begy, begx));
208 
209     /*
210      * make sure window fits inside the original one
211      */
212     if (begy < 0 || begx < 0 || orig == 0 || num_lines < 0 || num_columns < 0)
213 	returnWin(0);
214     if (begy + num_lines > orig->_maxy + 1
215 	|| begx + num_columns > orig->_maxx + 1)
216 	returnWin(0);
217 
218     if (num_lines == 0)
219 	num_lines = orig->_maxy + 1 - begy;
220 
221     if (num_columns == 0)
222 	num_columns = orig->_maxx + 1 - begx;
223 
224     if (IS_PAD(orig))
225 	flags |= _ISPAD;
226 
227     win = NCURSES_SP_NAME(_nc_makenew) (NCURSES_SP_ARGx num_lines, num_columns,
228 					orig->_begy + begy,
229 					orig->_begx + begx, flags);
230     if (win == 0)
231 	returnWin(0);
232 
233     win->_pary = begy;
234     win->_parx = begx;
235     WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
236     win->_nc_bkgd = orig->_nc_bkgd;
237 
238     for (i = 0; i < num_lines; i++)
239 	win->_line[i].text = &orig->_line[begy++].text[begx];
240 
241     win->_parent = orig;
242 
243     returnWin(win);
244 }
245 
246 NCURSES_EXPORT(WINDOW *)
subwin(WINDOW * w,int l,int c,int y,int x)247 subwin(WINDOW *w, int l, int c, int y, int x)
248 {
249     WINDOW *result = 0;
250 
251     T((T_CALLED("subwin(%p, %d, %d, %d, %d)"), (void *) w, l, c, y, x));
252     if (w != 0) {
253 	T(("parent has begy = %ld, begx = %ld", (long) w->_begy, (long) w->_begx));
254 
255 	result = derwin(w, l, c, y - w->_begy, x - w->_begx);
256     }
257     returnWin(result);
258 }
259 
260 static bool
dimension_limit(int value)261 dimension_limit(int value)
262 {
263     NCURSES_SIZE_T test = (NCURSES_SIZE_T) value;
264     return (test == value && value > 0);
265 }
266 
267 NCURSES_EXPORT(WINDOW *)
NCURSES_SP_NAME(_nc_makenew)268 NCURSES_SP_NAME(_nc_makenew) (NCURSES_SP_DCLx
269 			      int num_lines,
270 			      int num_columns,
271 			      int begy,
272 			      int begx,
273 			      int flags)
274 {
275     int i;
276     WINDOWLIST *wp;
277     WINDOW *win;
278     bool is_padwin = (flags & _ISPAD);
279 
280     T((T_CALLED("_nc_makenew(%p,%d,%d,%d,%d)"),
281        (void *) SP_PARM, num_lines, num_columns, begy, begx));
282 
283     if (SP_PARM == 0)
284 	returnWin(0);
285 
286     if (!dimension_limit(num_lines) || !dimension_limit(num_columns))
287 	returnWin(0);
288 
289     if ((wp = typeCalloc(WINDOWLIST, 1)) == 0)
290 	returnWin(0);
291 
292     win = &(wp->win);
293 
294     if ((win->_line = typeCalloc(struct ldat, ((unsigned) num_lines))) == 0) {
295 	free(wp);
296 	returnWin(0);
297     }
298 
299     _nc_nonsp_lock_global(curses);
300 
301     win->_curx = 0;
302     win->_cury = 0;
303     win->_maxy = (NCURSES_SIZE_T) (num_lines - 1);
304     win->_maxx = (NCURSES_SIZE_T) (num_columns - 1);
305     win->_begy = (NCURSES_SIZE_T) begy;
306     win->_begx = (NCURSES_SIZE_T) begx;
307     win->_yoffset = SP_PARM->_topstolen;
308 
309     win->_flags = (short) flags;
310     WINDOW_ATTRS(win) = A_NORMAL;
311     SetChar(win->_nc_bkgd, BLANK_TEXT, BLANK_ATTR);
312 
313     win->_clear = (is_padwin
314 		   ? FALSE
315 		   : (num_lines == screen_lines(SP_PARM)
316 		      && num_columns == screen_columns(SP_PARM)));
317     win->_idlok = FALSE;
318     win->_idcok = TRUE;
319     win->_scroll = FALSE;
320     win->_leaveok = FALSE;
321     win->_use_keypad = FALSE;
322     win->_delay = -1;
323     win->_immed = FALSE;
324     win->_sync = 0;
325     win->_parx = -1;
326     win->_pary = -1;
327     win->_parent = 0;
328 
329     win->_regtop = 0;
330     win->_regbottom = (NCURSES_SIZE_T) (num_lines - 1);
331 
332     win->_pad._pad_y = -1;
333     win->_pad._pad_x = -1;
334     win->_pad._pad_top = -1;
335     win->_pad._pad_bottom = -1;
336     win->_pad._pad_left = -1;
337     win->_pad._pad_right = -1;
338 
339     for (i = 0; i < num_lines; i++) {
340 	/*
341 	 * This used to do
342 	 *
343 	 * win->_line[i].firstchar = win->_line[i].lastchar = _NOCHANGE;
344 	 *
345 	 * which marks the whole window unchanged.  That's how
346 	 * SVr1 curses did it, but SVr4 curses marks the whole new
347 	 * window changed.
348 	 *
349 	 * With the old SVr1-like code, say you have stdscr full of
350 	 * characters, then create a new window with newwin(),
351 	 * then do a printw(win, "foo        ");, the trailing spaces are
352 	 * completely ignored by the following refreshes.  So, you
353 	 * get "foojunkjunk" on the screen instead of "foo        " as
354 	 * you actually intended.
355 	 *
356 	 * SVr4 doesn't do this.  Instead the spaces are actually written.
357 	 * So that's how we want ncurses to behave.
358 	 */
359 	win->_line[i].firstchar = 0;
360 	win->_line[i].lastchar = (NCURSES_SIZE_T) (num_columns - 1);
361 
362 	if_USE_SCROLL_HINTS(win->_line[i].oldindex = i);
363     }
364 
365     if (!is_padwin && (begx + num_columns == screen_columns(SP_PARM))) {
366 	win->_flags |= _ENDLINE;
367 
368 	if (begx == 0 && num_lines == screen_lines(SP_PARM) && begy == 0)
369 	    win->_flags |= _FULLWIN;
370 
371 	if (begy + num_lines == screen_lines(SP_PARM))
372 	    win->_flags |= _SCROLLWIN;
373     }
374 
375     wp->next = WindowList(SP_PARM);
376     wp->screen = SP_PARM;
377     WindowList(SP_PARM) = wp;
378 
379     T((T_CREATE("window %p"), (void *) win));
380 
381     _nc_nonsp_unlock_global(curses);
382     returnWin(win);
383 }
384 
385 /*
386  * wgetch() and other functions with a WINDOW* parameter may use a SCREEN*
387  * internally, and it is useful to allow those to be invoked without switching
388  * SCREEN's, e.g., for multi-threaded applications.
389  */
390 #if NCURSES_SP_FUNCS
391 NCURSES_EXPORT(WINDOW *)
_nc_curscr_of(SCREEN * sp)392 _nc_curscr_of(SCREEN *sp)
393 {
394     return (sp == 0) ? NULL : CurScreen(sp);
395 }
396 
397 NCURSES_EXPORT(WINDOW *)
_nc_newscr_of(SCREEN * sp)398 _nc_newscr_of(SCREEN *sp)
399 {
400     return (sp == 0) ? NULL : NewScreen(sp);
401 }
402 
403 NCURSES_EXPORT(WINDOW *)
_nc_stdscr_of(SCREEN * sp)404 _nc_stdscr_of(SCREEN *sp)
405 {
406     return (sp == 0) ? NULL : StdScreen(sp);
407 }
408 #endif
409