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