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