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