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