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