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