1 /*
2 * Copyright (c) 1981, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #ifndef lint
31 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94";
32 #endif /* not lint */
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "curses.h"
38
39 static int curwin;
40 static short ly, lx;
41
42 static void domvcur(int, int, int, int);
43 static int makech(WINDOW *, int);
44 static void quickch(WINDOW *);
45 static void scrolln(WINDOW *, int, int, int, int, int);
46
47 /*
48 * wrefresh --
49 * Make the current screen look like "win" over the area coverd by
50 * win.
51 */
52 int
wrefresh(win)53 wrefresh(win)
54 register WINDOW *win;
55 {
56 register __LINE *wlp;
57 register int retval;
58 register short wy;
59 int dnum;
60
61 /* Initialize loop parameters. */
62 ly = curscr->cury;
63 lx = curscr->curx;
64 wy = 0;
65 curwin = (win == curscr);
66
67 if (!curwin)
68 for (wy = 0; wy < win->maxy; wy++) {
69 wlp = win->lines[wy];
70 if (wlp->flags & __ISDIRTY)
71 wlp->hash = __hash((char *)wlp->line,
72 win->maxx * __LDATASIZE);
73 }
74
75 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
76 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
77 tputs(CL, 0, __cputchar);
78 ly = 0;
79 lx = 0;
80 if (!curwin) {
81 curscr->flags &= ~__CLEAROK;
82 curscr->cury = 0;
83 curscr->curx = 0;
84 werase(curscr);
85 }
86 __touchwin(win);
87 }
88 win->flags &= ~__CLEAROK;
89 }
90 if (!CA) {
91 if (win->curx != 0)
92 putchar('\n');
93 if (!curwin)
94 werase(curscr);
95 }
96 #ifdef DEBUG
97 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
98 __CTRACE("wrefresh: \tfirstch\tlastch\n");
99 #endif
100
101 #ifndef NOQCH
102 if ((win->flags & __FULLWIN) && !curwin) {
103 /*
104 * Invoke quickch() only if more than a quarter of the lines
105 * in the window are dirty.
106 */
107 for (wy = 0, dnum = 0; wy < win->maxy; wy++)
108 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT))
109 dnum++;
110 if (!__noqch && dnum > (int) win->maxy / 4)
111 quickch(win);
112 }
113 #endif
114
115 #ifdef DEBUG
116 { int i, j;
117 __CTRACE("#####################################\n");
118 for (i = 0; i < curscr->maxy; i++) {
119 __CTRACE("C: %d:", i);
120 __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
121 for (j = 0; j < curscr->maxx; j++)
122 __CTRACE("%c",
123 curscr->lines[i]->line[j].ch);
124 __CTRACE("\n");
125 for (j = 0; j < curscr->maxx; j++)
126 __CTRACE("%x",
127 curscr->lines[i]->line[j].attr);
128 __CTRACE("\n");
129 __CTRACE("W: %d:", i);
130 __CTRACE(" 0x%x \n", win->lines[i]->hash);
131 __CTRACE(" 0x%x ", win->lines[i]->flags);
132 for (j = 0; j < win->maxx; j++)
133 __CTRACE("%c",
134 win->lines[i]->line[j].ch);
135 __CTRACE("\n");
136 for (j = 0; j < win->maxx; j++)
137 __CTRACE("%x",
138 win->lines[i]->line[j].attr);
139 __CTRACE("\n");
140 }
141 }
142 #endif /* DEBUG */
143
144 for (wy = 0; wy < win->maxy; wy++) {
145 #ifdef DEBUG
146 __CTRACE("%d\t%d\t%d\n",
147 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp);
148 #endif
149 if (!curwin)
150 curscr->lines[wy]->hash = win->lines[wy]->hash;
151 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) {
152 if (makech(win, wy) == ERR)
153 return (ERR);
154 else {
155 if (*win->lines[wy]->firstchp >= win->ch_off)
156 *win->lines[wy]->firstchp = win->maxx +
157 win->ch_off;
158 if (*win->lines[wy]->lastchp < win->maxx +
159 win->ch_off)
160 *win->lines[wy]->lastchp = win->ch_off;
161 if (*win->lines[wy]->lastchp <
162 *win->lines[wy]->firstchp) {
163 #ifdef DEBUG
164 __CTRACE("wrefresh: line %d notdirty \n", wy);
165 #endif
166 win->lines[wy]->flags &= ~__ISDIRTY;
167 }
168 }
169
170 }
171 #ifdef DEBUG
172 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp,
173 *win->lines[wy]->lastchp);
174 #endif
175 }
176
177 #ifdef DEBUG
178 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx);
179 #endif
180
181 if (win == curscr)
182 domvcur(ly, lx, win->cury, win->curx);
183 else {
184 if (win->flags & __LEAVEOK) {
185 curscr->cury = ly;
186 curscr->curx = lx;
187 ly -= win->begy;
188 lx -= win->begx;
189 if (ly >= 0 && ly < win->maxy && lx >= 0 &&
190 lx < win->maxx) {
191 win->cury = ly;
192 win->curx = lx;
193 } else
194 win->cury = win->curx = 0;
195 } else {
196 domvcur(ly, lx, win->cury + win->begy,
197 win->curx + win->begx);
198 curscr->cury = win->cury + win->begy;
199 curscr->curx = win->curx + win->begx;
200 }
201 }
202 retval = OK;
203
204 (void)fflush(stdout);
205 return (retval);
206 }
207
208 /*
209 * makech --
210 * Make a change on the screen.
211 */
212 static int
makech(win,wy)213 makech(win, wy)
214 register WINDOW *win;
215 int wy;
216 {
217 static __LDATA blank = {' ', 0};
218 __LDATA *nsp, *csp, *cp, *cep;
219 u_int force;
220 int clsp, nlsp; /* Last space in lines. */
221 int lch, wx, y;
222 char *ce;
223
224 /* Is the cursor still on the end of the last line? */
225 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) {
226 domvcur(ly, lx, ly + 1, 0);
227 ly++;
228 lx = 0;
229 }
230 wx = *win->lines[wy]->firstchp - win->ch_off;
231 if (wx < 0)
232 wx = 0;
233 else if (wx >= win->maxx)
234 return (OK);
235 lch = *win->lines[wy]->lastchp - win->ch_off;
236 if (lch < 0)
237 return (OK);
238 else if (lch >= (int) win->maxx)
239 lch = win->maxx - 1;
240 y = wy + win->begy;
241
242 if (curwin)
243 csp = ␣
244 else
245 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
246
247 nsp = &win->lines[wy]->line[wx];
248 force = win->lines[wy]->flags & __FORCEPAINT;
249 win->lines[wy]->flags &= ~__FORCEPAINT;
250 if (CE && !curwin) {
251 for (cp = &win->lines[wy]->line[win->maxx - 1];
252 cp->ch == ' ' && cp->attr == 0; cp--)
253 if (cp <= win->lines[wy]->line)
254 break;
255 nlsp = cp - win->lines[wy]->line;
256 }
257 if (!curwin)
258 ce = CE;
259 else
260 ce = NULL;
261
262 if (force) {
263 if (CM)
264 tputs(tgoto(CM, lx, ly), 0, __cputchar);
265 else {
266 tputs(HO, 0, __cputchar);
267 __mvcur(0, 0, ly, lx, 1);
268 }
269 }
270
271 while (wx <= lch) {
272 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
273 if (wx <= lch) {
274 while (wx <= lch &&
275 memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
276 nsp++;
277 if (!curwin)
278 ++csp;
279 ++wx;
280 }
281 continue;
282 }
283 break;
284 }
285 domvcur(ly, lx, y, wx + win->begx);
286
287 #ifdef DEBUG
288 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n",
289 wx, ly, lx, y, wx + win->begx, force);
290 #endif
291 ly = y;
292 lx = wx + win->begx;
293 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0)
294 && wx <= lch) {
295
296 if (ce != NULL &&
297 win->maxx + win->begx == curscr->maxx &&
298 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) {
299 /* Check for clear to end-of-line. */
300 cep = &curscr->lines[wy]->line[win->maxx - 1];
301 while (cep->ch == ' ' && cep->attr == 0)
302 if (cep-- <= csp)
303 break;
304 clsp = cep - curscr->lines[wy]->line -
305 win->begx * __LDATASIZE;
306 #ifdef DEBUG
307 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp);
308 #endif
309 if ((clsp - nlsp >= strlen(CE)
310 && clsp < win->maxx * __LDATASIZE) ||
311 wy == win->maxy - 1) {
312 if (curscr->flags & __WSTANDOUT) {
313 tputs(SE, 0, __cputchar);
314 curscr->flags &= ~__WSTANDOUT;
315 }
316 tputs(CE, 0, __cputchar);
317 lx = wx + win->begx;
318 while (wx++ <= clsp) {
319 csp->ch = ' ';
320 csp->attr = 0;
321 csp++;
322 }
323 return (OK);
324 }
325 ce = NULL;
326 }
327
328 /*
329 * Enter/exit standout mode as appropriate.
330 * XXX
331 * Should use UC if SO/SE not available.
332 */
333 if (nsp->attr & __STANDOUT) {
334 if (!(curscr->flags & __WSTANDOUT) &&
335 SO != NULL && SE != NULL) {
336 tputs(SO, 0, __cputchar);
337 curscr->flags |= __WSTANDOUT;
338 }
339 } else
340 if (curscr->flags & __WSTANDOUT &&
341 SE != NULL) {
342 tputs(SE, 0, __cputchar);
343 curscr->flags &= ~__WSTANDOUT;
344 }
345
346 wx++;
347 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin)
348 if (win->flags & __SCROLLOK) {
349 if (curscr->flags & __WSTANDOUT
350 && win->flags & __ENDLINE)
351 if (!MS) {
352 tputs(SE, 0,
353 __cputchar);
354 curscr->flags &=
355 ~__WSTANDOUT;
356 }
357 if (!(win->flags & __SCROLLWIN)) {
358 if (!curwin) {
359 csp->attr = nsp->attr;
360 putchar(csp->ch = nsp->ch);
361 } else
362 putchar(nsp->ch);
363 }
364 if (wx + win->begx < curscr->maxx) {
365 domvcur(ly, wx + win->begx,
366 win->begy + win->maxy - 1,
367 win->begx + win->maxx - 1);
368 }
369 ly = win->begy + win->maxy - 1;
370 lx = win->begx + win->maxx - 1;
371 return (OK);
372 }
373 if (wx < win->maxx || wy < win->maxy - 1 ||
374 !(win->flags & __SCROLLWIN)) {
375 if (!curwin) {
376 csp->attr = nsp->attr;
377 putchar(csp->ch = nsp->ch);
378 csp++;
379 } else
380 putchar(nsp->ch);
381 }
382 #ifdef DEBUG
383 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177);
384 #endif
385 if (UC && (nsp->attr & __STANDOUT)) {
386 putchar('\b');
387 tputs(UC, 0, __cputchar);
388 }
389 nsp++;
390 #ifdef DEBUG
391 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
392 #endif
393 }
394 if (lx == wx + win->begx) /* If no change. */
395 break;
396 lx = wx + win->begx;
397 if (lx >= COLS && AM)
398 lx = COLS - 1;
399 else if (wx >= win->maxx) {
400 domvcur(ly, lx, ly, win->maxx + win->begx - 1);
401 lx = win->maxx + win->begx - 1;
402 }
403
404 #ifdef DEBUG
405 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
406 #endif
407 }
408
409 /* Don't leave the screen in standout mode. */
410 if (curscr->flags & __WSTANDOUT) {
411 tputs(SE, 0, __cputchar);
412 curscr->flags &= ~__WSTANDOUT;
413 }
414 return (OK);
415 }
416
417 /*
418 * domvcur --
419 * Do a mvcur, leaving standout mode if necessary.
420 */
421 static void
domvcur(oy,ox,ny,nx)422 domvcur(oy, ox, ny, nx)
423 int oy, ox, ny, nx;
424 {
425 if (curscr->flags & __WSTANDOUT && !MS) {
426 tputs(SE, 0, __cputchar);
427 curscr->flags &= ~__WSTANDOUT;
428 }
429
430 __mvcur(oy, ox, ny, nx, 1);
431 }
432
433 /*
434 * Quickch() attempts to detect a pattern in the change of the window
435 * in order to optimize the change, e.g., scroll n lines as opposed to
436 * repainting the screen line by line.
437 */
438
439 static void
quickch(win)440 quickch(win)
441 WINDOW *win;
442 {
443 #define THRESH (int) win->maxy / 4
444
445 register __LINE *clp, *tmp1, *tmp2;
446 register int bsize, curs, curw, starts, startw, i, j;
447 int n, target, cur_period, bot, top, sc_region;
448 __LDATA buf[1024];
449 u_int blank_hash;
450
451 /*
452 * Find how many lines from the top of the screen are unchanged.
453 */
454 for (top = 0; top < win->maxy; top++)
455 if (win->lines[top]->flags & __FORCEPAINT ||
456 win->lines[top]->hash != curscr->lines[top]->hash
457 || memcmp(win->lines[top]->line,
458 curscr->lines[top]->line,
459 win->maxx * __LDATASIZE) != 0)
460 break;
461 else
462 win->lines[top]->flags &= ~__ISDIRTY;
463 /*
464 * Find how many lines from bottom of screen are unchanged.
465 */
466 for (bot = win->maxy - 1; bot >= 0; bot--)
467 if (win->lines[bot]->flags & __FORCEPAINT ||
468 win->lines[bot]->hash != curscr->lines[bot]->hash
469 || memcmp(win->lines[bot]->line,
470 curscr->lines[bot]->line,
471 win->maxx * __LDATASIZE) != 0)
472 break;
473 else
474 win->lines[bot]->flags &= ~__ISDIRTY;
475
476 #ifdef NO_JERKINESS
477 /*
478 * If we have a bottom unchanged region return. Scrolling the
479 * bottom region up and then back down causes a screen jitter.
480 * This will increase the number of characters sent to the screen
481 * but it looks better.
482 */
483 if (bot < win->maxy - 1)
484 return;
485 #endif /* NO_JERKINESS */
486
487 /*
488 * Search for the largest block of text not changed.
489 * Invariants of the loop:
490 * - Startw is the index of the beginning of the examined block in win.
491 * - Starts is the index of the beginning of the examined block in
492 * curscr.
493 * - Curs is the index of one past the end of the exmined block in win.
494 * - Curw is the index of one past the end of the exmined block in
495 * curscr.
496 * - bsize is the current size of the examined block.
497 */
498 for (bsize = bot - top; bsize >= THRESH; bsize--) {
499 for (startw = top; startw <= bot - bsize; startw++)
500 for (starts = top; starts <= bot - bsize;
501 starts++) {
502 for (curw = startw, curs = starts;
503 curs < starts + bsize; curw++, curs++)
504 if (win->lines[curw]->flags &
505 __FORCEPAINT ||
506 (win->lines[curw]->hash !=
507 curscr->lines[curs]->hash ||
508 memcmp(win->lines[curw]->line,
509 curscr->lines[curs]->line,
510 win->maxx * __LDATASIZE) != 0))
511 break;
512 if (curs == starts + bsize)
513 goto done;
514 }
515 }
516 done:
517 /* Did not find anything */
518 if (bsize < THRESH)
519 return;
520
521 #ifdef DEBUG
522 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n",
523 bsize, starts, startw, curw, curs, top, bot);
524 #endif
525
526 /*
527 * Make sure that there is no overlap between the bottom and top
528 * regions and the middle scrolled block.
529 */
530 if (bot < curs)
531 bot = curs - 1;
532 if (top > starts)
533 top = starts;
534
535 n = startw - starts;
536
537 #ifdef DEBUG
538 __CTRACE("#####################################\n");
539 for (i = 0; i < curscr->maxy; i++) {
540 __CTRACE("C: %d:", i);
541 __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
542 for (j = 0; j < curscr->maxx; j++)
543 __CTRACE("%c",
544 curscr->lines[i]->line[j].ch);
545 __CTRACE("\n");
546 for (j = 0; j < curscr->maxx; j++)
547 __CTRACE("%x",
548 curscr->lines[i]->line[j].attr);
549 __CTRACE("\n");
550 __CTRACE("W: %d:", i);
551 __CTRACE(" 0x%x \n", win->lines[i]->hash);
552 __CTRACE(" 0x%x ", win->lines[i]->flags);
553 for (j = 0; j < win->maxx; j++)
554 __CTRACE("%c",
555 win->lines[i]->line[j].ch);
556 __CTRACE("\n");
557 for (j = 0; j < win->maxx; j++)
558 __CTRACE("%x",
559 win->lines[i]->line[j].attr);
560 __CTRACE("\n");
561 }
562 #endif
563
564 /* So we don't have to call __hash() each time */
565 for (i = 0; i < win->maxx; i++) {
566 buf[i].ch = ' ';
567 buf[i].attr = 0;
568 }
569 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE);
570
571 /*
572 * Perform the rotation to maintain the consistency of curscr.
573 * This is hairy since we are doing an *in place* rotation.
574 * Invariants of the loop:
575 * - I is the index of the current line.
576 * - Target is the index of the target of line i.
577 * - Tmp1 points to current line (i).
578 * - Tmp2 and points to target line (target);
579 * - Cur_period is the index of the end of the current period.
580 * (see below).
581 *
582 * There are 2 major issues here that make this rotation non-trivial:
583 * 1. Scrolling in a scrolling region bounded by the top
584 * and bottom regions determined (whose size is sc_region).
585 * 2. As a result of the use of the mod function, there may be a
586 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
587 * 0 to 2, which then causes all odd lines not to be rotated.
588 * To remedy this, an index of the end ( = beginning) of the
589 * current 'period' is kept, cur_period, and when it is reached,
590 * the next period is started from cur_period + 1 which is
591 * guaranteed not to have been reached since that would mean that
592 * all records would have been reached. (think about it...).
593 *
594 * Lines in the rotation can have 3 attributes which are marked on the
595 * line so that curscr is consistent with the visual screen.
596 * 1. Not dirty -- lines inside the scrolled block, top region or
597 * bottom region.
598 * 2. Blank lines -- lines in the differential of the scrolling
599 * region adjacent to top and bot regions
600 * depending on scrolling direction.
601 * 3. Dirty line -- all other lines are marked dirty.
602 */
603 sc_region = bot - top + 1;
604 i = top;
605 tmp1 = curscr->lines[top];
606 cur_period = top;
607 for (j = top; j <= bot; j++) {
608 target = (i - top + n + sc_region) % sc_region + top;
609 tmp2 = curscr->lines[target];
610 curscr->lines[target] = tmp1;
611 /* Mark block as clean and blank out scrolled lines. */
612 clp = curscr->lines[target];
613 #ifdef DEBUG
614 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
615 n, startw, curw, i, target);
616 #endif
617 if ((target >= startw && target < curw) || target < top
618 || target > bot) {
619 #ifdef DEBUG
620 __CTRACE("-- notdirty");
621 #endif
622 win->lines[target]->flags &= ~__ISDIRTY;
623 } else if ((n > 0 && target >= top && target < top + n) ||
624 (n < 0 && target <= bot && target > bot + n)) {
625 if (clp->hash != blank_hash || memcmp(clp->line,
626 buf, win->maxx * __LDATASIZE) !=0) {
627 (void)memcpy(clp->line, buf,
628 win->maxx * __LDATASIZE);
629 #ifdef DEBUG
630 __CTRACE("-- blanked out: dirty");
631 #endif
632 clp->hash = blank_hash;
633 __touchline(win, target, 0, win->maxx - 1, 0);
634 } else {
635 __touchline(win, target, 0, win->maxx - 1, 0);
636 #ifdef DEBUG
637 __CTRACE(" -- blank line already: dirty");
638 #endif
639 }
640 } else {
641 #ifdef DEBUG
642 __CTRACE(" -- dirty");
643 #endif
644 __touchline(win, target, 0, win->maxx - 1, 0);
645 }
646 #ifdef DEBUG
647 __CTRACE("\n");
648 #endif
649 if (target == cur_period) {
650 i = target + 1;
651 tmp1 = curscr->lines[i];
652 cur_period = i;
653 } else {
654 tmp1 = tmp2;
655 i = target;
656 }
657 }
658 #ifdef DEBUG
659 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
660 for (i = 0; i < curscr->maxy; i++) {
661 __CTRACE("C: %d:", i);
662 for (j = 0; j < curscr->maxx; j++)
663 __CTRACE("%c",
664 curscr->lines[i]->line[j].ch);
665 __CTRACE("\n");
666 __CTRACE("W: %d:", i);
667 for (j = 0; j < win->maxx; j++)
668 __CTRACE("%c", win->lines[i]->line[j].ch);
669 __CTRACE("\n");
670 }
671 #endif
672 if (n != 0) {
673 WINDOW *wp;
674 scrolln(win, starts, startw, curs, bot, top);
675 /*
676 * Need to repoint any subwindow lines to the rotated
677 * line structured.
678 */
679 for (wp = curscr->nextp; wp != curscr; wp = wp->nextp)
680 __set_subwin(wp->orig, wp);
681 }
682 }
683
684 /*
685 * scrolln --
686 * Scroll n lines, where n is starts - startw.
687 */
688 static void
scrolln(win,starts,startw,curs,bot,top)689 scrolln(win, starts, startw, curs, bot, top)
690 WINDOW *win;
691 int starts, startw, curs, bot, top;
692 {
693 int i, oy, ox, n;
694
695 oy = curscr->cury;
696 ox = curscr->curx;
697 n = starts - startw;
698
699 /*
700 * XXX
701 * The initial tests that set __noqch don't let us reach here unless
702 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr
703 * scrolling can only shift the entire scrolling region, not just a
704 * part of it, which means that the quickch() routine is going to be
705 * sadly disappointed in us if we don't have CS as well.
706 *
707 * If CS, HO and SF/sf are set, can use the scrolling region. Because
708 * the cursor position after CS is undefined, we need HO which gives us
709 * the ability to move to somewhere without knowledge of the current
710 * location of the cursor. Still call __mvcur() anyway, to update its
711 * idea of where the cursor is.
712 *
713 * When the scrolling region has been set, the cursor has to be at the
714 * last line of the region to make the scroll happen.
715 *
716 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr
717 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not
718 * SF/SR. So, if we're scrolling almost all of the screen, try and use
719 * AL/DL, otherwise use the scrolling region. The "almost all" is a
720 * shameless hack for vi.
721 */
722 if (n > 0) {
723 if (CS != NULL && HO != NULL && (SF != NULL ||
724 (AL == NULL || DL == NULL ||
725 top > 3 || bot + 3 < win->maxy) && sf != NULL)) {
726 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar);
727 __mvcur(oy, ox, 0, 0, 1);
728 tputs(HO, 0, __cputchar);
729 __mvcur(0, 0, bot, 0, 1);
730 if (SF != NULL)
731 tputs(__tscroll(SF, n, 0), 0, __cputchar);
732 else
733 for (i = 0; i < n; i++)
734 tputs(sf, 0, __cputchar);
735 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar);
736 __mvcur(bot, 0, 0, 0, 1);
737 tputs(HO, 0, __cputchar);
738 __mvcur(0, 0, oy, ox, 1);
739 return;
740 }
741
742 /* Scroll up the block. */
743 if (SF != NULL && top == 0) {
744 __mvcur(oy, ox, bot, 0, 1);
745 tputs(__tscroll(SF, n, 0), 0, __cputchar);
746 } else if (DL != NULL) {
747 __mvcur(oy, ox, top, 0, 1);
748 tputs(__tscroll(DL, n, 0), 0, __cputchar);
749 } else if (dl != NULL) {
750 __mvcur(oy, ox, top, 0, 1);
751 for (i = 0; i < n; i++)
752 tputs(dl, 0, __cputchar);
753 } else if (sf != NULL && top == 0) {
754 __mvcur(oy, ox, bot, 0, 1);
755 for (i = 0; i < n; i++)
756 tputs(sf, 0, __cputchar);
757 } else
758 abort();
759
760 /* Push down the bottom region. */
761 __mvcur(top, 0, bot - n + 1, 0, 1);
762 if (AL != NULL)
763 tputs(__tscroll(AL, n, 0), 0, __cputchar);
764 else if (al != NULL)
765 for (i = 0; i < n; i++)
766 tputs(al, 0, __cputchar);
767 else
768 abort();
769 __mvcur(bot - n + 1, 0, oy, ox, 1);
770 } else {
771 /*
772 * !!!
773 * n < 0
774 *
775 * If CS, HO and SR/sr are set, can use the scrolling region.
776 * See the above comments for details.
777 */
778 if (CS != NULL && HO != NULL && (SR != NULL ||
779 (AL == NULL || DL == NULL ||
780 top > 3 || bot + 3 < win->maxy) && sr != NULL)) {
781 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar);
782 __mvcur(oy, ox, 0, 0, 1);
783 tputs(HO, 0, __cputchar);
784 __mvcur(0, 0, top, 0, 1);
785
786 if (SR != NULL)
787 tputs(__tscroll(SR, -n, 0), 0, __cputchar);
788 else
789 for (i = n; i < 0; i++)
790 tputs(sr, 0, __cputchar);
791 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar);
792 __mvcur(top, 0, 0, 0, 1);
793 tputs(HO, 0, __cputchar);
794 __mvcur(0, 0, oy, ox, 1);
795 return;
796 }
797
798 /* Preserve the bottom lines. */
799 __mvcur(oy, ox, bot + n + 1, 0, 1);
800 if (SR != NULL && bot == win->maxy)
801 tputs(__tscroll(SR, -n, 0), 0, __cputchar);
802 else if (DL != NULL)
803 tputs(__tscroll(DL, -n, 0), 0, __cputchar);
804 else if (dl != NULL)
805 for (i = n; i < 0; i++)
806 tputs(dl, 0, __cputchar);
807 else if (sr != NULL && bot == win->maxy)
808 for (i = n; i < 0; i++)
809 tputs(sr, 0, __cputchar);
810 else
811 abort();
812
813 /* Scroll the block down. */
814 __mvcur(bot + n + 1, 0, top, 0, 1);
815 if (AL != NULL)
816 tputs(__tscroll(AL, -n, 0), 0, __cputchar);
817 else if (al != NULL)
818 for (i = n; i < 0; i++)
819 tputs(al, 0, __cputchar);
820 else
821 abort();
822 __mvcur(top, 0, oy, ox, 1);
823 }
824 }
825