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