Commit | Line | Data |
---|---|---|
60de5df9 | 1 | /* |
46e9ea25 KB |
2 | * Copyright (c) 1983 Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
60de5df9 EW |
11 | */ |
12 | ||
46e9ea25 | 13 | #ifndef lint |
16ea9636 | 14 | static char sccsid[] = "@(#)wwscroll.c 3.19 (Berkeley) %G%"; |
46e9ea25 KB |
15 | #endif /* not lint */ |
16 | ||
577dff1e | 17 | #include "ww.h" |
e908bfac | 18 | #include "tt.h" |
577dff1e | 19 | |
b0d4d9e2 EW |
20 | wwscroll(w, n) |
21 | register struct ww *w; | |
f2a77fe1 | 22 | int n; |
b0d4d9e2 | 23 | { |
f2a77fe1 EW |
24 | register dir; |
25 | register top; | |
b0d4d9e2 EW |
26 | |
27 | if (n == 0) | |
28 | return; | |
29 | dir = n < 0 ? -1 : 1; | |
f2a77fe1 EW |
30 | top = w->ww_b.t - n; |
31 | if (top > w->ww_w.t) | |
32 | top = w->ww_w.t; | |
33 | else if (top + w->ww_b.nr < w->ww_w.b) | |
34 | top = w->ww_w.b - w->ww_b.nr; | |
35 | n = abs(top - w->ww_b.t); | |
19f9784c | 36 | if (n < w->ww_i.nr) { |
b0d4d9e2 | 37 | while (--n >= 0) { |
f2a77fe1 EW |
38 | (void) wwscroll1(w, w->ww_i.t, w->ww_i.b, dir, 0); |
39 | w->ww_buf += dir; | |
40 | w->ww_b.t -= dir; | |
41 | w->ww_b.b -= dir; | |
b0d4d9e2 EW |
42 | } |
43 | } else { | |
f2a77fe1 EW |
44 | w->ww_buf -= top - w->ww_b.t; |
45 | w->ww_b.t = top; | |
46 | w->ww_b.b = top + w->ww_b.nr; | |
b0d4d9e2 EW |
47 | wwredrawwin(w); |
48 | } | |
49 | } | |
50 | ||
577dff1e | 51 | /* |
19f9784c | 52 | * Scroll one line, between 'row1' and 'row2', in direction 'dir'. |
577dff1e | 53 | * Don't adjust ww_scroll. |
b0d4d9e2 | 54 | * And don't redraw 'leaveit' lines. |
577dff1e | 55 | */ |
19f9784c | 56 | wwscroll1(w, row1, row2, dir, leaveit) |
577dff1e | 57 | register struct ww *w; |
19f9784c | 58 | int row1, row2, dir; |
b0d4d9e2 | 59 | int leaveit; |
577dff1e EW |
60 | { |
61 | register i; | |
19f9784c | 62 | int row1x, row2x; |
577dff1e EW |
63 | int nvis; |
64 | int nvismax; | |
16ea9636 EW |
65 | int scrolled = 0; |
66 | int (*scroll_func)(); | |
577dff1e EW |
67 | |
68 | /* | |
69 | * See how many lines on the screen are affected. | |
19f9784c | 70 | * And calculate row1x, row2x, and left at the same time. |
577dff1e | 71 | */ |
19f9784c | 72 | for (i = row1; i < row2 && w->ww_nvis[i] == 0; i++) |
577dff1e | 73 | ; |
19f9784c | 74 | if (i >= row2) /* can't do any fancy stuff */ |
577dff1e | 75 | goto out; |
19f9784c EW |
76 | row1x = i; |
77 | for (i = row2 - 1; i >= row1 && w->ww_nvis[i] == 0; i--) | |
577dff1e | 78 | ; |
19f9784c | 79 | if (i <= row1x) |
577dff1e | 80 | goto out; /* just one line is easy */ |
19f9784c | 81 | row2x = i + 1; |
577dff1e EW |
82 | |
83 | /* | |
84 | * See how much of this window is visible. | |
85 | */ | |
19f9784c | 86 | nvismax = wwncol * (row2x - row1x); |
577dff1e | 87 | nvis = 0; |
19f9784c | 88 | for (i = row1x; i < row2x; i++) |
577dff1e EW |
89 | nvis += w->ww_nvis[i]; |
90 | ||
91 | /* | |
05fb5c3b | 92 | * If it's a good idea to scroll and the terminal can, then do it. |
16ea9636 EW |
93 | * We handle retain (da and db) by putting the burden on scrolling up, |
94 | * which is the less common operation. It must ensure that | |
95 | * text is not pushed below the screen, so scrolling down doesn't | |
96 | * have to worry about it. | |
577dff1e | 97 | */ |
16ea9636 EW |
98 | if (nvis < nvismax / 2) |
99 | goto no_scroll; /* not worth it */ | |
100 | /* | |
101 | * Try scrolling region (or scrolling the whole screen) first. | |
102 | * Can we assume "sr" doesn't push text below the screen | |
103 | * so we don't have to worry about retain below? | |
104 | * What about scrolling down with a newline? It probably does | |
105 | * push text above (with da). Scrolling up would then have | |
106 | * to take care of that. | |
107 | * It's easy to be fool proof, but that slows things down. | |
108 | * The current solution is to disallow tt_scroll_up if da or db is true | |
109 | * but cs (scrolling region) is not. Again, we sacrifice scrolling | |
110 | * up in favor of scrolling down. The idea is having scrolling regions | |
111 | * probably means we can scroll (even the whole screen) with impunity. | |
112 | * This lets us work efficiently on simple terminals (use newline | |
113 | * on the bottom to scroll), on any terminal without retain, and | |
114 | * on vt100 style scrolling regions (I think). | |
115 | */ | |
116 | if (scroll_func = dir > 0 ? tt.tt_scroll_down : tt.tt_scroll_up) { | |
117 | if (tt.tt_scroll_top != row1x || tt.tt_scroll_bot != row2x - 1) | |
118 | if (tt.tt_setscroll == 0) | |
119 | scroll_func = 0; | |
120 | else | |
121 | (*tt.tt_setscroll)(row1x, row2x - 1); | |
122 | if (scroll_func) { | |
123 | (*scroll_func)(); | |
124 | goto did_scroll; | |
125 | } | |
126 | } | |
127 | /* | |
128 | * Try insert/delete line. | |
129 | * Don't worry about retain when scrolling down, | |
130 | * but do worry when scrolling up, for hp2621. | |
131 | */ | |
132 | if (tt.tt_delline == 0 || tt.tt_insline == 0) | |
133 | goto no_scroll; | |
134 | if (dir > 0) { | |
135 | (*tt.tt_move)(row1x, 0); | |
136 | (*tt.tt_delline)(); | |
137 | if (row2x < wwnrow) { | |
138 | (*tt.tt_move)(row2x - 1, 0); | |
05fb5c3b EW |
139 | (*tt.tt_insline)(); |
140 | } | |
16ea9636 EW |
141 | } else { |
142 | if (tt.tt_retain || row2x != wwnrow) { | |
143 | (*tt.tt_move)(row2x - 1, 0); | |
144 | (*tt.tt_delline)(); | |
145 | } | |
146 | (*tt.tt_move)(row1x, 0); | |
147 | (*tt.tt_insline)(); | |
05fb5c3b | 148 | } |
16ea9636 EW |
149 | did_scroll: |
150 | scrolled = 1; | |
05fb5c3b EW |
151 | /* |
152 | * Fix up the old screen. | |
153 | */ | |
16ea9636 | 154 | { |
05fb5c3b EW |
155 | register union ww_char *tmp; |
156 | register union ww_char **cpp, **cqq; | |
157 | ||
158 | if (dir > 0) { | |
f2a77fe1 | 159 | cpp = &wwos[row1x]; |
577dff1e EW |
160 | cqq = cpp + 1; |
161 | tmp = *cpp; | |
19f9784c | 162 | for (i = row2x - row1x; --i > 0;) |
577dff1e EW |
163 | *cpp++ = *cqq++; |
164 | *cpp = tmp; | |
577dff1e | 165 | } else { |
f2a77fe1 | 166 | cpp = &wwos[row2x]; |
19f9784c | 167 | cqq = cpp - 1; |
577dff1e | 168 | tmp = *cqq; |
19f9784c | 169 | for (i = row2x - row1x; --i > 0;) |
577dff1e EW |
170 | *--cpp = *--cqq; |
171 | *cqq = tmp; | |
577dff1e | 172 | } |
f2a77fe1 EW |
173 | for (i = wwncol; --i >= 0;) |
174 | tmp++->c_w = ' '; | |
577dff1e EW |
175 | } |
176 | ||
16ea9636 | 177 | no_scroll: |
577dff1e EW |
178 | /* |
179 | * Fix the new screen. | |
180 | */ | |
181 | if (nvis == nvismax) { | |
182 | /* | |
183 | * Can shift whole lines. | |
184 | */ | |
577dff1e | 185 | if (dir > 0) { |
861cd1ed EW |
186 | { |
187 | register union ww_char *tmp; | |
188 | register union ww_char **cpp, **cqq; | |
189 | ||
f2a77fe1 | 190 | cpp = &wwns[row1x]; |
861cd1ed EW |
191 | cqq = cpp + 1; |
192 | tmp = *cpp; | |
19f9784c | 193 | for (i = row2x - row1x; --i > 0;) |
861cd1ed EW |
194 | *cpp++ = *cqq++; |
195 | *cpp = tmp; | |
196 | } | |
16ea9636 | 197 | if (scrolled) { |
861cd1ed EW |
198 | register char *p, *q; |
199 | ||
f2a77fe1 | 200 | p = &wwtouched[row1x]; |
861cd1ed | 201 | q = p + 1; |
19f9784c | 202 | for (i = row2x - row1x; --i > 0;) |
861cd1ed | 203 | *p++ = *q++; |
04d70db4 | 204 | *p |= WWU_TOUCHED; |
26008571 EW |
205 | } else { |
206 | register char *p; | |
207 | ||
f2a77fe1 | 208 | p = &wwtouched[row1x]; |
19f9784c | 209 | for (i = row2x - row1x; --i >= 0;) |
04d70db4 | 210 | *p++ |= WWU_MAJOR|WWU_TOUCHED; |
861cd1ed | 211 | } |
f2a77fe1 EW |
212 | wwredrawwin1(w, row1, row1x, dir); |
213 | wwredrawwin1(w, row2x - 1, row2 - leaveit, dir); | |
577dff1e | 214 | } else { |
861cd1ed EW |
215 | { |
216 | register union ww_char *tmp; | |
217 | register union ww_char **cpp, **cqq; | |
218 | ||
f2a77fe1 | 219 | cpp = &wwns[row2x]; |
19f9784c | 220 | cqq = cpp - 1; |
861cd1ed | 221 | tmp = *cqq; |
19f9784c | 222 | for (i = row2x - row1x; --i > 0;) |
861cd1ed EW |
223 | *--cpp = *--cqq; |
224 | *cqq = tmp; | |
225 | } | |
16ea9636 | 226 | if (scrolled) { |
861cd1ed EW |
227 | register char *p, *q; |
228 | ||
f2a77fe1 | 229 | p = &wwtouched[row2x]; |
19f9784c EW |
230 | q = p - 1; |
231 | for (i = row2x - row1x; --i > 0;) | |
861cd1ed | 232 | *--p = *--q; |
5360b004 | 233 | *q |= WWU_TOUCHED; |
26008571 EW |
234 | } else { |
235 | register char *p; | |
236 | ||
f2a77fe1 | 237 | p = &wwtouched[row1x]; |
19f9784c | 238 | for (i = row2x - row1x; --i >= 0;) |
5360b004 | 239 | *p++ |= WWU_MAJOR|WWU_TOUCHED; |
861cd1ed | 240 | } |
f2a77fe1 EW |
241 | wwredrawwin1(w, row1 + leaveit, row1x + 1, dir); |
242 | wwredrawwin1(w, row2x, row2, dir); | |
577dff1e EW |
243 | } |
244 | } else { | |
16ea9636 | 245 | if (scrolled) { |
5360b004 EW |
246 | register char *p; |
247 | ||
248 | p = &wwtouched[row1x]; | |
249 | for (i = row2x - row1x; --i >= 0;) | |
250 | *p++ |= WWU_MAJOR|WWU_TOUCHED; | |
251 | } | |
577dff1e EW |
252 | out: |
253 | if (dir > 0) | |
f2a77fe1 | 254 | wwredrawwin1(w, row1, row2 - leaveit, dir); |
577dff1e | 255 | else |
f2a77fe1 | 256 | wwredrawwin1(w, row1 + leaveit, row2, dir); |
577dff1e | 257 | } |
16ea9636 | 258 | return scrolled; |
577dff1e | 259 | } |