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