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