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 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 */ 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