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
49MODULE_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
63static void
64remove_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
94NCURSES_EXPORT(int)
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
140NCURSES_EXPORT(WINDOW *)
141NCURSES_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
184NCURSES_EXPORT(WINDOW *)
185newwin(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
196NCURSES_EXPORT(WINDOW *)
197derwin(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
246NCURSES_EXPORT(WINDOW *)
247subwin(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
260static bool
261dimension_limit(int value)
262{
263    NCURSES_SIZE_T test = (NCURSES_SIZE_T) value;
264    return (test == value && value > 0);
265}
266
267NCURSES_EXPORT(WINDOW *)
268NCURSES_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
391NCURSES_EXPORT(WINDOW *)
392_nc_curscr_of(SCREEN *sp)
393{
394    return (sp == 0) ? NULL : CurScreen(sp);
395}
396
397NCURSES_EXPORT(WINDOW *)
398_nc_newscr_of(SCREEN *sp)
399{
400    return (sp == 0) ? NULL : NewScreen(sp);
401}
402
403NCURSES_EXPORT(WINDOW *)
404_nc_stdscr_of(SCREEN *sp)
405{
406    return (sp == 0) ? NULL : StdScreen(sp);
407}
408#endif
409