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