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