1 /* $NetBSD: refresh.c,v 1.42 2001/09/20 11:11:54 blymn 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.42 2001/09/20 11:11:54 blymn Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <stdlib.h> 46 #include <string.h> 47 48 #include "curses.h" 49 #include "curses_private.h" 50 51 /* the following is defined and set up in setterm.c */ 52 extern struct tinfo *_cursesi_genbuf; 53 54 static int curwin = 0; 55 static short ly, lx; 56 57 static void domvcur __P((int, int, int, int)); 58 static int makech __P((int)); 59 static void quickch __P((void)); 60 static void scrolln __P((int, int, int, int, int)); 61 62 #ifndef _CURSES_USE_MACROS 63 64 /* 65 * refresh -- 66 * Make the current screen look like "stdscr" over the area covered by 67 * stdscr. 68 */ 69 int 70 refresh(void) 71 { 72 return wrefresh(stdscr); 73 } 74 75 #endif 76 77 /* 78 * wnoutrefresh -- 79 * Add the contents of "win" to the virtual window. 80 */ 81 int 82 wnoutrefresh(WINDOW *win) 83 { 84 short wy, wx, x_off; 85 __LINE *wlp, *vlp; 86 87 #ifdef DEBUG 88 __CTRACE("wnoutrefresh: win %0.2o, flags 0x%08x\n", win, win->flags); 89 #endif 90 91 if (curwin) 92 return(OK); 93 __virtscr->cury = win->cury + win->begy; 94 __virtscr->curx = win->curx + win->begx; 95 96 /* Copy the window flags from "win" to "__virtscr" */ 97 if (win->flags & __CLEAROK) { 98 if (win->flags & __FULLWIN) 99 __virtscr->flags |= __CLEAROK; 100 win->flags &= ~__CLEAROK; 101 } 102 __virtscr->flags &= ~__LEAVEOK; 103 __virtscr->flags |= win->flags; 104 105 for (wy = 0; wy < win->maxy && wy < __virtscr->maxy - win->begy; wy++) { 106 wlp = win->lines[wy]; 107 #ifdef DEBUG 108 __CTRACE("wnoutrefresh: wy %d\tf: %d\tl:%d\tflags %x\n", wy, 109 *wlp->firstchp, *wlp->lastchp, wlp->flags); 110 #endif 111 if ((wlp->flags & __ISDIRTY) == 0) 112 continue; 113 vlp = __virtscr->lines[wy + win->begy]; 114 115 if (*wlp->firstchp < win->maxx + win->ch_off && 116 *wlp->lastchp >= win->ch_off) { 117 /* Copy line from "win" to "__virtscr". */ 118 for (wx = 0, x_off = win->begx; wx < win->maxx && 119 x_off < __virtscr->maxx; wx++, x_off++) { 120 vlp->line[x_off].attr = wlp->line[wx].attr; 121 if (wlp->line[wx].attr & __COLOR) 122 vlp->line[x_off].attr |= 123 wlp->line[wx].battr & ~__COLOR; 124 else 125 vlp->line[x_off].attr |= 126 wlp->line[wx].battr; 127 if (wlp->line[wx].ch == ' ' && 128 wlp->line[wx].bch != ' ') 129 vlp->line[x_off].ch 130 = wlp->line[wx].bch; 131 else 132 vlp->line[x_off].ch 133 = wlp->line[wx].ch; 134 } 135 136 /* Set flags on "__virtscr" and unset on "win". */ 137 if (wlp->flags & __ISPASTEOL) 138 vlp->flags |= __ISPASTEOL; 139 else 140 vlp->flags &= ~__ISPASTEOL; 141 if (wlp->flags & __ISDIRTY) 142 vlp->flags |= __ISDIRTY; 143 144 #ifdef DEBUG 145 __CTRACE("win: firstch = %d, lastch = %d\n", 146 *wlp->firstchp, *wlp->lastchp); 147 #endif 148 /* Set change pointers on "__virtscr". */ 149 if (*vlp->firstchp > 150 *wlp->firstchp + win->begx - win->ch_off) 151 *vlp->firstchp = 152 *wlp->firstchp + win->begx - win->ch_off; 153 if (*vlp->lastchp < 154 *wlp->lastchp + win->begx - win->ch_off) 155 *vlp->lastchp = 156 *wlp->lastchp + win->begx - win->ch_off; 157 #ifdef DEBUG 158 __CTRACE("__virtscr: firstch = %d, lastch = %d\n", 159 *vlp->firstchp, *vlp->lastchp); 160 #endif 161 162 /* Set change pointers on "win". */ 163 if (*wlp->firstchp >= win->ch_off) 164 *wlp->firstchp = win->maxx + win->ch_off; 165 if (*wlp->lastchp < win->maxx + win->ch_off) 166 *wlp->lastchp = win->ch_off; 167 if (*wlp->lastchp < *wlp->firstchp) { 168 #ifdef DEBUG 169 __CTRACE("wnoutrefresh: line %d notdirty\n", 170 wy); 171 #endif 172 wlp->flags &= ~__ISDIRTY; 173 } 174 } 175 } 176 177 return (OK); 178 } 179 180 /* 181 * wrefresh -- 182 * Make the current screen look like "win" over the area coverd by 183 * win. 184 */ 185 int 186 wrefresh(WINDOW *win) 187 { 188 int retval; 189 190 curwin = (win == curscr); 191 if (!curwin) 192 retval = wnoutrefresh(win); 193 else 194 retval = OK; 195 if (retval == OK) { 196 retval = doupdate(); 197 if (!win->flags & __LEAVEOK) { 198 win->cury = max(0, curscr->cury - win->begy); 199 win->curx = max(0, curscr->curx - win->begx); 200 } 201 } 202 curwin = 0; 203 return(retval); 204 } 205 206 /* 207 * doupdate -- 208 * Make the current screen look like the virtual window "__virtscr". 209 */ 210 int 211 doupdate(void) 212 { 213 WINDOW *win; 214 __LINE *wlp; 215 short wy; 216 int dnum; 217 218 /* Check if we need to restart ... */ 219 if (__endwin) 220 __restartwin(); 221 222 if (curwin) 223 win = curscr; 224 else 225 win = __virtscr; 226 227 /* Initialize loop parameters. */ 228 ly = curscr->cury; 229 lx = curscr->curx; 230 wy = 0; 231 232 if (!curwin) 233 for (wy = 0; wy < win->maxy; wy++) { 234 wlp = win->lines[wy]; 235 if (wlp->flags & __ISDIRTY) 236 wlp->hash = __hash((char *)(void *)wlp->line, 237 (int) (win->maxx * __LDATASIZE)); 238 } 239 240 if ((win->flags & __CLEAROK) || (curscr->flags & __CLEAROK) || curwin) { 241 if (curscr->wattr & __COLOR) 242 __unsetattr(0); 243 tputs(__tc_cl, 0, __cputchar); 244 ly = 0; 245 lx = 0; 246 if (!curwin) { 247 curscr->flags &= ~__CLEAROK; 248 curscr->cury = 0; 249 curscr->curx = 0; 250 werase(curscr); 251 } 252 __touchwin(win); 253 win->flags &= ~__CLEAROK; 254 } 255 if (!__CA) { 256 if (win->curx != 0) 257 __cputchar('\n'); 258 if (!curwin) 259 werase(curscr); 260 } 261 #ifdef DEBUG 262 __CTRACE("doupdate: (%0.2o): curwin = %d\n", win, curwin); 263 __CTRACE("doupdate: \tfirstch\tlastch\n"); 264 #endif 265 266 if (!curwin) { 267 /* 268 * Invoke quickch() only if more than a quarter of the lines 269 * in the window are dirty. 270 */ 271 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 272 if (win->lines[wy]->flags & __ISDIRTY) 273 dnum++; 274 if (!__noqch && dnum > (int) win->maxy / 4) 275 quickch(); 276 } 277 278 #ifdef DEBUG 279 { 280 int i, j; 281 282 __CTRACE("#####################################\n"); 283 for (i = 0; i < curscr->maxy; i++) { 284 __CTRACE("C: %d:", i); 285 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 286 for (j = 0; j < curscr->maxx; j++) 287 __CTRACE("%c", curscr->lines[i]->line[j].ch); 288 __CTRACE("\n"); 289 __CTRACE(" attr:"); 290 for (j = 0; j < curscr->maxx; j++) 291 __CTRACE(" %x", curscr->lines[i]->line[j].attr); 292 __CTRACE("\n"); 293 __CTRACE("W: %d:", i); 294 __CTRACE(" 0x%x \n", win->lines[i]->hash); 295 __CTRACE(" 0x%x ", win->lines[i]->flags); 296 for (j = 0; j < win->maxx; j++) 297 __CTRACE("%c", win->lines[i]->line[j].ch); 298 __CTRACE("\n"); 299 __CTRACE(" attr:"); 300 for (j = 0; j < win->maxx; j++) 301 __CTRACE(" %x", 302 win->lines[i]->line[j].attr); 303 __CTRACE("\n"); 304 } 305 } 306 #endif /* DEBUG */ 307 308 for (wy = 0; wy < win->maxy; wy++) { 309 wlp = win->lines[wy]; 310 /* XXX: remove this debug */ 311 #ifdef DEBUG 312 __CTRACE("doupdate: wy %d\tf: %d\tl:%d\tflags %x\n", wy, 313 *wlp->firstchp, *wlp->lastchp, wlp->flags); 314 #endif 315 if (!curwin) 316 curscr->lines[wy]->hash = wlp->hash; 317 if (wlp->flags & __ISDIRTY) { 318 if (makech(wy) == ERR) 319 return (ERR); 320 else { 321 if (*wlp->firstchp >= 0) 322 *wlp->firstchp = win->maxx; 323 if (*wlp->lastchp < win->maxx) 324 *wlp->lastchp = 0; 325 if (*wlp->lastchp < *wlp->firstchp) { 326 #ifdef DEBUG 327 __CTRACE("doupdate: line %d notdirty\n", wy); 328 #endif 329 wlp->flags &= ~__ISDIRTY; 330 } 331 } 332 333 } 334 #ifdef DEBUG 335 __CTRACE("\t%d\t%d\n", *wlp->firstchp, *wlp->lastchp); 336 #endif 337 } 338 339 #ifdef DEBUG 340 __CTRACE("doupdate: ly=%d, lx=%d\n", ly, lx); 341 #endif 342 343 if (curwin) 344 domvcur(ly, lx, (int) win->cury, (int) win->curx); 345 else { 346 if (win->flags & __LEAVEOK) { 347 curscr->cury = ly; 348 curscr->curx = lx; 349 } else { 350 domvcur(ly, lx, win->cury, win->curx); 351 curscr->cury = win->cury; 352 curscr->curx = win->curx; 353 } 354 } 355 356 /* Don't leave the screen with attributes set. */ 357 __unsetattr(0); 358 (void) fflush(stdout); 359 return (OK); 360 } 361 362 /* 363 * makech -- 364 * Make a change on the screen. 365 */ 366 static int 367 makech(wy) 368 int wy; 369 { 370 WINDOW *win; 371 static __LDATA blank = {' ', 0, ' ', 0}; 372 __LDATA *nsp, *csp, *cp, *cep; 373 int clsp, nlsp; /* Last space in lines. */ 374 int lch, wx; 375 char *ce; 376 attr_t lspc; /* Last space colour */ 377 attr_t off, on; 378 379 #ifdef __GNUC__ 380 nlsp = lspc = 0; /* XXX gcc -Wuninitialized */ 381 #endif 382 if (curwin) 383 win = curscr; 384 else 385 win = __virtscr; 386 /* Is the cursor still on the end of the last line? */ 387 if (wy > 0 && curscr->lines[wy - 1]->flags & __ISPASTEOL) { 388 domvcur(ly, lx, ly + 1, 0); 389 ly++; 390 lx = 0; 391 } 392 wx = *win->lines[wy]->firstchp; 393 if (wx < 0) 394 wx = 0; 395 else 396 if (wx >= win->maxx) 397 return (OK); 398 lch = *win->lines[wy]->lastchp; 399 if (lch < 0) 400 return (OK); 401 else 402 if (lch >= (int) win->maxx) 403 lch = win->maxx - 1; 404 405 if (curwin) 406 csp = ␣ 407 else 408 csp = &curscr->lines[wy]->line[wx]; 409 410 nsp = &win->lines[wy]->line[wx]; 411 if (__tc_ce && !curwin) { 412 cp = &win->lines[wy]->line[win->maxx - 1]; 413 lspc = cp->attr & __COLOR; 414 while (cp->ch == ' ' && cp->attr == lspc) 415 if (cp-- <= win->lines[wy]->line) 416 break; 417 nlsp = cp - win->lines[wy]->line; 418 if (nlsp < 0) 419 nlsp = 0; 420 } 421 if (!curwin) 422 ce = __tc_ce; 423 else 424 ce = NULL; 425 426 while (wx <= lch) { 427 if (memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 428 if (wx <= lch) { 429 while (wx <= lch && 430 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 431 nsp++; 432 if (!curwin) 433 ++csp; 434 ++wx; 435 } 436 continue; 437 } 438 break; 439 } 440 domvcur(ly, lx, wy, wx); 441 442 #ifdef DEBUG 443 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d\n", 444 wx, ly, lx, wy, wx); 445 #endif 446 ly = wy; 447 lx = wx; 448 while (memcmp(nsp, csp, sizeof(__LDATA)) != 0 && wx <= lch) { 449 if (ce != NULL && 450 wx >= nlsp && nsp->ch == ' ' && nsp->attr == lspc) { 451 /* Check for clear to end-of-line. */ 452 cep = &curscr->lines[wy]->line[win->maxx - 1]; 453 while (cep->ch == ' ' && cep->attr == lspc) 454 if (cep-- <= csp) 455 break; 456 clsp = cep - curscr->lines[wy]->line - 457 win->begx * __LDATASIZE; 458 #ifdef DEBUG 459 __CTRACE("makech: clsp = %d, nlsp = %d\n", 460 clsp, nlsp); 461 #endif 462 if (((clsp - nlsp >= strlen(__tc_ce) && 463 clsp < win->maxx * __LDATASIZE) || 464 wy == win->maxy - 1) && 465 (!(lspc & __COLOR) || 466 ((lspc & __COLOR) && __tc_ut))) { 467 __unsetattr(0); 468 if ((lspc & __COLOR) != 469 (curscr->wattr & __COLOR)) { 470 __set_color(lspc); 471 curscr->wattr &= ~__COLOR; 472 curscr->wattr |= lspc & __COLOR; 473 } 474 tputs(__tc_ce, 0, __cputchar); 475 lx = wx + win->begx; 476 while (wx++ <= clsp) { 477 csp->ch = ' '; 478 csp->attr = lspc; 479 csp++; 480 } 481 return (OK); 482 } 483 ce = NULL; 484 } 485 486 /* 487 * Unset colour if appropriate. Check to see 488 * if we also turn off standout, underscore and 489 * attributes. 490 */ 491 if (!(nsp->attr & __COLOR) && 492 (curscr->wattr & __COLOR)) { 493 if (__tc_oc != NULL && __tc_cc == NULL) 494 tputs(__tc_oc, 0, __cputchar); 495 if (__tc_op != NULL) { 496 tputs(__tc_op, 0, __cputchar); 497 curscr->wattr &= __mask_op; 498 } 499 } 500 501 off = ~nsp->attr & curscr->wattr; 502 503 /* 504 * Unset attributes as appropriate. Unset first 505 * so that the relevant attributes can be reset 506 * (because 'me' unsets 'mb', 'md', 'mh', 'mk', 507 * 'mp' and 'mr'). Check to see if we also turn off 508 * standout, attributes and colour. 509 */ 510 if (off & __TERMATTR && __tc_me != NULL) { 511 tputs(__tc_me, 0, __cputchar); 512 curscr->wattr &= __mask_me; 513 off &= __mask_me; 514 } 515 516 /* 517 * Exit underscore mode if appropriate. 518 * Check to see if we also turn off standout, 519 * attributes and colour. 520 */ 521 if (off & __UNDERSCORE && __tc_ue != NULL) { 522 tputs(__tc_ue, 0, __cputchar); 523 curscr->wattr &= __mask_ue; 524 off &= __mask_ue; 525 } 526 527 /* 528 * Exit standout mode as appropriate. 529 * Check to see if we also turn off underscore, 530 * attributes and colour. 531 * XXX 532 * Should use uc if so/se not available. 533 */ 534 if (off & __STANDOUT && __tc_se != NULL) { 535 tputs(__tc_se, 0, __cputchar); 536 curscr->wattr &= __mask_se; 537 off &= __mask_se; 538 } 539 540 if (off & __ALTCHARSET && __tc_ae != NULL) { 541 tputs(__tc_ae, 0, __cputchar); 542 curscr->wattr &= ~__ALTCHARSET; 543 } 544 545 on = nsp->attr & ~curscr->wattr; 546 547 /* 548 * Enter standout mode if appropriate. 549 */ 550 if (on & __STANDOUT && __tc_so != NULL && __tc_se 551 != NULL) { 552 tputs(__tc_so, 0, __cputchar); 553 curscr->wattr |= __STANDOUT; 554 } 555 556 /* 557 * Enter underscore mode if appropriate. 558 * XXX 559 * Should use uc if us/ue not available. 560 */ 561 if (on & __UNDERSCORE && __tc_us != NULL && 562 __tc_ue != NULL) { 563 tputs(__tc_us, 0, __cputchar); 564 curscr->wattr |= __UNDERSCORE; 565 } 566 567 /* 568 * Set other attributes as appropriate. 569 */ 570 if (__tc_me != NULL) { 571 if (on & __BLINK && __tc_mb != NULL) { 572 tputs(__tc_mb, 0, __cputchar); 573 curscr->wattr |= __BLINK; 574 } 575 if (on & __BOLD && __tc_md != NULL) { 576 tputs(__tc_md, 0, __cputchar); 577 curscr->wattr |= __BOLD; 578 } 579 if (on & __DIM && __tc_mh != NULL) { 580 tputs(__tc_mh, 0, __cputchar); 581 curscr->wattr |= __DIM; 582 } 583 if (on & __BLANK && __tc_mk != NULL) { 584 tputs(__tc_mk, 0, __cputchar); 585 curscr->wattr |= __BLANK; 586 } 587 if (on & __PROTECT && __tc_mp != NULL) { 588 tputs(__tc_mp, 0, __cputchar); 589 curscr->wattr |= __PROTECT; 590 } 591 if (on & __REVERSE && __tc_mr != NULL) { 592 tputs(__tc_mr, 0, __cputchar); 593 curscr->wattr |= __REVERSE; 594 } 595 } 596 597 /* Set/change colour as appropriate. */ 598 if ((nsp->attr & __COLOR) && __tc_Co != NULL && 599 (__tc_oc != NULL || __tc_op != NULL)) { 600 if ((nsp->attr & __COLOR) != 601 (curscr->wattr & __COLOR)) { 602 __set_color(nsp->attr); 603 curscr->wattr &= ~__COLOR; 604 curscr->wattr |= nsp->attr & 605 __COLOR; 606 } 607 } 608 609 /* Enter/exit altcharset mode as appropriate. */ 610 if (on & __ALTCHARSET && __tc_as != NULL && 611 __tc_ae != NULL) { 612 tputs(__tc_as, 0, __cputchar); 613 curscr->wattr |= __ALTCHARSET; 614 } 615 616 wx++; 617 if (wx >= win->maxx && 618 wy == win->maxy - 1 && !curwin) 619 if (win->flags & __SCROLLOK) { 620 if (win->flags & __ENDLINE) 621 __unsetattr(1); 622 if (!(win->flags & __SCROLLWIN)) { 623 if (!curwin) { 624 csp->attr = nsp->attr; 625 __cputchar((int) 626 (csp->ch = 627 nsp->ch)); 628 } else 629 __cputchar((int) nsp->ch); 630 } 631 if (wx < curscr->maxx) { 632 domvcur(ly, wx, 633 (int) (win->maxy - 1), 634 (int) (win->maxx - 1)); 635 } 636 ly = win->maxy - 1; 637 lx = win->maxx - 1; 638 return (OK); 639 } 640 if (wx < win->maxx || wy < win->maxy - 1 || 641 !(win->flags & __SCROLLWIN)) { 642 if (!curwin) { 643 csp->attr = nsp->attr; 644 __cputchar((int) (csp->ch = nsp->ch)); 645 csp++; 646 } else 647 __cputchar((int) nsp->ch); 648 } 649 #ifdef DEBUG 650 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 651 #endif 652 if (__tc_uc && ((nsp->attr & __STANDOUT) || 653 (nsp->attr & __UNDERSCORE))) { 654 __cputchar('\b'); 655 tputs(__tc_uc, 0, __cputchar); 656 } 657 nsp++; 658 #ifdef DEBUG 659 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 660 #endif 661 } 662 if (lx == wx) /* If no change. */ 663 break; 664 lx = wx; 665 if (lx >= COLS && __tc_am) 666 lx = COLS - 1; 667 else 668 if (wx >= win->maxx) { 669 domvcur(ly, lx, ly, 670 (int) (win->maxx - 1)); 671 lx = win->maxx - 1; 672 } 673 #ifdef DEBUG 674 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 675 #endif 676 } 677 678 return (OK); 679 } 680 681 /* 682 * domvcur -- 683 * Do a mvcur, leaving attributes if necessary. 684 */ 685 static void 686 domvcur(oy, ox, ny, nx) 687 int oy, ox, ny, nx; 688 { 689 __unsetattr(1); 690 __mvcur(oy, ox, ny, nx, 1); 691 } 692 693 /* 694 * Quickch() attempts to detect a pattern in the change of the window 695 * in order to optimize the change, e.g., scroll n lines as opposed to 696 * repainting the screen line by line. 697 */ 698 699 static void 700 quickch(void) 701 { 702 #define THRESH (int) __virtscr->maxy / 4 703 704 __LINE *clp, *tmp1, *tmp2; 705 int bsize, curs, curw, starts, startw, i, j; 706 int n, target, cur_period, bot, top, sc_region; 707 __LDATA buf[1024]; 708 u_int blank_hash; 709 attr_t bcolor; 710 711 #ifdef __GNUC__ 712 curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */ 713 #endif 714 /* 715 * Find how many lines from the top of the screen are unchanged. 716 */ 717 for (top = 0; top < __virtscr->maxy; top++) 718 if (__virtscr->lines[top]->flags & __ISDIRTY && 719 (__virtscr->lines[top]->hash != curscr->lines[top]->hash || 720 memcmp(__virtscr->lines[top]->line, 721 curscr->lines[top]->line, 722 (size_t) __virtscr->maxx * __LDATASIZE) != 0)) 723 break; 724 else 725 __virtscr->lines[top]->flags &= ~__ISDIRTY; 726 /* 727 * Find how many lines from bottom of screen are unchanged. 728 */ 729 for (bot = __virtscr->maxy - 1; bot >= 0; bot--) 730 if (__virtscr->lines[bot]->flags & __ISDIRTY && 731 (__virtscr->lines[bot]->hash != curscr->lines[bot]->hash || 732 memcmp(__virtscr->lines[bot]->line, 733 curscr->lines[bot]->line, 734 (size_t) __virtscr->maxx * __LDATASIZE) != 0)) 735 break; 736 else 737 __virtscr->lines[bot]->flags &= ~__ISDIRTY; 738 739 /* 740 * Work round an xterm bug where inserting lines causes all the 741 * inserted lines to be covered with the background colour we 742 * set on the first line (even if we unset it for subsequent 743 * lines). 744 */ 745 bcolor = __virtscr->lines[min(top, 746 __virtscr->maxy - 1)]->line[0].attr & __COLOR; 747 for (i = top + 1, j = 0; i < bot; i++) { 748 if ((__virtscr->lines[i]->line[0].attr & __COLOR) != bcolor) { 749 bcolor = __virtscr->lines[i]->line[__virtscr->maxx]. 750 attr & __COLOR; 751 j = i - top; 752 } else 753 break; 754 } 755 top += j; 756 757 #ifdef NO_JERKINESS 758 /* 759 * If we have a bottom unchanged region return. Scrolling the 760 * bottom region up and then back down causes a screen jitter. 761 * This will increase the number of characters sent to the screen 762 * but it looks better. 763 */ 764 if (bot < __virtscr->maxy - 1) 765 return; 766 #endif /* NO_JERKINESS */ 767 768 /* 769 * Search for the largest block of text not changed. 770 * Invariants of the loop: 771 * - Startw is the index of the beginning of the examined block in 772 * __virtscr. 773 * - Starts is the index of the beginning of the examined block in 774 * curscr. 775 * - Curw is the index of one past the end of the exmined block in 776 * __virtscr. 777 * - Curs is the index of one past the end of the exmined block in 778 * curscr. 779 * - bsize is the current size of the examined block. 780 */ 781 782 for (bsize = bot - top; bsize >= THRESH; bsize--) { 783 for (startw = top; startw <= bot - bsize; startw++) 784 for (starts = top; starts <= bot - bsize; 785 starts++) { 786 for (curw = startw, curs = starts; 787 curs < starts + bsize; curw++, curs++) 788 if (__virtscr->lines[curw]->hash != 789 curscr->lines[curs]->hash) 790 break; 791 if (curs != starts + bsize) 792 continue; 793 for (curw = startw, curs = starts; 794 curs < starts + bsize; curw++, curs++) 795 if (memcmp(__virtscr->lines[curw]->line, 796 curscr->lines[curs]->line, 797 (size_t) __virtscr->maxx * 798 __LDATASIZE) != 0) 799 break; 800 if (curs == starts + bsize) 801 goto done; 802 } 803 } 804 done: 805 806 /* Did not find anything */ 807 if (bsize < THRESH) 808 return; 809 810 #ifdef DEBUG 811 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 812 bsize, starts, startw, curw, curs, top, bot); 813 #endif 814 815 /* 816 * Make sure that there is no overlap between the bottom and top 817 * regions and the middle scrolled block. 818 */ 819 if (bot < curs) 820 bot = curs - 1; 821 if (top > starts) 822 top = starts; 823 824 n = startw - starts; 825 826 #ifdef DEBUG 827 __CTRACE("#####################################\n"); 828 for (i = 0; i < curscr->maxy; i++) { 829 __CTRACE("C: %d:", i); 830 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 831 for (j = 0; j < curscr->maxx; j++) 832 __CTRACE("%c", curscr->lines[i]->line[j].ch); 833 __CTRACE("\n"); 834 __CTRACE(" attr:"); 835 for (j = 0; j < curscr->maxx; j++) 836 __CTRACE(" %x", curscr->lines[i]->line[j].attr); 837 __CTRACE("\n"); 838 __CTRACE("W: %d:", i); 839 __CTRACE(" 0x%x \n", __virtscr->lines[i]->hash); 840 __CTRACE(" 0x%x ", __virtscr->lines[i]->flags); 841 for (j = 0; j < __virtscr->maxx; j++) 842 __CTRACE("%c", __virtscr->lines[i]->line[j].ch); 843 __CTRACE("\n"); 844 __CTRACE(" attr:"); 845 for (j = 0; j < __virtscr->maxx; j++) 846 __CTRACE(" %x", __virtscr->lines[i]->line[j].attr); 847 __CTRACE("\n"); 848 } 849 #endif 850 851 /* So we don't have to call __hash() each time */ 852 for (i = 0; i < __virtscr->maxx; i++) { 853 buf[i].ch = ' '; 854 buf[i].bch = ' '; 855 buf[i].attr = 0; 856 buf[i].battr = 0; 857 } 858 blank_hash = __hash((char *)(void *)buf, 859 (int) (__virtscr->maxx * __LDATASIZE)); 860 861 /* 862 * Perform the rotation to maintain the consistency of curscr. 863 * This is hairy since we are doing an *in place* rotation. 864 * Invariants of the loop: 865 * - I is the index of the current line. 866 * - Target is the index of the target of line i. 867 * - Tmp1 points to current line (i). 868 * - Tmp2 and points to target line (target); 869 * - Cur_period is the index of the end of the current period. 870 * (see below). 871 * 872 * There are 2 major issues here that make this rotation non-trivial: 873 * 1. Scrolling in a scrolling region bounded by the top 874 * and bottom regions determined (whose size is sc_region). 875 * 2. As a result of the use of the mod function, there may be a 876 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 877 * 0 to 2, which then causes all odd lines not to be rotated. 878 * To remedy this, an index of the end ( = beginning) of the 879 * current 'period' is kept, cur_period, and when it is reached, 880 * the next period is started from cur_period + 1 which is 881 * guaranteed not to have been reached since that would mean that 882 * all records would have been reached. (think about it...). 883 * 884 * Lines in the rotation can have 3 attributes which are marked on the 885 * line so that curscr is consistent with the visual screen. 886 * 1. Not dirty -- lines inside the scrolled block, top region or 887 * bottom region. 888 * 2. Blank lines -- lines in the differential of the scrolling 889 * region adjacent to top and bot regions 890 * depending on scrolling direction. 891 * 3. Dirty line -- all other lines are marked dirty. 892 */ 893 sc_region = bot - top + 1; 894 i = top; 895 tmp1 = curscr->lines[top]; 896 cur_period = top; 897 for (j = top; j <= bot; j++) { 898 target = (i - top + n + sc_region) % sc_region + top; 899 tmp2 = curscr->lines[target]; 900 curscr->lines[target] = tmp1; 901 /* Mark block as clean and blank out scrolled lines. */ 902 clp = curscr->lines[target]; 903 #ifdef DEBUG 904 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 905 n, startw, curw, i, target); 906 #endif 907 if ((target >= startw && target < curw) || target < top 908 || target > bot) { 909 #ifdef DEBUG 910 __CTRACE("-- notdirty\n"); 911 #endif 912 __virtscr->lines[target]->flags &= ~__ISDIRTY; 913 } else 914 if ((n > 0 && target >= top && target < top + n) || 915 (n < 0 && target <= bot && target > bot + n)) { 916 if (clp->hash != blank_hash || memcmp(clp->line, 917 buf, (size_t) __virtscr->maxx * __LDATASIZE) !=0) { 918 (void)memcpy(clp->line, buf, 919 (size_t) __virtscr->maxx * __LDATASIZE); 920 #ifdef DEBUG 921 __CTRACE("-- blanked out: dirty\n"); 922 #endif 923 clp->hash = blank_hash; 924 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 925 } else { 926 #ifdef DEBUG 927 __CTRACE(" -- blank line already: dirty\n"); 928 #endif 929 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 930 } 931 } else { 932 #ifdef DEBUG 933 __CTRACE(" -- dirty\n"); 934 #endif 935 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 936 } 937 if (target == cur_period) { 938 i = target + 1; 939 tmp1 = curscr->lines[i]; 940 cur_period = i; 941 } else { 942 tmp1 = tmp2; 943 i = target; 944 } 945 } 946 #ifdef DEBUG 947 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 948 for (i = 0; i < curscr->maxy; i++) { 949 __CTRACE("C: %d:", i); 950 for (j = 0; j < curscr->maxx; j++) 951 __CTRACE("%c", curscr->lines[i]->line[j].ch); 952 __CTRACE("\n"); 953 __CTRACE("W: %d:", i); 954 for (j = 0; j < __virtscr->maxx; j++) 955 __CTRACE("%c", __virtscr->lines[i]->line[j].ch); 956 __CTRACE("\n"); 957 } 958 #endif 959 if (n != 0) 960 scrolln(starts, startw, curs, bot, top); 961 } 962 963 /* 964 * scrolln -- 965 * Scroll n lines, where n is starts - startw. 966 */ 967 static void /* ARGSUSED */ 968 scrolln(starts, startw, curs, bot, top) 969 int starts, startw, curs, bot, top; 970 { 971 int i, oy, ox, n; 972 973 oy = curscr->cury; 974 ox = curscr->curx; 975 n = starts - startw; 976 977 /* 978 * XXX 979 * The initial tests that set __noqch don't let us reach here unless 980 * we have either cs + ho + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 981 * scrolling can only shift the entire scrolling region, not just a 982 * part of it, which means that the quickch() routine is going to be 983 * sadly disappointed in us if we don't have cs as well. 984 * 985 * If cs, ho and SF/sf are set, can use the scrolling region. Because 986 * the cursor position after cs is undefined, we need ho which gives us 987 * the ability to move to somewhere without knowledge of the current 988 * location of the cursor. Still call __mvcur() anyway, to update its 989 * idea of where the cursor is. 990 * 991 * When the scrolling region has been set, the cursor has to be at the 992 * last line of the region to make the scroll happen. 993 * 994 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 995 * or AL/DL, and, some terminals have AL/DL, sf/sr, and cs, but not 996 * SF/SR. So, if we're scrolling almost all of the screen, try and use 997 * AL/DL, otherwise use the scrolling region. The "almost all" is a 998 * shameless hack for vi. 999 */ 1000 if (n > 0) { 1001 if (__tc_cs != NULL && __tc_ho != NULL && (__tc_SF != NULL || 1002 ((__tc_AL == NULL || __tc_DL == NULL || 1003 top > 3 || bot + 3 < __virtscr->maxy) && 1004 __tc_sf != NULL))) { 1005 tputs(__tscroll(__tc_cs, top, bot + 1), 0, __cputchar); 1006 __mvcur(oy, ox, 0, 0, 1); 1007 tputs(__tc_ho, 0, __cputchar); 1008 __mvcur(0, 0, bot, 0, 1); 1009 if (__tc_SF != NULL) 1010 tputs(__tscroll(__tc_SF, n, 0), 0, __cputchar); 1011 else 1012 for (i = 0; i < n; i++) 1013 tputs(__tc_sf, 0, __cputchar); 1014 tputs(__tscroll(__tc_cs, 0, (int) __virtscr->maxy), 0, 1015 __cputchar); 1016 __mvcur(bot, 0, 0, 0, 1); 1017 tputs(__tc_ho, 0, __cputchar); 1018 __mvcur(0, 0, oy, ox, 1); 1019 return; 1020 } 1021 1022 /* Scroll up the block. */ 1023 if (__tc_SF != NULL && top == 0) { 1024 __mvcur(oy, ox, bot, 0, 1); 1025 tputs(__tscroll(__tc_SF, n, 0), 0, __cputchar); 1026 } else 1027 if (__tc_DL != NULL) { 1028 __mvcur(oy, ox, top, 0, 1); 1029 tputs(__tscroll(__tc_DL, n, 0), 0, __cputchar); 1030 } else 1031 if (__tc_dl != NULL) { 1032 __mvcur(oy, ox, top, 0, 1); 1033 for (i = 0; i < n; i++) 1034 tputs(__tc_dl, 0, __cputchar); 1035 } else 1036 if (__tc_sf != NULL && top == 0) { 1037 __mvcur(oy, ox, bot, 0, 1); 1038 for (i = 0; i < n; i++) 1039 tputs(__tc_sf, 0, 1040 __cputchar); 1041 } else 1042 abort(); 1043 1044 /* Push down the bottom region. */ 1045 __mvcur(top, 0, bot - n + 1, 0, 1); 1046 if (__tc_AL != NULL) 1047 tputs(__tscroll(__tc_AL, n, 0), 0, __cputchar); 1048 else 1049 if (__tc_al != NULL) 1050 for (i = 0; i < n; i++) 1051 tputs(__tc_al, 0, __cputchar); 1052 else 1053 abort(); 1054 __mvcur(bot - n + 1, 0, oy, ox, 1); 1055 } else { 1056 /* 1057 * !!! 1058 * n < 0 1059 * 1060 * If cs, ho and SR/sr are set, can use the scrolling region. 1061 * See the above comments for details. 1062 */ 1063 if (__tc_cs != NULL && __tc_ho != NULL && (__tc_SR != NULL || 1064 ((__tc_AL == NULL || __tc_DL == NULL || top > 3 || 1065 bot + 3 < __virtscr->maxy) && __tc_sr != NULL))) { 1066 tputs(__tscroll(__tc_cs, top, bot + 1), 0, __cputchar); 1067 __mvcur(oy, ox, 0, 0, 1); 1068 tputs(__tc_ho, 0, __cputchar); 1069 __mvcur(0, 0, top, 0, 1); 1070 1071 if (__tc_SR != NULL) 1072 tputs(__tscroll(__tc_SR, -n, 0), 0, __cputchar); 1073 else 1074 for (i = n; i < 0; i++) 1075 tputs(__tc_sr, 0, __cputchar); 1076 tputs(__tscroll(__tc_cs, 0, (int) __virtscr->maxy), 0, 1077 __cputchar); 1078 __mvcur(top, 0, 0, 0, 1); 1079 tputs(__tc_ho, 0, __cputchar); 1080 __mvcur(0, 0, oy, ox, 1); 1081 return; 1082 } 1083 1084 /* Preserve the bottom lines. */ 1085 __mvcur(oy, ox, bot + n + 1, 0, 1); 1086 if (__tc_SR != NULL && bot == __virtscr->maxy) 1087 tputs(__tscroll(__tc_SR, -n, 0), 0, __cputchar); 1088 else 1089 if (__tc_DL != NULL) 1090 tputs(__tscroll(__tc_DL, -n, 0), 0, __cputchar); 1091 else 1092 if (__tc_dl != NULL) 1093 for (i = n; i < 0; i++) 1094 tputs(__tc_dl, 0, __cputchar); 1095 else 1096 if (__tc_sr != NULL && 1097 bot == __virtscr->maxy) 1098 for (i = n; i < 0; i++) 1099 tputs(__tc_sr, 0, 1100 __cputchar); 1101 else 1102 abort(); 1103 1104 /* Scroll the block down. */ 1105 __mvcur(bot + n + 1, 0, top, 0, 1); 1106 if (__tc_AL != NULL) 1107 tputs(__tscroll(__tc_AL, -n, 0), 0, __cputchar); 1108 else 1109 if (__tc_al != NULL) 1110 for (i = n; i < 0; i++) 1111 tputs(__tc_al, 0, __cputchar); 1112 else 1113 abort(); 1114 __mvcur(top, 0, oy, ox, 1); 1115 } 1116 } 1117 1118 /* 1119 * __unsetattr -- 1120 * Unset attributes on curscr. Leave standout, attribute and colour 1121 * modes if necessary (!ms). Always leave altcharset (xterm at least 1122 * ignores a cursor move if we don't). 1123 */ 1124 void /* ARGSUSED */ 1125 __unsetattr(int checkms) 1126 { 1127 int isms; 1128 1129 if (checkms) 1130 if (!__tc_ms) { 1131 isms = 1; 1132 } else { 1133 isms = 0; 1134 } 1135 else 1136 isms = 1; 1137 #ifdef DEBUG 1138 __CTRACE("__unsetattr: checkms = %d, ms = %s, wattr = %08x\n", 1139 checkms, __tc_ms ? "TRUE" : "FALSE", curscr->wattr); 1140 #endif 1141 1142 /* 1143 * Don't leave the screen in standout mode (check against ms). Check 1144 * to see if we also turn off underscore, attributes and colour. 1145 */ 1146 if (curscr->wattr & __STANDOUT && isms) { 1147 tputs(__tc_se, 0, __cputchar); 1148 curscr->wattr &= __mask_se; 1149 } 1150 /* 1151 * Don't leave the screen in underscore mode (check against ms). 1152 * Check to see if we also turn off attributes. Assume that we 1153 * also turn off colour. 1154 */ 1155 if (curscr->wattr & __UNDERSCORE && isms) { 1156 tputs(__tc_ue, 0, __cputchar); 1157 curscr->wattr &= __mask_ue; 1158 } 1159 /* 1160 * Don't leave the screen with attributes set (check against ms). 1161 * Assume that also turn off colour. 1162 */ 1163 if (curscr->wattr & __TERMATTR && isms) { 1164 tputs(__tc_me, 0, __cputchar); 1165 curscr->wattr &= __mask_me; 1166 } 1167 /* Don't leave the screen with altcharset set (don't check ms). */ 1168 if (curscr->wattr & __ALTCHARSET) { 1169 tputs(__tc_ae, 0, __cputchar); 1170 curscr->wattr &= ~__ALTCHARSET; 1171 } 1172 /* Don't leave the screen with colour set (check against ms). */ 1173 if (curscr->wattr & __COLOR && isms) { 1174 if (__tc_oc != NULL && __tc_cc == NULL) 1175 tputs(__tc_oc, 0, __cputchar); 1176 if (__tc_op != NULL) { 1177 tputs(__tc_op, 0, __cputchar); 1178 curscr->wattr &= __mask_op; 1179 } 1180 } 1181 } 1182