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