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