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