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