1 /* 2 * Copyright (c) 1981, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 /* from: static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 7/20/93"; */ 36 static char *rcsid = "$Id: refresh.c,v 1.6 1993/11/09 04:08:34 cgd Exp $"; 37 #endif /* not lint */ 38 39 #include <curses.h> 40 #include <string.h> 41 42 static int curwin; 43 static short ly, lx; 44 45 static void domvcur __P((int, int, int, int)); 46 static int makech __P((WINDOW *, int)); 47 static void quickch __P((WINDOW *)); 48 static void scrolln __P((WINDOW *, int, int, int, int, int)); 49 50 /* 51 * wrefresh -- 52 * Make the current screen look like "win" over the area coverd by 53 * win. 54 */ 55 int 56 wrefresh(win) 57 register WINDOW *win; 58 { 59 register __LINE *wlp; 60 register int retval; 61 register short wy; 62 int dnum; 63 64 /* Initialize loop parameters. */ 65 ly = curscr->cury; 66 lx = curscr->curx; 67 wy = 0; 68 curwin = (win == curscr); 69 70 if (!curwin) 71 for (wy = 0; wy < win->maxy; wy++) { 72 wlp = win->lines[wy]; 73 if (wlp->flags & __ISDIRTY) 74 wlp->hash = 75 __hash((char *) wlp->line, win->maxx * __LDATASIZE); 76 } 77 78 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 79 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 80 tputs(CL, 0, __cputchar); 81 ly = 0; 82 lx = 0; 83 if (!curwin) { 84 curscr->flags &= ~__CLEAROK; 85 curscr->cury = 0; 86 curscr->curx = 0; 87 werase(curscr); 88 } 89 __touchwin(win); 90 } 91 win->flags &= ~__CLEAROK; 92 } 93 if (!CA) { 94 if (win->curx != 0) 95 putchar('\n'); 96 if (!curwin) 97 werase(curscr); 98 } 99 #ifdef DEBUG 100 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 101 __CTRACE("wrefresh: \tfirstch\tlastch\n"); 102 #endif 103 104 #ifndef NOQCH 105 if ((win->flags & __FULLWIN) && !curwin) { 106 /* 107 * Invoke quickch() only if more than a quarter of the lines 108 * in the window are dirty. 109 */ 110 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 111 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 112 dnum++; 113 if (!__noqch && dnum > (int) win->maxy / 4) 114 quickch(win); 115 } 116 #endif 117 118 #ifdef DEBUG 119 { int i, j; 120 __CTRACE("#####################################\n"); 121 for (i = 0; i < curscr->maxy; i++) { 122 __CTRACE("C: %d:", i); 123 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 124 for (j = 0; j < curscr->maxx; j++) 125 __CTRACE("%c", 126 curscr->lines[i]->line[j].ch); 127 __CTRACE("\n"); 128 for (j = 0; j < curscr->maxx; j++) 129 __CTRACE("%x", 130 curscr->lines[i]->line[j].attr); 131 __CTRACE("\n"); 132 __CTRACE("W: %d:", i); 133 __CTRACE(" 0x%x \n", win->lines[i]->hash); 134 __CTRACE(" 0x%x ", win->lines[i]->flags); 135 for (j = 0; j < win->maxx; j++) 136 __CTRACE("%c", 137 win->lines[i]->line[j].ch); 138 __CTRACE("\n"); 139 for (j = 0; j < win->maxx; j++) 140 __CTRACE("%x", 141 win->lines[i]->line[j].attr); 142 __CTRACE("\n"); 143 } 144 } 145 #endif /* DEBUG */ 146 147 for (wy = 0; wy < win->maxy; wy++) { 148 #ifdef DEBUG 149 __CTRACE("%d\t%d\t%d\n", 150 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); 151 #endif 152 if (!curwin) 153 curscr->lines[wy]->hash = win->lines[wy]->hash; 154 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { 155 if (makech(win, wy) == ERR) 156 return (ERR); 157 else { 158 if (*win->lines[wy]->firstchp >= win->ch_off) 159 *win->lines[wy]->firstchp = win->maxx + 160 win->ch_off; 161 if (*win->lines[wy]->lastchp < win->maxx + 162 win->ch_off) 163 *win->lines[wy]->lastchp = win->ch_off; 164 if (*win->lines[wy]->lastchp < 165 *win->lines[wy]->firstchp) { 166 #ifdef DEBUG 167 __CTRACE("wrefresh: line %d notdirty \n", wy); 168 #endif 169 win->lines[wy]->flags &= ~__ISDIRTY; 170 } 171 } 172 173 } 174 #ifdef DEBUG 175 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 176 *win->lines[wy]->lastchp); 177 #endif 178 } 179 180 #ifdef DEBUG 181 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); 182 #endif 183 184 if (win == curscr) 185 domvcur(ly, lx, win->cury, win->curx); 186 else { 187 if (win->flags & __LEAVEOK) { 188 curscr->cury = ly; 189 curscr->curx = lx; 190 ly -= win->begy; 191 lx -= win->begx; 192 if (ly >= 0 && ly < win->maxy && lx >= 0 && 193 lx < win->maxx) { 194 win->cury = ly; 195 win->curx = lx; 196 } else 197 win->cury = win->curx = 0; 198 } else { 199 domvcur(ly, lx, win->cury + win->begy, 200 win->curx + win->begx); 201 curscr->cury = win->cury + win->begy; 202 curscr->curx = win->curx + win->begx; 203 } 204 } 205 retval = OK; 206 207 (void)fflush(stdout); 208 return (retval); 209 } 210 211 /* 212 * makech -- 213 * Make a change on the screen. 214 */ 215 static int 216 makech(win, wy) 217 register WINDOW *win; 218 int wy; 219 { 220 static __LDATA blank = {' ', 0}; 221 register int nlsp, clsp; /* Last space in lines. */ 222 register int wx, lch, y; 223 register __LDATA *nsp, *csp, *cp, *cep; 224 u_int force; 225 char *ce; 226 227 /* Is the cursor still on the end of the last line? */ 228 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 229 domvcur(ly, lx, ly + 1, 0); 230 ly++; 231 lx = 0; 232 } 233 wx = *win->lines[wy]->firstchp - win->ch_off; 234 if (wx < 0) 235 wx = 0; 236 else if (wx >= win->maxx) 237 return (OK); 238 lch = *win->lines[wy]->lastchp - win->ch_off; 239 if (lch < 0) 240 return (OK); 241 else if (lch >= (int) win->maxx) 242 lch = win->maxx - 1; 243 y = wy + win->begy; 244 245 if (curwin) 246 csp = ␣ 247 else 248 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 249 250 nsp = &win->lines[wy]->line[wx]; 251 force = win->lines[wy]->flags & __FORCEPAINT; 252 win->lines[wy]->flags &= ~__FORCEPAINT; 253 if (CE && !curwin) { 254 for (cp = &win->lines[wy]->line[win->maxx - 1]; 255 cp->ch == ' ' && cp->attr == 0; cp--) 256 if (cp <= win->lines[wy]->line) 257 break; 258 nlsp = cp - win->lines[wy]->line; 259 } 260 if (!curwin) 261 ce = CE; 262 else 263 ce = NULL; 264 265 if (force) { 266 if (CM) 267 tputs(tgoto(CM, lx, ly), 0, __cputchar); 268 else { 269 tputs(HO, 0, __cputchar); 270 __mvcur(0, 0, ly, lx, 1); 271 } 272 } 273 while (wx <= lch) { 274 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 275 if (wx <= lch) { 276 while (wx <= lch && 277 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 278 nsp++; 279 if (!curwin) 280 csp++; 281 ++wx; 282 } 283 continue; 284 } 285 break; 286 } 287 domvcur(ly, lx, y, wx + win->begx); 288 289 #ifdef DEBUG 290 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 291 wx, ly, lx, y, wx + win->begx, force); 292 #endif 293 ly = y; 294 lx = wx + win->begx; 295 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 296 && wx <= lch) { 297 298 if (ce != NULL && win->maxx + win->begx == 299 curscr->maxx && wx >= nlsp && nsp->ch == ' ') { 300 /* Check for clear to end-of-line. */ 301 cep = &curscr->lines[wy]->line[win->maxx - 1]; 302 while (cep->ch == ' ' && cep->attr == 0) 303 if (cep-- <= csp) 304 break; 305 clsp = cep - curscr->lines[wy]->line - 306 win->begx * __LDATASIZE; 307 #ifdef DEBUG 308 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 309 #endif 310 if ((clsp - nlsp >= strlen(CE) 311 && clsp < win->maxx * __LDATASIZE) || 312 wy == win->maxy - 1) { 313 #ifdef DEBUG 314 __CTRACE("makech: using CE\n"); 315 #endif 316 tputs(CE, 0, __cputchar); 317 lx = wx + win->begx; 318 while (wx++ <= clsp) { 319 csp->ch = ' '; 320 csp->attr = 0; 321 csp++; 322 } 323 return (OK); 324 } 325 ce = NULL; 326 } 327 328 /* Enter/exit standout mode as appropriate. */ 329 if (SO && (nsp->attr & __STANDOUT) != 330 (curscr->flags & __WSTANDOUT)) { 331 if (nsp->attr & __STANDOUT) { 332 tputs(SO, 0, __cputchar); 333 curscr->flags |= __WSTANDOUT; 334 } else { 335 tputs(SE, 0, __cputchar); 336 curscr->flags &= ~__WSTANDOUT; 337 } 338 } 339 340 wx++; 341 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 342 if (win->flags & __SCROLLOK) { 343 if (curscr->flags & __WSTANDOUT 344 && win->flags & __ENDLINE) 345 if (!MS) { 346 tputs(SE, 0, 347 __cputchar); 348 curscr->flags &= 349 ~__WSTANDOUT; 350 } 351 if (!(win->flags & __SCROLLWIN)) { 352 if (!curwin) { 353 csp->attr = nsp->attr; 354 putchar(csp->ch = nsp->ch); 355 } else 356 putchar(nsp->ch); 357 } 358 if (wx + win->begx < curscr->maxx) { 359 domvcur(ly, wx + win->begx, 360 win->begy + win->maxy - 1, 361 win->begx + win->maxx - 1); 362 } 363 ly = win->begy + win->maxy - 1; 364 lx = win->begx + win->maxx - 1; 365 return (OK); 366 } 367 if (wx < win->maxx || wy < win->maxy - 1 || 368 !(win->flags & __SCROLLWIN)) { 369 if (!curwin) { 370 csp->attr = nsp->attr; 371 putchar(csp->ch = nsp->ch); 372 csp++; 373 } else 374 putchar(nsp->ch); 375 } 376 #ifdef DEBUG 377 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 378 #endif 379 if (UC && (nsp->attr & __STANDOUT)) { 380 putchar('\b'); 381 tputs(UC, 0, __cputchar); 382 } 383 nsp++; 384 #ifdef DEBUG 385 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 386 #endif 387 } 388 if (lx == wx + win->begx) /* If no change. */ 389 break; 390 lx = wx + win->begx; 391 if (lx >= COLS && AM) 392 lx = COLS - 1; 393 else if (wx >= win->maxx) { 394 domvcur(ly, lx, ly, win->maxx + win->begx - 1); 395 lx = win->maxx + win->begx - 1; 396 } 397 398 #ifdef DEBUG 399 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 400 #endif 401 } 402 return (OK); 403 } 404 405 /* 406 * domvcur -- 407 * Do a mvcur, leaving standout mode if necessary. 408 */ 409 static void 410 domvcur(oy, ox, ny, nx) 411 int oy, ox, ny, nx; 412 { 413 if (curscr->flags & __WSTANDOUT && !MS) { 414 tputs(SE, 0, __cputchar); 415 curscr->flags &= ~__WSTANDOUT; 416 } 417 418 __mvcur(oy, ox, ny, nx, 1); 419 } 420 421 /* 422 * Quickch() attempts to detect a pattern in the change of the window 423 * in order to optimize the change, e.g., scroll n lines as opposed to 424 * repainting the screen line by line. 425 */ 426 427 static void 428 quickch(win) 429 WINDOW *win; 430 { 431 #define THRESH (int) win->maxy / 4 432 433 register __LINE *clp, *tmp1, *tmp2; 434 register int bsize, curs, curw, starts, startw, i, j; 435 int n, target, cur_period, bot, top, sc_region; 436 __LDATA buf[1024]; 437 u_int blank_hash; 438 439 /* 440 * Find how many lines from the top of the screen are unchanged. 441 */ 442 for (top = 0; top < win->maxy; top++) 443 if (win->lines[top]->flags & __FORCEPAINT || 444 win->lines[top]->hash != curscr->lines[top]->hash 445 || memcmp(win->lines[top]->line, 446 curscr->lines[top]->line, 447 win->maxx * __LDATASIZE) != 0) 448 break; 449 else 450 win->lines[top]->flags &= ~__ISDIRTY; 451 /* 452 * Find how many lines from bottom of screen are unchanged. 453 */ 454 for (bot = win->maxy - 1; bot >= 0; bot--) 455 if (win->lines[bot]->flags & __FORCEPAINT || 456 win->lines[bot]->hash != curscr->lines[bot]->hash 457 || memcmp(win->lines[bot]->line, 458 curscr->lines[bot]->line, 459 win->maxx * __LDATASIZE) != 0) 460 break; 461 else 462 win->lines[bot]->flags &= ~__ISDIRTY; 463 464 #ifdef NO_JERKINESS 465 /* 466 * If we have a bottom unchanged region return. Scrolling the 467 * bottom region up and then back down causes a screen jitter. 468 * This will increase the number of characters sent to the screen 469 * but it looks better. 470 */ 471 if (bot < win->maxy - 1) 472 return; 473 #endif /* NO_JERKINESS */ 474 475 /* 476 * Search for the largest block of text not changed. 477 * Invariants of the loop: 478 * - Startw is the index of the beginning of the examined block in win. 479 * - Starts is the index of the beginning of the examined block in 480 * curscr. 481 * - Curs is the index of one past the end of the exmined block in win. 482 * - Curw is the index of one past the end of the exmined block in 483 * curscr. 484 * - bsize is the current size of the examined block. 485 */ 486 for (bsize = bot - top; bsize >= THRESH; bsize--) { 487 for (startw = top; startw <= bot - bsize; startw++) 488 for (starts = top; starts <= bot - bsize; 489 starts++) { 490 for (curw = startw, curs = starts; 491 curs < starts + bsize; curw++, curs++) 492 if (win->lines[curw]->flags & 493 __FORCEPAINT || 494 (win->lines[curw]->hash != 495 curscr->lines[curs]->hash || 496 memcmp(win->lines[curw]->line, 497 curscr->lines[curs]->line, 498 win->maxx * __LDATASIZE) != 0)) 499 break; 500 if (curs == starts + bsize) 501 goto done; 502 } 503 } 504 done: 505 /* Did not find anything */ 506 if (bsize < THRESH) 507 return; 508 509 #ifdef DEBUG 510 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 511 bsize, starts, startw, curw, curs, top, bot); 512 #endif 513 514 /* 515 * Make sure that there is no overlap between the bottom and top 516 * regions and the middle scrolled block. 517 */ 518 if (bot < curs) 519 bot = curs - 1; 520 if (top > starts) 521 top = starts; 522 523 n = startw - starts; 524 525 #ifdef DEBUG 526 __CTRACE("#####################################\n"); 527 for (i = 0; i < curscr->maxy; i++) { 528 __CTRACE("C: %d:", i); 529 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 530 for (j = 0; j < curscr->maxx; j++) 531 __CTRACE("%c", 532 curscr->lines[i]->line[j].ch); 533 __CTRACE("\n"); 534 for (j = 0; j < curscr->maxx; j++) 535 __CTRACE("%x", 536 curscr->lines[i]->line[j].attr); 537 __CTRACE("\n"); 538 __CTRACE("W: %d:", i); 539 __CTRACE(" 0x%x \n", win->lines[i]->hash); 540 __CTRACE(" 0x%x ", win->lines[i]->flags); 541 for (j = 0; j < win->maxx; j++) 542 __CTRACE("%c", 543 win->lines[i]->line[j].ch); 544 __CTRACE("\n"); 545 for (j = 0; j < win->maxx; j++) 546 __CTRACE("%x", 547 win->lines[i]->line[j].attr); 548 __CTRACE("\n"); 549 } 550 #endif 551 552 /* So we don't have to call __hash() each time */ 553 for (i = 0; i < win->maxx; i++) { 554 buf[i].ch = ' '; 555 buf[i].attr = 0; 556 } 557 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 558 559 /* 560 * Perform the rotation to maintain the consistency of curscr. 561 * This is hairy since we are doing an *in place* rotation. 562 * Invariants of the loop: 563 * - I is the index of the current line. 564 * - Target is the index of the target of line i. 565 * - Tmp1 points to current line (i). 566 * - Tmp2 and points to target line (target); 567 * - Cur_period is the index of the end of the current period. 568 * (see below). 569 * 570 * There are 2 major issues here that make this rotation non-trivial: 571 * 1. Scrolling in a scrolling region bounded by the top 572 * and bottom regions determined (whose size is sc_region). 573 * 2. As a result of the use of the mod function, there may be a 574 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 575 * 0 to 2, which then causes all odd lines not to be rotated. 576 * To remedy this, an index of the end ( = beginning) of the 577 * current 'period' is kept, cur_period, and when it is reached, 578 * the next period is started from cur_period + 1 which is 579 * guaranteed not to have been reached since that would mean that 580 * all records would have been reached. (think about it...). 581 * 582 * Lines in the rotation can have 3 attributes which are marked on the 583 * line so that curscr is consistent with the visual screen. 584 * 1. Not dirty -- lines inside the scrolled block, top region or 585 * bottom region. 586 * 2. Blank lines -- lines in the differential of the scrolling 587 * region adjacent to top and bot regions 588 * depending on scrolling direction. 589 * 3. Dirty line -- all other lines are marked dirty. 590 */ 591 sc_region = bot - top + 1; 592 i = top; 593 tmp1 = curscr->lines[top]; 594 cur_period = top; 595 for (j = top; j <= bot; j++) { 596 target = (i - top + n + sc_region) % sc_region + top; 597 tmp2 = curscr->lines[target]; 598 curscr->lines[target] = tmp1; 599 /* Mark block as clean and blank out scrolled lines. */ 600 clp = curscr->lines[target]; 601 #ifdef DEBUG 602 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 603 n, startw, curw, i, target); 604 #endif 605 if ((target >= startw && target < curw) || target < top 606 || target > bot) { 607 #ifdef DEBUG 608 __CTRACE("-- notdirty"); 609 #endif 610 win->lines[target]->flags &= ~__ISDIRTY; 611 } else if ((n > 0 && target >= top && target < top + n) || 612 (n < 0 && target <= bot && target > bot + n)) { 613 if (clp->hash != blank_hash || memcmp(clp->line, 614 buf, win->maxx * __LDATASIZE) !=0) { 615 (void)memcpy(clp->line, buf, 616 win->maxx * __LDATASIZE); 617 #ifdef DEBUG 618 __CTRACE("-- blanked out: dirty"); 619 #endif 620 clp->hash = blank_hash; 621 __touchline(win, target, 0, win->maxx - 1, 0); 622 } else { 623 __touchline(win, target, 0, win->maxx - 1, 0); 624 #ifdef DEBUG 625 __CTRACE(" -- blank line already: dirty"); 626 #endif 627 } 628 } else { 629 #ifdef DEBUG 630 __CTRACE(" -- dirty"); 631 #endif 632 __touchline(win, target, 0, win->maxx - 1, 0); 633 } 634 #ifdef DEBUG 635 __CTRACE("\n"); 636 #endif 637 if (target == cur_period) { 638 i = target + 1; 639 tmp1 = curscr->lines[i]; 640 cur_period = i; 641 } else { 642 tmp1 = tmp2; 643 i = target; 644 } 645 } 646 #ifdef DEBUG 647 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 648 for (i = 0; i < curscr->maxy; i++) { 649 __CTRACE("C: %d:", i); 650 for (j = 0; j < curscr->maxx; j++) 651 __CTRACE("%c", 652 curscr->lines[i]->line[j].ch); 653 __CTRACE("\n"); 654 __CTRACE("W: %d:", i); 655 for (j = 0; j < win->maxx; j++) 656 __CTRACE("%c", 657 win->lines[i]->line[j].ch); 658 __CTRACE("\n"); 659 } 660 #endif 661 if (n != 0) { 662 WINDOW *wp; 663 scrolln(win, starts, startw, curs, bot, top); 664 /* 665 * Need to repoint any subwindow lines to the rotated 666 * line structured. 667 */ 668 for (wp = win->nextp; wp != win; wp = wp->nextp) 669 __set_subwin(win, wp); 670 } 671 } 672 673 /* 674 * Scrolln performs the scroll by n lines, where n is starts - startw. 675 */ 676 static void 677 scrolln(win, starts, startw, curs, bot, top) 678 WINDOW *win; 679 int starts, startw, curs, bot, top; 680 { 681 int i, oy, ox, n; 682 683 oy = curscr->cury; 684 ox = curscr->curx; 685 n = starts - startw; 686 687 if (n > 0) { 688 __mvcur(oy, ox, top, 0, 1); 689 /* Scroll up the block */ 690 if (DL) 691 tputs(__tscroll(DL, n), 0, __cputchar); 692 else 693 for(i = 0; i < n; i++) 694 tputs(dl, 0, __cputchar); 695 696 /* 697 * Push down the bottom region. 698 */ 699 __mvcur(top, 0, bot - n + 1, 0, 1); 700 if (AL) 701 tputs(__tscroll(AL, n), 0, __cputchar); 702 else 703 for(i = 0; i < n; i++) 704 tputs(al, 0, __cputchar); 705 __mvcur(bot - n + 1, 0, oy, ox, 1); 706 } else { 707 /* Preserve the bottom lines */ 708 __mvcur(oy, ox, bot + n + 1, 0, 1); /* n < 0 */ 709 if (DL) 710 tputs(__tscroll(DL, -n), 0, __cputchar); 711 else 712 for(i = n; i < 0; i++) 713 tputs(dl, 0, __cputchar); 714 __mvcur(bot + n + 1, 0, top, 0, 1); 715 716 /* Scroll the block down */ 717 if (AL) 718 tputs(__tscroll(AL, -n), 0, __cputchar); 719 else 720 for(i = n; i < 0; i++) 721 tputs(al, 0, __cputchar); 722 __mvcur(top, 0, oy, ox, 1); 723 } 724 } 725