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