1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Edward Wang at The University of California, Berkeley.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)wwscroll.c 8.1 (Berkeley) 06/06/93";
13 #endif /* not lint */
14
15 #include "ww.h"
16 #include "tt.h"
17
wwscroll(w,n)18 wwscroll(w, n)
19 register struct ww *w;
20 int n;
21 {
22 register dir;
23 register top;
24
25 if (n == 0)
26 return;
27 dir = n < 0 ? -1 : 1;
28 top = w->ww_b.t - n;
29 if (top > w->ww_w.t)
30 top = w->ww_w.t;
31 else if (top + w->ww_b.nr < w->ww_w.b)
32 top = w->ww_w.b - w->ww_b.nr;
33 n = abs(top - w->ww_b.t);
34 if (n < w->ww_i.nr) {
35 while (--n >= 0) {
36 (void) wwscroll1(w, w->ww_i.t, w->ww_i.b, dir, 0);
37 w->ww_buf += dir;
38 w->ww_b.t -= dir;
39 w->ww_b.b -= dir;
40 }
41 } else {
42 w->ww_buf -= top - w->ww_b.t;
43 w->ww_b.t = top;
44 w->ww_b.b = top + w->ww_b.nr;
45 wwredrawwin(w);
46 }
47 }
48
49 /*
50 * Scroll one line, between 'row1' and 'row2', in direction 'dir'.
51 * Don't adjust ww_scroll.
52 * And don't redraw 'leaveit' lines.
53 */
wwscroll1(w,row1,row2,dir,leaveit)54 wwscroll1(w, row1, row2, dir, leaveit)
55 register struct ww *w;
56 int row1, row2, dir;
57 int leaveit;
58 {
59 register i;
60 int row1x, row2x;
61 int nvis;
62 int nvismax;
63 int scrolled = 0;
64
65 /*
66 * See how many lines on the screen are affected.
67 * And calculate row1x, row2x, and left at the same time.
68 */
69 for (i = row1; i < row2 && w->ww_nvis[i] == 0; i++)
70 ;
71 if (i >= row2) /* can't do any fancy stuff */
72 goto out;
73 row1x = i;
74 for (i = row2 - 1; i >= row1 && w->ww_nvis[i] == 0; i--)
75 ;
76 if (i <= row1x)
77 goto out; /* just one line is easy */
78 row2x = i + 1;
79
80 /*
81 * See how much of this window is visible.
82 */
83 nvismax = wwncol * (row2x - row1x);
84 nvis = 0;
85 for (i = row1x; i < row2x; i++)
86 nvis += w->ww_nvis[i];
87
88 /*
89 * If it's a good idea to scroll and the terminal can, then do it.
90 */
91 if (nvis < nvismax / 2)
92 goto no_scroll; /* not worth it */
93 if ((dir > 0 ? tt.tt_scroll_down == 0 : tt.tt_scroll_up == 0) ||
94 (tt.tt_scroll_top != row1x || tt.tt_scroll_bot != row2x - 1) &&
95 tt.tt_setscroll == 0)
96 if (tt.tt_delline == 0 || tt.tt_insline == 0)
97 goto no_scroll;
98 xxscroll(dir, row1x, row2x);
99 scrolled = 1;
100 /*
101 * Fix up the old screen.
102 */
103 {
104 register union ww_char *tmp;
105 register union ww_char **cpp, **cqq;
106
107 if (dir > 0) {
108 cpp = &wwos[row1x];
109 cqq = cpp + 1;
110 tmp = *cpp;
111 for (i = row2x - row1x; --i > 0;)
112 *cpp++ = *cqq++;
113 *cpp = tmp;
114 } else {
115 cpp = &wwos[row2x];
116 cqq = cpp - 1;
117 tmp = *cqq;
118 for (i = row2x - row1x; --i > 0;)
119 *--cpp = *--cqq;
120 *cqq = tmp;
121 }
122 for (i = wwncol; --i >= 0;)
123 tmp++->c_w = ' ';
124 }
125
126 no_scroll:
127 /*
128 * Fix the new screen.
129 */
130 if (nvis == nvismax) {
131 /*
132 * Can shift whole lines.
133 */
134 if (dir > 0) {
135 {
136 register union ww_char *tmp;
137 register union ww_char **cpp, **cqq;
138
139 cpp = &wwns[row1x];
140 cqq = cpp + 1;
141 tmp = *cpp;
142 for (i = row2x - row1x; --i > 0;)
143 *cpp++ = *cqq++;
144 *cpp = tmp;
145 }
146 if (scrolled) {
147 register char *p, *q;
148
149 p = &wwtouched[row1x];
150 q = p + 1;
151 for (i = row2x - row1x; --i > 0;)
152 *p++ = *q++;
153 *p |= WWU_TOUCHED;
154 } else {
155 register char *p;
156
157 p = &wwtouched[row1x];
158 for (i = row2x - row1x; --i >= 0;)
159 *p++ |= WWU_TOUCHED;
160 }
161 wwredrawwin1(w, row1, row1x, dir);
162 wwredrawwin1(w, row2x - 1, row2 - leaveit, dir);
163 } else {
164 {
165 register union ww_char *tmp;
166 register union ww_char **cpp, **cqq;
167
168 cpp = &wwns[row2x];
169 cqq = cpp - 1;
170 tmp = *cqq;
171 for (i = row2x - row1x; --i > 0;)
172 *--cpp = *--cqq;
173 *cqq = tmp;
174 }
175 if (scrolled) {
176 register char *p, *q;
177
178 p = &wwtouched[row2x];
179 q = p - 1;
180 for (i = row2x - row1x; --i > 0;)
181 *--p = *--q;
182 *q |= WWU_TOUCHED;
183 } else {
184 register char *p;
185
186 p = &wwtouched[row1x];
187 for (i = row2x - row1x; --i >= 0;)
188 *p++ |= WWU_TOUCHED;
189 }
190 wwredrawwin1(w, row1 + leaveit, row1x + 1, dir);
191 wwredrawwin1(w, row2x, row2, dir);
192 }
193 } else {
194 if (scrolled) {
195 register char *p;
196
197 p = &wwtouched[row1x];
198 for (i = row2x - row1x; --i >= 0;)
199 *p++ |= WWU_TOUCHED;
200 }
201 out:
202 if (dir > 0)
203 wwredrawwin1(w, row1, row2 - leaveit, dir);
204 else
205 wwredrawwin1(w, row1 + leaveit, row2, dir);
206 }
207 return scrolled;
208 }
209