ba516337b99634ca051f4342980a6efb575bbccf
[ncurses.git] / ncurses / base / lib_newwin.c
1 /****************************************************************************
2  * Copyright (c) 1998-2005,2006 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
44 MODULE_ID("$Id: lib_newwin.c,v 1.38 2006/10/14 20:31:19 tom Exp $")
45
46 static WINDOW *
47 remove_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
75 NCURSES_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
107 NCURSES_EXPORT(WINDOW *)
108 newwin(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
142 NCURSES_EXPORT(WINDOW *)
143 derwin(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     WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
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
187 NCURSES_EXPORT(WINDOW *)
188 subwin(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 = %ld, begx = %ld", (long) w->_begy, (long) w->_begx));
192
193     returnWin(derwin(w, l, c, y - w->_begy, x - w->_begx));
194 }
195
196 static bool
197 dimension_limit(int value)
198 {
199     NCURSES_SIZE_T test = value;
200     return (test == value && value > 0);
201 }
202
203 NCURSES_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     WINDOW_ATTRS(win) = 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 }