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