1 /* $NetBSD: resize.c,v 1.37 2024/12/23 02:58:04 blymn Exp $ */ 2 3 /* 4 * Copyright (c) 2001 5 * Brett Lymn. 6 * 7 * This code has been donated to The NetBSD Foundation by the Author. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #ifndef lint 33 #if 0 34 static char sccsid[] = "@(#)resize.c blymn 2001/08/26"; 35 #else 36 __RCSID("$NetBSD: resize.c,v 1.37 2024/12/23 02:58:04 blymn Exp $"); 37 #endif 38 #endif /* not lint */ 39 40 #include <stdlib.h> 41 42 #include "curses.h" 43 #include "curses_private.h" 44 45 static int __resizeterm(WINDOW *win, int nlines, int ncols); 46 static int __resizewin(WINDOW *win, int nlines, int ncols); 47 48 /* 49 * wresize -- 50 * Resize the given window to the new size. 51 */ 52 int 53 wresize(WINDOW *win, int req_nlines, int req_ncols) 54 { 55 int nlines = req_nlines; 56 int ncols = req_ncols; 57 58 if (__predict_false(win == NULL)) 59 return ERR; 60 61 __CTRACE(__CTRACE_WINDOW, "wresize: (%p, %d, %d)\n", 62 win, nlines, ncols); 63 if (win->orig != NULL) { 64 /* subwins must fit inside the parent - check this */ 65 if (win->begy > win->orig->begy + win->orig->maxy) 66 win->begy = win->orig->begy + win->orig->maxy - 1; 67 if (win->begy + nlines > win->orig->begy + win->orig->maxy) 68 nlines = 0; 69 if (nlines <= 0) 70 nlines += win->orig->begy + win->orig->maxy - win->begy; 71 if (nlines < 1) 72 nlines = 1; 73 if (win->begx > win->orig->begx + win->orig->maxx) 74 win->begx = win->orig->begx + win->orig->maxx - 1; 75 if (win->begx + ncols > win->orig->begx + win->orig->maxx) 76 ncols = 0; 77 if (ncols <= 0) 78 ncols += win->orig->begx + win->orig->maxx - win->begx; 79 if (ncols < 1) 80 ncols = 1; 81 } else if (!(win->flags & __ISPAD)) { 82 /* bound "our" windows by the screen size */ 83 if (win == curscr || win == __virtscr || win == stdscr) { 84 if (nlines > LINES) 85 nlines = LINES; 86 if (nlines < 1) 87 nlines = 1; 88 if (ncols > COLS) 89 ncols = COLS; 90 if (ncols < 1) 91 ncols = 1; 92 } else { 93 if (win->begy > LINES) 94 win->begy = 0; 95 if (win->begy + nlines > LINES) 96 nlines = 0; 97 if (nlines <= 0) 98 nlines += LINES - win->begy; 99 if (nlines < 1) 100 nlines = 1; 101 if (win->begx > COLS) 102 win->begx = 0; 103 if (win->begx + ncols > COLS) 104 ncols = 0; 105 if (ncols <= 0) 106 ncols += COLS - win->begx; 107 if (ncols < 1) 108 ncols = 1; 109 } 110 } 111 112 if ((__resizewin(win, nlines, ncols)) == ERR) 113 return ERR; 114 115 win->reqy = req_nlines; 116 win->reqx = req_ncols; 117 118 /* If someone resizes curscr, we must also resize __virtscr */ 119 if (win == curscr) { 120 if ((__resizewin(__virtscr, nlines, ncols)) == ERR) 121 return ERR; 122 __virtscr->reqy = req_nlines; 123 __virtscr->reqx = req_ncols; 124 } 125 126 return OK; 127 } 128 129 /* 130 * is_term_resized -- 131 * Return true if the given dimensions do not match the 132 * internal structures. 133 */ 134 bool 135 is_term_resized(int nlines, int ncols) 136 { 137 138 return (nlines > 0 && ncols > 0 && 139 (nlines != _cursesi_screen->LINES || 140 ncols != _cursesi_screen->COLS)); 141 } 142 143 /* 144 * resizeterm -- 145 * Resize the terminal window, resizing the dependent windows. 146 * Handles internal book-keeping. 147 */ 148 int 149 resizeterm(int nlines, int ncols) 150 { 151 int result; 152 153 __CTRACE(__CTRACE_WINDOW, "resizeterm: (%d, %d)\n", nlines, ncols); 154 155 /* Unconditionally inform application screen has been resized. */ 156 _cursesi_screen->resized = 1; 157 158 if (!is_term_resized(nlines, ncols)) 159 return OK; 160 161 result = resize_term(nlines, ncols); 162 163 /* Screen contents are unknown, libcurses is not libpanel, we don't 164 * know the correct draw order. */ 165 clearok(curscr, TRUE); 166 167 if (result == OK) { 168 /* Redraw the soft label keys to the new size. */ 169 __slk_resize(_cursesi_screen, ncols); 170 __slk_noutrefresh(_cursesi_screen); 171 } 172 173 return result; 174 } 175 176 /* 177 * resize_term -- 178 * Resize the terminal window, resizing the dependent windows. 179 */ 180 int 181 resize_term(int nlines, int ncols) 182 { 183 WINDOW *win; 184 struct __winlist *list; 185 int rlines; 186 187 __CTRACE(__CTRACE_WINDOW, "resize_term: (%d, %d)\n", nlines, ncols); 188 189 if (!is_term_resized(nlines, ncols)) 190 return OK; 191 192 if (__resizeterm(curscr, nlines, ncols) == ERR) 193 return ERR; 194 if (__resizeterm(__virtscr, nlines, ncols) == ERR) 195 return ERR; 196 rlines = nlines - __rippedlines(_cursesi_screen, 0); 197 if (__resizeterm(stdscr, rlines, ncols) == ERR) 198 return ERR; 199 200 _cursesi_screen->LINES = nlines; 201 _cursesi_screen->COLS = ncols; 202 LINES = nlines; 203 COLS = ncols; 204 205 /* tweak the flags now that we have updated the LINES and COLS */ 206 for (list = _cursesi_screen->winlistp; list != NULL; list = list->nextp) { 207 win = list->winp; 208 209 if (!(win->flags & __ISPAD)) 210 __swflags(win); 211 } 212 213 /* Resize and re-position the ripped off windows. */ 214 if (__ripoffresize(_cursesi_screen) == ERR) 215 return ERR; 216 217 return OK; 218 } 219 220 /* 221 * __resizeterm 222 * Setup window for resizing. 223 */ 224 static int 225 __resizeterm(WINDOW *win, int nlines, int ncols) 226 { 227 int newlines, newcols; 228 229 newlines = win->reqy; 230 if (win->begy + newlines >= nlines) 231 newlines = 0; 232 if (newlines == 0) 233 newlines = nlines - win->begy; 234 235 newcols = win->reqx; 236 if (win->begx + newcols >= ncols) 237 newcols = 0; 238 if (newcols == 0) 239 newcols = ncols - win->begx; 240 241 return __resizewin(win, newlines, newcols); 242 } 243 244 /* 245 * __resizewin -- 246 * Resize the given window. 247 */ 248 static int 249 __resizewin(WINDOW *win, int nlines, int ncols) 250 { 251 __LINE *lp, *olp, **newlines, *newlspace; 252 __LDATA *sp; 253 __LDATA *newwspace; 254 int i, j; 255 int y, x; 256 WINDOW *swin; 257 258 __CTRACE(__CTRACE_WINDOW, "resize: (%p, %d, %d)\n", win, nlines, ncols); 259 __CTRACE(__CTRACE_WINDOW, "resize: win->wattr = %08x\n", win->wattr); 260 __CTRACE(__CTRACE_WINDOW, "resize: win->flags = %#.4x\n", win->flags); 261 __CTRACE(__CTRACE_WINDOW, "resize: win->maxy = %d\n", win->maxy); 262 __CTRACE(__CTRACE_WINDOW, "resize: win->maxx = %d\n", win->maxx); 263 __CTRACE(__CTRACE_WINDOW, "resize: win->begy = %d\n", win->begy); 264 __CTRACE(__CTRACE_WINDOW, "resize: win->begx = %d\n", win->begx); 265 __CTRACE(__CTRACE_WINDOW, "resize: win->scr_t = %d\n", win->scr_t); 266 __CTRACE(__CTRACE_WINDOW, "resize: win->scr_b = %d\n", win->scr_b); 267 268 /* 269 * free up any non-spacing storage before we lose the 270 * pointers... 271 */ 272 #ifdef HAVE_WCHAR 273 __cursesi_win_free_nsp(win); 274 #endif 275 276 if (nlines <= 0 || ncols <= 0) 277 nlines = ncols = 0; 278 else { 279 /* Reallocate line pointer array and line space. */ 280 newlines = realloc(win->alines, nlines * sizeof(__LINE *)); 281 if (newlines == NULL) 282 return ERR; 283 win->alines = newlines; 284 285 newlspace = realloc(win->lspace, nlines * sizeof(__LINE)); 286 if (newlspace == NULL) 287 return ERR; 288 win->lspace = newlspace; 289 } 290 291 /* Don't allocate window and line space if it's a subwindow */ 292 if (win->orig == NULL) { 293 /* 294 * Allocate window space in one chunk. 295 */ 296 if (ncols != 0) { 297 newwspace = realloc(win->wspace, 298 ncols * nlines * sizeof(__LDATA)); 299 if (newwspace == NULL) 300 return ERR; 301 win->wspace = newwspace; 302 } 303 304 /* 305 * Point line pointers to line space, and lines themselves into 306 * window space. 307 */ 308 for (lp = win->lspace, i = 0; i < nlines; i++, lp++) { 309 win->alines[i] = lp; 310 lp->line = &win->wspace[i * ncols]; 311 #ifdef DEBUG 312 lp->sentinel = SENTINEL_VALUE; 313 #endif 314 lp->firstchp = &lp->firstch; 315 lp->lastchp = &lp->lastch; 316 lp->firstch = 0; 317 lp->lastch = ncols - 1; 318 lp->flags = __ISDIRTY; 319 } 320 } else { 321 322 win->ch_off = win->begx - win->orig->begx; 323 /* Point line pointers to line space. */ 324 for (lp = win->lspace, i = 0; i < nlines; i++, lp++) { 325 win->alines[i] = lp; 326 olp = win->orig->alines[i + win->begy - win->orig->begy]; 327 lp->line = &olp->line[win->ch_off]; 328 #ifdef DEBUG 329 lp->sentinel = SENTINEL_VALUE; 330 #endif 331 lp->firstchp = &olp->firstch; 332 lp->lastchp = &olp->lastch; 333 lp->flags = __ISDIRTY; 334 } 335 } 336 337 win->cury = win->curx = 0; 338 win->maxy = nlines; 339 win->maxx = ncols; 340 win->scr_b = win->maxy - 1; 341 __swflags(win); 342 343 /* 344 * we must zot the window contents otherwise lines may pick 345 * up attributes from the previous line when the window is 346 * made smaller. The client will redraw the window anyway 347 * so this is no big deal. 348 */ 349 for (i = 0; i < win->maxy; i++) { 350 lp = win->alines[i]; 351 for (sp = lp->line, j = 0; j < win->maxx; j++, sp++) { 352 sp->attr = 0; 353 sp->cflags = CA_BACKGROUND; 354 #ifndef HAVE_WCHAR 355 sp->ch = win->bch; 356 #else 357 sp->ch = (wchar_t)btowc((int)win->bch); 358 sp->nsp = NULL; 359 if (_cursesi_copy_nsp(win->bnsp, sp) == ERR) 360 return ERR; 361 sp->wcols = 1; 362 #endif /* HAVE_WCHAR */ 363 } 364 lp->hash = __hash_line(lp->line, ncols); 365 } 366 367 __CTRACE(__CTRACE_WINDOW, "resize: win->wattr = %08x\n", win->wattr); 368 __CTRACE(__CTRACE_WINDOW, "resize: win->flags = %#.4x\n", win->flags); 369 __CTRACE(__CTRACE_WINDOW, "resize: win->maxy = %d\n", win->maxy); 370 __CTRACE(__CTRACE_WINDOW, "resize: win->maxx = %d\n", win->maxx); 371 __CTRACE(__CTRACE_WINDOW, "resize: win->begy = %d\n", win->begy); 372 __CTRACE(__CTRACE_WINDOW, "resize: win->begx = %d\n", win->begx); 373 __CTRACE(__CTRACE_WINDOW, "resize: win->scr_t = %d\n", win->scr_t); 374 __CTRACE(__CTRACE_WINDOW, "resize: win->scr_b = %d\n", win->scr_b); 375 376 if (win->orig == NULL) { 377 /* bound subwindows to new size and fixup their pointers */ 378 for (swin = win->nextp; swin != win; swin = swin->nextp) { 379 y = swin->reqy; 380 if (swin->begy > win->begy + win->maxy) 381 swin->begy = win->begy + win->maxy - 1; 382 if (swin->begy + y > win->begy + win->maxy) 383 y = 0; 384 if (y <= 0) 385 y += win->begy + win->maxy - swin->begy; 386 if (y < 1) 387 y = 1; 388 x = swin->reqx; 389 if (swin->begx > win->begx + win->maxx) 390 swin->begx = win->begx + win->maxx - 1; 391 if (swin->begx + x > win->begx + win->maxx) 392 x = 0; 393 if (x <= 0) 394 x += win->begx + win->maxx - swin->begx; 395 if (x < 1) 396 x = 1; 397 __resizewin(swin, y, x); 398 } 399 } 400 401 return OK; 402 } 403