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