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