1 /* $NetBSD: refresh.c,v 1.88 2017/03/20 20:42:39 christos 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.88 2017/03/20 20:42:39 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <poll.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 #include "curses.h" 46 #include "curses_private.h" 47 48 static void domvcur(const WINDOW *, int, int, int, int); 49 static int makech(int); 50 static void quickch(void); 51 static void scrolln(int, int, int, int, int); 52 53 static int _wnoutrefresh(WINDOW *, int, int, int, int, int, int); 54 55 #ifdef HAVE_WCHAR 56 int cellcmp( __LDATA *, __LDATA * ); 57 int linecmp( __LDATA *, __LDATA *, size_t ); 58 #endif /* HAVE_WCHAR */ 59 60 #define CHECK_INTERVAL 5 /* Change N lines before checking typeahead */ 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 73 return wrefresh(stdscr); 74 } 75 76 #endif 77 78 /* 79 * wnoutrefresh -- 80 * Add the contents of "win" to the virtual window. 81 */ 82 int 83 wnoutrefresh(WINDOW *win) 84 { 85 86 #ifdef DEBUG 87 __CTRACE(__CTRACE_REFRESH, "wnoutrefresh: win %p\n", win); 88 #endif 89 90 return _wnoutrefresh(win, 0, 0, win->begy, win->begx, 91 win->maxy, win->maxx); 92 } 93 94 /* 95 * pnoutrefresh -- 96 * Add the contents of "pad" to the virtual window. 97 */ 98 int 99 pnoutrefresh(WINDOW *pad, int pbegy, int pbegx, int sbegy, int sbegx, 100 int smaxy, int smaxx) 101 { 102 int pmaxy, pmaxx; 103 104 #ifdef DEBUG 105 __CTRACE(__CTRACE_REFRESH, "pnoutrefresh: pad %p, flags 0x%08x\n", 106 pad, pad->flags); 107 __CTRACE(__CTRACE_REFRESH, 108 "pnoutrefresh: (%d, %d), (%d, %d), (%d, %d)\n", 109 pbegy, pbegx, sbegy, sbegx, smaxy, smaxx); 110 #endif 111 112 /* SUS says if these are negative, they should be treated as zero */ 113 if (pbegy < 0) 114 pbegy = 0; 115 if (pbegx < 0) 116 pbegx = 0; 117 if (sbegy < 0) 118 sbegy = 0; 119 if (sbegx < 0) 120 sbegx = 0; 121 122 /* Calculate rectangle on pad - used by _wnoutrefresh */ 123 pmaxy = pbegy + smaxy - sbegy + 1; 124 pmaxx = pbegx + smaxx - sbegx + 1; 125 126 /* Check rectangle fits in pad */ 127 if (pmaxy > pad->maxy - pad->begy) 128 pmaxy = pad->maxy - pad->begy; 129 if (pmaxx > pad->maxx - pad->begx) 130 pmaxx = pad->maxx - pad->begx; 131 132 if (smaxy - sbegy < 0 || smaxx - sbegx < 0 ) 133 return ERR; 134 135 return _wnoutrefresh(pad, 136 pad->begy + pbegy, pad->begx + pbegx, pad->begy + sbegy, 137 pad->begx + sbegx, pmaxy, pmaxx); 138 } 139 140 /* 141 * _wnoutrefresh -- 142 * Does the grunt work for wnoutrefresh to the given screen. 143 * Copies the part of the window given by the rectangle 144 * (begy, begx) to (maxy, maxx) at screen position (wbegy, wbegx). 145 */ 146 static int 147 _wnoutrefresh(WINDOW *win, int begy, int begx, int wbegy, int wbegx, 148 int maxy, int maxx) 149 { 150 SCREEN *screen = win->screen; 151 short sy, wy, wx, y_off, x_off, mx, dy_off, dx_off, endy; 152 __LINE *wlp, *vlp, *dwlp; 153 WINDOW *sub_win, *orig, *swin, *dwin; 154 155 #ifdef DEBUG 156 __CTRACE(__CTRACE_REFRESH, "_wnoutrefresh: win %p, flags 0x%08x\n", 157 win, win->flags); 158 __CTRACE(__CTRACE_REFRESH, 159 "_wnoutrefresh: (%d, %d), (%d, %d), (%d, %d)\n", 160 begy, begx, wbegy, wbegx, maxy, maxx); 161 #endif 162 163 if (screen->curwin) 164 return OK; 165 166 swin = dwin = win; 167 if (win->flags & __ISDERWIN) 168 swin = win->orig; 169 170 /* 171 * Recurse through any sub-windows, mark as dirty lines on the parent 172 * window that are dirty on the sub-window and clear the dirty flag on 173 * the sub-window. 174 */ 175 if (dwin->orig == 0) { 176 orig = dwin; 177 for (sub_win = dwin->nextp; sub_win != orig; 178 sub_win = sub_win->nextp) { 179 if (sub_win->flags & __ISDERWIN) 180 continue; 181 #ifdef DEBUG 182 __CTRACE(__CTRACE_REFRESH, 183 "wnout_refresh: win %p, sub_win %p\n", 184 orig, sub_win); 185 #endif 186 for (sy = 0; sy < sub_win->maxy; sy++) { 187 if (sub_win->alines[sy]->flags & __ISDIRTY) { 188 orig->alines[sy + sub_win->begy - orig->begy]->flags 189 |= __ISDIRTY; 190 sub_win->alines[sy]->flags 191 &= ~__ISDIRTY; 192 } 193 if (sub_win->alines[sy]->flags & __ISFORCED) { 194 orig->alines[sy + sub_win->begy - orig->begy]->flags 195 |= __ISFORCED; 196 sub_win->alines[sy]->flags 197 &= ~__ISFORCED; 198 } 199 } 200 } 201 } 202 203 /* Check that cursor position on "win" is valid for "__virtscr" */ 204 if (dwin->cury + wbegy - begy < screen->__virtscr->maxy && 205 dwin->cury + wbegy - begy >= 0 && dwin->cury < maxy - begy) 206 screen->__virtscr->cury = dwin->cury + wbegy - begy; 207 if (dwin->curx + wbegx - begx < screen->__virtscr->maxx && 208 dwin->curx + wbegx - begx >= 0 && dwin->curx < maxx - begx) 209 screen->__virtscr->curx = dwin->curx + wbegx - begx; 210 211 /* Copy the window flags from "win" to "__virtscr" */ 212 if (dwin->flags & __CLEAROK) { 213 if (dwin->flags & __FULLWIN) 214 screen->__virtscr->flags |= __CLEAROK; 215 dwin->flags &= ~__CLEAROK; 216 } 217 screen->__virtscr->flags &= ~__LEAVEOK; 218 screen->__virtscr->flags |= dwin->flags; 219 220 if ((dwin->flags & __ISDERWIN) != 0) 221 endy = begy + maxy; 222 else 223 endy = maxy; 224 225 for (wy = begy, y_off = wbegy, dy_off = 0; wy < endy && 226 y_off < screen->__virtscr->maxy; wy++, y_off++, dy_off++) 227 { 228 wlp = swin->alines[wy]; 229 dwlp = dwin->alines[dy_off]; 230 #ifdef DEBUG 231 __CTRACE(__CTRACE_REFRESH, 232 "_wnoutrefresh: wy %d\tf %d\tl %d\tflags %x\n", 233 wy, *wlp->firstchp, *wlp->lastchp, wlp->flags); 234 235 if ((dwin->flags & __ISDERWIN) != 0) { 236 __CTRACE(__CTRACE_REFRESH, 237 "_wnoutrefresh: derwin wy %d\tf %d\tl %d\tflags %x\n", 238 dy_off, *dwlp->firstchp, *dwlp->lastchp, dwlp->flags); 239 __CTRACE(__CTRACE_REFRESH, 240 "_wnoutrefresh: derwin maxx %d\tch_off %d\n", 241 dwin->maxx, dwin->ch_off); 242 } 243 #endif 244 if (((wlp->flags & (__ISDIRTY | __ISFORCED)) == 0) && 245 ((dwlp->flags & (__ISDIRTY | __ISFORCED)) == 0)) 246 continue; 247 vlp = screen->__virtscr->alines[y_off]; 248 249 if ((*wlp->firstchp < maxx + swin->ch_off && 250 *wlp->lastchp >= swin->ch_off) || 251 ((((dwin->flags & __ISDERWIN) != 0) && 252 (*dwlp->firstchp < dwin->maxx + dwin->ch_off && 253 *dwlp->lastchp >= dwin->ch_off)))) 254 { 255 /* Set start column */ 256 wx = begx; 257 x_off = wbegx; 258 dx_off = 0; 259 /* 260 * if a derwin then source change pointers aren't 261 * relevant. 262 */ 263 if ((dwin->flags & __ISDERWIN) != 0) 264 mx = wx + maxx; 265 else { 266 if (*wlp->firstchp - swin->ch_off > 0) { 267 wx += *wlp->firstchp - swin->ch_off; 268 x_off += *wlp->firstchp - swin->ch_off; 269 } 270 mx = maxx; 271 if (mx > *wlp->lastchp - swin->ch_off + 1) 272 mx = *dwlp->lastchp - dwin->ch_off + 1; 273 if (x_off + (mx - wx) > screen->__virtscr->maxx) 274 mx -= (x_off + maxx) - 275 screen->__virtscr->maxx; 276 } 277 278 /* Copy line from "win" to "__virtscr". */ 279 while (wx < mx) { 280 #ifdef DEBUG 281 __CTRACE(__CTRACE_REFRESH, 282 "_wnoutrefresh: copy from %d, " 283 "%d to %d, %d: %s, 0x%x", 284 wy, wx, y_off, x_off, 285 unctrl(wlp->line[wx].ch), 286 wlp->line[wx].attr); 287 #endif 288 /* Copy character */ 289 vlp->line[x_off].ch = wlp->line[wx].ch; 290 /* Copy attributes */ 291 vlp->line[x_off].attr = wlp->line[wx].attr; 292 /* Check for nca conflict with colour */ 293 if ((vlp->line[x_off].attr & __COLOR) && 294 (vlp->line[x_off].attr & screen->nca)) 295 vlp->line[x_off].attr &= ~__COLOR; 296 if (win->flags & __ISDERWIN) { 297 dwlp->line[dx_off].ch = 298 wlp->line[wx].ch; 299 dwlp->line[dx_off].attr = 300 wlp->line[wx].attr; 301 } 302 303 #ifdef HAVE_WCHAR 304 if (wlp->line[wx].ch 305 == (wchar_t)btowc((int) win->bch)) { 306 vlp->line[x_off].ch = win->bch; 307 SET_WCOL(vlp->line[x_off], 1); 308 if (_cursesi_copy_nsp(win->bnsp, 309 &vlp->line[x_off]) 310 == ERR) 311 return ERR; 312 if (win->flags & __ISDERWIN) { 313 dwlp->line[dx_off].ch = 314 win->bch; 315 SET_WCOL(dwlp->line[dx_off], 1); 316 if (_cursesi_copy_nsp(win->bnsp, 317 &dwlp->line[dx_off]) 318 == ERR) 319 return ERR; 320 } 321 } 322 #endif /* HAVE_WCHAR */ 323 #ifdef DEBUG 324 __CTRACE(__CTRACE_REFRESH, " = %s, 0x%x\n", 325 unctrl(vlp->line[x_off].ch), 326 vlp->line[x_off].attr); 327 #endif 328 wx++; 329 x_off++; 330 dx_off++; 331 } 332 333 /* Set flags on "__virtscr" and unset on "win". */ 334 if (wlp->flags & __ISPASTEOL) 335 vlp->flags |= __ISPASTEOL; 336 else 337 vlp->flags &= ~__ISPASTEOL; 338 if (wlp->flags & __ISDIRTY) 339 vlp->flags |= __ISDIRTY; 340 if (wlp->flags & __ISFORCED) 341 vlp->flags |= __ISFORCED; 342 343 #ifdef DEBUG 344 __CTRACE(__CTRACE_REFRESH, 345 "win: firstch = %d, lastch = %d\n", 346 *wlp->firstchp, *wlp->lastchp); 347 if (win->flags & __ISDERWIN) { 348 __CTRACE(__CTRACE_REFRESH, 349 "derwin: fistch = %d, lastch = %d\n", 350 *dwlp->firstchp, *dwlp->lastchp); 351 } 352 #endif 353 /* Set change pointers on "__virtscr". */ 354 if (*vlp->firstchp > 355 *wlp->firstchp + wbegx - win->ch_off) 356 *vlp->firstchp = 357 *wlp->firstchp + wbegx - win->ch_off; 358 if (*vlp->lastchp < 359 *wlp->lastchp + wbegx - win->ch_off) 360 *vlp->lastchp = 361 *wlp->lastchp + wbegx - win->ch_off; 362 363 if (win->flags & __ISDERWIN) { 364 if (*vlp->firstchp > 365 *dwlp->firstchp + wbegx - dwin->ch_off) 366 { 367 *vlp->firstchp = 368 *dwlp->firstchp + wbegx 369 - dwin->ch_off; 370 vlp->flags |= __ISDIRTY; 371 } 372 373 if (*vlp->lastchp < 374 *dwlp->lastchp + wbegx - dwin->ch_off) 375 { 376 *vlp->lastchp = *dwlp->lastchp 377 + wbegx - dwin->ch_off; 378 vlp->flags |= __ISDIRTY; 379 } 380 } 381 382 #ifdef DEBUG 383 __CTRACE(__CTRACE_REFRESH, 384 "__virtscr: firstch = %d, lastch = %d\n", 385 *vlp->firstchp, *vlp->lastchp); 386 #endif 387 /* 388 * Unset change pointers only if a window and we 389 * are not forcing a redraw. A pad can be displayed 390 * again without any of the contents changing. 391 */ 392 if ((!(win->flags & __ISPAD)) || 393 ((wlp->flags & __ISFORCED) == __ISFORCED)) 394 { 395 /* Set change pointers on "win". */ 396 if (*wlp->firstchp >= win->ch_off) 397 *wlp->firstchp = maxx + win->ch_off; 398 if (*wlp->lastchp < maxx + win->ch_off) 399 *wlp->lastchp = win->ch_off; 400 if ((*wlp->lastchp < *wlp->firstchp) || 401 (*wlp->firstchp >= maxx + win->ch_off) || 402 (*wlp->lastchp <= win->ch_off)) { 403 #ifdef DEBUG 404 __CTRACE(__CTRACE_REFRESH, 405 "_wnoutrefresh: " 406 "line %d notdirty\n", wy); 407 #endif 408 wlp->flags &= ~(__ISDIRTY | __ISFORCED); 409 } 410 } 411 } 412 } 413 return OK; 414 } 415 416 /* 417 * wrefresh -- 418 * Make the current screen look like "win" over the area covered by 419 * win. 420 */ 421 int 422 wrefresh(WINDOW *win) 423 { 424 int retval; 425 int pbegx, pbegy; 426 427 #ifdef DEBUG 428 __CTRACE(__CTRACE_REFRESH, "wrefresh: win %p\n", win); 429 #endif 430 431 _cursesi_screen->curwin = (win == _cursesi_screen->curscr); 432 if (!_cursesi_screen->curwin) { 433 pbegx = pbegy = 0; 434 if ((win->flags & __ISDERWIN) == __ISDERWIN) { 435 pbegx = win->derx; 436 pbegy = win->dery; 437 #ifdef DEBUG 438 __CTRACE(__CTRACE_REFRESH, "wrefresh: derwin, begy = %d, begx = %x\n", 439 pbegy, pbegx); 440 #endif 441 } 442 retval = _wnoutrefresh(win, pbegy, pbegx, win->begy, win->begx, 443 win->maxy, win->maxx); 444 } else 445 retval = OK; 446 if (retval == OK) { 447 retval = doupdate(); 448 if (!(win->flags & __LEAVEOK)) { 449 win->cury = max(0, curscr->cury - win->begy); 450 win->curx = max(0, curscr->curx - win->begx); 451 } 452 } 453 _cursesi_screen->curwin = 0; 454 return retval; 455 } 456 457 /* 458 * prefresh -- 459 * Make the current screen look like "pad" over the area coverd by 460 * the specified area of pad. 461 */ 462 int 463 prefresh(WINDOW *pad, int pbegy, int pbegx, int sbegy, int sbegx, 464 int smaxy, int smaxx) 465 { 466 int retval; 467 468 #ifdef DEBUG 469 __CTRACE(__CTRACE_REFRESH, "prefresh: pad %p, flags 0x%08x\n", 470 pad, pad->flags); 471 #endif 472 /* Retain values in case pechochar() is called. */ 473 pad->pbegy = pbegy; 474 pad->pbegx = pbegx; 475 pad->sbegy = sbegy; 476 pad->sbegx = sbegx; 477 pad->smaxy = smaxy; 478 pad->smaxx = smaxx; 479 480 /* Use pnoutrefresh() to avoid duplicating code here */ 481 retval = pnoutrefresh(pad, pbegy, pbegx, sbegy, sbegx, smaxy, smaxx); 482 if (retval == OK) { 483 retval = doupdate(); 484 if (!(pad->flags & __LEAVEOK)) { 485 pad->cury = max(0, curscr->cury - pad->begy); 486 pad->curx = max(0, curscr->curx - pad->begx); 487 } 488 } 489 return retval; 490 } 491 492 /* 493 * doupdate -- 494 * Make the current screen look like the virtual window "__virtscr". 495 */ 496 int 497 doupdate(void) 498 { 499 WINDOW *win; 500 __LINE *wlp, *vlp; 501 short wy; 502 int dnum, was_cleared, changed; 503 #ifdef HAVE_WCHAR 504 __LDATA *lp; 505 nschar_t *np; 506 int x; 507 #endif /* HAVE_WCHAR */ 508 509 /* Check if we need to restart ... */ 510 if (_cursesi_screen->endwin) 511 __restartwin(); 512 513 if (_cursesi_screen->curwin) 514 win = curscr; 515 else 516 win = _cursesi_screen->__virtscr; 517 518 /* Initialize loop parameters. */ 519 _cursesi_screen->ly = curscr->cury; 520 _cursesi_screen->lx = curscr->curx; 521 wy = 0; 522 523 if (!_cursesi_screen->curwin) { 524 for (wy = 0; wy < win->maxy; wy++) { 525 wlp = win->alines[wy]; 526 if (wlp->flags & __ISDIRTY) { 527 #ifndef HAVE_WCHAR 528 wlp->hash = __hash(wlp->line, 529 (size_t)(win->maxx * __LDATASIZE)); 530 #else 531 wlp->hash = 0; 532 for ( x = 0; x < win->maxx; x++ ) { 533 lp = &wlp->line[ x ]; 534 wlp->hash = __hash_more( &lp->ch, 535 sizeof(wchar_t), wlp->hash ); 536 wlp->hash = __hash_more( &lp->attr, 537 sizeof(attr_t), wlp->hash ); 538 np = lp->nsp; 539 if (np) { 540 while (np) { 541 wlp->hash 542 = __hash_more( 543 &np->ch, 544 sizeof(wchar_t), 545 wlp->hash); 546 np = np->next; 547 } 548 } 549 } 550 #endif /* HAVE_WCHAR */ 551 } 552 } 553 } 554 555 was_cleared = 0; 556 if ((win->flags & __CLEAROK) || (curscr->flags & __CLEAROK) || 557 _cursesi_screen->curwin) 558 { 559 if (curscr->wattr & __COLOR) 560 __unsetattr(0); 561 tputs(clear_screen, 0, __cputchar); 562 _cursesi_screen->ly = 0; 563 _cursesi_screen->lx = 0; 564 if (!_cursesi_screen->curwin) { 565 curscr->flags &= ~__CLEAROK; 566 curscr->cury = 0; 567 curscr->curx = 0; 568 werase(curscr); 569 } 570 __touchwin(win); 571 win->flags &= ~__CLEAROK; 572 /* note we cleared for later */ 573 was_cleared = 1; 574 } 575 if (!cursor_address) { 576 if (win->curx != 0) 577 __cputchar('\n'); 578 if (!_cursesi_screen->curwin) 579 werase(curscr); 580 } 581 #ifdef DEBUG 582 __CTRACE(__CTRACE_REFRESH, "doupdate: (%p): curwin = %d\n", win, 583 _cursesi_screen->curwin); 584 __CTRACE(__CTRACE_REFRESH, "doupdate: \tfirstch\tlastch\n"); 585 #endif 586 587 if (!_cursesi_screen->curwin) { 588 /* 589 * Invoke quickch() only if more than a quarter of the lines 590 * in the window are dirty. 591 */ 592 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 593 if (win->alines[wy]->flags & __ISDIRTY) 594 dnum++; 595 if (!__noqch && dnum > (int) win->maxy / 4) 596 quickch(); 597 } 598 599 #ifdef DEBUG 600 { 601 int i, j; 602 603 __CTRACE(__CTRACE_REFRESH, 604 "#####################################\n"); 605 __CTRACE(__CTRACE_REFRESH, 606 "stdscr(%p)-curscr(%p)-__virtscr(%p)\n", 607 stdscr, curscr, _cursesi_screen->__virtscr); 608 for (i = 0; i < curscr->maxy; i++) { 609 __CTRACE(__CTRACE_REFRESH, "C: %d:", i); 610 __CTRACE(__CTRACE_REFRESH, " 0x%x \n", 611 curscr->alines[i]->hash); 612 for (j = 0; j < curscr->maxx; j++) 613 __CTRACE(__CTRACE_REFRESH, "%c", 614 curscr->alines[i]->line[j].ch); 615 __CTRACE(__CTRACE_REFRESH, "\n"); 616 __CTRACE(__CTRACE_REFRESH, " attr:"); 617 for (j = 0; j < curscr->maxx; j++) 618 __CTRACE(__CTRACE_REFRESH, " %x", 619 curscr->alines[i]->line[j].attr); 620 __CTRACE(__CTRACE_REFRESH, "\n"); 621 __CTRACE(__CTRACE_REFRESH, "W: %d:", i); 622 __CTRACE(__CTRACE_REFRESH, " 0x%x \n", 623 win->alines[i]->hash); 624 __CTRACE(__CTRACE_REFRESH, " 0x%x ", 625 win->alines[i]->flags); 626 for (j = 0; j < win->maxx; j++) 627 __CTRACE(__CTRACE_REFRESH, "%c", 628 win->alines[i]->line[j].ch); 629 __CTRACE(__CTRACE_REFRESH, "\n"); 630 __CTRACE(__CTRACE_REFRESH, " attr:"); 631 for (j = 0; j < win->maxx; j++) 632 __CTRACE(__CTRACE_REFRESH, " %x", 633 win->alines[i]->line[j].attr); 634 __CTRACE(__CTRACE_REFRESH, "\n"); 635 #ifdef HAVE_WCHAR 636 __CTRACE(__CTRACE_REFRESH, " nsp:"); 637 for (j = 0; j < curscr->maxx; j++) 638 __CTRACE(__CTRACE_REFRESH, " %p", 639 win->alines[i]->line[j].nsp); 640 __CTRACE(__CTRACE_REFRESH, "\n"); 641 __CTRACE(__CTRACE_REFRESH, " bnsp:"); 642 for (j = 0; j < curscr->maxx; j++) 643 __CTRACE(__CTRACE_REFRESH, " %p", 644 win->bnsp); 645 __CTRACE(__CTRACE_REFRESH, "\n"); 646 #endif /* HAVE_WCHAR */ 647 } 648 } 649 #endif /* DEBUG */ 650 651 changed = 0; 652 for (wy = 0; wy < win->maxy; wy++) { 653 wlp = win->alines[wy]; 654 vlp = _cursesi_screen->__virtscr->alines[win->begy + wy]; 655 /* XXX: remove this debug */ 656 #ifdef DEBUG 657 __CTRACE(__CTRACE_REFRESH, 658 "doupdate: wy %d\tf: %d\tl:%d\tflags %x\n", 659 wy, *wlp->firstchp, *wlp->lastchp, wlp->flags); 660 #endif /* DEBUG */ 661 if (!_cursesi_screen->curwin) 662 curscr->alines[wy]->hash = wlp->hash; 663 if (wlp->flags & __ISDIRTY || wlp->flags & __ISFORCED) { 664 #ifdef DEBUG 665 __CTRACE(__CTRACE_REFRESH, 666 "doupdate: [ISDIRTY]wy:%d\tf:%d\tl:%d\n", wy, 667 *wlp->firstchp, *wlp->lastchp); 668 #endif /* DEBUG */ 669 /* 670 * We have just cleared so don't force an update 671 * otherwise we spray neeedless blanks to a cleared 672 * screen. 673 */ 674 if (was_cleared == 1) 675 win->alines[wy]->flags &= ~__ISFORCED; 676 677 if (makech(wy) == ERR) 678 return ERR; 679 else { 680 if (*wlp->firstchp >= 0) 681 *wlp->firstchp = win->maxx; 682 if (*wlp->lastchp < win->maxx) 683 *wlp->lastchp = win->ch_off; 684 if (*wlp->lastchp < *wlp->firstchp) { 685 #ifdef DEBUG 686 __CTRACE(__CTRACE_REFRESH, 687 "doupdate: line %d notdirty\n", wy); 688 #endif /* DEBUG */ 689 wlp->flags &= ~(__ISDIRTY | __ISFORCED); 690 } 691 692 /* Check if we have input after 693 * changing N lines. */ 694 if (_cursesi_screen->checkfd != -1 && 695 ++changed == CHECK_INTERVAL) 696 { 697 struct pollfd fds[1]; 698 699 /* If we have input, abort. */ 700 fds[0].fd = _cursesi_screen->checkfd; 701 fds[0].events = POLLIN; 702 if (poll(fds, 1, 0) > 0) 703 goto cleanup; 704 changed = 0; 705 } 706 } 707 } 708 709 /* 710 * virtscr is now synced for the line, unset the change 711 * pointers. 712 */ 713 if (*vlp->firstchp >= 0) 714 *vlp->firstchp = _cursesi_screen->__virtscr->maxx; 715 if (*vlp->lastchp <= _cursesi_screen->__virtscr->maxx) 716 *vlp->lastchp = 0; 717 718 #ifdef DEBUG 719 __CTRACE(__CTRACE_REFRESH, "\t%d\t%d\n", 720 *wlp->firstchp, *wlp->lastchp); 721 #endif /* DEBUG */ 722 } 723 724 #ifdef DEBUG 725 __CTRACE(__CTRACE_REFRESH, "doupdate: ly=%d, lx=%d\n", 726 _cursesi_screen->ly, _cursesi_screen->lx); 727 #endif /* DEBUG */ 728 729 if (_cursesi_screen->curwin) 730 domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx, 731 win->cury, win->curx); 732 else { 733 if (win->flags & __LEAVEOK) { 734 curscr->cury = _cursesi_screen->ly; 735 curscr->curx = _cursesi_screen->lx; 736 } else { 737 domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx, 738 win->cury, win->curx); 739 curscr->cury = win->cury; 740 curscr->curx = win->curx; 741 } 742 } 743 744 cleanup: 745 /* Don't leave the screen with attributes set. */ 746 __unsetattr(0); 747 #ifdef DEBUG 748 #ifdef HAVE_WCHAR 749 { 750 int i, j; 751 752 __CTRACE(__CTRACE_REFRESH, 753 "***********after*****************\n"); 754 __CTRACE(__CTRACE_REFRESH, 755 "stdscr(%p)-curscr(%p)-__virtscr(%p)\n", 756 stdscr, curscr, _cursesi_screen->__virtscr); 757 for (i = 0; i < curscr->maxy; i++) { 758 for (j = 0; j < curscr->maxx; j++) 759 __CTRACE(__CTRACE_REFRESH, 760 "[%d,%d](%x,%x,%p)-(%x,%x,%p)\n", 761 i, j, 762 curscr->alines[i]->line[j].ch, 763 curscr->alines[i]->line[j].attr, 764 curscr->alines[i]->line[j].nsp, 765 _cursesi_screen->__virtscr->alines[i]->line[j].ch, 766 _cursesi_screen->__virtscr->alines[i]->line[j].attr, 767 _cursesi_screen->__virtscr->alines[i]->line[j].nsp); 768 } 769 } 770 #endif /* HAVE_WCHAR */ 771 #endif /* DEBUG */ 772 return fflush(_cursesi_screen->outfd) == EOF ? ERR : OK; 773 } 774 775 /* 776 * makech -- 777 * Make a change on the screen. 778 */ 779 static int 780 makech(int wy) 781 { 782 WINDOW *win; 783 static __LDATA blank; 784 __LDATA *nsp, *csp, *cp, *cep; 785 __LINE *wlp; 786 size_t clsp, nlsp; /* Last space in lines. */ 787 int lch, wx; 788 const char *ce; 789 attr_t lspc; /* Last space colour */ 790 attr_t off, on; 791 792 #ifdef __GNUC__ 793 nlsp = lspc = 0; /* XXX gcc -Wuninitialized */ 794 #endif 795 if (_cursesi_screen->curwin) 796 win = curscr; 797 else 798 win = __virtscr; 799 #ifdef HAVE_WCHAR 800 blank.ch = (wchar_t)btowc((int) win->bch); 801 blank.attr = 0; 802 if (_cursesi_copy_nsp(win->bnsp, &blank) == ERR) 803 return ERR; 804 SET_WCOL(blank, 1); 805 #endif /* HAVE_WCHAR */ 806 #ifdef DEBUG 807 #if HAVE_WCHAR 808 { 809 int x; 810 __LDATA *lp, *vlp; 811 812 __CTRACE(__CTRACE_REFRESH, 813 "[makech-before]wy=%d,curscr(%p)-__virtscr(%p)\n", 814 wy, curscr, __virtscr); 815 for (x = 0; x < curscr->maxx; x++) { 816 lp = &curscr->alines[wy]->line[x]; 817 vlp = &__virtscr->alines[wy]->line[x]; 818 __CTRACE(__CTRACE_REFRESH, 819 "[%d,%d](%x,%x,%x,%x,%p)-" 820 "(%x,%x,%x,%x,%p)\n", 821 wy, x, lp->ch, lp->attr, 822 win->bch, win->battr, lp->nsp, 823 vlp->ch, vlp->attr, 824 win->bch, win->battr, vlp->nsp); 825 } 826 } 827 #endif /* HAVE_WCHAR */ 828 #endif /* DEBUG */ 829 /* Is the cursor still on the end of the last line? */ 830 if (wy > 0 && curscr->alines[wy - 1]->flags & __ISPASTEOL) { 831 domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx, 832 _cursesi_screen->ly + 1, 0); 833 _cursesi_screen->ly++; 834 _cursesi_screen->lx = 0; 835 } 836 wlp = win->alines[wy]; 837 wx = *win->alines[wy]->firstchp; 838 if (wx < 0) 839 wx = 0; 840 else 841 if (wx >= win->maxx) 842 return (OK); 843 lch = *win->alines[wy]->lastchp; 844 if (lch < 0) 845 return OK; 846 else 847 if (lch >= (int) win->maxx) 848 lch = win->maxx - 1; 849 850 if (_cursesi_screen->curwin) { 851 csp = ␣ 852 #ifdef DEBUG 853 __CTRACE(__CTRACE_REFRESH, "makech: csp is blank\n"); 854 #endif /* DEBUG */ 855 } else { 856 csp = &curscr->alines[wy]->line[wx]; 857 #ifdef DEBUG 858 __CTRACE(__CTRACE_REFRESH, 859 "makech: csp is on curscr:(%d,%d)\n", wy, wx); 860 #endif /* DEBUG */ 861 } 862 863 nsp = &win->alines[wy]->line[wx]; 864 #ifdef DEBUG 865 if (_cursesi_screen->curwin) 866 __CTRACE(__CTRACE_REFRESH, 867 "makech: nsp is at curscr:(%d,%d)\n", wy, wx); 868 else 869 __CTRACE(__CTRACE_REFRESH, 870 "makech: nsp is at __virtscr:(%d,%d)\n", wy, wx); 871 #endif /* DEBUG */ 872 if (clr_eol && !_cursesi_screen->curwin) { 873 cp = &win->alines[wy]->line[win->maxx - 1]; 874 lspc = cp->attr & __COLOR; 875 #ifndef HAVE_WCHAR 876 while (cp->ch == ' ' && cp->attr == lspc) /* XXX */ 877 if (cp-- <= win->alines[wy]->line) 878 break; 879 #else 880 while (cp->ch == ( wchar_t )btowc(( int )' ' ) 881 && ( cp->attr & WA_ATTRIBUTES ) == lspc) 882 if (cp-- <= win->alines[wy]->line) 883 break; 884 #endif /* HAVE_WCHAR */ 885 if (win->alines[wy]->line > cp) 886 nlsp = 0; 887 else 888 nlsp = cp - win->alines[wy]->line; 889 } 890 if (!_cursesi_screen->curwin) 891 ce = clr_eol; 892 else 893 ce = NULL; 894 895 while (wx <= lch) { 896 #ifdef DEBUG 897 __CTRACE(__CTRACE_REFRESH, "makech: wx=%d,lch=%d\n", wx, lch); 898 #endif /* DEBUG */ 899 #ifndef HAVE_WCHAR 900 if (!(wlp->flags & __ISFORCED) && 901 (memcmp(nsp, csp, sizeof(__LDATA)) == 0)) 902 { 903 if (wx <= lch) { 904 while (wx <= lch && 905 memcmp(nsp, csp, sizeof(__LDATA)) == 0) 906 { 907 nsp++; 908 if (!_cursesi_screen->curwin) 909 ++csp; 910 ++wx; 911 } 912 continue; 913 } 914 break; 915 } 916 #else 917 #ifdef DEBUG 918 __CTRACE(__CTRACE_REFRESH, "makech: nsp=(%x,%x,%x,%x,%p)\n", 919 nsp->ch, nsp->attr, win->bch, win->battr, nsp->nsp); 920 __CTRACE(__CTRACE_REFRESH, "makech: csp=(%x,%x,%x,%x,%p)\n", 921 csp->ch, csp->attr, win->bch, win->battr, csp->nsp); 922 #endif /* DEBUG */ 923 if (!(wlp->flags & __ISFORCED) && 924 (((nsp->attr & __WCWIDTH) != __WCWIDTH) && 925 cellcmp(nsp, csp))) 926 { 927 if (wx <= lch) { 928 while (wx <= lch && cellcmp( csp, nsp )) { 929 nsp++; 930 if (!_cursesi_screen->curwin) 931 ++csp; 932 ++wx; 933 } 934 continue; 935 } 936 break; 937 } 938 #endif /* HAVE_WCHAR */ 939 domvcur(win, _cursesi_screen->ly, _cursesi_screen->lx, wy, wx); 940 941 #ifdef DEBUG 942 __CTRACE(__CTRACE_REFRESH, "makech: 1: wx = %d, ly= %d, " 943 "lx = %d, newy = %d, newx = %d\n", 944 wx, _cursesi_screen->ly, _cursesi_screen->lx, wy, wx); 945 #endif 946 _cursesi_screen->ly = wy; 947 _cursesi_screen->lx = wx; 948 #ifndef HAVE_WCHAR 949 while (wx <= lch && (memcmp(nsp, csp, sizeof(__LDATA)) != 0) || 950 (wlp->flags & __ISFORCED)) 951 { 952 if (ce != NULL && 953 wx >= nlsp && nsp->ch == ' ' && nsp->attr == lspc) 954 { 955 #else 956 while ((!cellcmp(nsp, csp) || (wlp->flags & __ISFORCED)) && 957 wx <= lch) 958 { 959 if (ce != NULL && wx >= nlsp 960 && nsp->ch == (wchar_t)btowc((int)' ') /* XXX */ 961 && (nsp->attr & WA_ATTRIBUTES) == lspc) 962 { 963 964 #endif 965 /* Check for clear to end-of-line. */ 966 cep = &curscr->alines[wy]->line[win->maxx - 1]; 967 #ifndef HAVE_WCHAR 968 while (cep->ch == ' ' && cep->attr == lspc) /* XXX */ 969 #else 970 while (cep->ch == (wchar_t)btowc((int)' ') 971 && (cep->attr & WA_ATTRIBUTES) == lspc) 972 #endif /* HAVE_WCHAR */ 973 if (cep-- <= csp) 974 break; 975 if (cep > (curscr->alines[wy]->line + win->begx * __LDATASIZE)) 976 clsp = cep - curscr->alines[wy]->line - 977 win->begx * __LDATASIZE; 978 else 979 clsp = 0; 980 #ifdef DEBUG 981 __CTRACE(__CTRACE_REFRESH, 982 "makech: clsp = %zu, nlsp = %zu\n", 983 clsp, nlsp); 984 __CTRACE(__CTRACE_REFRESH, 985 "makech: line = %p, cep = %p, begx = %u\n", 986 curscr->alines[wy]->line, cep, win->begx); 987 #endif 988 if (((clsp - nlsp >= strlen(ce) && 989 clsp < win->maxx * __LDATASIZE) || 990 wy == win->maxy - 1) && 991 (!(lspc & __COLOR) || 992 ((lspc & __COLOR) && back_color_erase))) 993 { 994 __unsetattr(0); 995 if (__using_color && 996 ((lspc & __COLOR) != 997 (curscr->wattr & __COLOR))) 998 __set_color(curscr, lspc & 999 __COLOR); 1000 tputs(ce, 0, __cputchar); 1001 _cursesi_screen->lx = wx + win->begx; 1002 while (wx++ <= clsp) { 1003 csp->attr = lspc; 1004 #ifndef HAVE_WCHAR 1005 csp->ch = ' '; /* XXX */ 1006 #else 1007 csp->ch = (wchar_t)btowc((int)' '); 1008 SET_WCOL( *csp, 1 ); 1009 #endif /* HAVE_WCHAR */ 1010 csp++; 1011 } 1012 return OK; 1013 } 1014 ce = NULL; 1015 } 1016 1017 #ifdef DEBUG 1018 __CTRACE(__CTRACE_REFRESH, 1019 "makech: have attr %08x, need attr %08x\n", 1020 curscr->wattr 1021 #ifndef HAVE_WCHAR 1022 & __ATTRIBUTES 1023 #else 1024 & WA_ATTRIBUTES 1025 #endif 1026 , nsp->attr 1027 #ifndef HAVE_WCHAR 1028 & __ATTRIBUTES 1029 #else 1030 & WA_ATTRIBUTES 1031 #endif 1032 ); 1033 #endif 1034 1035 off = (~nsp->attr & curscr->wattr) 1036 #ifndef HAVE_WCHAR 1037 & __ATTRIBUTES 1038 #else 1039 & WA_ATTRIBUTES 1040 #endif 1041 ; 1042 1043 /* 1044 * Unset attributes as appropriate. Unset first 1045 * so that the relevant attributes can be reset 1046 * (because 'me' unsets 'mb', 'md', 'mh', 'mk', 1047 * 'mp' and 'mr'). Check to see if we also turn off 1048 * standout, attributes and colour. 1049 */ 1050 if (off & __TERMATTR && exit_attribute_mode != NULL) { 1051 tputs(exit_attribute_mode, 0, __cputchar); 1052 curscr->wattr &= __mask_me; 1053 off &= __mask_me; 1054 } 1055 1056 /* 1057 * Exit underscore mode if appropriate. 1058 * Check to see if we also turn off standout, 1059 * attributes and colour. 1060 */ 1061 if (off & __UNDERSCORE && exit_underline_mode != NULL) { 1062 tputs(exit_underline_mode, 0, __cputchar); 1063 curscr->wattr &= __mask_ue; 1064 off &= __mask_ue; 1065 } 1066 1067 /* 1068 * Exit standout mode as appropriate. 1069 * Check to see if we also turn off underscore, 1070 * attributes and colour. 1071 * XXX 1072 * Should use uc if so/se not available. 1073 */ 1074 if (off & __STANDOUT && exit_standout_mode != NULL) { 1075 tputs(exit_standout_mode, 0, __cputchar); 1076 curscr->wattr &= __mask_se; 1077 off &= __mask_se; 1078 } 1079 1080 if (off & __ALTCHARSET && exit_alt_charset_mode != NULL) { 1081 tputs(exit_alt_charset_mode, 0, __cputchar); 1082 curscr->wattr &= ~__ALTCHARSET; 1083 } 1084 1085 /* Set/change colour as appropriate. */ 1086 if (__using_color) 1087 __set_color(curscr, nsp->attr & __COLOR); 1088 1089 on = (nsp->attr & ~curscr->wattr) 1090 #ifndef HAVE_WCHAR 1091 & __ATTRIBUTES 1092 #else 1093 & WA_ATTRIBUTES 1094 #endif 1095 ; 1096 1097 /* 1098 * Enter standout mode if appropriate. 1099 */ 1100 if (on & __STANDOUT && 1101 enter_standout_mode != NULL && 1102 exit_standout_mode != NULL) 1103 { 1104 tputs(enter_standout_mode, 0, __cputchar); 1105 curscr->wattr |= __STANDOUT; 1106 } 1107 1108 /* 1109 * Enter underscore mode if appropriate. 1110 * XXX 1111 * Should use uc if us/ue not available. 1112 */ 1113 if (on & __UNDERSCORE && 1114 enter_underline_mode != NULL && 1115 exit_underline_mode != NULL) 1116 { 1117 tputs(enter_underline_mode, 0, __cputchar); 1118 curscr->wattr |= __UNDERSCORE; 1119 } 1120 1121 /* 1122 * Set other attributes as appropriate. 1123 */ 1124 if (exit_attribute_mode != NULL) { 1125 if (on & __BLINK && 1126 enter_blink_mode != NULL) 1127 { 1128 tputs(enter_blink_mode, 0, __cputchar); 1129 curscr->wattr |= __BLINK; 1130 } 1131 if (on & __BOLD && 1132 enter_bold_mode != NULL) 1133 { 1134 tputs(enter_bold_mode, 0, __cputchar); 1135 curscr->wattr |= __BOLD; 1136 } 1137 if (on & __DIM && 1138 enter_dim_mode != NULL) 1139 { 1140 tputs(enter_dim_mode, 0, __cputchar); 1141 curscr->wattr |= __DIM; 1142 } 1143 if (on & __BLANK && 1144 enter_secure_mode != NULL) 1145 { 1146 tputs(enter_secure_mode, 0, __cputchar); 1147 curscr->wattr |= __BLANK; 1148 } 1149 if (on & __PROTECT && 1150 enter_protected_mode != NULL) 1151 { 1152 tputs(enter_protected_mode, 0, __cputchar); 1153 curscr->wattr |= __PROTECT; 1154 } 1155 if (on & __REVERSE && 1156 enter_reverse_mode != NULL) 1157 { 1158 tputs(enter_reverse_mode, 0, __cputchar); 1159 curscr->wattr |= __REVERSE; 1160 } 1161 #ifdef HAVE_WCHAR 1162 if (on & WA_TOP && 1163 enter_top_hl_mode != NULL) 1164 { 1165 tputs(enter_top_hl_mode, 0, __cputchar); 1166 curscr->wattr |= WA_TOP; 1167 } 1168 if (on & WA_LOW && 1169 enter_low_hl_mode != NULL) 1170 { 1171 tputs(enter_low_hl_mode, 0, __cputchar); 1172 curscr->wattr |= WA_LOW; 1173 } 1174 if (on & WA_LEFT && 1175 enter_left_hl_mode != NULL) 1176 { 1177 tputs(enter_left_hl_mode, 0, __cputchar); 1178 curscr->wattr |= WA_LEFT; 1179 } 1180 if (on & WA_RIGHT && 1181 enter_right_hl_mode != NULL) 1182 { 1183 tputs(enter_right_hl_mode, 0, __cputchar); 1184 curscr->wattr |= WA_RIGHT; 1185 } 1186 if (on & WA_HORIZONTAL && 1187 enter_horizontal_hl_mode != NULL) 1188 { 1189 tputs(enter_horizontal_hl_mode, 0, __cputchar); 1190 curscr->wattr |= WA_HORIZONTAL; 1191 } 1192 if (on & WA_VERTICAL && 1193 enter_vertical_hl_mode != NULL) 1194 { 1195 tputs(enter_vertical_hl_mode, 0, __cputchar); 1196 curscr->wattr |= WA_VERTICAL; 1197 } 1198 #endif /* HAVE_WCHAR */ 1199 } 1200 1201 /* Enter/exit altcharset mode as appropriate. */ 1202 if (on & __ALTCHARSET && enter_alt_charset_mode != NULL && 1203 exit_alt_charset_mode != NULL) { 1204 tputs(enter_alt_charset_mode, 0, __cputchar); 1205 curscr->wattr |= __ALTCHARSET; 1206 } 1207 1208 wx++; 1209 if (wx >= win->maxx && 1210 wy == win->maxy - 1 && !_cursesi_screen->curwin) { 1211 if (win->flags & __SCROLLOK) { 1212 if (win->flags & __ENDLINE) 1213 __unsetattr(1); 1214 if (!(win->flags & __SCROLLWIN)) { 1215 if (!_cursesi_screen->curwin) { 1216 csp->attr = nsp->attr; 1217 csp->ch = nsp->ch; 1218 #ifdef HAVE_WCHAR 1219 if (_cursesi_copy_nsp(nsp->nsp, csp) == ERR) 1220 return ERR; 1221 #endif /* HAVE_WCHAR */ 1222 } 1223 #ifndef HAVE_WCHAR 1224 __cputchar((int) nsp->ch); 1225 #else 1226 if ( WCOL( *nsp ) > 0 ) { 1227 __cputwchar((int)nsp->ch); 1228 #ifdef DEBUG 1229 __CTRACE(__CTRACE_REFRESH, 1230 "makech: (%d,%d)putwchar(0x%x)\n", 1231 wy, wx - 1, 1232 nsp->ch ); 1233 #endif /* DEBUG */ 1234 /* 1235 * Output non-spacing 1236 * characters for the 1237 * cell. 1238 */ 1239 __cursesi_putnsp(nsp->nsp, 1240 wy, wx); 1241 1242 } 1243 #endif /* HAVE_WCHAR */ 1244 } 1245 if (wx < curscr->maxx) { 1246 domvcur(win, 1247 _cursesi_screen->ly, wx, 1248 (int)(win->maxy - 1), 1249 (int)(win->maxx - 1)); 1250 } 1251 _cursesi_screen->ly = win->maxy - 1; 1252 _cursesi_screen->lx = win->maxx - 1; 1253 return (OK); 1254 } 1255 } 1256 if (wx < win->maxx || wy < win->maxy - 1 || 1257 !(win->flags & __SCROLLWIN)) 1258 { 1259 if (!_cursesi_screen->curwin) { 1260 csp->attr = nsp->attr; 1261 csp->ch = nsp->ch; 1262 #ifdef HAVE_WCHAR 1263 if (_cursesi_copy_nsp(nsp->nsp, 1264 csp) == ERR) 1265 return ERR; 1266 #endif /* HAVE_WCHAR */ 1267 csp++; 1268 } 1269 #ifndef HAVE_WCHAR 1270 __cputchar((int)nsp->ch); 1271 #ifdef DEBUG 1272 __CTRACE(__CTRACE_REFRESH, 1273 "makech: putchar(%c)\n", nsp->ch & 0177); 1274 #endif 1275 #else 1276 if (WCOL(*nsp) > 0) { 1277 __cputwchar((int)nsp->ch); 1278 #ifdef DEBUG 1279 __CTRACE(__CTRACE_REFRESH, 1280 "makech:(%d,%d) putwchar(%x)\n", 1281 wy, wx - 1, nsp->ch); 1282 __cursesi_putnsp(nsp->nsp, wy, wx); 1283 #endif /* DEBUG */ 1284 } 1285 #endif /* HAVE_WCHAR */ 1286 } 1287 if (underline_char && ((nsp->attr & __STANDOUT) || 1288 (nsp->attr & __UNDERSCORE))) { 1289 __cputchar('\b'); 1290 tputs(underline_char, 0, __cputchar); 1291 } 1292 nsp++; 1293 #ifdef DEBUG 1294 __CTRACE(__CTRACE_REFRESH, 1295 "makech: 2: wx = %d, lx = %d\n", 1296 wx, _cursesi_screen->lx); 1297 #endif 1298 } 1299 if (_cursesi_screen->lx == wx) /* If no change. */ 1300 break; 1301 _cursesi_screen->lx = wx; 1302 if (_cursesi_screen->lx >= COLS && auto_right_margin) 1303 _cursesi_screen->lx = COLS - 1; 1304 else 1305 if (wx >= win->maxx) { 1306 domvcur(win, 1307 _cursesi_screen->ly, 1308 _cursesi_screen->lx, 1309 _cursesi_screen->ly, 1310 (int)(win->maxx - 1)); 1311 _cursesi_screen->lx = win->maxx - 1; 1312 } 1313 #ifdef DEBUG 1314 __CTRACE(__CTRACE_REFRESH, "makech: 3: wx = %d, lx = %d\n", 1315 wx, _cursesi_screen->lx); 1316 #endif 1317 } 1318 #ifdef DEBUG 1319 #if HAVE_WCHAR 1320 { 1321 int x; 1322 __LDATA *lp, *vlp; 1323 1324 __CTRACE(__CTRACE_REFRESH, 1325 "makech-after: curscr(%p)-__virtscr(%p)\n", 1326 curscr, __virtscr ); 1327 for (x = 0; x < curscr->maxx; x++) { 1328 lp = &curscr->alines[wy]->line[x]; 1329 vlp = &__virtscr->alines[wy]->line[x]; 1330 __CTRACE(__CTRACE_REFRESH, 1331 "[%d,%d](%x,%x,%x,%x,%p)-" 1332 "(%x,%x,%x,%x,%p)\n", 1333 wy, x, lp->ch, lp->attr, 1334 win->bch, win->battr, lp->nsp, 1335 vlp->ch, vlp->attr, 1336 win->bch, win->battr, vlp->nsp); 1337 } 1338 } 1339 #endif /* HAVE_WCHAR */ 1340 #endif /* DEBUG */ 1341 1342 return OK; 1343 } 1344 1345 /* 1346 * domvcur -- 1347 * Do a mvcur, leaving attributes if necessary. 1348 */ 1349 static void 1350 domvcur(const WINDOW *win, int oy, int ox, int ny, int nx) 1351 { 1352 1353 #ifdef DEBUG 1354 __CTRACE(__CTRACE_REFRESH, "domvcur: (%x,%d)=>(%d,%d)\n", 1355 oy, ox, ny, nx ); 1356 #endif /* DEBUG */ 1357 1358 __unsetattr(1); 1359 1360 /* Don't move the cursor unless we need to. */ 1361 if (oy == ny && ox == nx) { 1362 /* Check EOL. */ 1363 if (!(win->alines[oy]->flags & __ISPASTEOL)) 1364 return; 1365 } 1366 1367 /* Clear EOL flags. */ 1368 win->alines[oy]->flags &= ~__ISPASTEOL; 1369 win->alines[ny]->flags &= ~__ISPASTEOL; 1370 1371 __mvcur(oy, ox, ny, nx, 1); 1372 } 1373 1374 /* 1375 * Quickch() attempts to detect a pattern in the change of the window 1376 * in order to optimize the change, e.g., scroll n lines as opposed to 1377 * repainting the screen line by line. 1378 */ 1379 1380 static __LDATA buf[128]; 1381 static unsigned int last_hash; 1382 static size_t last_hash_len; 1383 #define BLANKSIZE (sizeof(buf) / sizeof(buf[0])) 1384 1385 static void 1386 quickch(void) 1387 { 1388 #define THRESH (int) __virtscr->maxy / 4 1389 1390 __LINE *clp, *tmp1, *tmp2; 1391 int bsize, curs, curw, starts, startw, i, j; 1392 int n, target, cur_period, bot, top, sc_region; 1393 unsigned int blank_hash; 1394 attr_t bcolor; 1395 1396 #ifdef __GNUC__ 1397 curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */ 1398 #endif 1399 /* 1400 * Find how many lines from the top of the screen are unchanged. 1401 */ 1402 for (top = 0; top < __virtscr->maxy; top++) { 1403 #ifndef HAVE_WCHAR 1404 if (__virtscr->alines[top]->flags & __ISDIRTY && 1405 (__virtscr->alines[top]->hash != curscr->alines[top]->hash || 1406 memcmp(__virtscr->alines[top]->line, 1407 curscr->alines[top]->line, 1408 (size_t) __virtscr->maxx * __LDATASIZE) 1409 != 0)) 1410 break; 1411 #else 1412 if (__virtscr->alines[top]->flags & __ISDIRTY && 1413 (__virtscr->alines[top]->hash != curscr->alines[top]->hash || 1414 !linecmp(__virtscr->alines[top]->line, 1415 curscr->alines[top]->line, 1416 (size_t) __virtscr->maxx ))) 1417 break; 1418 #endif /* HAVE_WCHAR */ 1419 else 1420 __virtscr->alines[top]->flags &= ~__ISDIRTY; 1421 } 1422 /* 1423 * Find how many lines from bottom of screen are unchanged. 1424 */ 1425 for (bot = __virtscr->maxy - 1; bot >= 0; bot--) { 1426 #ifndef HAVE_WCHAR 1427 if (__virtscr->alines[bot]->flags & __ISDIRTY && 1428 (__virtscr->alines[bot]->hash != curscr->alines[bot]->hash || 1429 memcmp(__virtscr->alines[bot]->line, 1430 curscr->alines[bot]->line, 1431 (size_t) __virtscr->maxx * __LDATASIZE) 1432 != 0)) 1433 break; 1434 #else 1435 if (__virtscr->alines[bot]->flags & __ISDIRTY && 1436 (__virtscr->alines[bot]->hash != curscr->alines[bot]->hash || 1437 !linecmp(__virtscr->alines[bot]->line, 1438 curscr->alines[bot]->line, 1439 (size_t) __virtscr->maxx ))) 1440 break; 1441 #endif /* HAVE_WCHAR */ 1442 else 1443 __virtscr->alines[bot]->flags &= ~__ISDIRTY; 1444 } 1445 1446 /* 1447 * Work round an xterm bug where inserting lines causes all the 1448 * inserted lines to be covered with the background colour we 1449 * set on the first line (even if we unset it for subsequent 1450 * lines). 1451 */ 1452 bcolor = __virtscr->alines[min(top, 1453 __virtscr->maxy - 1)]->line[0].attr & __COLOR; 1454 for (i = top + 1, j = 0; i < bot; i++) { 1455 if ((__virtscr->alines[i]->line[0].attr & __COLOR) != bcolor) { 1456 bcolor = __virtscr->alines[i]->line[__virtscr->maxx]. 1457 attr & __COLOR; 1458 j = i - top; 1459 } else 1460 break; 1461 } 1462 top += j; 1463 1464 #ifdef NO_JERKINESS 1465 /* 1466 * If we have a bottom unchanged region return. Scrolling the 1467 * bottom region up and then back down causes a screen jitter. 1468 * This will increase the number of characters sent to the screen 1469 * but it looks better. 1470 */ 1471 if (bot < __virtscr->maxy - 1) 1472 return; 1473 #endif /* NO_JERKINESS */ 1474 1475 /* 1476 * Search for the largest block of text not changed. 1477 * Invariants of the loop: 1478 * - Startw is the index of the beginning of the examined block in 1479 * __virtscr. 1480 * - Starts is the index of the beginning of the examined block in 1481 * curscr. 1482 * - Curw is the index of one past the end of the exmined block in 1483 * __virtscr. 1484 * - Curs is the index of one past the end of the exmined block in 1485 * curscr. 1486 * - bsize is the current size of the examined block. 1487 */ 1488 1489 for (bsize = bot - top; bsize >= THRESH; bsize--) { 1490 for (startw = top; startw <= bot - bsize; startw++) 1491 for (starts = top; starts <= bot - bsize; starts++) { 1492 for (curw = startw, curs = starts; 1493 curs < starts + bsize; curw++, curs++) 1494 if (__virtscr->alines[curw]->hash != 1495 curscr->alines[curs]->hash) 1496 break; 1497 if (curs != starts + bsize) 1498 continue; 1499 for (curw = startw, curs = starts; 1500 curs < starts + bsize; curw++, curs++) 1501 #ifndef HAVE_WCHAR 1502 if (memcmp(__virtscr->alines[curw]->line, 1503 curscr->alines[curs]->line, 1504 (size_t) __virtscr->maxx * 1505 __LDATASIZE) != 0) 1506 break; 1507 #else 1508 if (!linecmp(__virtscr->alines[curw]->line, 1509 curscr->alines[curs]->line, 1510 (size_t) __virtscr->maxx)) 1511 break; 1512 #endif /* HAVE_WCHAR */ 1513 if (curs == starts + bsize) 1514 goto done; 1515 } 1516 } 1517 done: 1518 1519 /* Did not find anything */ 1520 if (bsize < THRESH) 1521 return; 1522 1523 #ifdef DEBUG 1524 __CTRACE(__CTRACE_REFRESH, "quickch:bsize=%d, starts=%d, startw=%d, " 1525 "curw=%d, curs=%d, top=%d, bot=%d\n", 1526 bsize, starts, startw, curw, curs, top, bot); 1527 #endif 1528 1529 /* 1530 * Make sure that there is no overlap between the bottom and top 1531 * regions and the middle scrolled block. 1532 */ 1533 if (bot < curs) 1534 bot = curs - 1; 1535 if (top > starts) 1536 top = starts; 1537 1538 n = startw - starts; 1539 1540 #ifdef DEBUG 1541 __CTRACE(__CTRACE_REFRESH, "#####################################\n"); 1542 for (i = 0; i < curscr->maxy; i++) { 1543 __CTRACE(__CTRACE_REFRESH, "C: %d:", i); 1544 __CTRACE(__CTRACE_REFRESH, " 0x%x \n", curscr->alines[i]->hash); 1545 for (j = 0; j < curscr->maxx; j++) 1546 __CTRACE(__CTRACE_REFRESH, "%c", 1547 curscr->alines[i]->line[j].ch); 1548 __CTRACE(__CTRACE_REFRESH, "\n"); 1549 __CTRACE(__CTRACE_REFRESH, " attr:"); 1550 for (j = 0; j < curscr->maxx; j++) 1551 __CTRACE(__CTRACE_REFRESH, " %x", 1552 curscr->alines[i]->line[j].attr); 1553 __CTRACE(__CTRACE_REFRESH, "\n"); 1554 __CTRACE(__CTRACE_REFRESH, "W: %d:", i); 1555 __CTRACE(__CTRACE_REFRESH, " 0x%x \n", 1556 __virtscr->alines[i]->hash); 1557 __CTRACE(__CTRACE_REFRESH, " 0x%x ", 1558 __virtscr->alines[i]->flags); 1559 for (j = 0; j < __virtscr->maxx; j++) 1560 __CTRACE(__CTRACE_REFRESH, "%c", 1561 __virtscr->alines[i]->line[j].ch); 1562 __CTRACE(__CTRACE_REFRESH, "\n"); 1563 __CTRACE(__CTRACE_REFRESH, " attr:"); 1564 for (j = 0; j < __virtscr->maxx; j++) 1565 __CTRACE(__CTRACE_REFRESH, " %x", 1566 __virtscr->alines[i]->line[j].attr); 1567 __CTRACE(__CTRACE_REFRESH, "\n"); 1568 } 1569 #endif 1570 1571 #ifndef HAVE_WCHAR 1572 if (buf[0].ch != ' ') { 1573 for (i = 0; i < BLANKSIZE; i++) { 1574 buf[i].ch = ' '; 1575 buf[i].attr = 0; 1576 } 1577 } 1578 #else 1579 if (buf[0].ch != (wchar_t)btowc((int)curscr->bch )) { 1580 for (i = 0; i < BLANKSIZE; i++) { 1581 buf[i].ch = (wchar_t)btowc((int)curscr->bch); 1582 if (_cursesi_copy_nsp(curscr->bnsp, &buf[i]) == ERR) 1583 return; 1584 buf[i].attr = 0; 1585 SET_WCOL(buf[i], 1); 1586 } 1587 } 1588 #endif /* HAVE_WCHAR */ 1589 1590 if (__virtscr->maxx != last_hash_len) { 1591 blank_hash = 0; 1592 for (i = __virtscr->maxx; i > BLANKSIZE; i -= BLANKSIZE) { 1593 blank_hash = __hash_more(buf, sizeof(buf), blank_hash); 1594 } 1595 blank_hash = __hash_more((char *)(void *)buf, 1596 i * sizeof(buf[0]), blank_hash); 1597 /* cache result in static data - screen width doesn't change often */ 1598 last_hash_len = __virtscr->maxx; 1599 last_hash = blank_hash; 1600 } else 1601 blank_hash = last_hash; 1602 1603 /* 1604 * Perform the rotation to maintain the consistency of curscr. 1605 * This is hairy since we are doing an *in place* rotation. 1606 * Invariants of the loop: 1607 * - I is the index of the current line. 1608 * - Target is the index of the target of line i. 1609 * - Tmp1 points to current line (i). 1610 * - Tmp2 and points to target line (target); 1611 * - Cur_period is the index of the end of the current period. 1612 * (see below). 1613 * 1614 * There are 2 major issues here that make this rotation non-trivial: 1615 * 1. Scrolling in a scrolling region bounded by the top 1616 * and bottom regions determined (whose size is sc_region). 1617 * 2. As a result of the use of the mod function, there may be a 1618 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 1619 * 0 to 2, which then causes all odd lines not to be rotated. 1620 * To remedy this, an index of the end ( = beginning) of the 1621 * current 'period' is kept, cur_period, and when it is reached, 1622 * the next period is started from cur_period + 1 which is 1623 * guaranteed not to have been reached since that would mean that 1624 * all records would have been reached. (think about it...). 1625 * 1626 * Lines in the rotation can have 3 attributes which are marked on the 1627 * line so that curscr is consistent with the visual screen. 1628 * 1. Not dirty -- lines inside the scrolled block, top region or 1629 * bottom region. 1630 * 2. Blank lines -- lines in the differential of the scrolling 1631 * region adjacent to top and bot regions 1632 * depending on scrolling direction. 1633 * 3. Dirty line -- all other lines are marked dirty. 1634 */ 1635 sc_region = bot - top + 1; 1636 i = top; 1637 tmp1 = curscr->alines[top]; 1638 cur_period = top; 1639 for (j = top; j <= bot; j++) { 1640 target = (i - top + n + sc_region) % sc_region + top; 1641 tmp2 = curscr->alines[target]; 1642 curscr->alines[target] = tmp1; 1643 /* Mark block as clean and blank out scrolled lines. */ 1644 clp = curscr->alines[target]; 1645 #ifdef DEBUG 1646 __CTRACE(__CTRACE_REFRESH, 1647 "quickch: n=%d startw=%d curw=%d i = %d target=%d ", 1648 n, startw, curw, i, target); 1649 #endif 1650 if ((target >= startw && target < curw) || target < top 1651 || target > bot) 1652 { 1653 #ifdef DEBUG 1654 __CTRACE(__CTRACE_REFRESH, " notdirty\n"); 1655 #endif 1656 __virtscr->alines[target]->flags &= ~__ISDIRTY; 1657 } else 1658 if ((n > 0 && target >= top && target < top + n) || 1659 (n < 0 && target <= bot && target > bot + n)) 1660 { 1661 #ifndef HAVE_WCHAR 1662 if (clp->hash != blank_hash || 1663 memcmp(clp->line, clp->line + 1, 1664 (__virtscr->maxx - 1) 1665 * __LDATASIZE) || 1666 memcmp(clp->line, buf, __LDATASIZE)) 1667 { 1668 #else 1669 if (clp->hash != blank_hash 1670 || linecmp(clp->line, clp->line + 1, 1671 (unsigned int) (__virtscr->maxx - 1)) 1672 || cellcmp(clp->line, buf)) 1673 { 1674 #endif /* HAVE_WCHAR */ 1675 for (i = __virtscr->maxx; 1676 i > BLANKSIZE; 1677 i -= BLANKSIZE) { 1678 (void) memcpy(clp->line + i - 1679 BLANKSIZE, buf, sizeof(buf)); 1680 } 1681 (void) memcpy(clp->line , buf, i * 1682 sizeof(buf[0])); 1683 #ifdef DEBUG 1684 __CTRACE(__CTRACE_REFRESH, 1685 " blanked out: dirty\n"); 1686 #endif 1687 clp->hash = blank_hash; 1688 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 1689 } else { 1690 #ifdef DEBUG 1691 __CTRACE(__CTRACE_REFRESH, 1692 " -- blank line already: dirty\n"); 1693 #endif 1694 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 1695 } 1696 } else { 1697 #ifdef DEBUG 1698 __CTRACE(__CTRACE_REFRESH, " -- dirty\n"); 1699 #endif 1700 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 1701 } 1702 if (target == cur_period) { 1703 i = target + 1; 1704 tmp1 = curscr->alines[i]; 1705 cur_period = i; 1706 } else { 1707 tmp1 = tmp2; 1708 i = target; 1709 } 1710 } 1711 #ifdef DEBUG 1712 __CTRACE(__CTRACE_REFRESH, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 1713 for (i = 0; i < curscr->maxy; i++) { 1714 __CTRACE(__CTRACE_REFRESH, "C: %d:", i); 1715 for (j = 0; j < curscr->maxx; j++) 1716 __CTRACE(__CTRACE_REFRESH, "%c", 1717 curscr->alines[i]->line[j].ch); 1718 __CTRACE(__CTRACE_REFRESH, "\n"); 1719 __CTRACE(__CTRACE_REFRESH, "W: %d:", i); 1720 for (j = 0; j < __virtscr->maxx; j++) 1721 __CTRACE(__CTRACE_REFRESH, "%c", 1722 __virtscr->alines[i]->line[j].ch); 1723 __CTRACE(__CTRACE_REFRESH, "\n"); 1724 } 1725 #endif 1726 if (n != 0) 1727 scrolln(starts, startw, curs, bot, top); 1728 } 1729 1730 /* 1731 * scrolln -- 1732 * Scroll n lines, where n is starts - startw. 1733 */ 1734 static void /* ARGSUSED */ 1735 scrolln(int starts, int startw, int curs, int bot, int top) 1736 { 1737 int i, oy, ox, n; 1738 1739 oy = curscr->cury; 1740 ox = curscr->curx; 1741 n = starts - startw; 1742 1743 /* 1744 * XXX 1745 * The initial tests that set __noqch don't let us reach here unless 1746 * we have either cs + ho + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 1747 * scrolling can only shift the entire scrolling region, not just a 1748 * part of it, which means that the quickch() routine is going to be 1749 * sadly disappointed in us if we don't have cs as well. 1750 * 1751 * If cs, ho and SF/sf are set, can use the scrolling region. Because 1752 * the cursor position after cs is undefined, we need ho which gives us 1753 * the ability to move to somewhere without knowledge of the current 1754 * location of the cursor. Still call __mvcur() anyway, to update its 1755 * idea of where the cursor is. 1756 * 1757 * When the scrolling region has been set, the cursor has to be at the 1758 * last line of the region to make the scroll happen. 1759 * 1760 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 1761 * or AL/DL, and, some terminals have AL/DL, sf/sr, and cs, but not 1762 * SF/SR. So, if we're scrolling almost all of the screen, try and use 1763 * AL/DL, otherwise use the scrolling region. The "almost all" is a 1764 * shameless hack for vi. 1765 */ 1766 if (n > 0) { 1767 if (change_scroll_region != NULL && cursor_home != NULL && 1768 (parm_index != NULL || 1769 ((parm_insert_line == NULL || parm_delete_line == NULL || 1770 top > 3 || bot + 3 < __virtscr->maxy) && 1771 scroll_forward != NULL))) 1772 { 1773 tputs(tiparm(change_scroll_region, top, bot), 1774 0, __cputchar); 1775 __mvcur(oy, ox, 0, 0, 1); 1776 tputs(cursor_home, 0, __cputchar); 1777 __mvcur(0, 0, bot, 0, 1); 1778 if (parm_index != NULL) 1779 tputs(tiparm(parm_index, n), 1780 0, __cputchar); 1781 else 1782 for (i = 0; i < n; i++) 1783 tputs(scroll_forward, 0, __cputchar); 1784 tputs(tiparm(change_scroll_region, 1785 0, (int)__virtscr->maxy - 1), 0, __cputchar); 1786 __mvcur(bot, 0, 0, 0, 1); 1787 tputs(cursor_home, 0, __cputchar); 1788 __mvcur(0, 0, oy, ox, 1); 1789 return; 1790 } 1791 1792 /* Scroll up the block. */ 1793 if (parm_index != NULL && top == 0) { 1794 __mvcur(oy, ox, bot, 0, 1); 1795 tputs(tiparm(parm_index, n), 0, __cputchar); 1796 } else 1797 if (parm_delete_line != NULL) { 1798 __mvcur(oy, ox, top, 0, 1); 1799 tputs(tiparm(parm_delete_line, n), 1800 0, __cputchar); 1801 } else 1802 if (delete_line != NULL) { 1803 __mvcur(oy, ox, top, 0, 1); 1804 for (i = 0; i < n; i++) 1805 tputs(delete_line, 0, 1806 __cputchar); 1807 } else 1808 if (scroll_forward != NULL && top == 0) { 1809 __mvcur(oy, ox, bot, 0, 1); 1810 for (i = 0; i < n; i++) 1811 tputs(scroll_forward, 0, 1812 __cputchar); 1813 } else 1814 abort(); 1815 1816 /* Push down the bottom region. */ 1817 __mvcur(top, 0, bot - n + 1, 0, 1); 1818 if (parm_insert_line != NULL) 1819 tputs(tiparm(parm_insert_line, n), 0, __cputchar); 1820 else { 1821 if (insert_line != NULL) { 1822 for (i = 0; i < n; i++) 1823 tputs(insert_line, 0, __cputchar); 1824 } else 1825 abort(); 1826 } 1827 __mvcur(bot - n + 1, 0, oy, ox, 1); 1828 } else { 1829 /* 1830 * !!! 1831 * n < 0 1832 * 1833 * If cs, ho and SR/sr are set, can use the scrolling region. 1834 * See the above comments for details. 1835 */ 1836 if (change_scroll_region != NULL && cursor_home != NULL && 1837 (parm_rindex != NULL || 1838 ((parm_insert_line == NULL || parm_delete_line == NULL || 1839 top > 3 || 1840 bot + 3 < __virtscr->maxy) && scroll_reverse != NULL))) 1841 { 1842 tputs(tiparm(change_scroll_region, top, bot), 1843 0, __cputchar); 1844 __mvcur(oy, ox, 0, 0, 1); 1845 tputs(cursor_home, 0, __cputchar); 1846 __mvcur(0, 0, top, 0, 1); 1847 1848 if (parm_rindex != NULL) 1849 tputs(tiparm(parm_rindex, -n), 1850 0, __cputchar); 1851 else 1852 for (i = n; i < 0; i++) 1853 tputs(scroll_reverse, 0, __cputchar); 1854 tputs(tiparm(change_scroll_region, 1855 0, (int) __virtscr->maxy - 1), 0, __cputchar); 1856 __mvcur(top, 0, 0, 0, 1); 1857 tputs(cursor_home, 0, __cputchar); 1858 __mvcur(0, 0, oy, ox, 1); 1859 return; 1860 } 1861 1862 /* Preserve the bottom lines. */ 1863 __mvcur(oy, ox, bot + n + 1, 0, 1); 1864 if (parm_rindex != NULL && bot == __virtscr->maxy) 1865 tputs(tiparm(parm_rindex, -n), 0, __cputchar); 1866 else { 1867 if (parm_delete_line != NULL) 1868 tputs(tiparm(parm_delete_line, -n), 1869 0, __cputchar); 1870 else { 1871 if (delete_line != NULL) 1872 for (i = n; i < 0; i++) 1873 tputs(delete_line, 1874 0, __cputchar); 1875 else { 1876 if (scroll_reverse != NULL && 1877 bot == __virtscr->maxy) 1878 for (i = n; i < 0; i++) 1879 tputs(scroll_reverse, 0, 1880 __cputchar); 1881 else 1882 abort(); 1883 } 1884 } 1885 } 1886 /* Scroll the block down. */ 1887 __mvcur(bot + n + 1, 0, top, 0, 1); 1888 if (parm_insert_line != NULL) 1889 tputs(tiparm(parm_insert_line, -n), 0, __cputchar); 1890 else 1891 if (insert_line != NULL) 1892 for (i = n; i < 0; i++) 1893 tputs(insert_line, 0, __cputchar); 1894 else 1895 abort(); 1896 __mvcur(top, 0, oy, ox, 1); 1897 } 1898 } 1899 1900 /* 1901 * __unsetattr -- 1902 * Unset attributes on curscr. Leave standout, attribute and colour 1903 * modes if necessary (!ms). Always leave altcharset (xterm at least 1904 * ignores a cursor move if we don't). 1905 */ 1906 void /* ARGSUSED */ 1907 __unsetattr(int checkms) 1908 { 1909 int isms; 1910 1911 if (checkms) { 1912 if (!move_standout_mode) 1913 isms = 1; 1914 else 1915 isms = 0; 1916 } else 1917 isms = 1; 1918 #ifdef DEBUG 1919 __CTRACE(__CTRACE_REFRESH, 1920 "__unsetattr: checkms = %d, ms = %s, wattr = %08x\n", 1921 checkms, move_standout_mode ? "TRUE" : "FALSE", curscr->wattr); 1922 #endif 1923 1924 /* 1925 * Don't leave the screen in standout mode (check against ms). Check 1926 * to see if we also turn off underscore, attributes and colour. 1927 */ 1928 if (curscr->wattr & __STANDOUT && isms) { 1929 tputs(exit_standout_mode, 0, __cputchar); 1930 curscr->wattr &= __mask_se; 1931 } 1932 /* 1933 * Don't leave the screen in underscore mode (check against ms). 1934 * Check to see if we also turn off attributes. Assume that we 1935 * also turn off colour. 1936 */ 1937 if (curscr->wattr & __UNDERSCORE && isms) { 1938 tputs(exit_underline_mode, 0, __cputchar); 1939 curscr->wattr &= __mask_ue; 1940 } 1941 /* 1942 * Don't leave the screen with attributes set (check against ms). 1943 * Assume that also turn off colour. 1944 */ 1945 if (curscr->wattr & __TERMATTR && isms) { 1946 tputs(exit_attribute_mode, 0, __cputchar); 1947 curscr->wattr &= __mask_me; 1948 } 1949 /* Don't leave the screen with altcharset set (don't check ms). */ 1950 if (curscr->wattr & __ALTCHARSET) { 1951 tputs(exit_alt_charset_mode, 0, __cputchar); 1952 curscr->wattr &= ~__ALTCHARSET; 1953 } 1954 /* Don't leave the screen with colour set (check against ms). */ 1955 if (__using_color && isms) 1956 __unset_color(curscr); 1957 } 1958 1959 #ifdef HAVE_WCHAR 1960 /* compare two cells on screen, must have the same forground/background, 1961 * and the same sequence of non-spacing characters */ 1962 int 1963 cellcmp( __LDATA *x, __LDATA *y ) 1964 { 1965 nschar_t *xnp = x->nsp, *ynp = y->nsp; 1966 int ret = ( x->ch == y->ch ) & ( x->attr == y->attr ); 1967 1968 if (!ret) 1969 return 0; 1970 if (!xnp && !ynp) 1971 return 1; 1972 if ((xnp && !ynp) || (!xnp && ynp)) 1973 return 0; 1974 1975 while (xnp && ynp) { 1976 if (xnp->ch != ynp->ch) 1977 return 0; 1978 xnp = xnp->next; 1979 ynp = ynp->next; 1980 } 1981 return !xnp && !ynp; 1982 } 1983 1984 /* compare two line segments */ 1985 int 1986 linecmp( __LDATA *xl, __LDATA *yl, size_t len ) 1987 { 1988 int i = 0; 1989 __LDATA *xp = xl, *yp = yl; 1990 1991 for (i = 0; i < len; i++, xp++, yp++) { 1992 if (!cellcmp(xp, yp)) 1993 return 0; 1994 } 1995 return 1; 1996 } 1997 1998 /* 1999 * Output the non-spacing characters associated with the given character 2000 * cell to the screen. 2001 */ 2002 2003 void 2004 __cursesi_putnsp(nschar_t *nsp, const int wy, const int wx) 2005 { 2006 nschar_t *p; 2007 2008 /* this shuts up gcc warnings about wx and wy not being used */ 2009 if (wx > wy) { 2010 } 2011 2012 p = nsp; 2013 while (p != NULL) { 2014 __cputwchar((int)p->ch); 2015 #ifdef DEBUG 2016 __CTRACE(__CTRACE_REFRESH, 2017 "_cursesi_putnsp: (%d,%d) non-spacing putwchar(0x%x)\n", 2018 wy, wx - 1, p->ch); 2019 #endif 2020 p = p->next; 2021 } 2022 } 2023 2024 #endif /* HAVE_WCHAR */ 2025