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