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