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