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