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