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