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