1 /* $NetBSD: refresh.c,v 1.14 1999/09/17 14:21:04 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1981, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94"; 40 #else 41 __RCSID("$NetBSD: refresh.c,v 1.14 1999/09/17 14:21:04 simonb Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <string.h> 46 47 #include "curses.h" 48 49 static int curwin; 50 static short ly, lx; 51 52 static void domvcur __P((int, int, int, int)); 53 static int makech __P((WINDOW *, int)); 54 static void quickch __P((WINDOW *)); 55 static void scrolln __P((WINDOW *, int, int, int, int, int)); 56 57 /* 58 * wrefresh -- 59 * Make the current screen look like "win" over the area coverd by 60 * win. 61 */ 62 int 63 wrefresh(win) 64 WINDOW *win; 65 { 66 __LINE *wlp; 67 int retval; 68 short wy; 69 int dnum; 70 71 /* Check if we need to restart ... */ 72 if (__endwin) { 73 __endwin = 0; 74 __restartwin(); 75 } 76 77 /* Initialize loop parameters. */ 78 ly = curscr->cury; 79 lx = curscr->curx; 80 wy = 0; 81 curwin = (win == curscr); 82 83 if (!curwin) 84 for (wy = 0; wy < win->maxy; wy++) { 85 wlp = win->lines[wy]; 86 if (wlp->flags & __ISDIRTY) 87 wlp->hash = __hash((char *)(void *)wlp->line, 88 (int) (win->maxx * __LDATASIZE)); 89 } 90 91 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 92 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 93 tputs(CL, 0, __cputchar); 94 ly = 0; 95 lx = 0; 96 if (!curwin) { 97 curscr->flags &= ~__CLEAROK; 98 curscr->cury = 0; 99 curscr->curx = 0; 100 werase(curscr); 101 } 102 __touchwin(win); 103 } 104 win->flags &= ~__CLEAROK; 105 } 106 if (!CA) { 107 if (win->curx != 0) 108 putchar('\n'); 109 if (!curwin) 110 werase(curscr); 111 } 112 #ifdef DEBUG 113 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 114 __CTRACE("wrefresh: \tfirstch\tlastch\n"); 115 #endif 116 117 if ((win->flags & __FULLWIN) && !curwin) { 118 /* 119 * Invoke quickch() only if more than a quarter of the lines 120 * in the window are dirty. 121 */ 122 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 123 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 124 dnum++; 125 if (!__noqch && dnum > (int) win->maxy / 4) 126 quickch(win); 127 } 128 129 #ifdef DEBUG 130 { 131 int i, j; 132 133 __CTRACE("#####################################\n"); 134 for (i = 0; i < curscr->maxy; i++) { 135 __CTRACE("C: %d:", i); 136 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 137 for (j = 0; j < curscr->maxx; j++) 138 __CTRACE("%c", curscr->lines[i]->line[j].ch); 139 __CTRACE("\n"); 140 __CTRACE(" attr:"); 141 for (j = 0; j < curscr->maxx; j++) 142 __CTRACE(" %x", curscr->lines[i]->line[j].attr); 143 __CTRACE("\n"); 144 __CTRACE("W: %d:", i); 145 __CTRACE(" 0x%x \n", win->lines[i]->hash); 146 __CTRACE(" 0x%x ", win->lines[i]->flags); 147 for (j = 0; j < win->maxx; j++) 148 __CTRACE("%c", win->lines[i]->line[j].ch); 149 __CTRACE("\n"); 150 __CTRACE(" attr:"); 151 for (j = 0; j < win->maxx; j++) 152 __CTRACE(" %x", win->lines[i]->line[j].attr); 153 __CTRACE("\n"); 154 } 155 } 156 #endif /* DEBUG */ 157 158 for (wy = 0; wy < win->maxy; wy++) { 159 #ifdef DEBUG 160 __CTRACE("wy %d\tf: %d\tl:%d\tflags %x\n", 161 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp, 162 win->lines[wy]->flags); 163 #endif 164 if (!curwin) 165 curscr->lines[wy]->hash = win->lines[wy]->hash; 166 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { 167 if (makech(win, wy) == ERR) 168 return (ERR); 169 else { 170 if (*win->lines[wy]->firstchp >= win->ch_off) 171 *win->lines[wy]->firstchp = win->maxx + 172 win->ch_off; 173 if (*win->lines[wy]->lastchp < win->maxx + 174 win->ch_off) 175 *win->lines[wy]->lastchp = win->ch_off; 176 if (*win->lines[wy]->lastchp < 177 *win->lines[wy]->firstchp) { 178 #ifdef DEBUG 179 __CTRACE("wrefresh: line %d notdirty \n", wy); 180 #endif 181 win->lines[wy]->flags &= ~__ISDIRTY; 182 } 183 } 184 185 } 186 #ifdef DEBUG 187 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 188 *win->lines[wy]->lastchp); 189 #endif 190 } 191 192 #ifdef DEBUG 193 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); 194 #endif 195 196 if (win == curscr) 197 domvcur(ly, lx, (int) win->cury, (int) win->curx); 198 else { 199 if (win->flags & __LEAVEOK) { 200 curscr->cury = ly; 201 curscr->curx = lx; 202 ly -= win->begy; 203 lx -= win->begx; 204 if (ly >= 0 && ly < win->maxy && lx >= 0 && 205 lx < win->maxx) { 206 win->cury = ly; 207 win->curx = lx; 208 } else 209 win->cury = win->curx = 0; 210 } else { 211 domvcur(ly, lx, (int) (win->cury + win->begy), 212 (int) (win->curx + win->begx)); 213 curscr->cury = win->cury + win->begy; 214 curscr->curx = win->curx + win->begx; 215 } 216 } 217 retval = OK; 218 219 (void) fflush(stdout); 220 return (retval); 221 } 222 223 /* 224 * makech -- 225 * Make a change on the screen. 226 */ 227 static int 228 makech(win, wy) 229 WINDOW *win; 230 int wy; 231 { 232 static __LDATA blank = {' ', 0}; 233 __LDATA *nsp, *csp, *cp, *cep; 234 u_int force; 235 int clsp, nlsp; /* Last space in lines. */ 236 int lch, wx, y; 237 char *ce; 238 239 #ifdef __GNUC__ 240 nlsp = 0; /* XXX gcc -Wuninitialized */ 241 #endif 242 /* Is the cursor still on the end of the last line? */ 243 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 244 domvcur(ly, lx, ly + 1, 0); 245 ly++; 246 lx = 0; 247 } 248 wx = *win->lines[wy]->firstchp - win->ch_off; 249 if (wx < 0) 250 wx = 0; 251 else 252 if (wx >= win->maxx) 253 return (OK); 254 lch = *win->lines[wy]->lastchp - win->ch_off; 255 if (lch < 0) 256 return (OK); 257 else 258 if (lch >= (int) win->maxx) 259 lch = win->maxx - 1; 260 y = wy + win->begy; 261 262 if (curwin) 263 csp = ␣ 264 else 265 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 266 267 nsp = &win->lines[wy]->line[wx]; 268 force = win->lines[wy]->flags & __FORCEPAINT; 269 win->lines[wy]->flags &= ~__FORCEPAINT; 270 if (CE && !curwin) { 271 for (cp = &win->lines[wy]->line[win->maxx - 1]; 272 cp->ch == ' ' && cp->attr == 0; cp--) 273 if (cp <= win->lines[wy]->line) 274 break; 275 nlsp = cp - win->lines[wy]->line; 276 } 277 if (!curwin) 278 ce = CE; 279 else 280 ce = NULL; 281 282 if (force) { 283 if (CM) 284 tputs(tgoto(CM, lx, ly), 0, __cputchar); 285 else { 286 tputs(HO, 0, __cputchar); 287 __mvcur(0, 0, ly, lx, 1); 288 } 289 } 290 291 while (wx <= lch) { 292 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 293 if (wx <= lch) { 294 while (wx <= lch && 295 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 296 nsp++; 297 if (!curwin) 298 ++csp; 299 ++wx; 300 } 301 continue; 302 } 303 break; 304 } 305 domvcur(ly, lx, y, (int) (wx + win->begx)); 306 307 #ifdef DEBUG 308 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 309 wx, ly, lx, y, wx + win->begx, force); 310 #endif 311 ly = y; 312 lx = wx + win->begx; 313 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 314 && wx <= lch) { 315 316 if (ce != NULL && 317 win->maxx + win->begx == curscr->maxx && 318 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) { 319 /* Check for clear to end-of-line. */ 320 cep = &curscr->lines[wy]->line[win->maxx - 1]; 321 while (cep->ch == ' ' && cep->attr == 0) 322 if (cep-- <= csp) 323 break; 324 clsp = cep - curscr->lines[wy]->line - 325 win->begx * __LDATASIZE; 326 #ifdef DEBUG 327 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 328 #endif 329 if ((clsp - nlsp >= strlen(CE) 330 && clsp < win->maxx * __LDATASIZE) || 331 wy == win->maxy - 1) { 332 if ((curscr->flags & __WSTANDOUT) && 333 SE != NULL && UE != NULL && 334 ME != NULL) { 335 tputs(SE, 0, __cputchar); 336 curscr->flags &= ~__WSTANDOUT; 337 if (*SE == *UE) { 338 curscr->flags &= 339 ~__WUNDERSCORE; 340 } 341 if (*SE == *ME) { 342 curscr->flags &= 343 ~__WATTRIBUTES; 344 } 345 } 346 if ((curscr->flags & __WUNDERSCORE) && 347 UE != NULL && ME != NULL) { 348 tputs(UE, 0, __cputchar); 349 curscr->flags &= ~__WUNDERSCORE; 350 if (*UE == *ME) { 351 curscr->flags &= 352 ~__WATTRIBUTES; 353 } 354 } 355 if ((curscr->flags & __WATTRIBUTES) && 356 UE != NULL) { 357 tputs(UE, 0, __cputchar); 358 curscr->flags &= ~__WATTRIBUTES; 359 } 360 tputs(CE, 0, __cputchar); 361 lx = wx + win->begx; 362 while (wx++ <= clsp) { 363 csp->ch = ' '; 364 csp->attr = 0; 365 csp++; 366 } 367 return (OK); 368 } 369 ce = NULL; 370 } 371 372 /* 373 * Unset attributes as appropriate. Unset first 374 * so that the relevant attributes can be reset 375 * (because termcap 'me' unsets 'mb', 'md', 'mh', 376 * 'mk', 'mp' and 'mr'). However, 'me' might also 377 * do 'se' and/or 'ue'. If so, we change the 378 * screen flags to reflect this. 379 */ 380 if ((!(nsp->attr & __BLINK) && 381 curscr->flags & __WBLINK) || 382 (!(nsp->attr & __BOLD) && 383 curscr->flags & __WBOLD) || 384 (!(nsp->attr & __DIM) && 385 curscr->flags & __WDIM) || 386 (!(nsp->attr & __BLANK) && 387 curscr->flags & __WBLANK) || 388 (!(nsp->attr & __PROTECT) && 389 curscr->flags & __WPROTECT) || 390 (!(nsp->attr & __REVERSE) && 391 curscr->flags & __WREVERSE) || 392 (!(nsp->attr & __BOLD) && 393 curscr->flags & __WBOLD)) { 394 if (ME != NULL && SE != NULL && UE != NULL) { 395 tputs(ME, 0, __cputchar); 396 curscr->flags &= ~__WATTRIBUTES; 397 if (*ME == *SE) { 398 curscr->flags &= ~__WSTANDOUT; 399 } 400 if (*ME == *UE) { 401 curscr->flags &= ~__WUNDERSCORE; 402 } 403 } 404 } 405 406 /* 407 * Exit underscore mode if appropriate. 408 * 409 * Note: check to see if we also turn off attributes 410 * and standout. 411 */ 412 if (!(nsp->attr & __UNDERSCORE) && 413 (curscr->flags & __WUNDERSCORE) && 414 UE != NULL && ME != NULL && SE != NULL) { 415 tputs(UE, 0, __cputchar); 416 curscr->flags &= ~__WUNDERSCORE; 417 if (*UE == *ME) { 418 curscr->flags &= ~__WATTRIBUTES; 419 } 420 if (*UE == *SE) { 421 curscr->flags &= ~__WSTANDOUT; 422 } 423 } 424 425 /* 426 * Enter/exit standout mode as appropriate. 427 * XXX 428 * Should use UC if SO/SE not available. 429 * 430 * Note: check to see if we also turn off attributes 431 * and underscore. If we have turned off underscore 432 * and it should be on, turn it back on. 433 */ 434 if (nsp->attr & __STANDOUT) { 435 if (!(curscr->flags & __WSTANDOUT) && 436 SO != NULL && SE != NULL) { 437 tputs(SO, 0, __cputchar); 438 curscr->flags |= __WSTANDOUT; 439 } 440 } else { 441 if ((curscr->flags & __WSTANDOUT) && 442 SE != NULL && ME != NULL && UE != NULL) { 443 tputs(SE, 0, __cputchar); 444 curscr->flags &= ~__WSTANDOUT; 445 if (*SE == *ME) { 446 curscr->flags &= ~__WATTRIBUTES; 447 } 448 if (*SE == *UE) { 449 curscr->flags &= ~__WUNDERSCORE; 450 } 451 } 452 } 453 454 /* 455 * Enter underscore mode if appropriate. 456 * XXX 457 * Should use UC if US/UE not available. 458 * 459 * Note: check to see if we also turn off attributes 460 * and standout. 461 */ 462 if (nsp->attr & __UNDERSCORE && 463 !(curscr->flags & __WUNDERSCORE) && 464 US != NULL && UE != NULL) { 465 tputs(US, 0, __cputchar); 466 curscr->flags |= __WUNDERSCORE; 467 } 468 469 /* 470 * Set other attributes as appropriate. 471 */ 472 if (nsp->attr & __REVERSE) { 473 if (!(curscr->flags & __WREVERSE) && 474 MR != NULL && ME != NULL) { 475 tputs(MR, 0, __cputchar); 476 curscr->flags |= __WREVERSE; 477 } 478 } 479 if (nsp->attr & __BLINK) { 480 if (!(curscr->flags & __WBLINK) && 481 MB != NULL && ME != NULL) { 482 tputs(MB, 0, __cputchar); 483 curscr->flags |= __WBLINK; 484 } 485 } 486 if (nsp->attr & __DIM) { 487 if (!(curscr->flags & __WDIM) && 488 MH != NULL && ME != NULL) { 489 tputs(MH, 0, __cputchar); 490 curscr->flags |= __WDIM; 491 } 492 } 493 if (nsp->attr & __BOLD) { 494 if (!(curscr->flags & __WBOLD) && 495 MD != NULL && ME != NULL) { 496 tputs(MD, 0, __cputchar); 497 curscr->flags |= __WBOLD; 498 } 499 } 500 if (nsp->attr & __BLANK) { 501 if (!(curscr->flags & __WBLANK) && 502 MK != NULL && ME != NULL) { 503 tputs(MK, 0, __cputchar); 504 curscr->flags |= __WBLANK; 505 } 506 } 507 if (nsp->attr & __PROTECT) { 508 if (!(curscr->flags & __WPROTECT) && 509 MP != NULL && ME != NULL) { 510 tputs(MP, 0, __cputchar); 511 curscr->flags |= __WPROTECT; 512 } 513 } 514 515 wx++; 516 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 517 if (win->flags & __SCROLLOK) { 518 if (curscr->flags & __WSTANDOUT 519 && win->flags & __ENDLINE) 520 if (!MS) { 521 tputs(SE, 0, 522 __cputchar); 523 curscr->flags &= 524 ~__WSTANDOUT; 525 } 526 if (curscr->flags & __WUNDERSCORE 527 && win->flags & __ENDLINE) 528 if (!MS) { 529 tputs(UE, 0, 530 __cputchar); 531 curscr->flags &= 532 ~__WUNDERSCORE; 533 } 534 if (curscr->flags & __WATTRIBUTES 535 && win->flags & __ENDLINE) 536 if (!MS) { 537 tputs(ME, 0, 538 __cputchar); 539 curscr->flags &= 540 ~__WATTRIBUTES; 541 } 542 if (!(win->flags & __SCROLLWIN)) { 543 if (!curwin) { 544 csp->attr = nsp->attr; 545 putchar(csp->ch = nsp->ch); 546 } else 547 putchar(nsp->ch); 548 } 549 if (wx + win->begx < curscr->maxx) { 550 domvcur(ly, (int) (wx + win->begx), 551 (int) (win->begy + win->maxy - 1), 552 (int) (win->begx + win->maxx - 1)); 553 } 554 ly = win->begy + win->maxy - 1; 555 lx = win->begx + win->maxx - 1; 556 return (OK); 557 } 558 if (wx < win->maxx || wy < win->maxy - 1 || 559 !(win->flags & __SCROLLWIN)) { 560 if (!curwin) { 561 csp->attr = nsp->attr; 562 putchar(csp->ch = nsp->ch); 563 csp++; 564 } else 565 putchar(nsp->ch); 566 } 567 #ifdef DEBUG 568 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 569 #endif 570 if (UC && ((nsp->attr & __STANDOUT) || 571 (nsp->attr & __UNDERSCORE))) { 572 putchar('\b'); 573 tputs(UC, 0, __cputchar); 574 } 575 nsp++; 576 #ifdef DEBUG 577 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 578 #endif 579 } 580 if (lx == wx + win->begx) /* If no change. */ 581 break; 582 lx = wx + win->begx; 583 if (lx >= COLS && AM) 584 lx = COLS - 1; 585 else 586 if (wx >= win->maxx) { 587 domvcur(ly, lx, ly, (int) (win->maxx + win->begx - 1)); 588 lx = win->maxx + win->begx - 1; 589 } 590 #ifdef DEBUG 591 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 592 #endif 593 } 594 595 /* Don't leave the screen in standout mode. */ 596 if (curscr->flags & __WSTANDOUT) { 597 tputs(SE, 0, __cputchar); 598 curscr->flags &= ~__WSTANDOUT; 599 } 600 /* Don't leave the screen in underscore mode. */ 601 if (curscr->flags & __WUNDERSCORE) { 602 tputs(UE, 0, __cputchar); 603 curscr->flags &= ~__WUNDERSCORE; 604 } 605 /* Don't leave the screen with attributes set. */ 606 if (curscr->flags & __WATTRIBUTES) { 607 tputs(ME, 0, __cputchar); 608 curscr->flags &= ~__WATTRIBUTES; 609 } 610 return (OK); 611 } 612 613 /* 614 * domvcur -- 615 * Do a mvcur, leaving standout and attribute modes if necessary. 616 */ 617 static void 618 domvcur(oy, ox, ny, nx) 619 int oy, ox, ny, nx; 620 { 621 if (curscr->flags & __WSTANDOUT && !MS && SE) { 622 tputs(SE, 0, __cputchar); 623 curscr->flags &= ~__WSTANDOUT; 624 } 625 if (curscr->flags & __WUNDERSCORE && !MS && UE) { 626 tputs(UE, 0, __cputchar); 627 curscr->flags &= ~__WUNDERSCORE; 628 } 629 if (curscr->flags & __WATTRIBUTES && !MS && ME) { 630 tputs(ME, 0, __cputchar); 631 curscr->flags &= ~__WATTRIBUTES; 632 } 633 634 __mvcur(oy, ox, ny, nx, 1); 635 } 636 637 /* 638 * Quickch() attempts to detect a pattern in the change of the window 639 * in order to optimize the change, e.g., scroll n lines as opposed to 640 * repainting the screen line by line. 641 */ 642 643 static void 644 quickch(win) 645 WINDOW *win; 646 { 647 #define THRESH (int) win->maxy / 4 648 649 __LINE *clp, *tmp1, *tmp2; 650 int bsize, curs, curw, starts, startw, i, j; 651 int n, target, cur_period, bot, top, sc_region; 652 __LDATA buf[1024]; 653 u_int blank_hash; 654 655 #ifdef __GNUC__ 656 curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */ 657 #endif 658 /* 659 * Find how many lines from the top of the screen are unchanged. 660 */ 661 for (top = 0; top < win->maxy; top++) 662 if (win->lines[top]->flags & __FORCEPAINT || 663 win->lines[top]->hash != curscr->lines[top]->hash 664 || memcmp(win->lines[top]->line, 665 curscr->lines[top]->line, 666 win->maxx * __LDATASIZE) != 0) 667 break; 668 else 669 win->lines[top]->flags &= ~__ISDIRTY; 670 /* 671 * Find how many lines from bottom of screen are unchanged. 672 */ 673 for (bot = win->maxy - 1; bot >= 0; bot--) 674 if (win->lines[bot]->flags & __FORCEPAINT || 675 win->lines[bot]->hash != curscr->lines[bot]->hash 676 || memcmp(win->lines[bot]->line, 677 curscr->lines[bot]->line, 678 win->maxx * __LDATASIZE) != 0) 679 break; 680 else 681 win->lines[bot]->flags &= ~__ISDIRTY; 682 683 #ifdef NO_JERKINESS 684 /* 685 * If we have a bottom unchanged region return. Scrolling the 686 * bottom region up and then back down causes a screen jitter. 687 * This will increase the number of characters sent to the screen 688 * but it looks better. 689 */ 690 if (bot < win->maxy - 1) 691 return; 692 #endif /* NO_JERKINESS */ 693 694 /* 695 * Search for the largest block of text not changed. 696 * Invariants of the loop: 697 * - Startw is the index of the beginning of the examined block in win. 698 * - Starts is the index of the beginning of the examined block in 699 * curscr. 700 * - Curs is the index of one past the end of the exmined block in win. 701 * - Curw is the index of one past the end of the exmined block in 702 * curscr. 703 * - bsize is the current size of the examined block. 704 */ 705 for (bsize = bot - top; bsize >= THRESH; bsize--) { 706 for (startw = top; startw <= bot - bsize; startw++) 707 for (starts = top; starts <= bot - bsize; 708 starts++) { 709 for (curw = startw, curs = starts; 710 curs < starts + bsize; curw++, curs++) 711 if (win->lines[curw]->flags & 712 __FORCEPAINT || 713 (win->lines[curw]->hash != 714 curscr->lines[curs]->hash || 715 memcmp(win->lines[curw]->line, 716 curscr->lines[curs]->line, 717 win->maxx * __LDATASIZE) != 0)) 718 break; 719 if (curs == starts + bsize) 720 goto done; 721 } 722 } 723 done: 724 /* Did not find anything */ 725 if (bsize < THRESH) 726 return; 727 728 #ifdef DEBUG 729 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 730 bsize, starts, startw, curw, curs, top, bot); 731 #endif 732 733 /* 734 * Make sure that there is no overlap between the bottom and top 735 * regions and the middle scrolled block. 736 */ 737 if (bot < curs) 738 bot = curs - 1; 739 if (top > starts) 740 top = starts; 741 742 n = startw - starts; 743 744 #ifdef DEBUG 745 __CTRACE("#####################################\n"); 746 for (i = 0; i < curscr->maxy; i++) { 747 __CTRACE("C: %d:", i); 748 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 749 for (j = 0; j < curscr->maxx; j++) 750 __CTRACE("%c", curscr->lines[i]->line[j].ch); 751 __CTRACE("\n"); 752 __CTRACE(" attr:"); 753 for (j = 0; j < curscr->maxx; j++) 754 __CTRACE(" %x", curscr->lines[i]->line[j].attr); 755 __CTRACE("\n"); 756 __CTRACE("W: %d:", i); 757 __CTRACE(" 0x%x \n", win->lines[i]->hash); 758 __CTRACE(" 0x%x ", win->lines[i]->flags); 759 for (j = 0; j < win->maxx; j++) 760 __CTRACE("%c", win->lines[i]->line[j].ch); 761 __CTRACE("\n"); 762 __CTRACE(" attr:"); 763 for (j = 0; j < win->maxx; j++) 764 __CTRACE(" %x", win->lines[i]->line[j].attr); 765 __CTRACE("\n"); 766 } 767 #endif 768 769 /* So we don't have to call __hash() each time */ 770 for (i = 0; i < win->maxx; i++) { 771 buf[i].ch = ' '; 772 buf[i].attr = 0; 773 } 774 blank_hash = __hash((char *)(void *)buf, 775 (int) (win->maxx * __LDATASIZE)); 776 777 /* 778 * Perform the rotation to maintain the consistency of curscr. 779 * This is hairy since we are doing an *in place* rotation. 780 * Invariants of the loop: 781 * - I is the index of the current line. 782 * - Target is the index of the target of line i. 783 * - Tmp1 points to current line (i). 784 * - Tmp2 and points to target line (target); 785 * - Cur_period is the index of the end of the current period. 786 * (see below). 787 * 788 * There are 2 major issues here that make this rotation non-trivial: 789 * 1. Scrolling in a scrolling region bounded by the top 790 * and bottom regions determined (whose size is sc_region). 791 * 2. As a result of the use of the mod function, there may be a 792 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 793 * 0 to 2, which then causes all odd lines not to be rotated. 794 * To remedy this, an index of the end ( = beginning) of the 795 * current 'period' is kept, cur_period, and when it is reached, 796 * the next period is started from cur_period + 1 which is 797 * guaranteed not to have been reached since that would mean that 798 * all records would have been reached. (think about it...). 799 * 800 * Lines in the rotation can have 3 attributes which are marked on the 801 * line so that curscr is consistent with the visual screen. 802 * 1. Not dirty -- lines inside the scrolled block, top region or 803 * bottom region. 804 * 2. Blank lines -- lines in the differential of the scrolling 805 * region adjacent to top and bot regions 806 * depending on scrolling direction. 807 * 3. Dirty line -- all other lines are marked dirty. 808 */ 809 sc_region = bot - top + 1; 810 i = top; 811 tmp1 = curscr->lines[top]; 812 cur_period = top; 813 for (j = top; j <= bot; j++) { 814 target = (i - top + n + sc_region) % sc_region + top; 815 tmp2 = curscr->lines[target]; 816 curscr->lines[target] = tmp1; 817 /* Mark block as clean and blank out scrolled lines. */ 818 clp = curscr->lines[target]; 819 #ifdef DEBUG 820 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 821 n, startw, curw, i, target); 822 #endif 823 if ((target >= startw && target < curw) || target < top 824 || target > bot) { 825 #ifdef DEBUG 826 __CTRACE("-- notdirty"); 827 #endif 828 win->lines[target]->flags &= ~__ISDIRTY; 829 } else 830 if ((n > 0 && target >= top && target < top + n) || 831 (n < 0 && target <= bot && target > bot + n)) { 832 if (clp->hash != blank_hash || memcmp(clp->line, 833 buf, win->maxx * __LDATASIZE) !=0) { 834 (void)memcpy(clp->line, buf, 835 win->maxx * __LDATASIZE); 836 #ifdef DEBUG 837 __CTRACE("-- blanked out: dirty"); 838 #endif 839 clp->hash = blank_hash; 840 __touchline(win, target, 0, (int) win->maxx - 1, 0); 841 } else { 842 __touchline(win, target, 0, (int) win->maxx - 1, 0); 843 #ifdef DEBUG 844 __CTRACE(" -- blank line already: dirty"); 845 #endif 846 } 847 } else { 848 #ifdef DEBUG 849 __CTRACE(" -- dirty"); 850 #endif 851 __touchline(win, target, 0, (int) win->maxx - 1, 0); 852 } 853 #ifdef DEBUG 854 __CTRACE("\n"); 855 #endif 856 if (target == cur_period) { 857 i = target + 1; 858 tmp1 = curscr->lines[i]; 859 cur_period = i; 860 } else { 861 tmp1 = tmp2; 862 i = target; 863 } 864 } 865 #ifdef DEBUG 866 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 867 for (i = 0; i < curscr->maxy; i++) { 868 __CTRACE("C: %d:", i); 869 for (j = 0; j < curscr->maxx; j++) 870 __CTRACE("%c", curscr->lines[i]->line[j].ch); 871 __CTRACE("\n"); 872 __CTRACE("W: %d:", i); 873 for (j = 0; j < win->maxx; j++) 874 __CTRACE("%c", win->lines[i]->line[j].ch); 875 __CTRACE("\n"); 876 } 877 #endif 878 if (n != 0) { 879 WINDOW *wp; 880 scrolln(win, starts, startw, curs, bot, top); 881 /* 882 * Need to repoint any subwindow lines to the rotated 883 * line structured. 884 */ 885 for (wp = win->nextp; wp != win; wp = wp->nextp) 886 __set_subwin(win, wp); 887 } 888 } 889 890 /* 891 * scrolln -- 892 * Scroll n lines, where n is starts - startw. 893 */ 894 static void /* ARGSUSED */ 895 scrolln(win, starts, startw, curs, bot, top) 896 WINDOW *win; 897 int starts, startw, curs, bot, top; 898 { 899 int i, oy, ox, n; 900 901 oy = curscr->cury; 902 ox = curscr->curx; 903 n = starts - startw; 904 905 /* 906 * XXX 907 * The initial tests that set __noqch don't let us reach here unless 908 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 909 * scrolling can only shift the entire scrolling region, not just a 910 * part of it, which means that the quickch() routine is going to be 911 * sadly disappointed in us if we don't have CS as well. 912 * 913 * If CS, HO and SF/sf are set, can use the scrolling region. Because 914 * the cursor position after CS is undefined, we need HO which gives us 915 * the ability to move to somewhere without knowledge of the current 916 * location of the cursor. Still call __mvcur() anyway, to update its 917 * idea of where the cursor is. 918 * 919 * When the scrolling region has been set, the cursor has to be at the 920 * last line of the region to make the scroll happen. 921 * 922 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 923 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 924 * SF/SR. So, if we're scrolling almost all of the screen, try and use 925 * AL/DL, otherwise use the scrolling region. The "almost all" is a 926 * shameless hack for vi. 927 */ 928 if (n > 0) { 929 if (CS != NULL && HO != NULL && (SF != NULL || 930 ((AL == NULL || DL == NULL || 931 top > 3 || bot + 3 < win->maxy) && sf != NULL))) { 932 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 933 __mvcur(oy, ox, 0, 0, 1); 934 tputs(HO, 0, __cputchar); 935 __mvcur(0, 0, bot, 0, 1); 936 if (SF != NULL) 937 tputs(__tscroll(SF, n, 0), 0, __cputchar); 938 else 939 for (i = 0; i < n; i++) 940 tputs(sf, 0, __cputchar); 941 tputs(__tscroll(CS, 0, (int) win->maxy), 0, __cputchar); 942 __mvcur(bot, 0, 0, 0, 1); 943 tputs(HO, 0, __cputchar); 944 __mvcur(0, 0, oy, ox, 1); 945 return; 946 } 947 948 /* Scroll up the block. */ 949 if (SF != NULL && top == 0) { 950 __mvcur(oy, ox, bot, 0, 1); 951 tputs(__tscroll(SF, n, 0), 0, __cputchar); 952 } else 953 if (DL != NULL) { 954 __mvcur(oy, ox, top, 0, 1); 955 tputs(__tscroll(DL, n, 0), 0, __cputchar); 956 } else 957 if (dl != NULL) { 958 __mvcur(oy, ox, top, 0, 1); 959 for (i = 0; i < n; i++) 960 tputs(dl, 0, __cputchar); 961 } else 962 if (sf != NULL && top == 0) { 963 __mvcur(oy, ox, bot, 0, 1); 964 for (i = 0; i < n; i++) 965 tputs(sf, 0, __cputchar); 966 } else 967 abort(); 968 969 /* Push down the bottom region. */ 970 __mvcur(top, 0, bot - n + 1, 0, 1); 971 if (AL != NULL) 972 tputs(__tscroll(AL, n, 0), 0, __cputchar); 973 else 974 if (al != NULL) 975 for (i = 0; i < n; i++) 976 tputs(al, 0, __cputchar); 977 else 978 abort(); 979 __mvcur(bot - n + 1, 0, oy, ox, 1); 980 } else { 981 /* 982 * !!! 983 * n < 0 984 * 985 * If CS, HO and SR/sr are set, can use the scrolling region. 986 * See the above comments for details. 987 */ 988 if (CS != NULL && HO != NULL && (SR != NULL || 989 ((AL == NULL || DL == NULL || 990 top > 3 || bot + 3 < win->maxy) && sr != NULL))) { 991 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 992 __mvcur(oy, ox, 0, 0, 1); 993 tputs(HO, 0, __cputchar); 994 __mvcur(0, 0, top, 0, 1); 995 996 if (SR != NULL) 997 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 998 else 999 for (i = n; i < 0; i++) 1000 tputs(sr, 0, __cputchar); 1001 tputs(__tscroll(CS, 0, (int) win->maxy), 0, __cputchar); 1002 __mvcur(top, 0, 0, 0, 1); 1003 tputs(HO, 0, __cputchar); 1004 __mvcur(0, 0, oy, ox, 1); 1005 return; 1006 } 1007 1008 /* Preserve the bottom lines. */ 1009 __mvcur(oy, ox, bot + n + 1, 0, 1); 1010 if (SR != NULL && bot == win->maxy) 1011 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 1012 else 1013 if (DL != NULL) 1014 tputs(__tscroll(DL, -n, 0), 0, __cputchar); 1015 else 1016 if (dl != NULL) 1017 for (i = n; i < 0; i++) 1018 tputs(dl, 0, __cputchar); 1019 else 1020 if (sr != NULL && bot == win->maxy) 1021 for (i = n; i < 0; i++) 1022 tputs(sr, 0, __cputchar); 1023 else 1024 abort(); 1025 1026 /* Scroll the block down. */ 1027 __mvcur(bot + n + 1, 0, top, 0, 1); 1028 if (AL != NULL) 1029 tputs(__tscroll(AL, -n, 0), 0, __cputchar); 1030 else 1031 if (al != NULL) 1032 for (i = n; i < 0; i++) 1033 tputs(al, 0, __cputchar); 1034 else 1035 abort(); 1036 __mvcur(top, 0, oy, ox, 1); 1037 } 1038 } 1039