1/****************************************************************************
2 * Copyright (c) 1998-2004,2005 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 ****************************************************************************/
34
35/*
36**	lib_newwin.c
37**
38**	The routines newwin(), subwin() and their dependent
39**
40*/
41
42#include <curses.priv.h>
43
44MODULE_ID("$Id: lib_newwin.c,v 1.36 2005/04/09 15:23:04 tom Exp $")
45
46static WINDOW *
47remove_window_from_screen(WINDOW *win)
48{
49    SCREEN **scan = &_nc_screen_chain;
50
51    while (*scan) {
52	SCREEN *sp = *scan;
53	if (sp->_curscr == win) {
54	    sp->_curscr = 0;
55	    if (win == curscr)
56		curscr = 0;
57	} else if (sp->_stdscr == win) {
58	    sp->_stdscr = 0;
59	    if (win == stdscr)
60		stdscr = 0;
61	} else if (sp->_newscr == win) {
62	    sp->_newscr = 0;
63	    if (win == newscr)
64		newscr = 0;
65	} else {
66	    scan = &(*scan)->_next_screen;
67	    continue;
68	}
69	break;
70    }
71
72    return 0;
73}
74
75NCURSES_EXPORT(int)
76_nc_freewin(WINDOW *win)
77{
78    WINDOWLIST *p, *q;
79    int i;
80    int result = ERR;
81
82    if (win != 0) {
83	for (p = _nc_windows, q = 0; p != 0; q = p, p = p->next) {
84	    if (&(p->win) == win) {
85		remove_window_from_screen(win);
86		if (q == 0)
87		    _nc_windows = p->next;
88		else
89		    q->next = p->next;
90
91		if (!(win->_flags & _SUBWIN)) {
92		    for (i = 0; i <= win->_maxy; i++)
93			FreeIfNeeded(win->_line[i].text);
94		}
95		free(win->_line);
96		free(p);
97
98		result = OK;
99		T(("...deleted win=%p", win));
100		break;
101	    }
102	}
103    }
104    return result;
105}
106
107NCURSES_EXPORT(WINDOW *)
108newwin(int num_lines, int num_columns, int begy, int begx)
109{
110    WINDOW *win;
111    NCURSES_CH_T *ptr;
112    int i;
113
114    T((T_CALLED("newwin(%d,%d,%d,%d)"), num_lines, num_columns, begy, begx));
115
116    if (begy < 0 || begx < 0 || num_lines < 0 || num_columns < 0)
117	returnWin(0);
118
119    if (num_lines == 0)
120	num_lines = SP->_lines_avail - begy;
121    if (num_columns == 0)
122	num_columns = screen_columns - begx;
123
124    if ((win = _nc_makenew(num_lines, num_columns, begy, begx, 0)) == 0)
125	returnWin(0);
126
127    for (i = 0; i < num_lines; i++) {
128	win->_line[i].text = typeCalloc(NCURSES_CH_T, (unsigned) num_columns);
129	if (win->_line[i].text == 0) {
130	    (void) _nc_freewin(win);
131	    returnWin(0);
132	}
133	for (ptr = win->_line[i].text;
134	     ptr < win->_line[i].text + num_columns;
135	     ptr++)
136	    SetChar(*ptr, BLANK_TEXT, BLANK_ATTR);
137    }
138
139    returnWin(win);
140}
141
142NCURSES_EXPORT(WINDOW *)
143derwin(WINDOW *orig, int num_lines, int num_columns, int begy, int begx)
144{
145    WINDOW *win;
146    int i;
147    int flags = _SUBWIN;
148
149    T((T_CALLED("derwin(%p,%d,%d,%d,%d)"), orig, num_lines, num_columns,
150       begy, begx));
151
152    /*
153     * make sure window fits inside the original one
154     */
155    if (begy < 0 || begx < 0 || orig == 0 || num_lines < 0 || num_columns < 0)
156	returnWin(0);
157    if (begy + num_lines > orig->_maxy + 1
158	|| begx + num_columns > orig->_maxx + 1)
159	returnWin(0);
160
161    if (num_lines == 0)
162	num_lines = orig->_maxy + 1 - begy;
163
164    if (num_columns == 0)
165	num_columns = orig->_maxx + 1 - begx;
166
167    if (orig->_flags & _ISPAD)
168	flags |= _ISPAD;
169
170    if ((win = _nc_makenew(num_lines, num_columns, orig->_begy + begy,
171			   orig->_begx + begx, flags)) == 0)
172	returnWin(0);
173
174    win->_pary = begy;
175    win->_parx = begx;
176    win->_attrs = orig->_attrs;
177    win->_nc_bkgd = orig->_nc_bkgd;
178
179    for (i = 0; i < num_lines; i++)
180	win->_line[i].text = &orig->_line[begy++].text[begx];
181
182    win->_parent = orig;
183
184    returnWin(win);
185}
186
187NCURSES_EXPORT(WINDOW *)
188subwin(WINDOW *w, int l, int c, int y, int x)
189{
190    T((T_CALLED("subwin(%p, %d, %d, %d, %d)"), w, l, c, y, x));
191    T(("parent has begy = %d, begx = %d", w->_begy, w->_begx));
192
193    returnWin(derwin(w, l, c, y - w->_begy, x - w->_begx));
194}
195
196static bool
197dimension_limit(int value)
198{
199    NCURSES_SIZE_T test = value;
200    return (test == value && value > 0);
201}
202
203NCURSES_EXPORT(WINDOW *)
204_nc_makenew(int num_lines, int num_columns, int begy, int begx, int flags)
205{
206    int i;
207    WINDOWLIST *wp;
208    WINDOW *win;
209    bool is_pad = (flags & _ISPAD);
210
211    T(("_nc_makenew(%d,%d,%d,%d)", num_lines, num_columns, begy, begx));
212
213    if (SP == 0)
214	return 0;
215
216    if (!dimension_limit(num_lines) || !dimension_limit(num_columns))
217	return 0;
218
219    if ((wp = typeCalloc(WINDOWLIST, 1)) == 0)
220	return 0;
221
222    win = &(wp->win);
223
224    if ((win->_line = typeCalloc(struct ldat, ((unsigned) num_lines))) == 0) {
225	free(win);
226	return 0;
227    }
228
229    win->_curx = 0;
230    win->_cury = 0;
231    win->_maxy = num_lines - 1;
232    win->_maxx = num_columns - 1;
233    win->_begy = begy;
234    win->_begx = begx;
235    win->_yoffset = SP->_topstolen;
236
237    win->_flags = flags;
238    win->_attrs = A_NORMAL;
239    SetChar(win->_nc_bkgd, BLANK_TEXT, BLANK_ATTR);
240
241    win->_clear = is_pad ? FALSE : (num_lines == screen_lines
242				    && num_columns == screen_columns);
243    win->_idlok = FALSE;
244    win->_idcok = TRUE;
245    win->_scroll = FALSE;
246    win->_leaveok = FALSE;
247    win->_use_keypad = FALSE;
248    win->_delay = -1;
249    win->_immed = FALSE;
250    win->_sync = 0;
251    win->_parx = -1;
252    win->_pary = -1;
253    win->_parent = 0;
254
255    win->_regtop = 0;
256    win->_regbottom = num_lines - 1;
257
258    win->_pad._pad_y = -1;
259    win->_pad._pad_x = -1;
260    win->_pad._pad_top = -1;
261    win->_pad._pad_bottom = -1;
262    win->_pad._pad_left = -1;
263    win->_pad._pad_right = -1;
264
265    for (i = 0; i < num_lines; i++) {
266	/*
267	 * This used to do
268	 *
269	 * win->_line[i].firstchar = win->_line[i].lastchar = _NOCHANGE;
270	 *
271	 * which marks the whole window unchanged.  That's how
272	 * SVr1 curses did it, but SVr4 curses marks the whole new
273	 * window changed.
274	 *
275	 * With the old SVr1-like code, say you have stdscr full of
276	 * characters, then create a new window with newwin(),
277	 * then do a printw(win, "foo        ");, the trailing spaces are
278	 * completely ignored by the following refreshes.  So, you
279	 * get "foojunkjunk" on the screen instead of "foo        " as
280	 * you actually intended.
281	 *
282	 * SVr4 doesn't do this.  Instead the spaces are actually written.
283	 * So that's how we want ncurses to behave.
284	 */
285	win->_line[i].firstchar = 0;
286	win->_line[i].lastchar = num_columns - 1;
287
288	if_USE_SCROLL_HINTS(win->_line[i].oldindex = i);
289    }
290
291    if (!is_pad && (begx + num_columns == screen_columns)) {
292	win->_flags |= _ENDLINE;
293
294	if (begx == 0 && num_lines == screen_lines && begy == 0)
295	    win->_flags |= _FULLWIN;
296
297	if (begy + num_lines == screen_lines)
298	    win->_flags |= _SCROLLWIN;
299    }
300
301    wp->next = _nc_windows;
302    _nc_windows = wp;
303
304    T((T_CREATE("window %p"), win));
305
306    return (win);
307}
308