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