refresh.c revision 1.21 1 /* $NetBSD: refresh.c,v 1.21 2000/04/19 13:52:39 blymn Exp $ */
2
3 /*
4 * Copyright (c) 1981, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94";
40 #else
41 __RCSID("$NetBSD: refresh.c,v 1.21 2000/04/19 13:52:39 blymn Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <string.h>
46
47 #include "curses.h"
48 #include "curses_private.h"
49
50 /* the following is defined and set up in setterm.c */
51 extern struct tinfo *_cursesi_genbuf;
52
53 static int curwin;
54 static short ly, lx;
55
56 static void domvcur __P((int, int, int, int));
57 static int makech __P((WINDOW *, int));
58 static void quickch __P((WINDOW *));
59 static void scrolln __P((WINDOW *, int, int, int, int, int));
60 static void unsetattr __P((int));
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 return wrefresh(stdscr);
73 }
74
75 #endif
76
77 /*
78 * wrefresh --
79 * Make the current screen look like "win" over the area coverd by
80 * win.
81 */
82 int
83 wrefresh(WINDOW *win)
84 {
85 __LINE *wlp;
86 int retval;
87 short wy;
88 int dnum;
89
90 /* Check if we need to restart ... */
91 if (__endwin) {
92 __endwin = 0;
93 __restartwin();
94 }
95
96 /* Initialize loop parameters. */
97 ly = curscr->cury;
98 lx = curscr->curx;
99 wy = 0;
100 curwin = (win == curscr);
101
102 if (!curwin)
103 for (wy = 0; wy < win->maxy; wy++) {
104 wlp = win->lines[wy];
105 if (wlp->flags & __ISDIRTY)
106 wlp->hash = __hash((char *)(void *)wlp->line,
107 (int) (win->maxx * __LDATASIZE));
108 }
109
110 if ((win->flags & __CLEAROK) || (curscr->flags & __CLEAROK) || curwin) {
111 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
112 if ((!(win->battr & __COLOR) ||
113 ((win->battr & __COLOR) && BE)) &&
114 win->bch == ' ') {
115 if (win->battr & __COLOR) {
116 if ((win->battr & __COLOR) !=
117 (curscr->wattr & __COLOR)) {
118 __set_color(win->battr);
119 curscr->wattr &= ~__COLOR;
120 curscr->wattr |= win->battr &
121 __COLOR;
122 }
123 } else if (curscr->wattr & __COLOR) {
124 if (OC != NULL && CC == NULL)
125 tputs(OC, 0, __cputchar);
126 if (OP != NULL) {
127 tputs(OP, 0, __cputchar);
128 if (SE != NULL &&
129 !strcmp(OP, SE))
130 curscr->wattr &=
131 ~__STANDOUT;
132 if (UE != NULL &&
133 !strcmp(OP, UE))
134 curscr->wattr &=
135 ~__UNDERSCORE;
136 if (ME != NULL &&
137 !strcmp(OP, ME))
138 curscr->wattr &=
139 ~__TERMATTR;
140 }
141 curscr->wattr &= ~__COLOR;
142 }
143 tputs(CL, 0, __cputchar);
144 ly = 0;
145 lx = 0;
146 if (!curwin) {
147 curscr->flags &= ~__CLEAROK;
148 curscr->cury = 0;
149 curscr->curx = 0;
150 werase(curscr);
151 }
152 __touchwin(win);
153 } else {
154 if (!curwin)
155 curscr->flags &= ~__CLEAROK;
156 touchwin(win);
157 }
158 }
159 win->flags &= ~__CLEAROK;
160 }
161 if (!CA) {
162 if (win->curx != 0)
163 putchar('\n');
164 if (!curwin)
165 werase(curscr);
166 }
167 #ifdef DEBUG
168 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
169 __CTRACE("wrefresh: \tfirstch\tlastch\n");
170 #endif
171
172 if ((win->flags & __FULLWIN) && !curwin) {
173 /*
174 * Invoke quickch() only if more than a quarter of the lines
175 * in the window are dirty.
176 */
177 for (wy = 0, dnum = 0; wy < win->maxy; wy++)
178 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT))
179 dnum++;
180 if (!__noqch && dnum > (int) win->maxy / 4)
181 quickch(win);
182 }
183
184 #ifdef DEBUG
185 {
186 int i, j;
187
188 __CTRACE("#####################################\n");
189 for (i = 0; i < curscr->maxy; i++) {
190 __CTRACE("C: %d:", i);
191 __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
192 for (j = 0; j < curscr->maxx; j++)
193 __CTRACE("%c", curscr->lines[i]->line[j].ch);
194 __CTRACE("\n");
195 __CTRACE(" attr:");
196 for (j = 0; j < curscr->maxx; j++)
197 __CTRACE(" %x", curscr->lines[i]->line[j].attr);
198 __CTRACE("\n");
199 __CTRACE("W: %d:", i);
200 /* Handle small windows */
201 if (i >= win->begy && i < (win->begy + win->maxy)) {
202 __CTRACE(" 0x%x \n",
203 win->lines[i - win->begy]->hash);
204 __CTRACE(" 0x%x ",
205 win->lines[i - win->begy]->flags);
206 for (j = 0; j < win->maxx; j++)
207 __CTRACE("%c", win->lines[i - win
208 ->begy]->line[j].ch);
209 __CTRACE("\n");
210 __CTRACE(" attr:");
211 for (j = 0; j < win->maxx; j++)
212 __CTRACE(" %x", win->lines[i - win
213 ->begy]->line[j].attr);
214 __CTRACE("\n");
215 __CTRACE(" battr:");
216 for (j = 0; j < win->maxx; j++)
217 __CTRACE(" %x", win->lines[i - win
218 ->begy]->line[j].battr);
219 __CTRACE("\n");
220 }
221 }
222 }
223 #endif /* DEBUG */
224
225 for (wy = 0; wy < win->maxy; wy++) {
226 #ifdef DEBUG
227 __CTRACE("wy %d\tf: %d\tl:%d\tflags %x\n",
228 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp,
229 win->lines[wy]->flags);
230 #endif
231 if (!curwin)
232 curscr->lines[wy]->hash = win->lines[wy]->hash;
233 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) {
234 if (makech(win, wy) == ERR)
235 return (ERR);
236 else {
237 if (*win->lines[wy]->firstchp >= win->ch_off)
238 *win->lines[wy]->firstchp = win->maxx +
239 win->ch_off;
240 if (*win->lines[wy]->lastchp < win->maxx +
241 win->ch_off)
242 *win->lines[wy]->lastchp = win->ch_off;
243 if (*win->lines[wy]->lastchp <
244 *win->lines[wy]->firstchp) {
245 #ifdef DEBUG
246 __CTRACE("wrefresh: line %d notdirty \n", wy);
247 #endif
248 win->lines[wy]->flags &= ~__ISDIRTY;
249 }
250 }
251
252 }
253 #ifdef DEBUG
254 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp,
255 *win->lines[wy]->lastchp);
256 #endif
257 }
258
259 #ifdef DEBUG
260 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx);
261 #endif
262
263 if (win == curscr)
264 domvcur(ly, lx, (int) win->cury, (int) win->curx);
265 else {
266 if (win->flags & __LEAVEOK) {
267 curscr->cury = ly;
268 curscr->curx = lx;
269 ly -= win->begy;
270 lx -= win->begx;
271 if (ly >= 0 && ly < win->maxy && lx >= 0 &&
272 lx < win->maxx) {
273 win->cury = ly;
274 win->curx = lx;
275 } else
276 win->cury = win->curx = 0;
277 } else {
278 domvcur(ly, lx, (int) (win->cury + win->begy),
279 (int) (win->curx + win->begx));
280 curscr->cury = win->cury + win->begy;
281 curscr->curx = win->curx + win->begx;
282 }
283 }
284 retval = OK;
285
286 (void) fflush(stdout);
287 return (retval);
288 }
289
290 /*
291 * makech --
292 * Make a change on the screen.
293 */
294 static int
295 makech(win, wy)
296 WINDOW *win;
297 int wy;
298 {
299 static __LDATA blank = {' ', 0};
300 __LDATA *nsp, *csp, *cp, *cep;
301 u_int force;
302 int clsp, nlsp; /* Last space in lines. */
303 int lch, wx, y;
304 char *ce, cm_buff[1024];
305 attr_t lspb; /* Last space background colour */
306
307 #ifdef __GNUC__
308 nlsp = 0; /* XXX gcc -Wuninitialized */
309 #endif
310 /* Is the cursor still on the end of the last line? */
311 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) {
312 domvcur(ly, lx, ly + 1, 0);
313 ly++;
314 lx = 0;
315 }
316 wx = *win->lines[wy]->firstchp - win->ch_off;
317 if (wx < 0)
318 wx = 0;
319 else
320 if (wx >= win->maxx)
321 return (OK);
322 lch = *win->lines[wy]->lastchp - win->ch_off;
323 if (lch < 0)
324 return (OK);
325 else
326 if (lch >= (int) win->maxx)
327 lch = win->maxx - 1;
328 y = wy + win->begy;
329
330 if (curwin)
331 csp = ␣
332 else
333 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
334
335 nsp = &win->lines[wy]->line[wx];
336 force = win->lines[wy]->flags & __FORCEPAINT;
337 win->lines[wy]->flags &= ~__FORCEPAINT;
338 /* XXX: Check for background character here */
339 if (CE && !curwin) {
340 cp = &win->lines[wy]->line[win->maxx - 1];
341 if (cp->attr & __COLOR)
342 lspb = cp->attr & __COLOR;
343 else
344 lspb = cp->battr & __COLOR;
345 while (cp->ch == ' ' && cp->attr == lspb && cp->battr == lspb)
346 if (cp-- <= win->lines[wy]->line)
347 break;
348 nlsp = cp - win->lines[wy]->line;
349 }
350 if (!curwin)
351 ce = CE;
352 else
353 ce = NULL;
354
355 if (force) {
356 if (CM) {
357 t_goto(_cursesi_genbuf, CM, lx, ly, cm_buff, 1023);
358 tputs(cm_buff, 0, __cputchar);
359 } else {
360 tputs(HO, 0, __cputchar);
361 __mvcur(0, 0, ly, lx, 1);
362 }
363 }
364
365 while (wx <= lch) {
366 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
367 if (wx <= lch) {
368 while (wx <= lch &&
369 memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
370 nsp++;
371 if (!curwin)
372 ++csp;
373 ++wx;
374 }
375 continue;
376 }
377 break;
378 }
379 domvcur(ly, lx, y, (int) (wx + win->begx));
380
381 #ifdef DEBUG
382 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n",
383 wx, ly, lx, y, wx + win->begx, force);
384 #endif
385 ly = y;
386 lx = wx + win->begx;
387 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0)
388 && wx <= lch) {
389
390 if (ce != NULL &&
391 win->maxx + win->begx == curscr->maxx &&
392 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) {
393 /* Check for clear to end-of-line. */
394 cep = &curscr->lines[wy]->line[win->maxx - 1];
395 while (cep->ch == ' ' && cep->attr == lspb)
396 if (cep-- <= csp)
397 break;
398 clsp = cep - curscr->lines[wy]->line -
399 win->begx * __LDATASIZE;
400 #ifdef DEBUG
401 __CTRACE("makech: clsp = %d, nlsp = %d\n",
402 clsp, nlsp);
403 #endif
404 if (((clsp - nlsp >= strlen(CE) &&
405 clsp < win->maxx * __LDATASIZE) ||
406 wy == win->maxy - 1) &&
407 (!(lspb & __COLOR) ||
408 ((lspb & __COLOR) && BE)) &&
409 win->bch == ' ') {
410 unsetattr(0);
411 if ((lspb & __COLOR) !=
412 (curscr->wattr & __COLOR)) {
413 __set_color(lspb);
414 curscr->wattr &= ~__COLOR;
415 curscr->wattr |= lspb & __COLOR;
416 }
417 tputs(CE, 0, __cputchar);
418 lx = wx + win->begx;
419 while (wx++ <= clsp) {
420 csp->ch = ' ';
421 csp->attr = 0;
422 csp++;
423 }
424 return (OK);
425 }
426 ce = NULL;
427 }
428
429 /*
430 * Unset colour if appropriate. Check to see
431 * if we also turn off standout, underscore and
432 * attributes.
433 */
434 if (!(nsp->attr & __COLOR) &&
435 !(nsp->battr & __COLOR) &&
436 (curscr->wattr & __COLOR)) {
437 if (OC != NULL && CC == NULL)
438 tputs(OC, 0, __cputchar);
439 if (OP != NULL) {
440 tputs(OP, 0, __cputchar);
441 if (SE != NULL &&
442 !strcmp(OP, SE))
443 curscr->wattr &=
444 ~__STANDOUT;
445 if (UE != NULL &&
446 !strcmp(OP, UE))
447 curscr->wattr &=
448 ~__UNDERSCORE;
449 if (ME != NULL &&
450 !strcmp(OP, ME))
451 curscr->wattr &=
452 ~__TERMATTR;
453 }
454 curscr->wattr &= ~__COLOR;
455 }
456
457 /*
458 * Unset attributes as appropriate. Unset first
459 * so that the relevant attributes can be reset
460 * (because 'me' unsets 'mb', 'md', 'mh', 'mk',
461 * 'mp' and 'mr'). Check to see if we also turn off
462 * standout, attributes and colour.
463 */
464 if (((nsp->attr & __TERMATTR) |
465 (nsp->battr & __TERMATTR)) !=
466 (curscr->wattr & __TERMATTR)) {
467 tputs(ME, 0, __cputchar);
468 curscr->wattr &= ~__TERMATTR;
469 if (SE != NULL && !strcmp(ME, SE))
470 curscr->wattr &= ~__STANDOUT;
471 if (UE != NULL && !strcmp(ME, UE))
472 curscr->wattr &= ~__UNDERSCORE;
473 if (OP != NULL && !strcmp(ME, OP))
474 curscr->wattr &= ~__COLOR;
475 }
476
477 /*
478 * Exit underscore mode if appropriate.
479 * Check to see if we also turn off standout,
480 * attributes and colour.
481 */
482 if (!(nsp->attr & __UNDERSCORE) &&
483 !(nsp->battr & __UNDERSCORE) &&
484 (curscr->wattr & __UNDERSCORE)) {
485 tputs(UE, 0, __cputchar);
486 curscr->wattr &= ~__UNDERSCORE;
487 if (SE != NULL && !strcmp(UE, SE))
488 curscr->wattr &= ~__STANDOUT;
489 if (ME != NULL && !strcmp(UE, ME))
490 curscr->wattr &= ~__TERMATTR;
491 if (OP != NULL && !strcmp(UE, OP))
492 curscr->wattr &= ~__COLOR;
493 }
494
495 /*
496 * Enter/exit standout mode as appropriate.
497 * Check to see if we also turn off underscore,
498 * attributes and colour.
499 * XXX
500 * Should use UC if SO/SE not available.
501 */
502 if ((nsp->attr & __STANDOUT) ||
503 (nsp->battr & __STANDOUT)) {
504 if (!(curscr->wattr & __STANDOUT) &&
505 SO != NULL && SE != NULL) {
506 tputs(SO, 0, __cputchar);
507 curscr->wattr |= __STANDOUT;
508 }
509 } else {
510 if (curscr->wattr & __STANDOUT) {
511 tputs(SE, 0, __cputchar);
512 curscr->wattr &= ~__STANDOUT;
513 if (UE != NULL && !strcmp(SE, UE))
514 curscr->wattr &=
515 ~__UNDERSCORE;
516 if (ME != NULL && !strcmp(SE, ME))
517 curscr->wattr &= ~__TERMATTR;
518 if (OP != NULL && !strcmp(SE, OP))
519 curscr->wattr &= ~__COLOR;
520 }
521 }
522
523 /*
524 * Enter underscore mode if appropriate.
525 * XXX
526 * Should use UC if US/UE not available.
527 */
528 if (((nsp->attr & __UNDERSCORE) ||
529 (nsp->battr & __UNDERSCORE)) &&
530 !(curscr->wattr & __UNDERSCORE) &&
531 US != NULL && UE != NULL) {
532 tputs(US, 0, __cputchar);
533 curscr->wattr |= __UNDERSCORE;
534 }
535
536 /*
537 * Set other attributes as appropriate.
538 */
539 if (((nsp->attr & __BLINK) ||
540 (nsp->battr & __BLINK)) &&
541 !(curscr->wattr & __BLINK) &&
542 MB != NULL && ME != NULL) {
543 tputs(MB, 0, __cputchar);
544 curscr->wattr |= __BLINK;
545 }
546 if (((nsp->attr & __BOLD) ||
547 (nsp->battr & __BOLD)) &&
548 !(curscr->wattr & __BOLD) &&
549 MD != NULL && ME != NULL) {
550 tputs(MD, 0, __cputchar);
551 curscr->wattr |= __BOLD;
552 }
553 if (((nsp->attr & __DIM) ||
554 (nsp->battr & __DIM)) &&
555 !(curscr->wattr & __DIM) &&
556 MH != NULL && ME != NULL) {
557 tputs(MH, 0, __cputchar);
558 curscr->wattr |= __DIM;
559 }
560 if (((nsp->attr & __BLANK) ||
561 (nsp->battr & __BLANK)) &&
562 !(curscr->wattr & __BLANK) &&
563 MK != NULL && ME != NULL) {
564 tputs(MK, 0, __cputchar);
565 curscr->wattr |= __BLANK;
566 }
567 if (((nsp->attr & __PROTECT) ||
568 (nsp->battr & __PROTECT)) &&
569 !(curscr->wattr & __PROTECT) &&
570 MP != NULL && ME != NULL) {
571 tputs(MP, 0, __cputchar);
572 curscr->wattr |= __PROTECT;
573 }
574 if (((nsp->attr & __REVERSE) ||
575 (nsp->battr & __REVERSE)) &&
576 !(curscr->wattr & __REVERSE) &&
577 MR != NULL && ME != NULL) {
578 tputs(MR, 0, __cputchar);
579 curscr->wattr |= __REVERSE;
580 }
581
582 /* Set/change colour as appropriate. */
583 if (((nsp->attr & __COLOR) ||
584 (nsp->battr & __COLOR)) &&
585 cO != NULL && (OC != NULL || OP != NULL)) {
586 if (nsp->attr & __COLOR) {
587 if ((nsp->attr & __COLOR) !=
588 (curscr->wattr & __COLOR)) {
589 __set_color(nsp->attr);
590 curscr->wattr &= ~__COLOR;
591 curscr->wattr |= nsp->attr &
592 __COLOR;
593 }
594 } else if (nsp->battr & __COLOR) {
595 if ((nsp->battr & __COLOR) !=
596 (curscr->wattr & __COLOR)) {
597 __set_color(nsp->battr);
598 curscr->wattr &= ~__COLOR;
599 curscr->wattr |= nsp->battr &
600 __COLOR;
601 }
602 }
603 }
604
605 /* Enter/exit altcharset mode as appropriate. */
606 if ((nsp->attr & __ALTCHARSET) ||
607 (nsp->battr & __ALTCHARSET)) {
608 if (!(curscr->wattr & __ALTCHARSET) &&
609 AS != NULL && AE != NULL) {
610 tputs(AS, 0, __cputchar);
611 curscr->wattr |= __ALTCHARSET;
612 }
613 } else {
614 if (curscr->wattr & __ALTCHARSET) {
615 tputs(AE, 0, __cputchar);
616 curscr->wattr &= ~__ALTCHARSET;
617 }
618 }
619
620 wx++;
621 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin)
622 if (win->flags & __SCROLLOK) {
623 if (win->flags & __ENDLINE){
624 unsetattr(1);
625 }
626 if (!(win->flags & __SCROLLWIN)) {
627 if (!curwin) {
628 csp->attr = nsp->attr |
629 (nsp->battr &
630 ~__COLOR);
631 if (!(nsp->attr &
632 __COLOR) &&
633 (nsp->battr &
634 __COLOR))
635 csp->attr |=
636 nsp->battr
637 & __COLOR;
638 if (nsp->ch == ' ' &&
639 nsp->bch != ' ')
640 putchar((int)
641 (csp->ch =
642 nsp->bch));
643 else
644 putchar((int)
645 (csp->ch =
646 nsp->ch));
647 } else
648 putchar((int) nsp->ch);
649 }
650 if (wx + win->begx < curscr->maxx) {
651 domvcur(ly, (int) (wx + win->begx),
652 (int) (win->begy + win->maxy - 1),
653 (int) (win->begx + win->maxx - 1));
654 }
655 ly = win->begy + win->maxy - 1;
656 lx = win->begx + win->maxx - 1;
657 return (OK);
658 }
659 if (wx < win->maxx || wy < win->maxy - 1 ||
660 !(win->flags & __SCROLLWIN)) {
661 if (!curwin) {
662 csp->attr = nsp->attr | (nsp->battr &
663 ~__COLOR);
664 if (!(nsp->attr & __COLOR) &&
665 (nsp->battr & __COLOR))
666 csp->attr |= nsp->battr &
667 __COLOR;
668 if (nsp->ch == ' ' && nsp->bch != ' ')
669 putchar((int) (csp->ch =
670 nsp->bch));
671 else
672 putchar((int) (csp->ch =
673 nsp->ch));
674 csp++;
675 } else
676 putchar((int) nsp->ch);
677 }
678 #ifdef DEBUG
679 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177);
680 #endif
681 if (UC && ((nsp->attr & __STANDOUT) ||
682 (nsp->attr & __UNDERSCORE))) {
683 putchar('\b');
684 tputs(UC, 0, __cputchar);
685 }
686 nsp++;
687 #ifdef DEBUG
688 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
689 #endif
690 }
691 if (lx == wx + win->begx) /* If no change. */
692 break;
693 lx = wx + win->begx;
694 if (lx >= COLS && AM)
695 lx = COLS - 1;
696 else
697 if (wx >= win->maxx) {
698 domvcur(ly, lx, ly, (int) (win->maxx + win->begx - 1));
699 lx = win->maxx + win->begx - 1;
700 }
701 #ifdef DEBUG
702 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
703 #endif
704 }
705
706 /*
707 * Don't leave the screen with attributes set.
708 * XXX Should this be at the end of wrefresh() and not here?
709 */
710 unsetattr(0);
711 return (OK);
712 }
713
714 /*
715 * domvcur --
716 * Do a mvcur, leaving attributes if necessary.
717 */
718 static void
719 domvcur(oy, ox, ny, nx)
720 int oy, ox, ny, nx;
721 {
722 unsetattr(1);
723 __mvcur(oy, ox, ny, nx, 1);
724 }
725
726 /*
727 * Quickch() attempts to detect a pattern in the change of the window
728 * in order to optimize the change, e.g., scroll n lines as opposed to
729 * repainting the screen line by line.
730 */
731
732 static void
733 quickch(win)
734 WINDOW *win;
735 {
736 #define THRESH (int) win->maxy / 4
737
738 __LINE *clp, *tmp1, *tmp2;
739 int bsize, curs, curw, starts, startw, i, j;
740 int n, target, cur_period, bot, top, sc_region;
741 __LDATA buf[1024];
742 u_int blank_hash;
743
744 #ifdef __GNUC__
745 curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */
746 #endif
747 /*
748 * Find how many lines from the top of the screen are unchanged.
749 */
750 for (top = 0; top < win->maxy; top++)
751 if (win->lines[top]->flags & __FORCEPAINT ||
752 win->lines[top]->hash != curscr->lines[top]->hash
753 || memcmp(win->lines[top]->line,
754 curscr->lines[top]->line,
755 (size_t) win->maxx * __LDATASIZE) != 0)
756 break;
757 else
758 win->lines[top]->flags &= ~__ISDIRTY;
759 /*
760 * Find how many lines from bottom of screen are unchanged.
761 */
762 for (bot = win->maxy - 1; bot >= 0; bot--)
763 if (win->lines[bot]->flags & __FORCEPAINT ||
764 win->lines[bot]->hash != curscr->lines[bot]->hash
765 || memcmp(win->lines[bot]->line,
766 curscr->lines[bot]->line,
767 (size_t) win->maxx * __LDATASIZE) != 0)
768 break;
769 else
770 win->lines[bot]->flags &= ~__ISDIRTY;
771
772 #ifdef NO_JERKINESS
773 /*
774 * If we have a bottom unchanged region return. Scrolling the
775 * bottom region up and then back down causes a screen jitter.
776 * This will increase the number of characters sent to the screen
777 * but it looks better.
778 */
779 if (bot < win->maxy - 1)
780 return;
781 #endif /* NO_JERKINESS */
782
783 /*
784 * Search for the largest block of text not changed.
785 * Invariants of the loop:
786 * - Startw is the index of the beginning of the examined block in win.
787 * - Starts is the index of the beginning of the examined block in
788 * curscr.
789 * - Curs is the index of one past the end of the exmined block in win.
790 * - Curw is the index of one past the end of the exmined block in
791 * curscr.
792 * - bsize is the current size of the examined block.
793 */
794 for (bsize = bot - top; bsize >= THRESH; bsize--) {
795 for (startw = top; startw <= bot - bsize; startw++)
796 for (starts = top; starts <= bot - bsize;
797 starts++) {
798 for (curw = startw, curs = starts;
799 curs < starts + bsize; curw++, curs++)
800 if (win->lines[curw]->flags &
801 __FORCEPAINT ||
802 (win->lines[curw]->hash !=
803 curscr->lines[curs]->hash ||
804 memcmp(win->lines[curw]->line,
805 curscr->lines[curs]->line,
806 (size_t) win->maxx * __LDATASIZE) != 0))
807 break;
808 if (curs == starts + bsize)
809 goto done;
810 }
811 }
812 done:
813 /* Did not find anything */
814 if (bsize < THRESH)
815 return;
816
817 #ifdef DEBUG
818 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n",
819 bsize, starts, startw, curw, curs, top, bot);
820 #endif
821
822 /*
823 * Make sure that there is no overlap between the bottom and top
824 * regions and the middle scrolled block.
825 */
826 if (bot < curs)
827 bot = curs - 1;
828 if (top > starts)
829 top = starts;
830
831 n = startw - starts;
832
833 #ifdef DEBUG
834 __CTRACE("#####################################\n");
835 for (i = 0; i < curscr->maxy; i++) {
836 __CTRACE("C: %d:", i);
837 __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
838 for (j = 0; j < curscr->maxx; j++)
839 __CTRACE("%c", curscr->lines[i]->line[j].ch);
840 __CTRACE("\n");
841 __CTRACE(" attr:");
842 for (j = 0; j < curscr->maxx; j++)
843 __CTRACE(" %x", curscr->lines[i]->line[j].attr);
844 __CTRACE("\n");
845 __CTRACE("W: %d:", i);
846 __CTRACE(" 0x%x \n", win->lines[i]->hash);
847 __CTRACE(" 0x%x ", win->lines[i]->flags);
848 for (j = 0; j < win->maxx; j++)
849 __CTRACE("%c", win->lines[i]->line[j].ch);
850 __CTRACE("\n");
851 __CTRACE(" attr:");
852 for (j = 0; j < win->maxx; j++)
853 __CTRACE(" %x", win->lines[i]->line[j].attr);
854 __CTRACE("\n");
855 }
856 #endif
857
858 /* So we don't have to call __hash() each time */
859 for (i = 0; i < win->maxx; i++) {
860 buf[i].ch = ' ';
861 buf[i].bch = ' ';
862 buf[i].attr = 0;
863 buf[i].battr = 0;
864 }
865 blank_hash = __hash((char *)(void *)buf,
866 (int) (win->maxx * __LDATASIZE));
867
868 /*
869 * Perform the rotation to maintain the consistency of curscr.
870 * This is hairy since we are doing an *in place* rotation.
871 * Invariants of the loop:
872 * - I is the index of the current line.
873 * - Target is the index of the target of line i.
874 * - Tmp1 points to current line (i).
875 * - Tmp2 and points to target line (target);
876 * - Cur_period is the index of the end of the current period.
877 * (see below).
878 *
879 * There are 2 major issues here that make this rotation non-trivial:
880 * 1. Scrolling in a scrolling region bounded by the top
881 * and bottom regions determined (whose size is sc_region).
882 * 2. As a result of the use of the mod function, there may be a
883 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
884 * 0 to 2, which then causes all odd lines not to be rotated.
885 * To remedy this, an index of the end ( = beginning) of the
886 * current 'period' is kept, cur_period, and when it is reached,
887 * the next period is started from cur_period + 1 which is
888 * guaranteed not to have been reached since that would mean that
889 * all records would have been reached. (think about it...).
890 *
891 * Lines in the rotation can have 3 attributes which are marked on the
892 * line so that curscr is consistent with the visual screen.
893 * 1. Not dirty -- lines inside the scrolled block, top region or
894 * bottom region.
895 * 2. Blank lines -- lines in the differential of the scrolling
896 * region adjacent to top and bot regions
897 * depending on scrolling direction.
898 * 3. Dirty line -- all other lines are marked dirty.
899 */
900 sc_region = bot - top + 1;
901 i = top;
902 tmp1 = curscr->lines[top];
903 cur_period = top;
904 for (j = top; j <= bot; j++) {
905 target = (i - top + n + sc_region) % sc_region + top;
906 tmp2 = curscr->lines[target];
907 curscr->lines[target] = tmp1;
908 /* Mark block as clean and blank out scrolled lines. */
909 clp = curscr->lines[target];
910 #ifdef DEBUG
911 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
912 n, startw, curw, i, target);
913 #endif
914 if ((target >= startw && target < curw) || target < top
915 || target > bot) {
916 #ifdef DEBUG
917 __CTRACE("-- notdirty");
918 #endif
919 win->lines[target]->flags &= ~__ISDIRTY;
920 } else
921 if ((n > 0 && target >= top && target < top + n) ||
922 (n < 0 && target <= bot && target > bot + n)) {
923 if (clp->hash != blank_hash || memcmp(clp->line,
924 buf, (size_t) win->maxx * __LDATASIZE) !=0) {
925 (void)memcpy(clp->line, buf,
926 (size_t) win->maxx * __LDATASIZE);
927 #ifdef DEBUG
928 __CTRACE("-- blanked out: dirty");
929 #endif
930 clp->hash = blank_hash;
931 __touchline(win, target, 0, (int) win->maxx - 1, 0);
932 } else {
933 __touchline(win, target, 0, (int) win->maxx - 1, 0);
934 #ifdef DEBUG
935 __CTRACE(" -- blank line already: dirty");
936 #endif
937 }
938 } else {
939 #ifdef DEBUG
940 __CTRACE(" -- dirty");
941 #endif
942 __touchline(win, target, 0, (int) win->maxx - 1, 0);
943 }
944 #ifdef DEBUG
945 __CTRACE("\n");
946 #endif
947 if (target == cur_period) {
948 i = target + 1;
949 tmp1 = curscr->lines[i];
950 cur_period = i;
951 } else {
952 tmp1 = tmp2;
953 i = target;
954 }
955 }
956 #ifdef DEBUG
957 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
958 for (i = 0; i < curscr->maxy; i++) {
959 __CTRACE("C: %d:", i);
960 for (j = 0; j < curscr->maxx; j++)
961 __CTRACE("%c", curscr->lines[i]->line[j].ch);
962 __CTRACE("\n");
963 __CTRACE("W: %d:", i);
964 for (j = 0; j < win->maxx; j++)
965 __CTRACE("%c", win->lines[i]->line[j].ch);
966 __CTRACE("\n");
967 }
968 #endif
969 if (n != 0) {
970 WINDOW *wp;
971 scrolln(win, starts, startw, curs, bot, top);
972 /*
973 * Need to repoint any subwindow lines to the rotated
974 * line structured.
975 */
976 for (wp = win->nextp; wp != win; wp = wp->nextp)
977 __set_subwin(win, wp);
978 }
979 }
980
981 /*
982 * scrolln --
983 * Scroll n lines, where n is starts - startw.
984 */
985 static void /* ARGSUSED */
986 scrolln(win, starts, startw, curs, bot, top)
987 WINDOW *win;
988 int starts, startw, curs, bot, top;
989 {
990 int i, oy, ox, n;
991
992 oy = curscr->cury;
993 ox = curscr->curx;
994 n = starts - startw;
995
996 /*
997 * XXX
998 * The initial tests that set __noqch don't let us reach here unless
999 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr
1000 * scrolling can only shift the entire scrolling region, not just a
1001 * part of it, which means that the quickch() routine is going to be
1002 * sadly disappointed in us if we don't have CS as well.
1003 *
1004 * If CS, HO and SF/sf are set, can use the scrolling region. Because
1005 * the cursor position after CS is undefined, we need HO which gives us
1006 * the ability to move to somewhere without knowledge of the current
1007 * location of the cursor. Still call __mvcur() anyway, to update its
1008 * idea of where the cursor is.
1009 *
1010 * When the scrolling region has been set, the cursor has to be at the
1011 * last line of the region to make the scroll happen.
1012 *
1013 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr
1014 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not
1015 * SF/SR. So, if we're scrolling almost all of the screen, try and use
1016 * AL/DL, otherwise use the scrolling region. The "almost all" is a
1017 * shameless hack for vi.
1018 */
1019 /* XXX: check for background colour and bce here */
1020 if (n > 0) {
1021 if (CS != NULL && HO != NULL && (SF != NULL ||
1022 ((AL == NULL || DL == NULL ||
1023 top > 3 || bot + 3 < win->maxy) && sf != NULL))) {
1024 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar);
1025 __mvcur(oy, ox, 0, 0, 1);
1026 tputs(HO, 0, __cputchar);
1027 __mvcur(0, 0, bot, 0, 1);
1028 if (SF != NULL)
1029 tputs(__tscroll(SF, n, 0), 0, __cputchar);
1030 else
1031 for (i = 0; i < n; i++)
1032 tputs(sf, 0, __cputchar);
1033 tputs(__tscroll(CS, 0, (int) win->maxy), 0, __cputchar);
1034 __mvcur(bot, 0, 0, 0, 1);
1035 tputs(HO, 0, __cputchar);
1036 __mvcur(0, 0, oy, ox, 1);
1037 return;
1038 }
1039
1040 /* Scroll up the block. */
1041 if (SF != NULL && top == 0) {
1042 __mvcur(oy, ox, bot, 0, 1);
1043 tputs(__tscroll(SF, n, 0), 0, __cputchar);
1044 } else
1045 if (DL != NULL) {
1046 __mvcur(oy, ox, top, 0, 1);
1047 tputs(__tscroll(DL, n, 0), 0, __cputchar);
1048 } else
1049 if (dl != NULL) {
1050 __mvcur(oy, ox, top, 0, 1);
1051 for (i = 0; i < n; i++)
1052 tputs(dl, 0, __cputchar);
1053 } else
1054 if (sf != NULL && top == 0) {
1055 __mvcur(oy, ox, bot, 0, 1);
1056 for (i = 0; i < n; i++)
1057 tputs(sf, 0, __cputchar);
1058 } else
1059 abort();
1060
1061 /* Push down the bottom region. */
1062 __mvcur(top, 0, bot - n + 1, 0, 1);
1063 if (AL != NULL)
1064 tputs(__tscroll(AL, n, 0), 0, __cputchar);
1065 else
1066 if (al != NULL)
1067 for (i = 0; i < n; i++)
1068 tputs(al, 0, __cputchar);
1069 else
1070 abort();
1071 __mvcur(bot - n + 1, 0, oy, ox, 1);
1072 } else {
1073 /*
1074 * !!!
1075 * n < 0
1076 *
1077 * If CS, HO and SR/sr are set, can use the scrolling region.
1078 * See the above comments for details.
1079 */
1080 if (CS != NULL && HO != NULL && (SR != NULL ||
1081 ((AL == NULL || DL == NULL ||
1082 top > 3 || bot + 3 < win->maxy) && sr != NULL))) {
1083 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar);
1084 __mvcur(oy, ox, 0, 0, 1);
1085 tputs(HO, 0, __cputchar);
1086 __mvcur(0, 0, top, 0, 1);
1087
1088 if (SR != NULL)
1089 tputs(__tscroll(SR, -n, 0), 0, __cputchar);
1090 else
1091 for (i = n; i < 0; i++)
1092 tputs(sr, 0, __cputchar);
1093 tputs(__tscroll(CS, 0, (int) win->maxy), 0, __cputchar);
1094 __mvcur(top, 0, 0, 0, 1);
1095 tputs(HO, 0, __cputchar);
1096 __mvcur(0, 0, oy, ox, 1);
1097 return;
1098 }
1099
1100 /* Preserve the bottom lines. */
1101 __mvcur(oy, ox, bot + n + 1, 0, 1);
1102 if (SR != NULL && bot == win->maxy)
1103 tputs(__tscroll(SR, -n, 0), 0, __cputchar);
1104 else
1105 if (DL != NULL)
1106 tputs(__tscroll(DL, -n, 0), 0, __cputchar);
1107 else
1108 if (dl != NULL)
1109 for (i = n; i < 0; i++)
1110 tputs(dl, 0, __cputchar);
1111 else
1112 if (sr != NULL && bot == win->maxy)
1113 for (i = n; i < 0; i++)
1114 tputs(sr, 0, __cputchar);
1115 else
1116 abort();
1117
1118 /* Scroll the block down. */
1119 __mvcur(bot + n + 1, 0, top, 0, 1);
1120 if (AL != NULL)
1121 tputs(__tscroll(AL, -n, 0), 0, __cputchar);
1122 else
1123 if (al != NULL)
1124 for (i = n; i < 0; i++)
1125 tputs(al, 0, __cputchar);
1126 else
1127 abort();
1128 __mvcur(top, 0, oy, ox, 1);
1129 }
1130 }
1131
1132 /*
1133 * unsetattr --
1134 * Unset attributes on curscr. Leave standout, attribute and colour
1135 * modes if necessary (!MS). Always leave altcharset (xterm at least
1136 * ignores a cursor move if we don't).
1137 */
1138 static void /* ARGSUSED */
1139 unsetattr(int checkms)
1140 {
1141 int isms;
1142
1143 if (checkms)
1144 if (!MS) {
1145 isms = 1;
1146 } else {
1147 isms = 0;
1148 }
1149 else
1150 isms = 1;
1151 #ifdef DEBUG
1152 __CTRACE("unsetattr: checkms = %d, MS = %s, wattr = %08x\n",
1153 checkms, MS ? "TRUE" : "FALSE", curscr->wattr);
1154 #endif
1155
1156 /*
1157 * Don't leave the screen in standout mode (check against MS). Check
1158 * to see if we also turn off underscore, attributes and colour.
1159 */
1160 if (curscr->wattr & __STANDOUT && isms) {
1161 tputs(SE, 0, __cputchar);
1162 curscr->wattr &= ~__STANDOUT;
1163 if (UE != NULL && !strcmp(SE, UE))
1164 curscr->wattr &= ~__UNDERSCORE;
1165 if (ME != NULL && !strcmp(SE, ME))
1166 curscr->wattr &= ~__TERMATTR;
1167 if (OP != NULL && !strcmp(SE, OP))
1168 curscr->wattr &= ~__COLOR;
1169 }
1170 /*
1171 * Don't leave the screen in underscore mode (check against MS).
1172 * Check to see if we also turn off attributes and colour.
1173 */
1174 if (curscr->wattr & __UNDERSCORE && isms) {
1175 tputs(UE, 0, __cputchar);
1176 curscr->wattr &= ~__UNDERSCORE;
1177 if (ME != NULL && !strcmp(UE, ME))
1178 curscr->wattr &= ~__TERMATTR;
1179 if (OP != NULL && !strcmp(UE, OP))
1180 curscr->wattr &= ~__COLOR;
1181 }
1182 /*
1183 * Don't leave the screen with attributes set (check against MS).
1184 * Check to see if we also turn off colour.
1185 */
1186 if (curscr->wattr & __TERMATTR && isms) {
1187 tputs(ME, 0, __cputchar);
1188 curscr->wattr &= ~__TERMATTR;
1189 if (OP != NULL && !strcmp(ME, OP))
1190 curscr->wattr &= ~__COLOR;
1191 }
1192 /* Don't leave the screen with altcharset set (don't check MS). */
1193 if (curscr->wattr & __ALTCHARSET) {
1194 tputs(AE, 0, __cputchar);
1195 curscr->wattr &= ~__ALTCHARSET;
1196 }
1197 /* Don't leave the screen with colour set (check against MS). */
1198 if (curscr->wattr & __COLOR && isms) {
1199 if (OC != NULL && CC == NULL)
1200 tputs(OC, 0, __cputchar);
1201 if (OP != NULL)
1202 tputs(OP, 0, __cputchar);
1203 curscr->wattr &= ~__COLOR;
1204 }
1205 }
1206