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