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