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