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