1 /* 2 * Copyright (c) 1981, 1993, 1994 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 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94"; 36 #endif /* not lint */ 37 38 #include <string.h> 39 40 #include "curses.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 = __hash((char *)wlp->line, 75 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 __LDATA *nsp, *csp, *cp, *cep; 222 u_int force; 223 int clsp, nlsp; /* Last space in lines. */ 224 int lch, wx, y; 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 274 while (wx <= lch) { 275 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 276 if (wx <= lch) { 277 while (wx <= lch && 278 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 279 nsp++; 280 if (!curwin) 281 ++csp; 282 ++wx; 283 } 284 continue; 285 } 286 break; 287 } 288 domvcur(ly, lx, y, wx + win->begx); 289 290 #ifdef DEBUG 291 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 292 wx, ly, lx, y, wx + win->begx, force); 293 #endif 294 ly = y; 295 lx = wx + win->begx; 296 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 297 && wx <= lch) { 298 299 if (ce != NULL && 300 win->maxx + win->begx == curscr->maxx && 301 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) { 302 /* Check for clear to end-of-line. */ 303 cep = &curscr->lines[wy]->line[win->maxx - 1]; 304 while (cep->ch == ' ' && cep->attr == 0) 305 if (cep-- <= csp) 306 break; 307 clsp = cep - curscr->lines[wy]->line - 308 win->begx * __LDATASIZE; 309 #ifdef DEBUG 310 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 311 #endif 312 if ((clsp - nlsp >= strlen(CE) 313 && clsp < win->maxx * __LDATASIZE) || 314 wy == win->maxy - 1) { 315 if (curscr->flags & __WSTANDOUT) { 316 tputs(SE, 0, __cputchar); 317 curscr->flags &= ~__WSTANDOUT; 318 } 319 tputs(CE, 0, __cputchar); 320 lx = wx + win->begx; 321 while (wx++ <= clsp) { 322 csp->ch = ' '; 323 csp->attr = 0; 324 csp++; 325 } 326 return (OK); 327 } 328 ce = NULL; 329 } 330 331 /* 332 * Enter/exit standout mode as appropriate. 333 * XXX 334 * Should use UC if SO/SE not available. 335 */ 336 if (nsp->attr & __STANDOUT) { 337 if (!(curscr->flags & __WSTANDOUT) && 338 SO != NULL && SE != NULL) { 339 tputs(SO, 0, __cputchar); 340 curscr->flags |= __WSTANDOUT; 341 } 342 } else 343 if (curscr->flags & __WSTANDOUT && 344 SE != NULL) { 345 tputs(SE, 0, __cputchar); 346 curscr->flags &= ~__WSTANDOUT; 347 } 348 349 wx++; 350 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 351 if (win->flags & __SCROLLOK) { 352 if (curscr->flags & __WSTANDOUT 353 && win->flags & __ENDLINE) 354 if (!MS) { 355 tputs(SE, 0, 356 __cputchar); 357 curscr->flags &= 358 ~__WSTANDOUT; 359 } 360 if (!(win->flags & __SCROLLWIN)) { 361 if (!curwin) { 362 csp->attr = nsp->attr; 363 putchar(csp->ch = nsp->ch); 364 } else 365 putchar(nsp->ch); 366 } 367 if (wx + win->begx < curscr->maxx) { 368 domvcur(ly, wx + win->begx, 369 win->begy + win->maxy - 1, 370 win->begx + win->maxx - 1); 371 } 372 ly = win->begy + win->maxy - 1; 373 lx = win->begx + win->maxx - 1; 374 return (OK); 375 } 376 if (wx < win->maxx || wy < win->maxy - 1 || 377 !(win->flags & __SCROLLWIN)) { 378 if (!curwin) { 379 csp->attr = nsp->attr; 380 putchar(csp->ch = nsp->ch); 381 csp++; 382 } else 383 putchar(nsp->ch); 384 } 385 #ifdef DEBUG 386 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 387 #endif 388 if (UC && (nsp->attr & __STANDOUT)) { 389 putchar('\b'); 390 tputs(UC, 0, __cputchar); 391 } 392 nsp++; 393 #ifdef DEBUG 394 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 395 #endif 396 } 397 if (lx == wx + win->begx) /* If no change. */ 398 break; 399 lx = wx + win->begx; 400 if (lx >= COLS && AM) 401 lx = COLS - 1; 402 else if (wx >= win->maxx) { 403 domvcur(ly, lx, ly, win->maxx + win->begx - 1); 404 lx = win->maxx + win->begx - 1; 405 } 406 407 #ifdef DEBUG 408 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 409 #endif 410 } 411 412 /* Don't leave the screen in standout mode. */ 413 if (curscr->flags & __WSTANDOUT) { 414 tputs(SE, 0, __cputchar); 415 curscr->flags &= ~__WSTANDOUT; 416 } 417 return (OK); 418 } 419 420 /* 421 * domvcur -- 422 * Do a mvcur, leaving standout mode if necessary. 423 */ 424 static void 425 domvcur(oy, ox, ny, nx) 426 int oy, ox, ny, nx; 427 { 428 if (curscr->flags & __WSTANDOUT && !MS) { 429 tputs(SE, 0, __cputchar); 430 curscr->flags &= ~__WSTANDOUT; 431 } 432 433 __mvcur(oy, ox, ny, nx, 1); 434 } 435 436 /* 437 * Quickch() attempts to detect a pattern in the change of the window 438 * in order to optimize the change, e.g., scroll n lines as opposed to 439 * repainting the screen line by line. 440 */ 441 442 static void 443 quickch(win) 444 WINDOW *win; 445 { 446 #define THRESH (int) win->maxy / 4 447 448 register __LINE *clp, *tmp1, *tmp2; 449 register int bsize, curs, curw, starts, startw, i, j; 450 int n, target, cur_period, bot, top, sc_region; 451 __LDATA buf[1024]; 452 u_int blank_hash; 453 454 /* 455 * Find how many lines from the top of the screen are unchanged. 456 */ 457 for (top = 0; top < win->maxy; top++) 458 if (win->lines[top]->flags & __FORCEPAINT || 459 win->lines[top]->hash != curscr->lines[top]->hash 460 || memcmp(win->lines[top]->line, 461 curscr->lines[top]->line, 462 win->maxx * __LDATASIZE) != 0) 463 break; 464 else 465 win->lines[top]->flags &= ~__ISDIRTY; 466 /* 467 * Find how many lines from bottom of screen are unchanged. 468 */ 469 for (bot = win->maxy - 1; bot >= 0; bot--) 470 if (win->lines[bot]->flags & __FORCEPAINT || 471 win->lines[bot]->hash != curscr->lines[bot]->hash 472 || memcmp(win->lines[bot]->line, 473 curscr->lines[bot]->line, 474 win->maxx * __LDATASIZE) != 0) 475 break; 476 else 477 win->lines[bot]->flags &= ~__ISDIRTY; 478 479 #ifdef NO_JERKINESS 480 /* 481 * If we have a bottom unchanged region return. Scrolling the 482 * bottom region up and then back down causes a screen jitter. 483 * This will increase the number of characters sent to the screen 484 * but it looks better. 485 */ 486 if (bot < win->maxy - 1) 487 return; 488 #endif /* NO_JERKINESS */ 489 490 /* 491 * Search for the largest block of text not changed. 492 * Invariants of the loop: 493 * - Startw is the index of the beginning of the examined block in win. 494 * - Starts is the index of the beginning of the examined block in 495 * curscr. 496 * - Curs is the index of one past the end of the exmined block in win. 497 * - Curw is the index of one past the end of the exmined block in 498 * curscr. 499 * - bsize is the current size of the examined block. 500 */ 501 for (bsize = bot - top; bsize >= THRESH; bsize--) { 502 for (startw = top; startw <= bot - bsize; startw++) 503 for (starts = top; starts <= bot - bsize; 504 starts++) { 505 for (curw = startw, curs = starts; 506 curs < starts + bsize; curw++, curs++) 507 if (win->lines[curw]->flags & 508 __FORCEPAINT || 509 (win->lines[curw]->hash != 510 curscr->lines[curs]->hash || 511 memcmp(win->lines[curw]->line, 512 curscr->lines[curs]->line, 513 win->maxx * __LDATASIZE) != 0)) 514 break; 515 if (curs == starts + bsize) 516 goto done; 517 } 518 } 519 done: 520 /* Did not find anything */ 521 if (bsize < THRESH) 522 return; 523 524 #ifdef DEBUG 525 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 526 bsize, starts, startw, curw, curs, top, bot); 527 #endif 528 529 /* 530 * Make sure that there is no overlap between the bottom and top 531 * regions and the middle scrolled block. 532 */ 533 if (bot < curs) 534 bot = curs - 1; 535 if (top > starts) 536 top = starts; 537 538 n = startw - starts; 539 540 #ifdef DEBUG 541 __CTRACE("#####################################\n"); 542 for (i = 0; i < curscr->maxy; i++) { 543 __CTRACE("C: %d:", i); 544 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 545 for (j = 0; j < curscr->maxx; j++) 546 __CTRACE("%c", 547 curscr->lines[i]->line[j].ch); 548 __CTRACE("\n"); 549 for (j = 0; j < curscr->maxx; j++) 550 __CTRACE("%x", 551 curscr->lines[i]->line[j].attr); 552 __CTRACE("\n"); 553 __CTRACE("W: %d:", i); 554 __CTRACE(" 0x%x \n", win->lines[i]->hash); 555 __CTRACE(" 0x%x ", win->lines[i]->flags); 556 for (j = 0; j < win->maxx; j++) 557 __CTRACE("%c", 558 win->lines[i]->line[j].ch); 559 __CTRACE("\n"); 560 for (j = 0; j < win->maxx; j++) 561 __CTRACE("%x", 562 win->lines[i]->line[j].attr); 563 __CTRACE("\n"); 564 } 565 #endif 566 567 /* So we don't have to call __hash() each time */ 568 for (i = 0; i < win->maxx; i++) { 569 buf[i].ch = ' '; 570 buf[i].attr = 0; 571 } 572 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 573 574 /* 575 * Perform the rotation to maintain the consistency of curscr. 576 * This is hairy since we are doing an *in place* rotation. 577 * Invariants of the loop: 578 * - I is the index of the current line. 579 * - Target is the index of the target of line i. 580 * - Tmp1 points to current line (i). 581 * - Tmp2 and points to target line (target); 582 * - Cur_period is the index of the end of the current period. 583 * (see below). 584 * 585 * There are 2 major issues here that make this rotation non-trivial: 586 * 1. Scrolling in a scrolling region bounded by the top 587 * and bottom regions determined (whose size is sc_region). 588 * 2. As a result of the use of the mod function, there may be a 589 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 590 * 0 to 2, which then causes all odd lines not to be rotated. 591 * To remedy this, an index of the end ( = beginning) of the 592 * current 'period' is kept, cur_period, and when it is reached, 593 * the next period is started from cur_period + 1 which is 594 * guaranteed not to have been reached since that would mean that 595 * all records would have been reached. (think about it...). 596 * 597 * Lines in the rotation can have 3 attributes which are marked on the 598 * line so that curscr is consistent with the visual screen. 599 * 1. Not dirty -- lines inside the scrolled block, top region or 600 * bottom region. 601 * 2. Blank lines -- lines in the differential of the scrolling 602 * region adjacent to top and bot regions 603 * depending on scrolling direction. 604 * 3. Dirty line -- all other lines are marked dirty. 605 */ 606 sc_region = bot - top + 1; 607 i = top; 608 tmp1 = curscr->lines[top]; 609 cur_period = top; 610 for (j = top; j <= bot; j++) { 611 target = (i - top + n + sc_region) % sc_region + top; 612 tmp2 = curscr->lines[target]; 613 curscr->lines[target] = tmp1; 614 /* Mark block as clean and blank out scrolled lines. */ 615 clp = curscr->lines[target]; 616 #ifdef DEBUG 617 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 618 n, startw, curw, i, target); 619 #endif 620 if ((target >= startw && target < curw) || target < top 621 || target > bot) { 622 #ifdef DEBUG 623 __CTRACE("-- notdirty"); 624 #endif 625 win->lines[target]->flags &= ~__ISDIRTY; 626 } else if ((n > 0 && target >= top && target < top + n) || 627 (n < 0 && target <= bot && target > bot + n)) { 628 if (clp->hash != blank_hash || memcmp(clp->line, 629 buf, win->maxx * __LDATASIZE) !=0) { 630 (void)memcpy(clp->line, buf, 631 win->maxx * __LDATASIZE); 632 #ifdef DEBUG 633 __CTRACE("-- blanked out: dirty"); 634 #endif 635 clp->hash = blank_hash; 636 __touchline(win, target, 0, win->maxx - 1, 0); 637 } else { 638 __touchline(win, target, 0, win->maxx - 1, 0); 639 #ifdef DEBUG 640 __CTRACE(" -- blank line already: dirty"); 641 #endif 642 } 643 } else { 644 #ifdef DEBUG 645 __CTRACE(" -- dirty"); 646 #endif 647 __touchline(win, target, 0, win->maxx - 1, 0); 648 } 649 #ifdef DEBUG 650 __CTRACE("\n"); 651 #endif 652 if (target == cur_period) { 653 i = target + 1; 654 tmp1 = curscr->lines[i]; 655 cur_period = i; 656 } else { 657 tmp1 = tmp2; 658 i = target; 659 } 660 } 661 #ifdef DEBUG 662 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 663 for (i = 0; i < curscr->maxy; i++) { 664 __CTRACE("C: %d:", i); 665 for (j = 0; j < curscr->maxx; j++) 666 __CTRACE("%c", 667 curscr->lines[i]->line[j].ch); 668 __CTRACE("\n"); 669 __CTRACE("W: %d:", i); 670 for (j = 0; j < win->maxx; j++) 671 __CTRACE("%c", win->lines[i]->line[j].ch); 672 __CTRACE("\n"); 673 } 674 #endif 675 if (n != 0) { 676 WINDOW *wp; 677 scrolln(win, starts, startw, curs, bot, top); 678 /* 679 * Need to repoint any subwindow lines to the rotated 680 * line structured. 681 */ 682 for (wp = win->nextp; wp != win; wp = wp->nextp) 683 __set_subwin(win, wp); 684 } 685 } 686 687 /* 688 * scrolln -- 689 * Scroll n lines, where n is starts - startw. 690 */ 691 static void 692 scrolln(win, starts, startw, curs, bot, top) 693 WINDOW *win; 694 int starts, startw, curs, bot, top; 695 { 696 int i, oy, ox, n; 697 698 oy = curscr->cury; 699 ox = curscr->curx; 700 n = starts - startw; 701 702 /* 703 * XXX 704 * The initial tests that set __noqch don't let us reach here unless 705 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 706 * scrolling can only shift the entire scrolling region, not just a 707 * part of it, which means that the quickch() routine is going to be 708 * sadly disappointed in us if we don't have CS as well. 709 * 710 * If CS, HO and SF/sf are set, can use the scrolling region. Because 711 * the cursor position after CS is undefined, we need HO which gives us 712 * the ability to move to somewhere without knowledge of the current 713 * location of the cursor. Still call __mvcur() anyway, to update its 714 * idea of where the cursor is. 715 * 716 * When the scrolling region has been set, the cursor has to be at the 717 * last line of the region to make the scroll happen. 718 * 719 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 720 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 721 * SF/SR. So, if we're scrolling almost all of the screen, try and use 722 * AL/DL, otherwise use the scrolling region. The "almost all" is a 723 * shameless hack for vi. 724 */ 725 if (n > 0) { 726 if (CS != NULL && HO != NULL && (SF != NULL || 727 (AL == NULL || DL == NULL || 728 top > 3 || bot + 3 < win->maxy) && sf != NULL)) { 729 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 730 __mvcur(oy, ox, 0, 0, 1); 731 tputs(HO, 0, __cputchar); 732 __mvcur(0, 0, bot, 0, 1); 733 if (SF != NULL) 734 tputs(__tscroll(SF, n, 0), 0, __cputchar); 735 else 736 for (i = 0; i < n; i++) 737 tputs(sf, 0, __cputchar); 738 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 739 __mvcur(bot, 0, 0, 0, 1); 740 tputs(HO, 0, __cputchar); 741 __mvcur(0, 0, oy, ox, 1); 742 return; 743 } 744 745 /* Scroll up the block. */ 746 if (SF != NULL && top == 0) { 747 __mvcur(oy, ox, bot, 0, 1); 748 tputs(__tscroll(SF, n, 0), 0, __cputchar); 749 } else if (DL != NULL) { 750 __mvcur(oy, ox, top, 0, 1); 751 tputs(__tscroll(DL, n, 0), 0, __cputchar); 752 } else if (dl != NULL) { 753 __mvcur(oy, ox, top, 0, 1); 754 for (i = 0; i < n; i++) 755 tputs(dl, 0, __cputchar); 756 } else if (sf != NULL && top == 0) { 757 __mvcur(oy, ox, bot, 0, 1); 758 for (i = 0; i < n; i++) 759 tputs(sf, 0, __cputchar); 760 } else 761 abort(); 762 763 /* Push down the bottom region. */ 764 __mvcur(top, 0, bot - n + 1, 0, 1); 765 if (AL != NULL) 766 tputs(__tscroll(AL, n, 0), 0, __cputchar); 767 else if (al != NULL) 768 for (i = 0; i < n; i++) 769 tputs(al, 0, __cputchar); 770 else 771 abort(); 772 __mvcur(bot - n + 1, 0, oy, ox, 1); 773 } else { 774 /* 775 * !!! 776 * n < 0 777 * 778 * If CS, HO and SR/sr are set, can use the scrolling region. 779 * See the above comments for details. 780 */ 781 if (CS != NULL && HO != NULL && (SR != NULL || 782 (AL == NULL || DL == NULL || 783 top > 3 || bot + 3 < win->maxy) && sr != NULL)) { 784 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 785 __mvcur(oy, ox, 0, 0, 1); 786 tputs(HO, 0, __cputchar); 787 __mvcur(0, 0, top, 0, 1); 788 789 if (SR != NULL) 790 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 791 else 792 for (i = n; i < 0; i++) 793 tputs(sr, 0, __cputchar); 794 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 795 __mvcur(top, 0, 0, 0, 1); 796 tputs(HO, 0, __cputchar); 797 __mvcur(0, 0, oy, ox, 1); 798 return; 799 } 800 801 /* Preserve the bottom lines. */ 802 __mvcur(oy, ox, bot + n + 1, 0, 1); 803 if (SR != NULL && bot == win->maxy) 804 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 805 else if (DL != NULL) 806 tputs(__tscroll(DL, -n, 0), 0, __cputchar); 807 else if (dl != NULL) 808 for (i = n; i < 0; i++) 809 tputs(dl, 0, __cputchar); 810 else if (sr != NULL && bot == win->maxy) 811 for (i = n; i < 0; i++) 812 tputs(sr, 0, __cputchar); 813 else 814 abort(); 815 816 /* Scroll the block down. */ 817 __mvcur(bot + n + 1, 0, top, 0, 1); 818 if (AL != NULL) 819 tputs(__tscroll(AL, -n, 0), 0, __cputchar); 820 else if (al != NULL) 821 for (i = n; i < 0; i++) 822 tputs(al, 0, __cputchar); 823 else 824 abort(); 825 __mvcur(top, 0, oy, ox, 1); 826 } 827 } 828